Program: 33378
Project: 33378
Buggy source:
/** 
 * Merges a list of TIFF images into one regardless of the original bit depth
 * @param merged RandomAccessOutputStream for the merged TIFF
 * @param images input TIFF image files to be merged
 * @throws IOException
 */
public static void mergeTiffImagesEx(RandomAccessOutputStream merged,File... images) throws IOException {
  if (images != null && images.length > 1) {
    FileInputStream fis1=new FileInputStream(images[0]);
    RandomAccessInputStream image1=new FileCacheRandomAccessInputStream(fis1);
    List<IFD> ifds1=new ArrayList<IFD>();
    int offset1=copyHeader(image1,merged);
    readIFDs(null,null,TiffTag.class,ifds1,offset1,image1);
    for (int i=0; i < ifds1.size(); i++) {
      ifds1.get(i).removeField(TiffTag.PAGE_NUMBER.getValue());
      ifds1.get(i).addField(new ShortField(TiffTag.PAGE_NUMBER.getValue(),new short[]{0,0}));
    }
    int offset=copyPages(ifds1,FIRST_WRITE_OFFSET,image1,merged);
    image1.close();
    fis1.close();
    short writeEndian=merged.getEndian();
    for (int i=1; i < images.length; i++) {
      List<IFD> ifds2=new ArrayList<IFD>();
      FileInputStream fis2=new FileInputStream(images[i]);
      RandomAccessInputStream image2=new FileCacheRandomAccessInputStream(fis2);
      readIFDs(ifds2,image2);
      for (int j=0; j < ifds2.size(); j++) {
        ifds2.get(j).removeField(TiffTag.PAGE_NUMBER.getValue());
        ifds2.get(j).addField(new ShortField(TiffTag.PAGE_NUMBER.getValue(),new short[]{0,0}));
      }
      short readEndian=image2.getEndian();
      if (readEndian == writeEndian)       offset=copyPages(ifds2,offset,image2,merged);
 else {
        IFD prevIFD=null;
        for (int j=0; j < ifds2.size(); j++) {
          IFD currIFD=ifds2.get(j);
          int bitsPerSample=1;
          TiffField<?> f_bitsPerSample=currIFD.getField(TiffTag.BITS_PER_SAMPLE.getValue());
          if (f_bitsPerSample != null)           bitsPerSample=f_bitsPerSample.getDataAsLong()[0];
          if (bitsPerSample <= 8) {
            offset=copyPageData(currIFD,offset,image2,merged);
          }
 else           if (bitsPerSample == 16) {
            ImageDecoder decoder=null;
            ImageEncoder encoder=null;
            TiffField<?> stripOffSets=currIFD.removeField(TiffTag.STRIP_OFFSETS.getValue());
            if (stripOffSets == null)             stripOffSets=currIFD.removeField(TiffTag.TILE_OFFSETS.getValue());
            TiffField<?> stripByteCounts=currIFD.getField(TiffTag.STRIP_BYTE_COUNTS.getValue());
            if (stripByteCounts == null)             stripByteCounts=currIFD.getField(TiffTag.TILE_BYTE_COUNTS.getValue());
            if (stripOffSets != null) {
              int[] counts=stripByteCounts.getDataAsLong();
              int[] off=stripOffSets.getDataAsLong();
              int[] temp=new int[off.length];
              int[] uncompressedStripByteCounts=getUncompressedStripByteCounts(currIFD,off.length);
              merged.seek(offset);
              TiffField<?> tiffField=currIFD.getField(TiffTag.COMPRESSION.getValue());
              TiffFieldEnum.Compression compression=TiffFieldEnum.Compression.fromValue(tiffField.getDataAsLong()[0]);
switch (compression) {
case LZW:
                decoder=new LZWTreeDecoder(8,true);
              encoder=new LZWTreeEncoder(merged,8,4096,null);
            break;
case DEFLATE:
case DEFLATE_ADOBE:
          decoder=new DeflateDecoder();
        encoder=new DeflateEncoder(merged,4096,4,null);
      break;
case PACKBITS:
    for (int k=0; k < off.length; k++) {
      image2.seek(off[k]);
      byte[] buf=new byte[counts[k]];
      image2.readFully(buf);
      byte[] buf2=new byte[uncompressedStripByteCounts[k]];
      Packbits.unpackbits(buf,buf2);
      short[] sbuf=ArrayUtils.byteArrayToShortArray(buf2,0,buf2.length,readEndian == IOUtils.BIG_ENDIAN);
      buf=ArrayUtils.shortArrayToByteArray(sbuf,writeEndian == IOUtils.BIG_ENDIAN);
      buf2=new byte[buf.length + (buf.length + 127) / 128];
      int bytesCompressed=Packbits.packbits(buf,buf2);
      merged.write(buf2,0,bytesCompressed);
      temp[k]=offset;
      offset+=bytesCompressed;
    }
  break;
case NONE:
int planaryConfiguration=1;
tiffField=currIFD.getField(TiffTag.PLANAR_CONFIGURATTION.getValue());
if (tiffField != null) planaryConfiguration=tiffField.getDataAsLong()[0];
tiffField=currIFD.getField(TiffTag.SAMPLES_PER_PIXEL.getValue());
int samplesPerPixel=1;
if (tiffField != null) samplesPerPixel=tiffField.getDataAsLong()[0];
if (planaryConfiguration == 1 && off.length == 1 || planaryConfiguration == 2 && off.length == samplesPerPixel) {
int[] totalBytes2Read=getBytes2Read(currIFD);
for (int k=0; k < off.length; k++) counts[k]=totalBytes2Read[k];
}
for (int k=0; k < off.length; k++) {
image2.seek(off[k]);
byte[] buf=new byte[counts[k]];
image2.readFully(buf);
buf=ArrayUtils.flipEndian(buf,0,bitsPerSample,buf.length,readEndian == IOUtils.BIG_ENDIAN);
merged.write(buf);
temp[k]=offset;
offset+=buf.length;
}
break;
default :
for (int l=0; l < off.length; l++) {
image2.seek(off[l]);
byte[] buf=new byte[counts[l]];
image2.readFully(buf);
merged.write(buf);
temp[l]=offset;
offset+=buf.length;
}
break;
}
if (decoder != null) {
for (int k=0; k < off.length; k++) {
image2.seek(off[k]);
byte[] buf=new byte[counts[k]];
image2.readFully(buf);
decoder.setInput(buf);
int bytesDecompressed=0;
byte[] decompressed=new byte[uncompressedStripByteCounts[k]];
try {
bytesDecompressed=decoder.decode(decompressed,0,uncompressedStripByteCounts[k]);
}
 catch (Exception e) {
e.printStackTrace();
}
short[] sbuf=ArrayUtils.byteArrayToShortArray(decompressed,0,bytesDecompressed,readEndian == IOUtils.BIG_ENDIAN);
buf=ArrayUtils.shortArrayToByteArray(sbuf,writeEndian == IOUtils.BIG_ENDIAN);
try {
encoder.initialize();
encoder.encode(buf,0,buf.length);
encoder.finish();
}
 catch (Exception e) {
e.printStackTrace();
}
temp[k]=offset;
offset+=encoder.getCompressedDataLen();
}
}
if (currIFD.getField(TiffTag.STRIP_BYTE_COUNTS.getValue()) != null) stripOffSets=new LongField(TiffTag.STRIP_OFFSETS.getValue(),temp);
 else stripOffSets=new LongField(TiffTag.TILE_OFFSETS.getValue(),temp);
currIFD.addField(stripOffSets);
}
}
 else {
offset=copyPageData(currIFD,offset,image2,merged);
}
if (prevIFD != null) prevIFD.setNextIFDOffset(merged,offset);
offset=currIFD.write(merged,offset);
prevIFD=currIFD;
}
}
ifds1.get(ifds1.size() - 1).setNextIFDOffset(merged,ifds2.get(0).getStartOffset());
ifds1.addAll(ifds2);
image2.close();
fis2.close();
}
int maxPageNumber=ifds1.size();
for (int i=0; i < ifds1.size(); i++) {
offset=ifds1.get(i).getField(TiffTag.PAGE_NUMBER.getValue()).getDataOffset();
merged.seek(offset);
merged.writeShort((short)i);
merged.writeShort((short)maxPageNumber);
}
int firstIFDOffset=ifds1.get(0).getStartOffset();
writeToStream(merged,firstIFDOffset);
}
}

