private boolean readDirectory()

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;
        }
    }