libtiff: Add test case for scenario of issue #489

From db1d2127862bb70df6b9d145c15ee592ee29bb7b Mon Sep 17 00:00:00 2001
From: Even Rouault <[EMAIL REDACTED]>
Date: Tue, 29 Nov 2022 14:58:27 +0100
Subject: [PATCH] Add test case for scenario of issue #489

---
 test/CMakeLists.txt         |   5 ++
 test/Makefile.am            |   4 +-
 test/test_append_to_strip.c | 108 ++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 test/test_append_to_strip.c

diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 7a1c97bc..742aba5b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -180,6 +180,11 @@ target_sources(test_open_options PRIVATE test_open_options.c)
 target_link_libraries(test_open_options PRIVATE tiff tiff_port)
 list(APPEND simple_tests test_open_options)
 
+add_executable(test_append_to_strip ../placeholder.h)
+target_sources(test_append_to_strip PRIVATE test_append_to_strip.c)
+target_link_libraries(test_append_to_strip PRIVATE tiff tiff_port)
+list(APPEND simple_tests test_append_to_strip)
+
 if(WEBP_SUPPORT AND EMSCRIPTEN)
   # Emscripten is pretty finnicky about linker flags.
   # It needs --shared-memory if and only if atomics or bulk-memory is used.
diff --git a/test/Makefile.am b/test/Makefile.am
index 64ae9493..f7c2477e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -76,7 +76,7 @@ if TIFF_TESTS
 check_PROGRAMS = \
 	ascii_tag long_tag short_tag strip_rw rewrite custom_dir custom_dir_EXIF_231 \
 	defer_strile_loading defer_strile_writing test_directory test_open_options \
-	testtypes test_signed_tags $(JPEG_DEPENDENT_CHECK_PROG) $(STATIC_CHECK_PROGS)
+	test_append_to_strip testtypes test_signed_tags $(JPEG_DEPENDENT_CHECK_PROG) $(STATIC_CHECK_PROGS)
 endif
 
 # Test scripts to execute
@@ -248,6 +248,8 @@ test_directory_SOURCES = test_directory.c
 test_directory_LDADD = $(LIBTIFF)
 test_open_options_SOURCES = test_open_options.c
 test_open_options_LDADD = $(LIBTIFF)
+test_append_to_strip_SOURCES = test_append_to_strip.c
+test_append_to_strip_LDADD = $(LIBTIFF)
 
 AM_CPPFLAGS = -I$(top_srcdir)/libtiff
 
diff --git a/test/test_append_to_strip.c b/test/test_append_to_strip.c
new file mode 100644
index 00000000..abf88000
--- /dev/null
+++ b/test/test_append_to_strip.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2022, Even Rouault <even.rouault at spatialys.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and 
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
+ * 
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Test TIFFAppendToStrip() through TIFFWriteRawStrip()
+ * Scenario of https://gitlab.com/libtiff/libtiff/-/issues/489
+ */
+
+#include "tif_config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+int main()
+{
+    int ret;
+    TIFF* tif = TIFFOpen("test_append_to_strip.tif", "w");
+    if (tif == NULL )
+    {
+        fprintf(stderr, "Cannot create test_append_to_strip.tif");
+        return 1;
+    }
+    ret = TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+    assert(ret);
+    ret = TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, 1);
+    assert(ret);
+    ret = TIFFSetField(tif, TIFFTAG_IMAGELENGTH, 9);
+    assert(ret);
+    ret = TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 5);
+    assert(ret);
+    ret = TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+    assert(ret);
+    ret = TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+    assert(ret);
+    int row;
+    for(row = 0; row < 9; ++row )
+    {
+        char c = (char)row;
+        int strip = (row < 5) ? 0 : 1;
+        ret = TIFFWriteRawStrip(tif, strip, &c, 1);
+        assert(ret == 1);
+    }
+    (void)ret;
+    TIFFClose(tif);
+    tif = TIFFOpen("test_append_to_strip.tif", "r");
+    if (tif == NULL )
+    {
+        fprintf(stderr, "Cannot create test_append_to_strip.tif");
+        return 1;
+    }
+    toff_t *panByteCounts = NULL;
+    TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts );
+    assert(panByteCounts);
+    int exitCode = 0;
+    if( panByteCounts[0] != 5 )
+    {
+        exitCode = 1;
+        fprintf(stderr, "panByteCounts[0] = %d. Expected 5.\n", (int)panByteCounts[0]);
+    }
+    if( panByteCounts[1] != 4 )
+    {
+        exitCode = 1;
+        fprintf(stderr, "panByteCounts[1] = %d. Expected 4.\n", (int)panByteCounts[1]);
+    }
+    for(row = 0; row < 9; ++row )
+    {
+        char c;
+        TIFFReadScanline(tif, &c, row, 0);
+        if( c != row )
+        {
+            fprintf(stderr, "TIFFReadScanline() for scanline %d returned %d. %d expected\n", row, c, row);
+            exitCode = 1;
+        }
+    }
+    TIFFClose(tif);
+    unlink("test_append_to_strip.tif");
+    return exitCode;
+}