@@ -70,24 +70,6 @@ public class FIXMessageDecoder implements MessageDecoder {
70
70
private int position ;
71
71
private final String charsetEncoding ;
72
72
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
-
91
73
private void resetState () {
92
74
state = SEEKING_HEADER ;
93
75
bodyLength = 0 ;
@@ -106,14 +88,13 @@ public FIXMessageDecoder(String charset, String delimiter) throws UnsupportedEnc
106
88
charsetEncoding = CharsetSupport .validate (charset );
107
89
HEADER_PATTERN = getBytes ("8=FIXt.?.?" + delimiter + "9=" );
108
90
CHECKSUM_PATTERN = getBytes ("10=???" + delimiter );
109
- LOGON_PATTERN = getBytes (" \001 35 =A" + delimiter );
91
+ LOGON_PATTERN = getBytes (delimiter + "35 =A" + delimiter );
110
92
resetState ();
111
93
}
112
94
113
95
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 :
117
98
(in .remaining () > MAX_UNDECODED_DATA_LENGTH ? MessageDecoderResult .NOT_OK : MessageDecoderResult .NEED_DATA );
118
99
}
119
100
@@ -148,18 +129,19 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
148
129
while (in .hasRemaining () && !messageFound ) {
149
130
if (state == SEEKING_HEADER ) {
150
131
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 ) {
154
134
break ;
155
135
}
136
+ int headerOffset = (int )headerPos ;
137
+ int headerLength = (int )(headerPos >>> 32 );
156
138
in .position (headerOffset );
157
139
158
140
if (log .isDebugEnabled ()) {
159
141
log .debug ("detected header: " + getBufferDebugInfo (in ));
160
142
}
161
143
162
- position = headerOffset + bufPos . _length ;
144
+ position = headerOffset + headerLength ;
163
145
state = PARSING_LENGTH ;
164
146
}
165
147
@@ -201,7 +183,7 @@ private boolean parseMessage(IoBuffer in, ProtocolDecoderOutput out)
201
183
}
202
184
203
185
if (state == PARSING_CHECKSUM ) {
204
- if (startsWith (in , position , CHECKSUM_PATTERN ) > 0 ) {
186
+ if (matches (in , position , CHECKSUM_PATTERN ) > 0 ) {
205
187
// we are trying to parse the checksum but should
206
188
// check if the CHECKSUM_PATTERN is preceded by SOH
207
189
// or if the pattern just occurs inside of another field
@@ -268,12 +250,12 @@ private boolean hasRemaining(IoBuffer in) {
268
250
return position < in .limit ();
269
251
}
270
252
271
- private static int minMaskLength (byte [] data ) {
253
+ private static int minPatternLength (byte [] pattern ) {
272
254
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
+ }
277
259
}
278
260
return len ;
279
261
}
@@ -306,53 +288,65 @@ private void handleError(IoBuffer buffer, int recoveryPosition, String text,
306
288
}
307
289
308
290
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 ;
311
292
}
312
293
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 ;
318
311
}
319
312
}
320
- return new BufPos (- 1 , 0 ) ;
313
+ return - 1L ;
321
314
}
322
315
323
316
/**
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.
326
319
*
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
331
324
*/
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 ()) {
334
327
return -1 ;
335
328
}
336
329
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 ;
352
345
}
346
+ return -1 ; // no match
353
347
}
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
356
350
return -1 ;
357
351
}
358
352
return bufferOffset - initOffset ;
0 commit comments