8167278: ArrayIndexOutOfBoundsException when calling ImageIO.read(InputStream) with RLE4 BMP

Reviewed-by: prr, bpb, jdv
This commit is contained in:
Prahalad Kumar Narayanan 2017-01-30 16:32:46 +05:30
parent 6a4b1fbe61
commit e3cb927146

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1559,6 +1559,59 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
decodeRLE4(imSize, padding, values, bdata);
}
private boolean copyRLE4ScanlineToDst(int lineNo,
byte[] val,
byte[] bdata) throws IOException {
// Return value
boolean isSuccess = false;
// Reusing the code to copy 1 row of pixels or scanline to required
// destination buffer.
if (lineNo >= sourceRegion.y &&
lineNo < sourceRegion.y + sourceRegion.height) {
if (noTransform) {
int pos = lineNo * (width + 1 >> 1);
for(int i = 0, j = 0; i < width >> 1; i++)
bdata[pos++] =
(byte)((val[j++] << 4) | val[j++]);
if ((width & 1) == 1)
bdata[pos] |= val[width - 1] << 4;
processImageUpdate(bi, 0, lineNo,
destinationRegion.width, 1, 1, 1,
new int[]{0});
isSuccess = true;
} else if ((lineNo - sourceRegion.y) % scaleY == 0) {
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
int currentLine = (lineNo - sourceRegion.y) / scaleY +
destinationRegion.y;
int pos = currentLine * lineStride;
pos += destinationRegion.x >> 1;
int shift = (1 - (destinationRegion.x & 1)) << 2;
for (int i = sourceRegion.x;
i < sourceRegion.x + sourceRegion.width;
i += scaleX) {
bdata[pos] |= val[i] << shift;
shift += 4;
if (shift == 4) {
pos++;
}
shift &= 7;
}
processImageUpdate(bi, 0, currentLine,
destinationRegion.width, 1, 1, 1,
new int[]{0});
isSuccess = true;
}
// Ensure to reset the scanline buffer once the copy is complete.
for(int scIndex = 0; scIndex < width; scIndex++) {
val[scIndex] = 0;
}
}
return isSuccess;
}
private void decodeRLE4(int imSize,
int padding,
byte[] values,
@ -1568,57 +1621,22 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
int value;
boolean flag = false;
int lineNo = isBottomUp ? height - 1 : 0;
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
int finished = 0;
while (count != imSize) {
// Ensure the image has sufficient data before proceeding to decode
while ((count + 1) < imSize) {
value = values[count++] & 0xFF;
if (value == 0) {
// Absolute mode
switch(values[count++] & 0xFF) {
case 0:
// End-of-scanline marker
// End-of-scanline marker
if (lineNo >= sourceRegion.y &&
lineNo < sourceRegion.y + sourceRegion.height) {
if (noTransform) {
int pos = lineNo * (width + 1 >> 1);
for(int i = 0, j = 0; i < width >> 1; i++)
bdata[pos++] =
(byte)((val[j++] << 4) | val[j++]);
if ((width & 1) == 1)
bdata[pos] |= val[width - 1] << 4;
processImageUpdate(bi, 0, lineNo,
destinationRegion.width, 1, 1, 1,
new int[]{0});
finished++;
} else if ((lineNo - sourceRegion.y) % scaleY == 0) {
int currentLine = (lineNo - sourceRegion.y) / scaleY +
destinationRegion.y;
int pos = currentLine * lineStride;
pos += destinationRegion.x >> 1;
int shift = (1 - (destinationRegion.x & 1)) << 2;
for (int i = sourceRegion.x;
i < sourceRegion.x + sourceRegion.width;
i += scaleX) {
bdata[pos] |= val[i] << shift;
shift += 4;
if (shift == 4) {
pos++;
}
shift &= 7;
}
processImageUpdate(bi, 0, currentLine,
destinationRegion.width, 1, 1, 1,
new int[]{0});
finished++;
}
// Copy the decoded scanline to destination
if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
@ -1633,21 +1651,61 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
case 1:
// End-of-RLE marker
flag = true;
// Check if the last decoded scanline was copied to
// destination bitmap
if (l != 0) {
// Copy the decoded scanline to destination
if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
}
break;
case 2:
// delta or vector marker
int xoff = values[count++] & 0xFF;
int yoff = values[count] & 0xFF;
// Move to the position xoff, yoff down
l += xoff + yoff*width;
if ((count + 1) < imSize) {
int xoff = values[count++] & 0xFF;
int yoff = values[count++] & 0xFF;
// Check if the yOffset shifts the decoding to another
// row. In such cases, the decoded pixels in scanline
// buffer-val must be copied to the destination image.
if (yoff != 0) {
// Copy the decoded scanline to destination
if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished
/ destinationRegion.height);
lineNo += isBottomUp ? -yoff : yoff;
}
// Move to the position (xoff, yoff). Since l-is used
// to index into the scanline buffer, the accumulated
// offset is limited to the width of the scanline
l += xoff + yoff*width;
l %= width;
}
break;
default:
int end = values[count-1] & 0xFF;
for (int i=0; i<end; i++) {
val[l++] = (byte)(((i & 1) == 0) ? (values[count] & 0xf0) >> 4
: (values[count++] & 0x0f));
byte readByte = 0;
// Ensure to check if the source index-count, does not
// exceed the source image size
for (int i = 0; (i < end) && (count < imSize); i++) {
readByte = (byte)(((i & 1) == 0) ?
(values[count] & 0xf0) >> 4 :
(values[count++] & 0x0f));
// Ensure to check if scanline index-l, does not
// exceed the scanline buffer size (width of image)
if (l < width) {
val[l++] = readByte;
}
}
// When end is odd, the above for loop does not
@ -1665,10 +1723,14 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
}
} else {
// Encoded mode
int alternate[] = { (values[count] & 0xf0) >> 4,
values[count] & 0x0f };
for (int i=0; (i < value) && (l < width); i++) {
val[l++] = (byte)alternate[i & 1];
// Ensure to check if the source index-count, does not
// exceed the source image size
if (count < imSize) {
int alternate[] = { (values[count] & 0xf0) >> 4,
values[count] & 0x0f };
for (int i=0; (i < value) && (l < width); i++) {
val[l++] = (byte)alternate[i & 1];
}
}
count++;