Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The <action> type attribute can be add,update,fix,remove.
<body>
<release version="1.0.0-alpha7" date="YYYY-MM-DD" description="This release requires Java 8.">
<!-- FIX -->
<action type="fix" due-to="Aryan Ganjoo" issue="IMAGING-389">Fix BinaryFunctions.searchQuad matching for high-bit bytes and overlapping prefixes.</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Fix Apache RAT plugin console warnings.</action>
<action type="fix" dev="ggregory" due-to="Gary Gregory">Fix Javadoc warnings.</action>
<action type="fix" dev="ggregory" due-to="alhuda, Gary Gregory">Fix int overflow in PCX image buffer sizing, now throws AllocationRequestException (#552).</action>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,17 +426,16 @@ public static byte[] remainingBytes(final String name, final byte[] bytes, final
* @throws IOException Thrown if it fails to read from the given input stream.
*/
public static boolean searchQuad(final int quad, final InputStream in) throws IOException {
final byte[] needle = quadsToByteArray(quad);
int b = -1;
int position = 0;
// Slide a 4-byte window over the stream, so that bytes >= 0x80 and overlapping partial matches are handled.
int window = 0;
int count = 0;
int b;
while ((b = in.read()) != -1) {
if (needle[position] == b) {
position++;
if (position == needle.length) {
return true;
}
} else {
position = 0;
window = window << 8 | b;
if (count < 3) {
count++;
} else if (window == quad) {
return true;
}
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,35 @@ public void testReadBytes() throws IOException {
assertArrayEquals(new byte[] { 1, 2, 3 }, read);
}

@Test
public void testSearchQuad() throws IOException {
final int quad = BinaryFunctions.charsToQuad('8', 'B', 'I', 'M');
assertTrue(BinaryFunctions.searchQuad(quad, new ByteArrayInputStream(new byte[] { 0, '8', 'B', 'I', 'M', 1 })));
assertFalse(BinaryFunctions.searchQuad(quad, new ByteArrayInputStream(new byte[] { '8', 'B', 'I', 'X' })));
assertFalse(BinaryFunctions.searchQuad(quad, new ByteArrayInputStream(new byte[] { '8', 'B', 'I' })));
}

@Test
public void testSearchQuadAfterPartialMatch() throws IOException {
// The byte that breaks a partial match may itself start the quad.
final int quad = BinaryFunctions.charsToQuad('8', 'B', 'I', 'M');
final InputStream is = new ByteArrayInputStream(new byte[] { '8', '8', 'B', 'I', 'M', 1 });
assertTrue(BinaryFunctions.searchQuad(quad, is));
// The stream is left positioned right after the quad.
assertEquals(1, is.read());
// Overlapping prefix: "AAAB" inside "AAAAB".
final int aaab = BinaryFunctions.charsToQuad('A', 'A', 'A', 'B');
assertTrue(BinaryFunctions.searchQuad(aaab, new ByteArrayInputStream(new byte[] { 'A', 'A', 'A', 'A', 'B' })));
}

@Test
public void testSearchQuadWithHighBitBytes() throws IOException {
// Bytes >= 0x80 must match, for example a JPEG SOI + APP0 marker.
final InputStream is = new ByteArrayInputStream(new byte[] { 0, (byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0, 7 });
assertTrue(BinaryFunctions.searchQuad(0xFFD8FFE0, is));
assertEquals(7, is.read());
}

@Test
public void testStartsWith() {
final byte[] haystack = { 1, 2, 3, 4, 5 };
Expand Down