From 8f38557ef614f9af8b95ed164412e6157d1a5df8 Mon Sep 17 00:00:00 2001
From: Even Rouault <[EMAIL REDACTED]>
Date: Mon, 12 Dec 2022 19:02:54 +0100
Subject: [PATCH] TIFFCurrentDirectory(), TIFFNumberOfDirectories(),
TIFFSetDirectory(), TIFFUnlinkDirectory(): use tdir_t that is now a uint32_t,
and raise limit of IFDs to 1048576
---
doc/functions/TIFFCreateDirectory.rst | 2 +-
doc/functions/TIFFquery.rst | 4 +--
doc/functions/libtiff.rst | 6 +++-
libtiff/tif_dir.c | 50 ++++++++++++---------------
libtiff/tif_dir.h | 4 +--
libtiff/tif_dirread.c | 28 +++++++++------
libtiff/tif_open.c | 2 +-
libtiff/tiffio.h | 10 +++---
libtiff/tiffiop.h | 8 ++---
9 files changed, 59 insertions(+), 55 deletions(-)
diff --git a/doc/functions/TIFFCreateDirectory.rst b/doc/functions/TIFFCreateDirectory.rst
index 5e7377e5..7c285c05 100644
--- a/doc/functions/TIFFCreateDirectory.rst
+++ b/doc/functions/TIFFCreateDirectory.rst
@@ -14,7 +14,7 @@ Synopsis
.. c:function:: int TIFFFreeDirectory(TIFF* tif)
-.. c:function:: int TIFFUnlinkDirectory(TIFF* tif, uint16_t dirn)
+.. c:function:: int TIFFUnlinkDirectory(TIFF* tif, tdir_t dirn)
Description
-----------
diff --git a/doc/functions/TIFFquery.rst b/doc/functions/TIFFquery.rst
index 6a03c626..75ccb4e1 100644
--- a/doc/functions/TIFFquery.rst
+++ b/doc/functions/TIFFquery.rst
@@ -12,11 +12,11 @@ Synopsis
.. c:function:: tdir_t TIFFCurrentDirectory(TIFF* tif)
-.. c:function:: int TIFFCurrentDirOffset(TIFF* tif)
+.. c:function:: uint64_t TIFFCurrentDirOffset(TIFF* tif)
.. c:function:: int TIFFLastDirectory(TIFF* tif)
-.. c:function:: int TIFFNumberOfDirectories(TIFF* tif)
+.. c:function:: tdir_t TIFFNumberOfDirectories(TIFF* tif)
.. c:function:: uint32_t TIFFCurrentRow(TIFF* tif)
diff --git a/doc/functions/libtiff.rst b/doc/functions/libtiff.rst
index 54a08614..b4ad327f 100644
--- a/doc/functions/libtiff.rst
+++ b/doc/functions/libtiff.rst
@@ -70,7 +70,7 @@ definitions or through parameters passed through the varargs interfaces.
::
typedef uint32_t ttag_t; // directory tag
- typedef uint16_t tdir_t; // directory index
+ typedef uint32_t tdir_t; // directory index
typedef uint16_t tsample_t; // sample number
typedef uint32_t tstrip_t; // strip number
typedef uint32_t ttile_t; // tile number
@@ -94,10 +94,14 @@ Likewise
is limited by the 16-bit field used to store the
``SamplesPerPixel``
tag.
+
:c:type:`tdir_t`
constrains the maximum number of
IFDs
that may appear in an image and may be an arbitrary size (w/o penalty).
+Starting with libtiff 4.5.0, tdir_t is a 32-bit unsigned integer. Previously,
+it was a 16-bit unsigned integer.
+
:c:type:`ttag_t`
must be either int, unsigned int, pointer, or double because the library uses
a varargs interface and
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
index 6b58a2a3..3c3cb340 100644
--- a/libtiff/tif_dir.c
+++ b/libtiff/tif_dir.c
@@ -1812,7 +1812,7 @@ int TIFFDefaultDirectory(TIFF *tif)
}
static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
- uint16_t *nextdirnum)
+ tdir_t *nextdirnum)
{
static const char module[] = "TIFFAdvanceDirectory";
@@ -1820,8 +1820,8 @@ static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
if (!_TIFFCheckDirNumberAndOffset(tif, *nextdirnum, *nextdiroff))
{
TIFFErrorExtR(tif, module,
- "Starting directory %" PRIu16 " at offset 0x%" PRIx64
- " (%" PRIu64 ") might cause an IFD loop",
+ "Starting directory %u at offset 0x%" PRIx64 " (%" PRIu64
+ ") might cause an IFD loop",
*nextdirnum, *nextdiroff, *nextdiroff);
*nextdiroff = 0;
*nextdirnum = 0;
@@ -1995,12 +1995,11 @@ static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
/*
* Count the number of directories in a file.
*/
-uint16_t TIFFNumberOfDirectories(TIFF *tif)
+tdir_t TIFFNumberOfDirectories(TIFF *tif)
{
- static const char module[] = "TIFFNumberOfDirectories";
uint64_t nextdiroff;
- uint16_t nextdirnum;
- uint16_t n;
+ tdir_t nextdirnum;
+ tdir_t n;
if (!(tif->tif_flags & TIFF_BIGTIFF))
nextdiroff = tif->tif_header.classic.tiff_diroff;
else
@@ -2010,17 +2009,7 @@ uint16_t TIFFNumberOfDirectories(TIFF *tif)
while (nextdiroff != 0 &&
TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
{
- if (n != 65535)
- {
- ++n;
- }
- else
- {
- TIFFErrorExtR(tif, module,
- "Directory count exceeded 65535 limit,"
- " giving up on counting.");
- return (65535);
- }
+ ++n;
}
return (n);
}
@@ -2029,11 +2018,11 @@ uint16_t TIFFNumberOfDirectories(TIFF *tif)
* Set the n-th directory as the current directory.
* NB: Directories are numbered starting at 0.
*/
-int TIFFSetDirectory(TIFF *tif, uint16_t dirn)
+int TIFFSetDirectory(TIFF *tif, tdir_t dirn)
{
uint64_t nextdiroff;
- uint16_t nextdirnum;
- uint16_t n;
+ tdir_t nextdirnum;
+ tdir_t n;
if (!(tif->tif_flags & TIFF_BIGTIFF))
nextdiroff = tif->tif_header.classic.tiff_diroff;
@@ -2076,12 +2065,12 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
* https://www.awaresystems.be/imaging/tiff/specification/TIFFPM6.pdf.)
*/
int retval;
- uint16_t curdir = 0;
+ uint32_t curdir = 0;
int8_t probablySubIFD = 0;
if (diroff == 0)
{
/* Special case to invalidate the tif_lastdiroff member. */
- tif->tif_curdir = 65535;
+ tif->tif_curdir = 0xffffffffu;
}
else
{
@@ -2091,7 +2080,7 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
probablySubIFD = 1;
}
/* -1 because TIFFReadDirectory() will increment tif_curdir. */
- tif->tif_curdir = curdir - 1;
+ tif->tif_curdir = curdir == 0 ? 0xffffffffu : curdir - 1;
}
tif->tif_nextdiroff = diroff;
@@ -2099,7 +2088,12 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
/* If failed, curdir was not incremented in TIFFReadDirectory(), so set it
* back. */
if (!retval)
- tif->tif_curdir++;
+ {
+ if (tif->tif_curdir == 0xffffffffu)
+ tif->tif_curdir = 0;
+ else
+ tif->tif_curdir++;
+ }
if (retval && probablySubIFD)
{
/* Reset IFD list to start new one for SubIFD chain and also start
@@ -2129,13 +2123,13 @@ int TIFFLastDirectory(TIFF *tif) { return (tif->tif_nextdiroff == 0); }
* This is different to TIFFSetDirectory() where the first directory starts with
* zero.
*/
-int TIFFUnlinkDirectory(TIFF *tif, uint16_t dirn)
+int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn)
{
static const char module[] = "TIFFUnlinkDirectory";
uint64_t nextdir;
- uint16_t nextdirnum;
+ tdir_t nextdirnum;
uint64_t off;
- uint16_t n;
+ tdir_t n;
if (tif->tif_mode == O_RDONLY)
{
diff --git a/libtiff/tif_dir.h b/libtiff/tif_dir.h
index 3c5fd282..fad1eb02 100644
--- a/libtiff/tif_dir.h
+++ b/libtiff/tif_dir.h
@@ -325,10 +325,10 @@ extern "C"
TIFFDataType);
extern TIFFField *_TIFFCreateAnonField(TIFF *, uint32_t, TIFFDataType);
extern int _TIFFCheckFieldIsValidForCodec(TIFF *tif, ttag_t tag);
- extern int _TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn,
+ extern int _TIFFCheckDirNumberAndOffset(TIFF *tif, tdir_t dirn,
uint64_t diroff);
extern int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff,
- uint16_t *dirn);
+ tdir_t *dirn);
#if defined(__cplusplus)
}
diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
index 0dbe1f3e..e2f563eb 100644
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -4075,9 +4075,11 @@ int TIFFReadDirectory(TIFF *tif)
/* tif_curdir++ and tif_nextdiroff should only be updated after SUCCESSFUL
* reading of the directory. Otherwise, invalid IFD offsets could corrupt
* the IFD list. */
- if (!_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir + 1, nextdiroff))
+ if (!_TIFFCheckDirNumberAndOffset(
+ tif, tif->tif_curdir == 0xFFFFFFFFU ? 0 : tif->tif_curdir + 1,
+ nextdiroff))
{
- return 0; /* bad offset (IFD looping or more than 65535 IFDs) */
+ return 0; /* bad offset (IFD looping or more than 1048576 IFDs) */
}
dircount = TIFFFetchDirectory(tif, nextdiroff, &dir, &tif->tif_nextdiroff);
if (!dircount)
@@ -4090,7 +4092,10 @@ int TIFFReadDirectory(TIFF *tif)
/* Set global values after a valid directory has been fetched.
* tif_diroff is already set to nextdiroff in TIFFFetchDirectory() in the
* beginning. */
- tif->tif_curdir++;
+ if (tif->tif_curdir == 0xffffffffu)
+ tif->tif_curdir = 0;
+ else
+ tif->tif_curdir++;
(*tif->tif_cleanup)(tif); /* cleanup any previous compression state */
TIFFReadDirectoryCheckOrder(tif, dir, dircount);
@@ -5319,7 +5324,7 @@ static bool equalFuncNumberToOffset(const void *elt1, const void *elt2)
* Returns 1 if all is ok; 0 if last directory or IFD loop is encountered,
* or an error has occurred.
*/
-int _TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff)
+int _TIFFCheckDirNumberAndOffset(TIFF *tif, tdir_t dirn, uint64_t diroff)
{
if (diroff == 0) /* no more directories */
return 0;
@@ -5391,10 +5396,11 @@ int _TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff)
return 1;
}
- if (tif->tif_dirnumber == 65535)
+ /* Arbitrary (hopefully big enough) limit */
+ if (tif->tif_dirnumber >= 1048576)
{
TIFFErrorExtR(tif, "_TIFFCheckDirNumberAndOffset",
- "Cannot handle more than 65535 TIFF directories");
+ "Cannot handle more than 1048576 TIFF directories");
return 0;
}
@@ -5437,14 +5443,14 @@ int _TIFFCheckDirNumberAndOffset(TIFF *tif, uint16_t dirn, uint64_t diroff)
* can be returned.
* Otherwise returns 0 or if an error occurred.
*/
-int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t *dirn)
+int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, tdir_t *dirn)
{
if (diroff == 0) /* no more directories */
return 0;
- if (tif->tif_dirnumber == 65535)
+ if (tif->tif_dirnumber >= 1048576)
{
TIFFErrorExtR(tif, "_TIFFGetDirNumberFromOffset",
- "Cannot handle more than 65535 TIFF directories");
+ "Cannot handle more than 1048576 TIFF directories");
return 0;
}
@@ -5463,7 +5469,7 @@ int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t *dirn)
tif->tif_map_dir_offset_to_number, &entry);
if (foundEntry)
{
- *dirn = (uint16_t)foundEntry->dirNumber;
+ *dirn = foundEntry->dirNumber;
return 1;
}
@@ -5473,7 +5479,7 @@ int _TIFFGetDirNumberFromOffset(TIFF *tif, uint64_t diroff, uint16_t *dirn)
tif->tif_map_dir_offset_to_number, &entry);
if (foundEntry)
{
- *dirn = (uint16_t)foundEntry->dirNumber;
+ *dirn = foundEntry->dirNumber;
return 1;
}
diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c
index 77372533..953d8258 100644
--- a/libtiff/tif_open.c
+++ b/libtiff/tif_open.c
@@ -721,7 +721,7 @@ uint32_t TIFFCurrentRow(TIFF *tif) { return (tif->tif_row); }
/*
* Return index of the current directory.
*/
-uint16_t TIFFCurrentDirectory(TIFF *tif) { return (tif->tif_curdir); }
+tdir_t TIFFCurrentDirectory(TIFF *tif) { return (tif->tif_curdir); }
/*
* Return current strip.
diff --git a/libtiff/tiffio.h b/libtiff/tiffio.h
index df20f8bb..4df57665 100644
--- a/libtiff/tiffio.h
+++ b/libtiff/tiffio.h
@@ -69,7 +69,7 @@ typedef uint64_t toff_t; /* file offset */
/* the following are deprecated and should be replaced by their defining
counterparts */
typedef uint32_t ttag_t; /* directory tag */
-typedef uint16_t tdir_t; /* directory index */
+typedef uint32_t tdir_t; /* directory index */
typedef uint16_t tsample_t; /* sample number */
typedef uint32_t tstrile_t; /* strip or tile number */
typedef tstrile_t tstrip_t; /* strip number */
@@ -414,8 +414,8 @@ extern "C"
extern TIFFMapFileProc TIFFGetMapFileProc(TIFF *);
extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF *);
extern uint32_t TIFFCurrentRow(TIFF *);
- extern uint16_t TIFFCurrentDirectory(TIFF *);
- extern uint16_t TIFFNumberOfDirectories(TIFF *);
+ extern tdir_t TIFFCurrentDirectory(TIFF *);
+ extern tdir_t TIFFNumberOfDirectories(TIFF *);
extern uint64_t TIFFCurrentDirOffset(TIFF *);
extern uint32_t TIFFCurrentStrip(TIFF *);
extern uint32_t TIFFCurrentTile(TIFF *tif);
@@ -429,9 +429,9 @@ extern "C"
extern int TIFFCreateEXIFDirectory(TIFF *);
extern int TIFFCreateGPSDirectory(TIFF *);
extern int TIFFLastDirectory(TIFF *);
- extern int TIFFSetDirectory(TIFF *, uint16_t);
+ extern int TIFFSetDirectory(TIFF *, tdir_t);
extern int TIFFSetSubDirectory(TIFF *, uint64_t);
- extern int TIFFUnlinkDirectory(TIFF *, uint16_t);
+ extern int TIFFUnlinkDirectory(TIFF *, tdir_t);
extern int TIFFSetField(TIFF *, uint32_t, ...);
extern int TIFFVSetField(TIFF *, uint32_t, va_list);
extern int TIFFUnsetField(TIFF *, uint32_t);
diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
index fc41be5b..1d4add0a 100644
--- a/libtiff/tiffiop.h
+++ b/libtiff/tiffiop.h
@@ -90,7 +90,7 @@ typedef void (*TIFFTileMethod)(TIFF *, uint32_t *, uint32_t *);
struct TIFFOffsetAndDirNumber
{
uint64_t offset;
- uint32_t dirNumber;
+ tdir_t dirNumber;
};
typedef struct TIFFOffsetAndDirNumber TIFFOffsetAndDirNumber;
@@ -142,8 +142,8 @@ struct tiff
prevent IFD looping */
TIFFHashSet *tif_map_dir_offset_to_number;
TIFFHashSet *tif_map_dir_number_to_offset;
- uint16_t tif_dirnumber; /* number of already seen directories */
- TIFFDirectory tif_dir; /* internal rep of current directory */
+ tdir_t tif_dirnumber; /* number of already seen directories */
+ TIFFDirectory tif_dir; /* internal rep of current directory */
TIFFDirectory
tif_customdir; /* custom IFDs are separated from the main ones */
union
@@ -154,7 +154,7 @@ struct tiff
} tif_header;
uint16_t tif_header_size; /* file's header block and its length */
uint32_t tif_row; /* current scanline */
- uint16_t tif_curdir; /* current directory (index) */
+ 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