@@ -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