@@ -70,24 +70,6 @@ public class FIXMessageDecoder implements MessageDecoder {
7070 private int position ;
7171 private final String charsetEncoding ;
7272
73- static class BufPos {
74- final int _offset ;
75- final int _length ;
76-
77- /**
78- * @param offset
79- * @param length
80- */
81- public BufPos (int offset , int length ) {
82- _offset = offset ;
83- _length = length ;
84- }
85-
86- public String toString () {
87- return _offset + "," + _length ;
88- }
89- }
90-
9173 private void resetState () {
9274 state = SEEKING_HEADER ;
9375 bodyLength = 0 ;
@@ -106,14 +88,13 @@ public FIXMessageDecoder(String charset, String delimiter) throws UnsupportedEnc
10688 charsetEncoding = CharsetSupport .validate (charset );
10789 HEADER_PATTERN = getBytes ("8=FIXt.?.?" + delimiter + "9=" );
10890 CHECKSUM_PATTERN = getBytes ("10=???" + delimiter );
109- LOGON_PATTERN = getBytes (" \001 35 =A" + delimiter );
91+ LOGON_PATTERN = getBytes (delimiter + "35 =A" + delimiter );
11092 resetState ();
11193 }
11294
11395 public MessageDecoderResult decodable (IoSession session , IoBuffer in ) {
114- BufPos bufPos = indexOf (in , in .position (), HEADER_PATTERN );
115- int headerOffset = bufPos ._offset ;
116- return headerOffset != -1 ? MessageDecoderResult .OK :
96+ boolean hasHeader = indexOf (in , in .position (), HEADER_PATTERN ) != -1L ;
97+ return hasHeader ? MessageDecoderResult .OK :
11798 (in .remaining () > MAX_UNDECODED_DATA_LENGTH ? MessageDecoderResult .NOT_OK : MessageDecoderResult .NEED_DATA );
11899 }
119100
@@ -148,18 +129,19 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
148129 while (in .hasRemaining () && !messageFound ) {
149130 if (state == SEEKING_HEADER ) {
150131
151- BufPos bufPos = indexOf (in , position , HEADER_PATTERN );
152- int headerOffset = bufPos ._offset ;
153- if (headerOffset == -1 ) {
132+ long headerPos = indexOf (in , position , HEADER_PATTERN );
133+ if (headerPos == -1L ) {
154134 break ;
155135 }
136+ int headerOffset = (int )headerPos ;
137+ int headerLength = (int )(headerPos >>> 32 );
156138 in .position (headerOffset );
157139
158140 if (log .isDebugEnabled ()) {
159141 log .debug ("detected header: " + getBufferDebugInfo (in ));
160142 }
161143
162- position = headerOffset + bufPos . _length ;
144+ position = headerOffset + headerLength ;
163145 state = PARSING_LENGTH ;
164146 }
165147
@@ -201,7 +183,7 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
201183 }
202184
203185 if (state == PARSING_CHECKSUM ) {
204- if (startsWith (in , position , CHECKSUM_PATTERN ) > 0 ) {
186+ if (matches (in , position , CHECKSUM_PATTERN ) > 0 ) {
205187 // we are trying to parse the checksum but should
206188 // check if the CHECKSUM_PATTERN is preceded by SOH
207189 // or if the pattern just occurs inside of another field
@@ -268,12 +250,12 @@ private boolean hasRemaining(IoBuffer in) {
268250 return position < in .limit ();
269251 }
270252
271- private static int minMaskLength (byte [] data ) {
253+ private static int minPatternLength (byte [] pattern ) {
272254 int len = 0 ;
273- for (byte aChar : data ) {
274- if (Character . isLetter ( aChar ) && Character . isLowerCase ( aChar ) )
275- continue ;
276- ++ len ;
255+ for (byte b : pattern ) {
256+ if (b < 'a' || b > 'z' ) { // if not optional character (lowercase )
257+ len ++ ;
258+ }
277259 }
278260 return len ;
279261 }
@@ -306,53 +288,65 @@ private void handleError(IoBuffer buffer, int recoveryPosition, String text,
306288 }
307289
308290 private boolean isLogon (IoBuffer buffer ) {
309- BufPos bufPos = indexOf (buffer , buffer .position (), LOGON_PATTERN );
310- return bufPos ._offset != -1 ;
291+ return indexOf (buffer , buffer .position (), LOGON_PATTERN ) != -1L ;
311292 }
312293
313- private static BufPos indexOf (IoBuffer buffer , int position , byte [] data ) {
314- for (int offset = position , limit = buffer .limit () - minMaskLength (data ) + 1 ; offset < limit ; offset ++) {
315- int length ;
316- if (buffer .get (offset ) == data [0 ] && (length = startsWith (buffer , offset , data )) > 0 ) {
317- return new BufPos (offset , length );
294+ /**
295+ * Searches for the given pattern within a buffer,
296+ * starting at the given buffer position.
297+ *
298+ * @param buffer the buffer to search within
299+ * @param position the buffer position to start searching at
300+ * @param pattern the pattern to search for
301+ * @return a long value whose lower 32 bits contain the index of the
302+ * found pattern, and upper 32 bits contain the found pattern length;
303+ * if the pattern is not found at all, returns -1L
304+ */
305+ private static long indexOf (IoBuffer buffer , int position , byte [] pattern ) {
306+ int length ;
307+ byte first = pattern [0 ];
308+ for (int limit = buffer .limit () - minPatternLength (pattern ) + 1 ; position < limit ; position ++) {
309+ if (buffer .get (position ) == first && (length = matches (buffer , position , pattern )) > 0 ) {
310+ return (long )length << 32 | position ;
318311 }
319312 }
320- return new BufPos (- 1 , 0 ) ;
313+ return - 1L ;
321314 }
322315
323316 /**
324- * Checks to see if the byte_buffer[buffer_offset] starts with data[]. The
325- * character ? is a one byte wildcard, lowercase letters are optional.
317+ * Checks if the buffer at the given offset matches the given pattern.
318+ * The character '?' is a one byte wildcard, and lowercase letters are optional.
326319 *
327- * @param buffer
328- * @param bufferOffset
329- * @param data
330- * @return
320+ * @param buffer the buffer to check
321+ * @param bufferOffset the buffer offset at which to check
322+ * @param pattern the pattern to try matching
323+ * @return the length of the matched pattern, or -1 if there is no match
331324 */
332- private static int startsWith (IoBuffer buffer , int bufferOffset , byte [] data ) {
333- if (bufferOffset + minMaskLength ( data ) > buffer .limit ()) {
325+ private static int matches (IoBuffer buffer , int bufferOffset , byte [] pattern ) {
326+ if (bufferOffset + minPatternLength ( pattern ) > buffer .limit ()) {
334327 return -1 ;
335328 }
336329 final int initOffset = bufferOffset ;
337- int dataOffset = 0 ;
338- for (int bufferLimit = buffer .limit (); dataOffset < data .length
339- && bufferOffset < bufferLimit ; dataOffset ++, bufferOffset ++) {
340- if ( buffer . get ( bufferOffset ) != data [ dataOffset ] && data [ dataOffset ] != '?' ) {
341- // Now check for optional characters, at this point we know we didn't
342- // match, so we can just check to see if we failed a match on an optional character,
343- // and if so then just rewind the buffer one byte and keep going.
344- if ( Character . toUpperCase ( data [ dataOffset ]) == buffer . get ( bufferOffset ))
345- continue ;
346- // Didn't match the optional character, so act like it was not included and keep going
347- if ( Character . isLetter ( data [ dataOffset ]) && Character . isLowerCase ( data [ dataOffset ])) {
348- -- bufferOffset ;
349- continue ;
350- }
351- return - 1 ;
330+ int patternOffset = 0 ;
331+ for (int bufferLimit = buffer .limit (); patternOffset < pattern .length
332+ && bufferOffset < bufferLimit ; patternOffset ++, bufferOffset ++) {
333+ byte b = pattern [ patternOffset ];
334+ // check exact character match or wildcard match
335+ if ( buffer . get ( bufferOffset ) == b || b == '?' )
336+ continue ;
337+ // check optional character match
338+ if ( b >= 'a' && b <= 'z' ) { // lowercase is optional
339+ // at this point we know it's not an exact match, so we only need to check the
340+ // uppercase character. If there's a match we go on as usual, and if not we
341+ // ignore the optional character by rewinding the buffer offset
342+ if ( b - 'a' + 'A' != buffer . get ( bufferOffset )) // no uppercase match
343+ bufferOffset --;
344+ continue ;
352345 }
346+ return -1 ; // no match
353347 }
354- if (dataOffset != data .length ) {
355- // when minMaskLength(data ) != data .length we might run out of buffer before we run out of data
348+ if (patternOffset != pattern .length ) {
349+ // when minPatternLength(pattern ) != pattern .length we might run out of buffer before we run out of pattern
356350 return -1 ;
357351 }
358352 return bufferOffset - initOffset ;
0 commit comments