TMI-74: Make JPEG segment parsing more lenient

This commit is contained in:
Harald Kuhr 2014-11-03 21:05:58 +01:00
parent bc448b10e4
commit add6e07cae
3 changed files with 28 additions and 24 deletions

View File

@ -89,20 +89,25 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
// Scan forward // Scan forward
while (true) { while (true) {
long realPosition = stream.getStreamPosition(); long realPosition = stream.getStreamPosition();
int marker = stream.readUnsignedShort();
// Skip over weird 0x00 padding, but leave in stream, read seems to handle it well with a warning
int trash = 0; int trash = 0;
while (marker == 0) { int marker = stream.readUnsignedByte();
marker = stream.readUnsignedShort();
trash += 2; // Skip bad padding before the marker
while (marker != 0xff) {
marker = stream.readUnsignedByte();
trash++;
realPosition++;
} }
if (marker == 0x00ff) { if (trash != 0) {
trash++; // NOTE: We previously allowed these bytes to pass through to the native reader, as it could cope
marker = 0xff00 | stream.readUnsignedByte(); // and issued the correct warning. However, the native metadata chokes on it, so we'll mask it out.
// TODO: Issue warning from the JPEGImageReader, telling how many bytes we skipped
} }
marker = 0xff00 | stream.readUnsignedByte();
// Skip over 0xff padding between markers // Skip over 0xff padding between markers
while (marker == 0xffff) { while (marker == 0xffff) {
realPosition++; realPosition++;
@ -113,7 +118,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
// TODO: Refactor to make various segments optional, we probably only want the "Adobe" APP14 segment, 'Exif' APP1 and very few others // TODO: Refactor to make various segments optional, we probably only want the "Adobe" APP14 segment, 'Exif' APP1 and very few others
if (isAppSegmentMarker(marker) && !(marker == JPEG.APP1 && isAppSegmentWithId("Exif", stream)) && marker != JPEG.APP14) { if (isAppSegmentMarker(marker) && !(marker == JPEG.APP1 && isAppSegmentWithId("Exif", stream)) && marker != JPEG.APP14) {
int length = stream.readUnsignedShort(); // Length including length field itself int length = stream.readUnsignedShort(); // Length including length field itself
stream.seek(realPosition + trash + 2 + length); // Skip marker (2) + length stream.seek(realPosition + 2 + length); // Skip marker (2) + length
} }
else { else {
if (marker == JPEG.EOI) { if (marker == JPEG.EOI) {
@ -129,7 +134,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
} }
else { else {
// Length including length field itself // Length including length field itself
length = trash + stream.readUnsignedShort() + 2; length = stream.readUnsignedShort() + 2;
} }
segment = new Segment(marker, realPosition, segment.end(), length); segment = new Segment(marker, realPosition, segment.end(), length);

View File

@ -87,7 +87,8 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTestCase<JPEGImageRe
new TestData(getClassLoaderResource("/jpeg/cmyk-sample.jpg"), new Dimension(160, 227)), new TestData(getClassLoaderResource("/jpeg/cmyk-sample.jpg"), new Dimension(160, 227)),
new TestData(getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), new Dimension(2707, 3804)), new TestData(getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), new Dimension(2707, 3804)),
new TestData(getClassLoaderResource("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"), new Dimension(640, 480)), new TestData(getClassLoaderResource("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"), new Dimension(640, 480)),
new TestData(getClassLoaderResource("/jpeg/jfif-padded-segments.jpg"), new Dimension(20, 45)) new TestData(getClassLoaderResource("/jpeg/jfif-padded-segments.jpg"), new Dimension(20, 45)),
new TestData(getClassLoaderResource("/jpeg/0x00-to-0xFF-between-segments.jpg"), new Dimension(16, 16))
); );
// More test data in specific tests below // More test data in specific tests below

View File

@ -159,23 +159,21 @@ public final class JPEGSegmentUtil {
} }
static JPEGSegment readSegment(final ImageInputStream stream, final Map<Integer, List<String>> segmentIdentifiers) throws IOException { static JPEGSegment readSegment(final ImageInputStream stream, final Map<Integer, List<String>> segmentIdentifiers) throws IOException {
int marker = stream.readUnsignedShort(); // int trash = 0;
int marker = stream.readUnsignedByte();
// Skip over weird 0x00 padding...? // Skip trash padding before the marker
int bad = 0; while (marker != 0xff) {
while (marker == 0) { marker = stream.readUnsignedByte();
marker = stream.readUnsignedShort(); // trash++;
bad += 2;
} }
if (marker == 0x00ff) { // if (trash != 0) {
bad++; // TODO: Issue warning?
marker = 0xff00 | stream.readUnsignedByte(); // System.err.println("trash: " + trash);
} // }
if (bad != 0) { marker = 0xff00 | stream.readUnsignedByte();
// System.err.println("bad: " + bad);
}
// Skip over 0xff padding between markers // Skip over 0xff padding between markers
while (marker == 0xffff) { while (marker == 0xffff) {