libtiff: test_ifd_loop_detection: Added test to check loops in SubIFDs that are chained. (8ef8f)

From 8ef8f7ce21f28c25c36f4c380387b0b3037eea30 Mon Sep 17 00:00:00 2001
From: Su Laus <[EMAIL REDACTED]>
Date: Sat, 4 Feb 2023 19:34:11 +0000
Subject: [PATCH] test_ifd_loop_detection: Added test to check loops in SubIFDs
 that are chained.

---
 test/Makefile.am                     |   1 +
 test/images/test_ifd_loop_subifd.tif | Bin 0 -> 1654 bytes
 test/test_ifd_loop_detection.c       | 137 +++++++++++++++++++++++++++
 3 files changed, 138 insertions(+)
 create mode 100644 test/images/test_ifd_loop_subifd.tif

diff --git a/test/Makefile.am b/test/Makefile.am
index b0fe276a..148406ab 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -216,6 +216,7 @@ IMAGES_EXTRA_DIST = \
 	images/test_ifd_loop_to_self.tif \
 	images/test_ifd_loop_to_first.tif \
 	images/test_two_ifds.tif \
+	images/test_ifd_loop_subifd.tif \
 	$(PNMIMAGES) \
 	$(TIFFIMAGES)
 
diff --git a/test/images/test_ifd_loop_subifd.tif b/test/images/test_ifd_loop_subifd.tif
new file mode 100644
index 0000000000000000000000000000000000000000..7294085e400a7f5ae3c1b9c14bc9cd2ab1f9464f
GIT binary patch
literal 1654
zcmebD)MDUa0D}7e4BQM1jLZy-Kn@rqv6+BuW}x^qAZA7qXM?htfZ~FTEMR>cK(;7U
z9Hd7KNxe8!4M<!DNnDnZiGd3!HV24T0Wk*{8Yq-x=qY%*xiHuRT?cd}k`6{BHq3Pn
zKxY$j-7=u*<hm{hXucOCFE}LJfb0~YHy|!e0P=W%fv^LJ4dJfN1iShl10-C4N(lPk
z8&DA;AH)FFkmCbTEdPPJ6XI$k14Ia~Ala>pfPN+9Rt}&Va^1QD8lEt>BEt1K$!_%n
z#uOp9ZlS=fAwcs%@egyW5j+jl0o_VCU%ey3eF;D{<b)+CUwr}UWnzK55AM3XM7gd9
zsFP6W{iDEjlYr(gfV<8Z?z%rjxlW6fu<PakO(!?(41ne%a=HoJbv8t~?gSC8vjVCi
o*LCNBdhY-+B;}dHT~|$%>(bZ=husYdT$ckh9|Rz-GlRPh0L@KM%>V!Z

literal 0
HcmV?d00001

diff --git a/test/test_ifd_loop_detection.c b/test/test_ifd_loop_detection.c
index 52b089bf..99a749e5 100644
--- a/test/test_ifd_loop_detection.c
+++ b/test/test_ifd_loop_detection.c
@@ -36,6 +36,142 @@
 
 #include "tiffio.h"
 
+int is_requested_directory(TIFF *tif, int requested_dir_number,
+                           const char *filename)
+{
+    char *ptr;
+
+    if (!TIFFGetField(tif, TIFFTAG_PAGENAME, &ptr))
+    {
+        fprintf(stderr, "Can't get TIFFTAG_PAGENAME tag.\n");
+        return 0;
+    }
+    /* Retrieve directory number from ASCII string */
+    char *auxStr = strchr(ptr, ' ');
+    int nthIFD;
+    nthIFD = atoi(ptr);
+
+    /* Check for reading errors */
+    if (strncmp(auxStr, " th.", 4))
+    {
+        fprintf(stderr,
+                "Error reading IFD directory number from PageName tag: %s\n",
+                ptr);
+        return 0;
+    }
+
+    if (nthIFD == requested_dir_number)
+    {
+        return 1;
+    }
+    fprintf(stderr, "Expected directory %d from %s was not loaded but: %s\n",
+            requested_dir_number, filename, ptr);
+
+    return 0;
+}
+
+/* Test loop detection within chained SubIFDs.
+ * test_ifd_loop_subifd.tif contains seven main-IFDs (0 to 6) and within IFD 1
+ * there are three SubIFDs (0 to 2). Main IFD 4 loops back to main IFD 2.
+ * SubIFD 2 loops back to SubIFD 1.
+ * Within each IFD the tag PageName is filled with a string, indicating the
+ * IFD. The main IFDs are numbered 0 to 6 and the SubIFDs 200 to 202. */
+int test_subifd_loop(void)
+{
+    const char *filename = SOURCE_DIR "/images/test_ifd_loop_subifd.tif";
+    TIFF *tif;
+    int i, n;
+    int ret = 0;
+#define NUMBER_OF_SUBIFDs 3
+    toff_t sub_IFDs_offsets[NUMBER_OF_SUBIFDs] = {
+        0UL}; /* array for SubIFD tag */
+    void *ptr;
+    uint16_t number_of_sub_IFDs = 0;
+
+    tif = TIFFOpen(filename, "r");
+    if (!tif)
+    {
+        fprintf(stderr, "Can't open  %s\n", filename);
+        return 1;
+    }
+
+    /* Try to read six further main directories. Fifth read shall fail. */
+    for (i = 0; i < 6; i++)
+    {
+        if (!TIFFReadDirectory(tif))
+            break;
+    }
+    if (i != 4)
+    {
+        fprintf(stderr, "(20) Expected fifth TIFFReadDirectory() to fail\n");
+        ret = 1;
+    }
+    if (!is_requested_directory(tif, 4, filename))
+    {
+        fprintf(stderr, "(21) Expected fifth main IFD to be loaded\n");
+        ret = 1;
+    }
+
+    /* Switch to IFD 1 and get SubIFDs.
+     * Then read through SubIFDs and detect SubIFD loop.
+     * Finally go back to main-IFD and check if right IFD is loaded.
+     */
+    if (!TIFFSetDirectory(tif, 1))
+        ret = 1;
+
+    /* Check if there are SubIFD subfiles */
+    if (TIFFGetField(tif, TIFFTAG_SUBIFD, &number_of_sub_IFDs, &ptr) &&
+        (number_of_sub_IFDs == 3))
+    {
+        /* Copy SubIFD array from pointer */
+        memcpy(sub_IFDs_offsets, ptr,
+               number_of_sub_IFDs * sizeof(sub_IFDs_offsets[0]));
+
+        for (i = 0; i < number_of_sub_IFDs; i++)
+        {
+            /* Read SubIFD directory directly via offset.
+             * SubIFDs PageName string contains numbers 200 to 202. */
+            if (!TIFFSetSubDirectory(tif, sub_IFDs_offsets[i]))
+                ret = 1;
+            if (!is_requested_directory(tif, 200 + i, filename))
+            {
+                fprintf(stderr, "(22) Expected SubIFD %d to be loaded.\n", i);
+                ret = 1;
+            }
+            /* Now test SubIFD loop detection.
+             * The (i+n).th read in the SubIFD chain shall fail. */
+            for (n = 0; n < number_of_sub_IFDs; n++)
+            {
+                if (!TIFFReadDirectory(tif))
+                    break;
+            }
+            if ((i + n) != 2)
+            {
+                fprintf(
+                    stderr,
+                    "(23) Expected third SubIFD-TIFFReadDirectory() to fail\n");
+                ret = 1;
+            }
+        }
+        /* Go back to main-IFD chain and re-read that main-IFD directory */
+        if (!TIFFSetDirectory(tif, 3))
+            ret = 1;
+        if (!is_requested_directory(tif, 3, filename))
+        {
+            fprintf(stderr, "(24) Expected fourth main IFD to be loaded\n");
+            ret = 1;
+        }
+    }
+    else
+    {
+        fprintf(stderr, "(25) No or wrong expected SubIFDs within main IFD\n");
+        ret = 1;
+    }
+
+    TIFFClose(tif);
+    return ret;
+} /*-- test_subifd_loop() --*/
+
 int main()
 {
     int ret = 0;
@@ -175,5 +311,6 @@ int main()
         }
         TIFFClose(tif);
     }
+    ret += test_subifd_loop();
     return ret;
 }