in src/main/java/org/apache/commons/imaging/formats/tiff/TiffReader.java [269:413]
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;
}
BinaryFunctions.skipBytes(is, directoryOffset);
final List<TiffField> fields = new ArrayList<>();
final long entryCount;
try {
if (standardTiff) {
entryCount = BinaryFunctions.read2Bytes("DirectoryEntryCount", is, "Not a Valid TIFF File", getByteOrder());
} else {
entryCount = BinaryFunctions.read8Bytes("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 = BinaryFunctions.read2Bytes("Tag", is, "Not a Valid TIFF File", getByteOrder());
final int type = BinaryFunctions.read2Bytes("Type", is, "Not a Valid TIFF File", getByteOrder());
final long count;
final byte[] offsetBytes;
final long offset;
if (standardTiff) {
count = 0xFFFFffffL & BinaryFunctions.read4Bytes("Count", is, "Not a Valid TIFF File", getByteOrder());
offsetBytes = BinaryFunctions.readBytes("Offset", is, 4, "Not a Valid TIFF File");
offset = 0xFFFFffffL & ByteConversions.toInt(offsetBytes, getByteOrder());
} else {
count = BinaryFunctions.read8Bytes("Count", is, "Not a Valid TIFF File", getByteOrder());
offsetBytes = BinaryFunctions.readBytes("Offset", is, 8, "Not a Valid TIFF File");
offset = ByteConversions.toLong(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 AbstractFieldType abstractFieldType;
try {
abstractFieldType = AbstractFieldType.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 * abstractFieldType.getSize();
final byte[] value;
if (valueLength > entryMaxValueLength) {
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, abstractFieldType, count, offset, value, getByteOrder(), i);
fields.add(field);
if (!listener.addField(field)) {
return true;
}
}
final long nextDirectoryOffset = 0xFFFFffffL & BinaryFunctions.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 AbstractTiffImageData 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) {
final long subDirectoryOffset;
final 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;
}
}