@@ -118,7 +118,7 @@ public FixedBoundaryParser(final byte[] boundary) {
118118 @ Override
119119 public byte [] readChunk (final InputStream in ) throws IOException {
120120 final ByteArrayOutputStream buffer = new ByteArrayOutputStream ();
121- final byte [] delimiterBuffer = new byte [delimiter .length ];
121+ byte [] delimiterBuffer = new byte [delimiter .length ];
122122
123123 int data ;
124124 int dPos ;
@@ -135,24 +135,24 @@ public byte[] readChunk(final InputStream in) throws IOException {
135135 break ;
136136 }
137137 } else if (dPos > 0 ) {
138- // flush delimiter buffer
139- buffer .write (delimiterBuffer , 0 , dPos );
140- dPos = 0 ;
141-
142- if (b == delimiter [dPos ]) {
143- // last read byte is the first byte of of the chunk delimiter
144- delimiterBuffer [dPos ++] = b ;
145- if (dPos == delimiter .length ) {
146- // found chunk delimiter
147- break ;
148- }
149- } else {
150- // last read byte is not the first byte of the chunk delimiter
138+ delimiterBuffer [dPos ] = b ;
139+
140+ int matched = matchTail (delimiterBuffer , 1 , dPos , delimiter );
141+ if (matched == 0 ) {
142+ // flush delimiter buffer
143+ buffer .write (delimiterBuffer , 0 , dPos );
151144 buffer .write (b );
145+ dPos = 0 ;
146+ } else if (matched == delimiter .length ) {
147+ // found chunk delimiter
148+ break ;
149+ } else {
150+ // one or more elements of a previous buffered delimiter
151+ // are parts of a current buffered delimiter
152+ buffer .write (delimiterBuffer , 0 , dPos + 1 - matched );
153+ dPos = matched ;
152154 }
153-
154155 } else {
155- // last read byte is not part of the chunk delimiter
156156 buffer .write (b );
157157 }
158158 }
@@ -166,6 +166,47 @@ public byte[] readChunk(final InputStream in) throws IOException {
166166
167167 return (buffer .size () > 0 ) ? buffer .toByteArray () : null ;
168168 }
169+
170+ /**
171+ * Tries to find an element intersection between two arrays in a way that intersecting elements must be
172+ * at the tail of the first array and at the beginning of the second array.
173+ * <p>
174+ * For example, consider the following two arrays:
175+ * <pre>
176+ * a1: {a, b, c, d, e}
177+ * a2: {d, e, f, g}
178+ * </pre>
179+ * In this example, the intersection of tail of {@code a1} with head of {@code a2} is <tt>{d, e}</tt>
180+ * and consists of 2 overlapping elements.
181+ * </p>
182+ * The method takes the first array represented as a sub-array in buffer demarcated by an offset and length.
183+ * The second array is a fixed pattern to be matched. The method then compares the tail of the
184+ * array in the buffer with the head of the pattern and returns the number of intersecting elements,
185+ * or zero in case the two arrays do not intersect tail to head.
186+ *
187+ * @param buffer byte buffer containing the array whose tail to intersect.
188+ * @param offset start of the array to be tail-matched in the {@code buffer}.
189+ * @param length length of the array to be tail-matched.
190+ * @param pattern pattern to be head-matched.
191+ * @return {@code 0} if any part of the tail of the array in the buffer does not match
192+ * any part of the head of the pattern, otherwise returns number of overlapping elements.
193+ */
194+ private static int matchTail (byte [] buffer , int offset , int length , byte [] pattern ) {
195+ outer :
196+ for (int i = 0 ; i < length ; i ++) {
197+ final int tailLength = length - i ;
198+ for (int j = 0 ; j < tailLength ; j ++) {
199+ if (buffer [offset + i + j ] != pattern [j ]) {
200+ // mismatch - continue with shorter tail
201+ continue outer ;
202+ }
203+ }
204+
205+ // found the longest matching tail
206+ return tailLength ;
207+ }
208+ return 0 ;
209+ }
169210 }
170211
171212 /**
0 commit comments