11/*
2- * Copyright 2002-2019 Drew Noakes and contributors
2+ * Copyright 2002-2022 Drew Noakes and contributors
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -40,17 +40,15 @@ public class TiffReader
4040 *
4141 * @param reader the {@link RandomAccessReader} from which the data should be read
4242 * @param handler the {@link TiffHandler} that will coordinate processing and accept read values
43- * @param tiffHeaderOffset the offset within <code>reader</code> at which the TIFF header starts
4443 * @throws TiffProcessingException if an error occurred during the processing of TIFF data that could not be
4544 * ignored or recovered from
4645 * @throws IOException an error occurred while accessing the required data
4746 */
4847 public void processTiff (@ NotNull final RandomAccessReader reader ,
49- @ NotNull final TiffHandler handler ,
50- final int tiffHeaderOffset ) throws TiffProcessingException , IOException
48+ @ NotNull final TiffHandler handler ) throws TiffProcessingException , IOException
5149 {
5250 // This must be either "MM" or "II".
53- short byteOrderIdentifier = reader .getInt16 (tiffHeaderOffset );
51+ short byteOrderIdentifier = reader .getInt16 (0 );
5452
5553 if (byteOrderIdentifier == 0x4d4d ) { // "MM"
5654 reader .setMotorolaByteOrder (true );
@@ -61,21 +59,21 @@ public void processTiff(@NotNull final RandomAccessReader reader,
6159 }
6260
6361 // Check the next two values for correctness.
64- final int tiffMarker = reader .getUInt16 (2 + tiffHeaderOffset );
62+ final int tiffMarker = reader .getUInt16 (2 );
6563 handler .setTiffMarker (tiffMarker );
6664
67- int firstIfdOffset = reader .getInt32 (4 + tiffHeaderOffset ) + tiffHeaderOffset ;
65+ int firstIfdOffset = reader .getInt32 (4 ) ;
6866
6967 // David Ekholm sent a digital camera image that has this problem
7068 // TODO getLength should be avoided as it causes RandomAccessStreamReader to read to the end of the stream
7169 if (firstIfdOffset >= reader .getLength () - 1 ) {
7270 handler .warn ("First IFD offset is beyond the end of the TIFF data segment -- trying default offset" );
7371 // First directory normally starts immediately after the offset bytes, so try that
74- firstIfdOffset = tiffHeaderOffset + 2 + 2 + 4 ;
72+ firstIfdOffset = 2 + 2 + 4 ;
7573 }
7674
7775 Set <Integer > processedIfdOffsets = new HashSet <Integer >();
78- processIfd (handler , reader , processedIfdOffsets , firstIfdOffset , tiffHeaderOffset );
76+ processIfd (handler , reader , processedIfdOffsets , firstIfdOffset );
7977 }
8078
8179 /**
@@ -96,27 +94,28 @@ public void processTiff(@NotNull final RandomAccessReader reader,
9694 *
9795 * @param handler the {@link com.drew.imaging.tiff.TiffHandler} that will coordinate processing and accept read values
9896 * @param reader the {@link com.drew.lang.RandomAccessReader} from which the data should be read
99- * @param processedIfdOffsets the set of visited IFD offsets, to avoid revisiting the same IFD in an endless loop
97+ * @param processedGlobalIfdOffsets the set of visited IFD offsets, to avoid revisiting the same IFD in an endless loop
10098 * @param ifdOffset the offset within <code>reader</code> at which the IFD data starts
101- * @param tiffHeaderOffset the offset within <code>reader</code> at which the TIFF header starts
10299 * @throws IOException an error occurred while accessing the required data
103100 */
104101 public static void processIfd (@ NotNull final TiffHandler handler ,
105102 @ NotNull final RandomAccessReader reader ,
106- @ NotNull final Set <Integer > processedIfdOffsets ,
107- final int ifdOffset ,
108- final int tiffHeaderOffset ) throws IOException
103+ @ NotNull final Set <Integer > processedGlobalIfdOffsets ,
104+ final int ifdOffset ) throws IOException
109105 {
110106 Boolean resetByteOrder = null ;
111107 try {
112- // check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist
113- if (processedIfdOffsets .contains (Integer .valueOf (ifdOffset ))) {
108+ // Check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist.
109+ // Note that we track these offsets in the global frame, not the reader's local frame.
110+ int globalIfdOffset = reader .toUnshiftedOffset (ifdOffset );
111+ if (processedGlobalIfdOffsets .contains (Integer .valueOf (globalIfdOffset ))) {
114112 return ;
115113 }
116114
117115 // remember that we've visited this directory so that we don't visit it again later
118- processedIfdOffsets .add (ifdOffset );
116+ processedGlobalIfdOffsets .add (globalIfdOffset );
119117
118+ // Validate IFD offset
120119 if (ifdOffset >= reader .getLength () || ifdOffset < 0 ) {
121120 handler .error ("Ignored IFD marked to start outside data segment" );
122121 return ;
@@ -180,13 +179,12 @@ public static void processIfd(@NotNull final TiffHandler handler,
180179 final long tagValueOffset ;
181180 if (byteCount > 4 ) {
182181 // If it's bigger than 4 bytes, the dir entry contains an offset.
183- final long offsetVal = reader .getUInt32 (tagOffset + 8 );
184- if (offsetVal + byteCount > reader .getLength ()) {
182+ tagValueOffset = reader .getUInt32 (tagOffset + 8 );
183+ if (tagValueOffset + byteCount > reader .getLength ()) {
185184 // Bogus pointer offset and / or byteCount value
186185 handler .error ("Illegal TIFF tag pointer offset" );
187186 continue ;
188187 }
189- tagValueOffset = tiffHeaderOffset + offsetVal ;
190188 } else {
191189 // 4 bytes or less and value is in the dir entry itself.
192190 tagValueOffset = tagOffset + 8 ;
@@ -210,14 +208,14 @@ public static void processIfd(@NotNull final TiffHandler handler,
210208 for (int i = 0 ; i < componentCount ; i ++) {
211209 if (handler .tryEnterSubIfd (tagId )) {
212210 isIfdPointer = true ;
213- int subDirOffset = tiffHeaderOffset + reader .getInt32 ((int ) (tagValueOffset + i * 4 ));
214- processIfd (handler , reader , processedIfdOffsets , subDirOffset , tiffHeaderOffset );
211+ long subDirOffset = reader .getUInt32 ((int ) (tagValueOffset + i * 4 ));
212+ processIfd (handler , reader , processedGlobalIfdOffsets , ( int ) subDirOffset );
215213 }
216214 }
217215 }
218216
219217 // If it wasn't an IFD pointer, allow custom tag processing to occur
220- if (!isIfdPointer && !handler .customProcessTag ((int ) tagValueOffset , processedIfdOffsets , tiffHeaderOffset , reader , tagId , (int ) byteCount )) {
218+ if (!isIfdPointer && !handler .customProcessTag ((int ) tagValueOffset , processedGlobalIfdOffsets , reader , tagId , (int ) byteCount )) {
221219 // If no custom processing occurred, process the tag in the standard fashion
222220 processTag (handler , tagId , (int ) tagValueOffset , (int ) componentCount , formatCode , reader );
223221 }
@@ -227,10 +225,8 @@ public static void processIfd(@NotNull final TiffHandler handler,
227225 final int finalTagOffset = calculateTagOffset (ifdOffset , dirTagCount );
228226 int nextIfdOffset = reader .getInt32 (finalTagOffset );
229227 if (nextIfdOffset != 0 ) {
230- nextIfdOffset += tiffHeaderOffset ;
231228 if (nextIfdOffset >= reader .getLength ()) {
232229 // Last 4 bytes of IFD reference another IFD with an address that is out of bounds
233- // Note this could have been caused by jhead 1.3 cropping too much
234230 return ;
235231 } else if (nextIfdOffset < ifdOffset ) {
236232 // TODO is this a valid restriction?
@@ -239,7 +235,7 @@ public static void processIfd(@NotNull final TiffHandler handler,
239235 }
240236
241237 if (handler .hasFollowerIfd ()) {
242- processIfd (handler , reader , processedIfdOffsets , nextIfdOffset , tiffHeaderOffset );
238+ processIfd (handler , reader , processedGlobalIfdOffsets , nextIfdOffset );
243239 }
244240 }
245241 } finally {
@@ -326,7 +322,7 @@ private static void processTag(@NotNull final TiffHandler handler,
326322 break ;
327323 case TiffDataFormat .CODE_INT16_S :
328324 if (componentCount == 1 ) {
329- handler .setInt16s (tagId , ( int ) reader .getInt16 (tagValueOffset ));
325+ handler .setInt16s (tagId , reader .getInt16 (tagValueOffset ));
330326 } else {
331327 short [] array = new short [componentCount ];
332328 for (int i = 0 ; i < componentCount ; i ++)
0 commit comments