8154093: [TIFF] NPE when reading LZW-compressed image

LZW decompressor was ignoring the value of the FillOrder field.

Reviewed-by: prr
This commit is contained in:
Brian Burkhalter 2016-11-04 15:31:38 -07:00
parent 099928305c
commit 9ecae6db48
3 changed files with 42 additions and 16 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -101,7 +101,8 @@ class TIFFFaxDecompressor extends TIFFDecompressor {
0xff // 8 0xff // 8
}; };
// Table to be used when fillOrder = 2, for flipping bytes. // Table to be used for flipping bytes when fillOrder is
// BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT (2).
static byte flipTable[] = { static byte flipTable[] = {
0, -128, 64, -64, 32, -96, 96, -32, 0, -128, 64, -64, 32, -96, 96, -32,
16, -112, 80, -48, 48, -80, 112, -16, 16, -112, 80, -48, 48, -80, 112, -16,
@ -597,7 +598,8 @@ class TIFFFaxDecompressor extends TIFFDecompressor {
TIFFField f; TIFFField f;
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER); f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
this.fillOrder = f == null ? 1 : f.getAsInt(0); this.fillOrder = f == null ?
BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT : f.getAsInt(0);
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION); f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
this.compression = f == null ? this.compression = f == null ?
@ -612,7 +614,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor {
f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_T6_OPTIONS); f = tmetadata.getTIFFField(BaselineTIFFTagSet.TAG_T6_OPTIONS);
this.t6Options = f == null ? 0 : f.getAsInt(0); this.t6Options = f == null ? 0 : f.getAsInt(0);
} else { } else {
this.fillOrder = 1; // MSB-to-LSB this.fillOrder = BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT;
this.compression = BaselineTIFFTagSet.COMPRESSION_CCITT_RLE; // RLE this.compression = BaselineTIFFTagSet.COMPRESSION_CCITT_RLE; // RLE
@ -1458,7 +1460,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor {
int l = data.length - 1; int l = data.length - 1;
int bp = this.bytePointer; int bp = this.bytePointer;
if (fillOrder == 1) { if (fillOrder == BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT) {
b = data[bp]; b = data[bp];
if (bp == l) { if (bp == l) {
@ -1471,7 +1473,7 @@ class TIFFFaxDecompressor extends TIFFDecompressor {
next = data[bp + 1]; next = data[bp + 1];
next2next = data[bp + 2]; next2next = data[bp + 2];
} }
} else if (fillOrder == 2) { } else if (fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT) {
b = flipTable[data[bp] & 0xff]; b = flipTable[data[bp] & 0xff];
if (bp == l) { if (bp == l) {
@ -1527,14 +1529,14 @@ class TIFFFaxDecompressor extends TIFFDecompressor {
int l = data.length - 1; int l = data.length - 1;
int bp = this.bytePointer; int bp = this.bytePointer;
if (fillOrder == 1) { if (fillOrder == BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT) {
b = data[bp]; b = data[bp];
if (bp == l) { if (bp == l) {
next = 0x00; next = 0x00;
} else { } else {
next = data[bp + 1]; next = data[bp + 1];
} }
} else if (fillOrder == 2) { } else if (fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT) {
b = flipTable[data[bp] & 0xff]; b = flipTable[data[bp] & 0xff];
if (bp == l) { if (bp == l) {
next = 0x00; next = 0x00;

View File

@ -1174,7 +1174,14 @@ public class TIFFImageReader extends ImageReader {
int predictor = ((predictorField == null) int predictor = ((predictorField == null)
? BaselineTIFFTagSet.PREDICTOR_NONE ? BaselineTIFFTagSet.PREDICTOR_NONE
: predictorField.getAsInt(0)); : predictorField.getAsInt(0));
this.decompressor = new TIFFLZWDecompressor(predictor);
TIFFField fillOrderField
= imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
int fillOrder = ((fillOrderField == null)
? BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT
: fillOrderField.getAsInt(0));
this.decompressor = new TIFFLZWDecompressor(predictor, fillOrder);
} else if (compression } else if (compression
== BaselineTIFFTagSet.COMPRESSION_JPEG) { == BaselineTIFFTagSet.COMPRESSION_JPEG) {
this.decompressor = new TIFFJPEGDecompressor(); this.decompressor = new TIFFJPEGDecompressor();

View File

@ -30,6 +30,10 @@ import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
class TIFFLZWDecompressor extends TIFFDecompressor { class TIFFLZWDecompressor extends TIFFDecompressor {
private static final int CLEAR_CODE = 256;
private static final int EOI_CODE = 257;
private static final int FIRST_CODE = 258;
private static final int andTable[] = { private static final int andTable[] = {
511, 511,
1023, 1023,
@ -39,6 +43,10 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
private int predictor; private int predictor;
// whether to reverse the bits in each byte of the input data, i.e.,
// convert right-to-left fill order (lsb) to left-to-right (msb).
private boolean flipBits;
private byte[] srcData; private byte[] srcData;
private byte[] dstData; private byte[] dstData;
@ -51,7 +59,8 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
private int nextData = 0; private int nextData = 0;
private int nextBits = 0; private int nextBits = 0;
public TIFFLZWDecompressor(int predictor) throws IIOException { public TIFFLZWDecompressor(int predictor, int fillOrder)
throws IIOException {
super(); super();
if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE && if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
@ -62,6 +71,8 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
} }
this.predictor = predictor; this.predictor = predictor;
flipBits = fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT;
} }
public void decodeRaw(byte[] b, public void decodeRaw(byte[] b,
@ -88,6 +99,12 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
byte[] sdata = new byte[byteCount]; byte[] sdata = new byte[byteCount];
stream.readFully(sdata); stream.readFully(sdata);
if (flipBits) {
for (int i = 0; i < byteCount; i++) {
sdata[i] = TIFFFaxDecompressor.flipTable[sdata[i] & 0xff];
}
}
int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8; int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
byte[] buf; byte[] buf;
int bufOffset; int bufOffset;
@ -133,11 +150,11 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
int code, oldCode = 0; int code, oldCode = 0;
byte[] string; byte[] string;
while ((code = getNextCode()) != 257) { while ((code = getNextCode()) != EOI_CODE) {
if (code == 256) { if (code == CLEAR_CODE) {
initializeStringTable(); initializeStringTable();
code = getNextCode(); code = getNextCode();
if (code == 257) { if (code == EOI_CODE) {
break; break;
} }
@ -186,12 +203,12 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
public void initializeStringTable() { public void initializeStringTable() {
stringTable = new byte[4096][]; stringTable = new byte[4096][];
for (int i = 0; i < 256; i++) { for (int i = 0; i < CLEAR_CODE; i++) {
stringTable[i] = new byte[1]; stringTable[i] = new byte[1];
stringTable[i][0] = (byte)i; stringTable[i][0] = (byte)i;
} }
tableIndex = 258; tableIndex = FIRST_CODE;
bitsToGet = 9; bitsToGet = 9;
} }
@ -281,7 +298,7 @@ class TIFFLZWDecompressor extends TIFFDecompressor {
return code; return code;
} catch (ArrayIndexOutOfBoundsException e) { } catch (ArrayIndexOutOfBoundsException e) {
// Strip not terminated as expected: return EndOfInformation code. // Strip not terminated as expected: return EndOfInformation code.
return 257; return EOI_CODE;
} }
} }
} }