summaryrefslogtreecommitdiff
path: root/libtiff
diff options
context:
space:
mode:
authorSu Laus <sulau@freenet.de>2023-03-12 21:05:56 +0000
committerEven Rouault <even.rouault@spatialys.com>2023-03-12 21:05:56 +0000
commitf0a7bb7bdc77b404c79592be684f3c5d234751cf (patch)
tree4de6f440b9fb5deebe5559e43c4c69a1e51d4193 /libtiff
parent1d5b1181c980090a6518f11e61a18b0e268bf31a (diff)
downloadlibtiff-git-f0a7bb7bdc77b404c79592be684f3c5d234751cf.tar.gz
Optimize relative seeking with TIFFSetDirectory
Diffstat (limited to 'libtiff')
-rw-r--r--libtiff/tif_dir.c50
-rw-r--r--libtiff/tif_dirread.c7
-rw-r--r--libtiff/tif_open.c1
-rw-r--r--libtiff/tiffiop.h4
4 files changed, 49 insertions, 13 deletions
diff --git a/libtiff/tif_dir.c b/libtiff/tif_dir.c
index 56ecbf39..293d6fde 100644
--- a/libtiff/tif_dir.c
+++ b/libtiff/tif_dir.c
@@ -1702,6 +1702,12 @@ int TIFFCreateCustomDirectory(TIFF *tif, const TIFFFieldArray *infoarray)
tif->tif_curoff = 0;
tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1;
+ /* invalidate directory index */
+ tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
+ /* invalidate IFD loop lists */
+ _TIFFCleanupIFDOffsetAndNumberMaps(tif);
+ /* To be able to return from SubIFD or custom-IFD to main-IFD */
+ tif->tif_setdirectory_force_absolute = TRUE;
return 0;
}
@@ -2022,14 +2028,31 @@ tdir_t TIFFNumberOfDirectories(TIFF *tif)
int TIFFSetDirectory(TIFF *tif, tdir_t dirn)
{
uint64_t nextdiroff;
- tdir_t nextdirnum;
+ tdir_t nextdirnum = 0;
tdir_t n;
-
- if (!(tif->tif_flags & TIFF_BIGTIFF))
+ /* Fast path when we just advance relative to the current directory:
+ * start at the current dir offset and continue to seek from there.
+ * Check special cases when relative is not allowed:
+ * - jump back from SubIFD or custom directory
+ * - right after TIFFWriteDirectory() jump back to that directory
+ * using TIFFSetDirectory() */
+ const int relative = (dirn >= tif->tif_curdir) && (tif->tif_diroff != 0) &&
+ !tif->tif_setdirectory_force_absolute;
+
+ if (relative)
+ {
+ nextdiroff = tif->tif_diroff;
+ dirn -= tif->tif_curdir;
+ nextdirnum = tif->tif_curdir;
+ }
+ else if (!(tif->tif_flags & TIFF_BIGTIFF))
nextdiroff = tif->tif_header.classic.tiff_diroff;
else
nextdiroff = tif->tif_header.big.tiff_diroff;
- nextdirnum = 0;
+
+ /* Reset to relative stepping */
+ tif->tif_setdirectory_force_absolute = FALSE;
+
for (n = dirn; n > 0 && nextdiroff != 0; n--)
if (!TIFFAdvanceDirectory(tif, &nextdiroff, NULL, &nextdirnum))
return (0);
@@ -2039,12 +2062,15 @@ int TIFFSetDirectory(TIFF *tif, tdir_t dirn)
return (0);
tif->tif_nextdiroff = nextdiroff;
- /*
- * Set curdir to the actual directory index. The
- * -1 decrement is because TIFFReadDirectory will increment
- * tif_curdir after successfully reading the directory.
- */
- tif->tif_curdir = (dirn - n);
+
+ /* Set curdir to the actual directory index. */
+ if (relative)
+ tif->tif_curdir += dirn - n;
+ else
+ tif->tif_curdir = dirn - n;
+
+ /* The -1 decrement is because TIFFReadDirectory will increment
+ * tif_curdir after successfully reading the directory. */
if (tif->tif_curdir == 0)
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
else
@@ -2108,6 +2134,8 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
tif->tif_curdir = 0; /* first directory of new chain */
/* add this offset to new IFD list */
_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff);
+ /* To be able to return from SubIFD or custom-IFD to main-IFD */
+ tif->tif_setdirectory_force_absolute = TRUE;
}
return (retval);
}
@@ -2250,6 +2278,6 @@ 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;
- _TIFFCleanupIFDOffsetAndNumberMaps(tif);
+ _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */
return (1);
}
diff --git a/libtiff/tif_dirread.c b/libtiff/tif_dirread.c
index ef21f7f5..d4cc11d0 100644
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -4067,8 +4067,11 @@ int TIFFReadDirectory(TIFF *tif)
if (tif->tif_nextdiroff == 0)
{
- /* In this special case, tif_diroff needs also to be set to 0. */
+ /* In this special case, tif_diroff needs also to be set to 0.
+ * Furthermore, TIFFSetDirectory() needs to be switched to
+ * absolute stepping. */
tif->tif_diroff = tif->tif_nextdiroff;
+ tif->tif_setdirectory_force_absolute = TRUE;
return 0; /* last offset, thus no checking necessary */
}
@@ -5131,6 +5134,8 @@ int TIFFReadCustomDirectory(TIFF *tif, toff_t diroff,
} /*-- if (!dp->tdir_ignore) */
}
}
+ /* To be able to return from SubIFD or custom-IFD to main-IFD */
+ tif->tif_setdirectory_force_absolute = TRUE;
if (dir)
_TIFFfreeExt(tif, dir);
return 1;
diff --git a/libtiff/tif_open.c b/libtiff/tif_open.c
index e84ef6d2..aa16a64f 100644
--- a/libtiff/tif_open.c
+++ b/libtiff/tif_open.c
@@ -485,6 +485,7 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
goto bad;
tif->tif_diroff = 0;
tif->tif_lastdiroff = 0;
+ tif->tif_setdirectory_force_absolute = FALSE;
return (tif);
}
/*
diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
index c419608d..fbf7b070 100644
--- a/libtiff/tiffiop.h
+++ b/libtiff/tiffiop.h
@@ -148,7 +148,9 @@ struct tiff
uint64_t tif_lastdiroff; /* file offset of last directory written so far */
TIFFHashSet *tif_map_dir_offset_to_number;
TIFFHashSet *tif_map_dir_number_to_offset;
- TIFFDirectory tif_dir; /* internal rep of current directory */
+ int tif_setdirectory_force_absolute; /* switch between relative and absolute
+ stepping in TIFFSetDirectory() */
+ TIFFDirectory tif_dir; /* internal rep of current directory */
TIFFDirectory
tif_customdir; /* custom IFDs are separated from the main ones */
union