From 5eb068a4cd11a5f8d05fb3fbe2399aac55e4e837 Mon Sep 17 00:00:00 2001
From: Su Laus <[EMAIL REDACTED]>
Date: Sun, 11 Aug 2024 15:59:39 +0000
Subject: [PATCH] Fix cases where tif_curdir is set incorrectly
Fix cases where the current directory number (tif_curdir) is set inconsistently or incorrectly, depending on the previous history.
See additional checks and tests in test/test_directory.c of this MR for intended setting of tif_curdir (i.e. TIFFCurrentDirectory(tif)).
---
libtiff/tif_dir.c | 44 ++-
libtiff/tif_dir.h | 3 +
libtiff/tif_dirread.c | 8 +-
libtiff/tif_dirwrite.c | 135 +++++--
libtiff/tif_open.c | 4 +
libtiff/tiffiop.h | 32 +-
test/test_directory.c | 877 ++++++++++++++++++++++++++++++++++++++++-
7 files changed, 1048 insertions(+), 55 deletions(-)
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
index a491097b..459f9696 100644
--- a/libtiff/tif_dir.c
+++ b/libtiff/tif_dir.c
@@ -1662,6 +1662,7 @@ void TIFFFreeDirectory(TIFF *tif)
tif->tif_dir.td_dirdatasize_offsets = NULL;
tif->tif_dir.td_dirdatasize_Noffsets = 0;
}
+ tif->tif_dir.td_iswrittentofile = FALSE;
}
#undef CleanupField
@@ -1694,6 +1695,7 @@ int TIFFCreateDirectory(TIFF *tif)
tif->tif_curoff = 0;
tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1;
+ tif->tif_dir.td_iswrittentofile = FALSE;
return 0;
}
@@ -2042,6 +2044,8 @@ tdir_t TIFFNumberOfDirectories(TIFF *tif)
{
++n;
}
+ /* Update number of main-IFDs in file. */
+ tif->tif_curdircount = n;
return (n);
}
@@ -2124,7 +2128,19 @@ int TIFFSetDirectory(TIFF *tif, tdir_t dirn)
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
else
tif->tif_curdir--;
- return (TIFFReadDirectory(tif));
+
+ tdir_t curdir = tif->tif_curdir;
+
+ int retval = TIFFReadDirectory(tif);
+
+ if (!retval && tif->tif_curdir == curdir)
+ {
+ /* If tif_curdir has not be incremented, TIFFFetchDirectory() in
+ * TIFFReadDirectory() has failed and tif_curdir shall be set
+ * specifically. */
+ tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+ }
+ return (retval);
}
/*
@@ -2149,8 +2165,11 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
int8_t probablySubIFD = 0;
if (diroff == 0)
{
- /* Special case to invalidate the tif_lastdiroff member. */
+ /* Special case to set tif_diroff=0, which is done in
+ * TIFFReadDirectory() below to indicate that the currently read IFD is
+ * treated as a new, fresh IFD. */
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+ tif->tif_dir.td_iswrittentofile = FALSE;
}
else
{
@@ -2165,24 +2184,25 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
else
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
}
+ curdir = tif->tif_curdir;
tif->tif_nextdiroff = diroff;
retval = TIFFReadDirectory(tif);
- /* If failed, curdir was not incremented in TIFFReadDirectory(), so set it
- * back, but leave it for diroff==0. */
- if (!retval && diroff != 0)
+
+ /* tif_curdir is incremented in TIFFReadDirectory(), but if it has not been
+ * incremented, TIFFFetchDirectory() has failed there and tif_curdir shall
+ * be set specifically. */
+ if (!retval && diroff != 0 && tif->tif_curdir == curdir)
{
- if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER)
- tif->tif_curdir = 0;
- else
- tif->tif_curdir++;
+ tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
}
+
if (probablySubIFD)
{
if (retval)
{
/* Reset IFD list to start new one for SubIFD chain and also start
- * SubIFD chain with tif_curdir=0. */
+ * SubIFD chain with tif_curdir=0 for IFD loop checking. */
/* invalidate IFD loop lists */
_TIFFCleanupIFDOffsetAndNumberMaps(tif);
tif->tif_curdir = 0; /* first directory of new chain */
@@ -2336,6 +2356,10 @@ int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn)
tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1;
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+ if (tif->tif_curdircount > 0)
+ tif->tif_curdircount--;
+ else
+ tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
_TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */
return (1);
}
diff --git a/libtiff/tif_dir.h b/libtiff/tif_dir.h
index f9558b62..f4182a2c 100644
--- a/libtiff/tif_dir.h
+++ b/libtiff/tif_dir.h
@@ -145,6 +145,9 @@ typedef struct
unsigned char
td_deferstrilearraywriting; /* see TIFFDeferStrileArrayWriting() */
+ unsigned char
+ td_iswrittentofile; /* indicates if current IFD is present on file */
+
/* LibTIFF writes all data that does not fit into the IFD entries directly
* after the IFD tag entry part. When reading, only the IFD data directly
* and continuously behind the IFD tags is taken into account for the IFD
diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
index 4305a512..b360deae 100644
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -4281,6 +4281,7 @@ int TIFFReadDirectory(TIFF *tif)
tif->tif_curdir = 0;
else
tif->tif_curdir++;
+
(*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
TIFFReadDirectoryCheckOrder(tif, dir, dircount);
@@ -4314,6 +4315,11 @@ int TIFFReadDirectory(TIFF *tif)
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif);
+ /* After setup a fresh directory indicate that now active IFD is also
+ * present on file, even if its entries could not be read successfully
+ * below. */
+ tif->tif_dir.td_iswrittentofile = TRUE;
+
/* Allocate arrays for offset values outside IFD entry for IFD data size
* checking. Note: Counter are reset within TIFFFreeDirectory(). */
tif->tif_dir.td_dirdatasize_offsets =
@@ -5191,7 +5197,7 @@ int TIFFReadDirectory(TIFF *tif)
if (dir)
_TIFFfreeExt(tif, dir);
return (0);
-}
+} /*-- TIFFReadDirectory() --*/
static void TIFFReadDirectoryCheckOrder(TIFF *tif, TIFFDirEntry *dir,
uint16_t dircount)
diff --git a/libtiff/tif_dirwrite.c b/libtiff/tif_dirwrite.c
index 7ebcbb26..48407a3b 100644
--- a/libtiff/tif_dirwrite.c
+++ b/libtiff/tif_dirwrite.c
@@ -1185,17 +1185,12 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
}
if (tif->tif_dataoff & 1)
tif->tif_dataoff++;
- if (isimage)
- {
- if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER)
- tif->tif_curdir = 0;
- else
- tif->tif_curdir++;
- }
} /* while() */
if (isimage)
{
- /* For SubIFDs remember offset of SubIFD tag within main IFD. */
+ /* For SubIFDs remember offset of SubIFD tag within main IFD.
+ * However, might be already done in TIFFWriteDirectoryTagSubifd() if
+ * there are more than one SubIFD. */
if (TIFFFieldSet(tif, FIELD_SUBIFD) && (tif->tif_subifdoff == 0))
{
uint32_t na;
@@ -1297,7 +1292,8 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
dir = NULL;
if (!SeekOK(tif, tif->tif_diroff))
{
- TIFFErrorExtR(tif, module, "IO error writing directory");
+ TIFFErrorExtR(tif, module,
+ "IO error writing directory at seek to offset");
goto bad;
}
if (!WriteOK(tif, dirmem, (tmsize_t)dirsize))
@@ -1306,6 +1302,68 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
goto bad;
}
_TIFFfreeExt(tif, dirmem);
+
+ /* Increment tif_curdir if IFD wasn't already written to file and no error
+ * occurred during IFD writing above. */
+ if (isimage && !tif->tif_dir.td_iswrittentofile)
+ {
+ if (!((tif->tif_flags & TIFF_INSUBIFD) &&
+ !(TIFFFieldSet(tif, FIELD_SUBIFD))))
+ {
+ /*-- Normal main-IFD case --*/
+ if (tif->tif_curdircount != TIFF_NON_EXISTENT_DIR_NUMBER)
+ {
+ tif->tif_curdir = tif->tif_curdircount;
+ }
+ else
+ {
+ /*ToDo SU: NEW_IFD_CURDIR_INCREMENTING: Delete this
+ * unexpected case after some testing time. */
+ /* Attention: tif->tif_curdircount is already set within
+ * TIFFNumberOfDirectories() */
+ tif->tif_curdircount = TIFFNumberOfDirectories(tif);
+ tif->tif_curdir = tif->tif_curdircount;
+ TIFFErrorExtR(
+ tif, module,
+ "tif_curdircount is TIFF_NON_EXISTENT_DIR_NUMBER, "
+ "not expected !! Line %d",
+ __LINE__);
+ goto bad;
+ }
+ }
+ else
+ {
+ /*-- SubIFD case -- */
+ /* tif_curdir is always set to 0 for all SubIFDs. */
+ tif->tif_curdir = 0;
+ }
+ }
+ /* Increment tif_curdircount only if main-IFD of an image was not already
+ * present on file. */
+ /* Check in combination with (... && !(TIFFFieldSet(tif, FIELD_SUBIFD)))
+ * is necessary here because TIFF_INSUBIFD was already set above for the
+ * next SubIFD when this main-IFD (with FIELD_SUBIFD) is currently being
+ * written. */
+ if (isimage && !tif->tif_dir.td_iswrittentofile &&
+ !((tif->tif_flags & TIFF_INSUBIFD) &&
+ !(TIFFFieldSet(tif, FIELD_SUBIFD))))
+ tif->tif_curdircount++;
+
+ tif->tif_dir.td_iswrittentofile = TRUE;
+
+ /* Reset SubIFD writing stage after last SubIFD has been written. */
+ if (imagedone && (tif->tif_flags & TIFF_INSUBIFD) && tif->tif_nsubifd == 0)
+ tif->tif_flags &= ~TIFF_INSUBIFD;
+
+ /* Add or update this directory to the IFD list. */
+ if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, tif->tif_diroff))
+ {
+ TIFFErrorExtR(tif, module,
+ "Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64
+ ") might cause an IFD loop",
+ tif->tif_curdir, tif->tif_diroff, tif->tif_diroff);
+ }
+
if (imagedone)
{
TIFFFreeDirectory(tif);
@@ -1317,9 +1375,8 @@ static int TIFFWriteDirectorySec(TIFF *tif, int isimage, int imagedone,
}
else
{
- /* IFD is only checkpointed to file, thus set IFD data size written to
- * file.
- */
+ /* IFD is only checkpointed to file (or a custom IFD like EXIF is
+ * written), thus set IFD data size written to file. */
tif->tif_dir.td_dirdatasize_read = tif->tif_dir.td_dirdatasize_write;
}
return (1);
@@ -3073,15 +3130,15 @@ static int TIFFLinkDirectory(TIFF *tif)
"Error writing SubIFD directory link");
return (0);
}
+
/*
* Advance to the next SubIFD or, if this is
- * the last one configured, revert back to the
- * normal directory linkage.
+ * the last one configured, reverting back to the
+ * normal directory linkage is done in TIFFWriteDirectorySec()
+ * by tif->tif_flags &= ~TIFF_INSUBIFD;.
*/
if (--tif->tif_nsubifd)
tif->tif_subifdoff += 4;
- else
- tif->tif_flags &= ~TIFF_INSUBIFD;
return (1);
}
else
@@ -3097,19 +3154,23 @@ static int TIFFLinkDirectory(TIFF *tif)
"Error writing SubIFD directory link");
return (0);
}
+
/*
* Advance to the next SubIFD or, if this is
- * the last one configured, revert back to the
- * normal directory linkage.
+ * the last one configured, reverting back to the
+ * normal directory linkage is done in TIFFWriteDirectorySec()
+ * by tif->tif_flags &= ~TIFF_INSUBIFD;.
*/
if (--tif->tif_nsubifd)
tif->tif_subifdoff += 8;
- else
- tif->tif_flags &= ~TIFF_INSUBIFD;
return (1);
}
}
+ /*
+ * Handle main-IFDs
+ */
+ tdir_t ndir = 1; /* count current number of main-IFDs */
if (!(tif->tif_flags & TIFF_BIGTIFF))
{
uint32_t m;
@@ -3130,18 +3191,26 @@ static int TIFFLinkDirectory(TIFF *tif)
TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
return (0);
}
+ if (!tif->tif_dir.td_iswrittentofile)
+ tif->tif_curdircount = 0;
return (1);
}
/*
* Not the first directory, search to the last and append.
*/
- if (tif->tif_lastdiroff != 0)
+ tdir_t dirn = -1;
+ if (tif->tif_lastdiroff != 0 &&
+ _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn))
{
+ /* Start searching from the lastely written IFD. Thus get its IFD
+ * number. */
nextdir = (uint32_t)tif->tif_lastdiroff;
+ ndir = dirn + 1;
}
else
{
nextdir = tif->tif_header.classic.tiff_diroff;
+ ndir = 1; /* start searching from the first IFD */
}
while (1)
@@ -3176,10 +3245,12 @@ static int TIFFLinkDirectory(TIFF *tif)
break;
}
nextdir = nextnextdir;
+ ndir++;
}
}
else
{
+ /*- BigTIFF -*/
uint64_t m;
uint64_t nextdir;
m = tif->tif_diroff;
@@ -3198,18 +3269,26 @@ static int TIFFLinkDirectory(TIFF *tif)
TIFFErrorExtR(tif, tif->tif_name, "Error writing TIFF header");
return (0);
}
+ if (!tif->tif_dir.td_iswrittentofile)
+ tif->tif_curdircount = 0;
return (1);
}
/*
* Not the first directory, search to the last and append.
*/
- if (tif->tif_lastdiroff != 0)
+ tdir_t dirn = -1;
+ if (tif->tif_lastdiroff != 0 &&
+ _TIFFGetDirNumberFromOffset(tif, tif->tif_lastdiroff, &dirn))
{
+ /* Start searching from the lastely written IFD. Thus get its IFD
+ * number. */
nextdir = tif->tif_lastdiroff;
+ ndir = dirn + 1;
}
else
{
nextdir = tif->tif_header.big.tiff_diroff;
+ ndir = 1; /* start searching from the first IFD */
}
while (1)
{
@@ -3252,8 +3331,20 @@ static int TIFFLinkDirectory(TIFF *tif)
break;
}
nextdir = nextnextdir;
+ ndir++;
}
}
+ /* Offset of next IFD is written to file.
+ * Update number of main-IFDs in file.
+ * However, tif_curdircount shall count only newly written main-IFDs with
+ * entries and not only number of linked offsets! Thus, tif_curdircount is
+ * incremented at the end of TIFFWriteDirectorySec().
+ * TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs'
+ * 0 means 'empty file opened for writing, but no IFD written yet' */
+ if (!tif->tif_dir.td_iswrittentofile && !(tif->tif_flags & TIFF_INSUBIFD))
+ {
+ tif->tif_curdircount = ndir;
+ }
return (1);
}
diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c
index b18e8948..56330d77 100644
--- a/libtiff/tif_open.c
+++ b/libtiff/tif_open.c
@@ -366,6 +366,7 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
strcpy(tif->tif_name, name);
tif->tif_mode = m & ~(O_CREAT | O_TRUNC);
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; /* non-existent directory */
+ tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
tif->tif_curoff = 0;
tif->tif_curstrip = (uint32_t)-1; /* invalid strip */
tif->tif_row = (uint32_t)-1; /* read/write pre-increment */
@@ -607,6 +608,9 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
tif->tif_diroff = 0;
tif->tif_lastdiroff = 0;
tif->tif_setdirectory_force_absolute = FALSE;
+ /* tif_curdircount = 0 means 'empty file opened for writing, but no IFD
+ * written yet' */
+ tif->tif_curdircount = 0;
return (tif);
}
diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
index 803ca98c..c4348206 100644
--- a/libtiff/tiffiop.h
+++ b/libtiff/tiffiop.h
@@ -163,12 +163,32 @@ struct tiff
TIFFHeaderUnion tif_header; /* file's header block Classic/BigTIFF union */
uint16_t tif_header_size; /* file's header block and its length */
uint32_t tif_row; /* current scanline */
- tdir_t tif_curdir; /* current directory (index) */
- uint32_t tif_curstrip; /* current strip for read/write */
- uint64_t tif_curoff; /* current offset for read/write */
- uint64_t tif_lastvalidoff; /* last valid offset allowed for rewrite in
- place. Used only by TIFFAppendToStrip() */
- uint64_t tif_dataoff; /* current offset for writing dir (IFD) */
+
+ /* There are IFDs in the file and an "active" IFD in memory,
+ * from which fields are "set" and "get".
+ * tif_curdir is set to:
+ * a) TIFF_NON_EXISTENT_DIR_NUMBER if there is no IFD in the file
+ * or the state is unknown,
+ * or the last read (i.e. TIFFFetchDirectory()) failed,
+ * or a custom directory was written.
+ * b) IFD index of last IFD written in the file. In this case the
+ * active IFD is a new (empty) one and tif_diroff is zero.
+ * If writing fails, tif_curdir is not changed.
+ * c) IFD index of IFD read from file into memory (=active IFD),
+ * even if IFD is corrupt and TIFFReadDirectory() returns 0.
+ * Then tif_diroff contains the offset of the IFD in the file.
+ * d) IFD index 0, whenever a custom directory or an unchained SubIFD
+ * was read. */
+ tdir_t tif_curdir; /* current directory (index) */
+ /* tif_curdircount: number of directories (main-IFDs) in file:
+ * - TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs'.
+ * - 0 means 'empty file opened for writing, but no IFD written yet' */
+ tdir_t tif_curdircount;
+ uint32_t tif_curstrip; /* current strip for read/write */
+ uint64_t tif_curoff; /* current offset for read/write */
+ uint64_t tif_lastvalidoff; /* last valid offset allowed for rewrite in
+ place. Used only by TIFFAppendToStrip() */
+ uint64_t tif_dataoff; /* current offset for writing dir (IFD) */
/* SubIFD support */
uint16_t tif_nsubifd; /* remaining subifds to write */
uint64_t tif_subifdoff; /* offset for patching SubIFD link */
diff --git a/test/test_directory.c b/test/test_directory.c
index b8ba8d2f..a50096a4 100644
--- a/test/test_directory.c
+++ b/test/test_directory.c
@@ -30,6 +30,10 @@
* Furthermore, tests are performed with big-endian, little-endian and BigTIFF
* images.
*
+ * Furthermore the correctness of tif_curdir = TIFFCurrentDirectory() when
+ * moving though a multi-IFD file and creating new IFDs, overwriting or
+ * re-writing IFDs as well for reading and writing SubIFDs is tested.
+ *
*/
#include "tif_config.h"
@@ -59,6 +63,51 @@ char *openModeStrings[] = {"wl", "wb", "w8l", "w8b"};
char *openModeText[] = {"non-BigTIFF and LE", "non-BigTIFF and BE",
"BigTIFF and LE", "BigTIFF and BE"};
+/* Some functions and macros to get more readable test code. */
+int CheckCurDirNum(TIFF *tif, tdir_t expected_dirnum, int line)
+{
+
+ tdir_t curdir = TIFFCurrentDirectory(tif);
+ if (curdir != expected_dirnum)
+ {
+ fprintf(stderr,
+ "Error: curdir %d is different to expected one %d at line %d\n",
+ curdir, expected_dirnum, line);
+ return 1;
+ }
+ return 0;
+}
+
+#define TIFFWriteDirectory_M(tif, filename, line) \
+ if (!TIFFWriteDirectory(tif)) \
+ { \
+ fprintf(stderr, "Can't write directory to %s at line %d\n", filename, \
+ line); \
+ goto failure; \
+ }
+
+#define TIFFCheckpointDirectory_M(tif, dirnum, filename, line) \
+ if (!TIFFCheckpointDirectory(tif)) \
+ { \
+ fprintf(stderr, "Can't checkpoint directory %d of %s at line %d\n", \
+ dirnum, filename, line); \
+ goto failure; \
+ }
+
+#define TIFFSetDirectory_M(tif, dirnum, filename, line) \
+ if (!TIFFSetDirectory(tif, dirnum)) \
+ { \
+ fprintf(stderr, "Can't set directory %d of %s at line %d\n", dirnum, \
+ filename, line); \
+ goto failure; \
+ }
+
+#define CHECKCURDIRNUM_M(tif, x, line) \
+ if (CheckCurDirNum(tif, x, line)) \
+ { \
+ goto failure; \
+ }
+
/* Writes basic tags to current directory (IFD) as well one pixel to the file.
* For is_corrupted = TRUE a corrupted IFD (missing image width tag) is
* generated. */
@@ -180,9 +229,10 @@ int count_directories(const char *filename, int *count)
do
{
+ CHECKCURDIRNUM_M(tif, (tdir_t)(*count), __LINE__);
(*count)++;
} while (TIFFReadDirectory(tif));
-
+failure:
TIFFClose(tif);
return 0;
}
@@ -303,6 +353,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
TIFF *tif;
uint64_t offsets_base[N_DIRECTORIES];
int expected_original_dirnumber;
+ tdir_t expected_curdir = (tdir_t)(-1);
if (openMode >= (sizeof(openModeStrings) / sizeof(openModeStrings[0])))
{
@@ -324,6 +375,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
return 1;
}
TIFFSetDirectory(tif, 0);
+ CHECKCURDIRNUM_M(tif, expected_curdir, __LINE__);
for (int i = 0; i < N_DIRECTORIES; i++)
{
if (write_data_to_current_directory(tif, i, false))
@@ -337,11 +389,15 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
fprintf(stderr, "Can't write directory to %s\n", filename);
goto failure;
}
+ expected_curdir++;
+ /* Fails in 4.6.0 */
+ CHECKCURDIRNUM_M(tif, expected_curdir, __LINE__);
if (i >= 2 && i <= 4)
{
if (i == 3)
{
- /* Invalidate directory - TIFFSetSubDirectory() will fail */
+ /* Invalidate directory - TIFFSetSubDirectory() will fail.
+ * The next TIFFSetDirectory(i) will revoke this action.*/
if (TIFFSetSubDirectory(tif, 0))
{
fprintf(stderr,
@@ -362,7 +418,10 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
}
if (i == 4)
{
- /* Invalidate directory - TIFFSetSubDirectory() will fail */
+ /* Invalidate directory - TIFFSetSubDirectory() will fail.
+ * This time, tif_curdir keeps set to -1 and counts now again
+ * from 0, despite the directory number in the file is equal
+ * "i". */
if (TIFFSetSubDirectory(tif, 0))
{
fprintf(stderr,
@@ -413,6 +472,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
N_DIRECTORIES + 1, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, N_DIRECTORIES - 1, __LINE__);
/* Test very fast TIFFSetDirectory() using IFD loop directory list.
* First populate IFD loop directory list and then go through directories in
@@ -425,8 +485,10 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
fprintf(stderr, "Can't set %d.th directory from %s\n", i, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, i, __LINE__);
}
TIFFReadDirectory(tif);
+ CHECKCURDIRNUM_M(tif, N_DIRECTORIES - 1, __LINE__);
for (int i = N_DIRECTORIES - 1; i >= 0; i--)
{
if (!TIFFSetDirectory(tif, i))
@@ -438,6 +500,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
{
goto failure;
}
+ CHECKCURDIRNUM_M(tif, i, __LINE__);
}
/* Test not existing directory number */
@@ -449,6 +512,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
N_DIRECTORIES, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 0, __LINE__);
/* Close and Reopen prepared testfile */
TIFFClose(tif);
@@ -471,6 +535,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
{
goto failure;
}
+ CHECKCURDIRNUM_M(tif, i, __LINE__);
}
/* More specialized test cases for relative seeking within TIFFSetDirectory.
@@ -481,6 +546,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
fprintf(stderr, "Can't set directory %d within %s\n", 2, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 2, __LINE__);
uint64_t off2 = TIFFCurrentDirOffset(tif);
/* Note that dirnum = 2 is deleted here since TIFFUnlinkDirectory()
* starts with 1 instead of 0. */
@@ -500,6 +566,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
goto failure;
}
/*Check if correct directory is loaded */
+ CHECKCURDIRNUM_M(tif, 0, __LINE__);
expected_original_dirnumber = 2;
if (!is_requested_directory(tif, expected_original_dirnumber, filename))
{
@@ -512,6 +579,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
fprintf(stderr, "Can't set new directory %d within %s\n", 3, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 3, __LINE__);
expected_original_dirnumber = 4;
if (!is_requested_directory(tif, expected_original_dirnumber, filename))
{
@@ -544,6 +612,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
2, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 2, __LINE__);
/* which should now be the previous dir-3. */
expected_original_dirnumber = 4;
if (!is_requested_directory(tif, expected_original_dirnumber, filename))
@@ -551,8 +620,11 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
goto failure;
}
- /* Check, if third original directory could be loaded and the following,
- * still chained one. This is like for a SubIFD. */
+ /* Check, if third original directory, which is unlinked, could be loaded
+ * and the following, still chained one. This is like for a SubIFD.
+ * tif_curdir will be set to 0 because deleted IFD is not in main sequence
+ * and then incremented to 1 when reading the still chained next IFD using
+ * TIFFReadDirectory(). */
if (!TIFFSetSubDirectory(tif, offsets_base[2]))
{
fprintf(stderr,
@@ -561,6 +633,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
offsets_base[2], offsets_base[2], filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 0, __LINE__);
if (!TIFFReadDirectory(tif))
{
fprintf(stderr,
@@ -572,6 +645,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
/* Check if correct directory is loaded, which was unlinked the second
* time.
*/
+ CHECKCURDIRNUM_M(tif, 1, __LINE__);
expected_original_dirnumber = 3;
if (!is_requested_directory(tif, expected_original_dirnumber, filename))
{
@@ -589,6 +663,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
offsets_base[2], offsets_base[2], filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 0, __LINE__);
if (!TIFFSetDirectory(tif, 3))
{
fprintf(stderr, "Can't set new directory %d within %s\n", 3, filename);
@@ -600,6 +675,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
3, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 3, __LINE__);
/*Check if correct directory is loaded. Because two original IFDs are
* unlinked / missing, the original dirnumber is now 5. */
expected_original_dirnumber = 5;
@@ -653,11 +729,13 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
* Furthermore, this test checks that TIFFUnlinkDirectory() can unlink
* the first directory dirnum = 0 and a following TIFFSetDirectory(0)
* does not load the unlinked directory. */
+ CHECKCURDIRNUM_M(tif, 3, __LINE__);
if (!TIFFUnlinkDirectory(tif, 1))
{
fprintf(stderr, "Can't unlink directory %d within %s\n", 0, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, (tdir_t)(-1), __LINE__);
/* Now three directories are missing (0,2,3) and thus directory 0 is
* original directory 1 and directory 2 is original directory 5. */
if (!TIFFSetDirectory(tif, 0))
@@ -668,6 +746,7 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
0, filename);
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 0, __LINE__);
expected_original_dirnumber = 1;
if (!is_requested_directory(tif, expected_original_dirnumber, filename))
{
@@ -690,11 +769,15 @@ int test_arbitrary_directrory_loading(unsigned int openMode)
/* TIFFUnlinkDirectory(0) is not allowed, because dirnum starts for
* this function with 1 instead of 0.
* An error return is expected here. */
+ CHECKCURDIRNUM_M(tif, 2, __LINE__);
+ fprintf(stderr, "----- Expect error messages about 'TIFFUnlinkDirectory() "
+ "first directory starts with number 1 and not 0.' -----\n");
if (TIFFUnlinkDirectory(tif, 0))
{
fprintf(stderr, "TIFFUnlinkDirectory(0) did not return an error.\n");
goto failure;
}
+ CHECKCURDIRNUM_M(tif, 2, __LINE__);
TIFFClose(tif);
unlink(filename);
@@ -717,7 +800,7 @@ int test_SubIFD_directrory_handling(unsigned int openMode)
char filename[128] = {0};
/* Define the number of sub-IFDs you are going to write */
-#define NUMBER_OF_SUBIFDs 3
+#define NUMBER_OF_SUBIFDs 4
uint16_t number_of_sub_IFDs = NUMBER_OF_SUBIFDs;
toff_t sub_IFDs_offsets[NUMBER_OF_SUBIFDs] = {
0UL}; /* array for SubIFD tag */
@@ -763,6 +846,8 @@ int test_SubIFD_directrory_handling(unsigned int openMode)
goto failure;
}
+ expected_origin
(Patch may be truncated, please check the link at the top of this post.)