From f0a7bb7bdc77b404c79592be684f3c5d234751cf Mon Sep 17 00:00:00 2001 From: Su Laus Date: Sun, 12 Mar 2023 21:05:56 +0000 Subject: Optimize relative seeking with TIFFSetDirectory --- libtiff/tif_dir.c | 50 +++++++++++++++++++++++++++++++++++++++----------- libtiff/tif_dirread.c | 7 ++++++- libtiff/tif_open.c | 1 + libtiff/tiffiop.h | 4 +++- 4 files changed, 49 insertions(+), 13 deletions(-) (limited to 'libtiff') 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 -- cgit v1.2.1