in src/main/java/org/apache/commons/imaging/formats/tiff/TiffReader.java [276:430]
private boolean readDirectory(final ByteSource byteSource, final long directoryOffset,
final int dirType, final FormatCompliance formatCompliance, final Listener listener,
final boolean ignoreNextDirectory, final List<Number> visited)
throws ImagingException, IOException {
if (visited.contains(directoryOffset)) {
return false;
}
visited.add(directoryOffset);
try (InputStream is = byteSource.getInputStream()) {
if (directoryOffset >= byteSource.size()) {
return true;
}
skipBytes(is, directoryOffset);
final List<TiffField> fields = new ArrayList<>();
int entryCount;
try {
entryCount = read2Bytes("DirectoryEntryCount", is, "Not a Valid TIFF File", getByteOrder());
} catch (final IOException e) {
if (strict) {
throw e;
}
return true;
}
for (int i = 0; i < entryCount; i++) {
final int tag = read2Bytes("Tag", is, "Not a Valid TIFF File", getByteOrder());
final int type = read2Bytes("Type", is, "Not a Valid TIFF File", getByteOrder());
final long count = 0xFFFFffffL & read4Bytes("Count", is, "Not a Valid TIFF File", getByteOrder());
final byte[] offsetBytes = readBytes("Offset", is, 4, "Not a Valid TIFF File");
final long offset = 0xFFFFffffL & ByteConversions.toInt(offsetBytes, getByteOrder());
if (tag == 0) {
// skip invalid fields.
// These are seen very rarely, but can have invalid value
// lengths,
// which can cause OOM problems.
continue;
}
final FieldType fieldType;
try {
fieldType = FieldType.getFieldType(type);
} catch (final ImagingException imageReadEx) {
// skip over unknown fields types, since we
// can't calculate their size without
// knowing their type
continue;
}
final long valueLength = count * fieldType.getSize();
final byte[] value;
if (valueLength > TIFF_ENTRY_MAX_VALUE_LENGTH) {
if ((offset < 0) || (offset + valueLength) > byteSource.size()) {
if (strict) {
throw new IOException(
"Attempt to read byte range starting from " + offset + " "
+ "of length " + valueLength + " "
+ "which is outside the file's size of "
+ byteSource.size());
}
// corrupt field, ignore it
continue;
}
value = byteSource.getByteArray(offset, (int) valueLength);
} else {
value = offsetBytes;
}
final TiffField field = new TiffField(tag, dirType, fieldType, count,
offset, value, getByteOrder(), i);
fields.add(field);
if (!listener.addField(field)) {
return true;
}
}
final long nextDirectoryOffset = 0xFFFFffffL & read4Bytes("nextDirectoryOffset", is,
"Not a Valid TIFF File", getByteOrder());
final TiffDirectory directory = new TiffDirectory(
dirType,
fields,
directoryOffset,
nextDirectoryOffset,
getByteOrder());
if (listener.readImageData()) {
if (directory.hasTiffImageData()) {
final TiffImageData rawImageData = getTiffRawImageData(
byteSource, directory);
directory.setTiffImageData(rawImageData);
}
if (directory.hasJpegImageData()) {
final JpegImageData rawJpegImageData = getJpegRawImageData(
byteSource, directory);
directory.setJpegImageData(rawJpegImageData);
}
}
if (!listener.addDirectory(directory)) {
return true;
}
if (listener.readOffsetDirectories()) {
final TagInfoDirectory[] offsetFields = {
ExifTagConstants.EXIF_TAG_EXIF_OFFSET,
ExifTagConstants.EXIF_TAG_GPSINFO,
ExifTagConstants.EXIF_TAG_INTEROP_OFFSET
};
final int[] directoryTypes = {
TiffDirectoryConstants.DIRECTORY_TYPE_EXIF,
TiffDirectoryConstants.DIRECTORY_TYPE_GPS,
TiffDirectoryConstants.DIRECTORY_TYPE_INTEROPERABILITY
};
for (int i = 0; i < offsetFields.length; i++) {
final TagInfoDirectory offsetField = offsetFields[i];
final TiffField field = directory.findField(offsetField);
if (field != null) {
long subDirectoryOffset;
int subDirectoryType;
boolean subDirectoryRead = false;
try {
subDirectoryOffset = directory.getFieldValue(offsetField);
subDirectoryType = directoryTypes[i];
subDirectoryRead = readDirectory(byteSource,
subDirectoryOffset, subDirectoryType,
formatCompliance, listener, true, visited);
} catch (final ImagingException imageReadException) {
if (strict) {
throw imageReadException;
}
}
if (!subDirectoryRead) {
fields.remove(field);
}
}
}
}
if (!ignoreNextDirectory && directory.getNextDirectoryOffset() > 0) {
// Debug.debug("next dir", directory.nextDirectoryOffset );
readDirectory(byteSource, directory.getNextDirectoryOffset(),
dirType + 1, formatCompliance, listener, visited);
}
return true;
}
}