Fixed version (ground truth):
/** 
 * Merges a list of TIFF images into one regardless of the original bit depth
 * @param merged RandomAccessOutputStream for the merged TIFF
 * @param images input TIFF image files to be merged
 * @throws IOException
 */
public static void mergeTiffImagesEx(RandomAccessOutputStream merged,File... images) throws IOException {
  if (images != null && images.length > 1) {
    FileInputStream fis1=new FileInputStream(images[0]);
    RandomAccessInputStream image1=new FileCacheRandomAccessInputStream(fis1);
    List<IFD> ifds1=new ArrayList<IFD>();
    int offset1=copyHeader(image1,merged);
    readIFDs(null,null,TiffTag.class,ifds1,offset1,image1);
    for (int i=0; i < ifds1.size(); i++) {
      ifds1.get(i).removeField(TiffTag.PAGE_NUMBER.getValue());
      ifds1.get(i).addField(new ShortField(TiffTag.PAGE_NUMBER.getValue(),new short[]{0,0}));
    }
    int offset=copyPages(ifds1,FIRST_WRITE_OFFSET,image1,merged);
    image1.close();
    fis1.close();
    short writeEndian=merged.getEndian();
    for (int i=1; i < images.length; i++) {
      List<IFD> ifds2=new ArrayList<IFD>();
      FileInputStream fis2=new FileInputStream(images[i]);
      RandomAccessInputStream image2=new FileCacheRandomAccessInputStream(fis2);
      readIFDs(ifds2,image2);
      for (int j=0; j < ifds2.size(); j++) {
        ifds2.get(j).removeField(TiffTag.PAGE_NUMBER.getValue());
        ifds2.get(j).addField(new ShortField(TiffTag.PAGE_NUMBER.getValue(),new short[]{0,0}));
      }
      short readEndian=image2.getEndian();
      if (readEndian == writeEndian)       offset=copyPages(ifds2,offset,image2,merged);
 else {
        IFD prevIFD=null;
        for (int j=0; j < ifds2.size(); j++) {
          IFD currIFD=ifds2.get(j);
          int bitsPerSample=1;
          TiffField<?> f_bitsPerSample=currIFD.getField(TiffTag.BITS_PER_SAMPLE.getValue());
          if (f_bitsPerSample != null)           bitsPerSample=f_bitsPerSample.getDataAsLong()[0];
          if (bitsPerSample <= 8) {
            offset=copyPageData(currIFD,offset,image2,merged);
          }
 else           if (bitsPerSample == 16) {
            ImageDecoder decoder=null;
            ImageEncoder encoder=null;
            TiffField<?> stripOffSets=currIFD.removeField(TiffTag.STRIP_OFFSETS.getValue());
            if (stripOffSets == null)             stripOffSets=currIFD.removeField(TiffTag.TILE_OFFSETS.getValue());
            TiffField<?> stripByteCounts=currIFD.getField(TiffTag.STRIP_BYTE_COUNTS.getValue());
            if (stripByteCounts == null)             stripByteCounts=currIFD.getField(TiffTag.TILE_BYTE_COUNTS.getValue());
            if (stripOffSets != null) {
              int[] counts=stripByteCounts.getDataAsLong();
              int[] off=stripOffSets.getDataAsLong();
              int[] temp=new int[off.length];
              int[] uncompressedStripByteCounts=getUncompressedStripByteCounts(currIFD,off.length);
              merged.seek(offset);
              TiffField<?> tiffField=currIFD.getField(TiffTag.COMPRESSION.getValue());
              int tiffCompression=1;
              if (tiffField != null)               tiffCompression=tiffField.getDataAsLong()[0];
              TiffFieldEnum.Compression compression=TiffFieldEnum.Compression.fromValue(tiffCompression);
switch (compression) {
case LZW:
                decoder=new LZWTreeDecoder(8,true);
              encoder=new LZWTreeEncoder(merged,8,4096,null);
            break;
case DEFLATE:
case DEFLATE_ADOBE:
          decoder=new DeflateDecoder();
        encoder=new DeflateEncoder(merged,4096,4,null);
      break;
case PACKBITS:
    for (int k=0; k < off.length; k++) {
      image2.seek(off[k]);
      byte[] buf=new byte[counts[k]];
      image2.readFully(buf);
      byte[] buf2=new byte[uncompressedStripByteCounts[k]];
      Packbits.unpackbits(buf,buf2);
      short[] sbuf=ArrayUtils.byteArrayToShortArray(buf2,0,buf2.length,readEndian == IOUtils.BIG_ENDIAN);
      buf=ArrayUtils.shortArrayToByteArray(sbuf,writeEndian == IOUtils.BIG_ENDIAN);
      buf2=new byte[buf.length + (buf.length + 127) / 128];
      int bytesCompressed=Packbits.packbits(buf,buf2);
      merged.write(buf2,0,bytesCompressed);
      temp[k]=offset;
      offset+=bytesCompressed;
    }
  break;
case NONE:
int planaryConfiguration=1;
tiffField=currIFD.getField(TiffTag.PLANAR_CONFIGURATTION.getValue());
if (tiffField != null) planaryConfiguration=tiffField.getDataAsLong()[0];
tiffField=currIFD.getField(TiffTag.SAMPLES_PER_PIXEL.getValue());
int samplesPerPixel=1;
if (tiffField != null) samplesPerPixel=tiffField.getDataAsLong()[0];
if (planaryConfiguration == 1 && off.length == 1 || planaryConfiguration == 2 && off.length == samplesPerPixel) {
int[] totalBytes2Read=getBytes2Read(currIFD);
for (int k=0; k < off.length; k++) counts[k]=totalBytes2Read[k];
}
for (int k=0; k < off.length; k++) {
image2.seek(off[k]);
byte[] buf=new byte[counts[k]];
image2.readFully(buf);
buf=ArrayUtils.flipEndian(buf,0,bitsPerSample,buf.length,readEndian == IOUtils.BIG_ENDIAN);
merged.write(buf);
temp[k]=offset;
offset+=buf.length;
}
break;
default :
for (int l=0; l < off.length; l++) {
image2.seek(off[l]);
byte[] buf=new byte[counts[l]];
image2.readFully(buf);
merged.write(buf);
temp[l]=offset;
offset+=buf.length;
}
break;
}
if (decoder != null) {
for (int k=0; k < off.length; k++) {
image2.seek(off[k]);
byte[] buf=new byte[counts[k]];
image2.readFully(buf);
decoder.setInput(buf);
int bytesDecompressed=0;
byte[] decompressed=new byte[uncompressedStripByteCounts[k]];
try {
bytesDecompressed=decoder.decode(decompressed,0,uncompressedStripByteCounts[k]);
}
 catch (Exception e) {
e.printStackTrace();
}
short[] sbuf=ArrayUtils.byteArrayToShortArray(decompressed,0,bytesDecompressed,readEndian == IOUtils.BIG_ENDIAN);
buf=ArrayUtils.shortArrayToByteArray(sbuf,writeEndian == IOUtils.BIG_ENDIAN);
try {
encoder.initialize();
encoder.encode(buf,0,buf.length);
encoder.finish();
}
 catch (Exception e) {
e.printStackTrace();
}
temp[k]=offset;
offset+=encoder.getCompressedDataLen();
}
}
if (currIFD.getField(TiffTag.STRIP_BYTE_COUNTS.getValue()) != null) stripOffSets=new LongField(TiffTag.STRIP_OFFSETS.getValue(),temp);
 else stripOffSets=new LongField(TiffTag.TILE_OFFSETS.getValue(),temp);
currIFD.addField(stripOffSets);
}
}
 else {
offset=copyPageData(currIFD,offset,image2,merged);
}
if (prevIFD != null) prevIFD.setNextIFDOffset(merged,offset);
offset=currIFD.write(merged,offset);
prevIFD=currIFD;
}
}
ifds1.get(ifds1.size() - 1).setNextIFDOffset(merged,ifds2.get(0).getStartOffset());
ifds1.addAll(ifds2);
image2.close();
fis2.close();
}
int maxPageNumber=ifds1.size();
for (int i=0; i < ifds1.size(); i++) {
offset=ifds1.get(i).getField(TiffTag.PAGE_NUMBER.getValue()).getDataOffset();
merged.seek(offset);
merged.writeShort((short)i);
merged.writeShort((short)maxPageNumber);
}
int firstIFDOffset=ifds1.get(0).getStartOffset();
writeToStream(merged,firstIFDOffset);
}
}