Cherry-pick libtiff commit to fix OJPEG hack.
Apply [1], even though OJPEG support is disabled.
[1] https://gitlab.com/libtiff/libtiff/-/commit/87f580f39011109b3bb5f6eca13fac543a542798
Bug: chromium:1399080
Change-Id: Iced64900732de884647950203c0eed8bcb42a9e6
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/102210
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/libtiff/0038-fix-ojpeg-hack.patch b/third_party/libtiff/0038-fix-ojpeg-hack.patch
new file mode 100644
index 0000000..96aad74
--- /dev/null
+++ b/third_party/libtiff/0038-fix-ojpeg-hack.patch
@@ -0,0 +1,201 @@
+diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
+index 58c918181..e93072456 100644
+--- a/third_party/libtiff/tif_dirread.c
++++ b/third_party/libtiff/tif_dirread.c
+@@ -3796,57 +3796,7 @@ TIFFReadDirectory(TIFF* tif)
+ MissingRequired(tif,"ImageLength");
+ goto bad;
+ }
+- /*
+- * Setup appropriate structures (by strip or by tile)
+- */
+- if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+- tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
+- tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
+- tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
+- tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
+- tif->tif_flags &= ~TIFF_ISTILED;
+- } else {
+- tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
+- tif->tif_flags |= TIFF_ISTILED;
+- }
+- if (!tif->tif_dir.td_nstrips) {
+- TIFFErrorExt(tif->tif_clientdata, module,
+- "Cannot handle zero number of %s",
+- isTiled(tif) ? "tiles" : "strips");
+- goto bad;
+- }
+- if (tif->tif_dir.td_nstrips > INT_MAX) {
+- TIFFErrorExt(tif->tif_clientdata, module,
+- "Cannot handle %u number of %s",
+- tif->tif_dir.td_nstrips,
+- isTiled(tif) ? "tiles" : "strips");
+- goto bad;
+- }
+- tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
+- if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
+- tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
+- if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
+-#ifdef OJPEG_SUPPORT
+- if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
+- (isTiled(tif)==0) &&
+- (tif->tif_dir.td_nstrips==1)) {
+- /*
+- * XXX: OJPEG hack.
+- * If a) compression is OJPEG, b) it's not a tiled TIFF,
+- * and c) the number of strips is 1,
+- * then we tolerate the absence of stripoffsets tag,
+- * because, presumably, all required data is in the
+- * JpegInterchangeFormat stream.
+- */
+- TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+- } else
+-#endif
+- {
+- MissingRequired(tif,
+- isTiled(tif) ? "TileOffsets" : "StripOffsets");
+- goto bad;
+- }
+- }
++
+ /*
+ * Second pass: extract other information.
+ */
+@@ -4051,41 +4001,6 @@ TIFFReadDirectory(TIFF* tif)
+ } /* -- if (!dp->tdir_ignore) */
+ } /* -- for-loop -- */
+
+- if( tif->tif_mode == O_RDWR &&
+- tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
+- tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
+- tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
+- tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
+- tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
+- tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
+- tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
+- tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
+- {
+- /* Directory typically created with TIFFDeferStrileArrayWriting() */
+- TIFFSetupStrips(tif);
+- }
+- else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
+- {
+- if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
+- {
+- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
+- tif->tif_dir.td_nstrips,
+- &tif->tif_dir.td_stripoffset_p))
+- {
+- goto bad;
+- }
+- }
+- if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
+- {
+- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
+- tif->tif_dir.td_nstrips,
+- &tif->tif_dir.td_stripbytecount_p))
+- {
+- goto bad;
+- }
+- }
+- }
+-
+ /*
+ * OJPEG hack:
+ * - If a) compression is OJPEG, and b) photometric tag is missing,
+@@ -4156,6 +4071,95 @@ TIFFReadDirectory(TIFF* tif)
+ }
+ }
+
++ /*
++ * Setup appropriate structures (by strip or by tile)
++ * We do that only after the above OJPEG hack which alters SamplesPerPixel
++ * and thus influences the number of strips in the separate planarconfig.
++ */
++ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
++ tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
++ tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
++ tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
++ tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
++ tif->tif_flags &= ~TIFF_ISTILED;
++ } else {
++ tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
++ tif->tif_flags |= TIFF_ISTILED;
++ }
++ if (!tif->tif_dir.td_nstrips) {
++ TIFFErrorExt(tif->tif_clientdata, module,
++ "Cannot handle zero number of %s",
++ isTiled(tif) ? "tiles" : "strips");
++ goto bad;
++ }
++ if (tif->tif_dir.td_nstrips > INT_MAX) {
++ TIFFErrorExt(tif->tif_clientdata, module,
++ "Cannot handle %u number of %s",
++ tif->tif_dir.td_nstrips,
++ isTiled(tif) ? "tiles" : "strips");
++ goto bad;
++ }
++ tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
++ if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
++ tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
++ if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
++#ifdef OJPEG_SUPPORT
++ if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
++ (isTiled(tif)==0) &&
++ (tif->tif_dir.td_nstrips==1)) {
++ /*
++ * XXX: OJPEG hack.
++ * If a) compression is OJPEG, b) it's not a tiled TIFF,
++ * and c) the number of strips is 1,
++ * then we tolerate the absence of stripoffsets tag,
++ * because, presumably, all required data is in the
++ * JpegInterchangeFormat stream.
++ */
++ TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
++ } else
++#endif
++ {
++ MissingRequired(tif,
++ isTiled(tif) ? "TileOffsets" : "StripOffsets");
++ goto bad;
++ }
++ }
++
++ if( tif->tif_mode == O_RDWR &&
++ tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
++ tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
++ tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
++ tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
++ tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
++ tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
++ tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
++ tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
++ {
++ /* Directory typically created with TIFFDeferStrileArrayWriting() */
++ TIFFSetupStrips(tif);
++ }
++ else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
++ {
++ if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
++ {
++ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
++ tif->tif_dir.td_nstrips,
++ &tif->tif_dir.td_stripoffset_p))
++ {
++ goto bad;
++ }
++ }
++ if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
++ {
++ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
++ tif->tif_dir.td_nstrips,
++ &tif->tif_dir.td_stripbytecount_p))
++ {
++ goto bad;
++ }
++ }
++ }
++
+ /*
+ * Make sure all non-color channels are extrasamples.
+ * If it's not the case, define them as such.
diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium
index 7b01880..08bbe37 100644
--- a/third_party/libtiff/README.pdfium
+++ b/third_party/libtiff/README.pdfium
@@ -21,3 +21,4 @@
0035-memcpy-nullptr-zero-size.patch: Check for nullptr and zero size before calling memcpy().
0036-Replace-sprintf-calls-with-snprintf.patch: Replace sprintf with snprintf for macOS 13 SDK compatibility, from https://gitlab.com/libtiff/libtiff/-/merge_requests/408, edited to apply to PDFium, which does not have libtiff 352cb5a4fb11.
0037-tiff-read-rgba-tile-ext.patch: Fix (unsigned) integer overflow on strips/tiles > 2 GB.
+0038-fix-ojpeg-hack.patch: Fix OJPEG hack.
diff --git a/third_party/libtiff/tif_dirread.c b/third_party/libtiff/tif_dirread.c
index 58c9181..e930724 100644
--- a/third_party/libtiff/tif_dirread.c
+++ b/third_party/libtiff/tif_dirread.c
@@ -3796,57 +3796,7 @@
MissingRequired(tif,"ImageLength");
goto bad;
}
- /*
- * Setup appropriate structures (by strip or by tile)
- */
- if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
- tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
- tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
- tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
- tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
- tif->tif_flags &= ~TIFF_ISTILED;
- } else {
- tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
- tif->tif_flags |= TIFF_ISTILED;
- }
- if (!tif->tif_dir.td_nstrips) {
- TIFFErrorExt(tif->tif_clientdata, module,
- "Cannot handle zero number of %s",
- isTiled(tif) ? "tiles" : "strips");
- goto bad;
- }
- if (tif->tif_dir.td_nstrips > INT_MAX) {
- TIFFErrorExt(tif->tif_clientdata, module,
- "Cannot handle %u number of %s",
- tif->tif_dir.td_nstrips,
- isTiled(tif) ? "tiles" : "strips");
- goto bad;
- }
- tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
- if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
- tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
- if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
-#ifdef OJPEG_SUPPORT
- if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
- (isTiled(tif)==0) &&
- (tif->tif_dir.td_nstrips==1)) {
- /*
- * XXX: OJPEG hack.
- * If a) compression is OJPEG, b) it's not a tiled TIFF,
- * and c) the number of strips is 1,
- * then we tolerate the absence of stripoffsets tag,
- * because, presumably, all required data is in the
- * JpegInterchangeFormat stream.
- */
- TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
- } else
-#endif
- {
- MissingRequired(tif,
- isTiled(tif) ? "TileOffsets" : "StripOffsets");
- goto bad;
- }
- }
+
/*
* Second pass: extract other information.
*/
@@ -4051,41 +4001,6 @@
} /* -- if (!dp->tdir_ignore) */
} /* -- for-loop -- */
- if( tif->tif_mode == O_RDWR &&
- tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
- tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
- tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
- tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
- {
- /* Directory typically created with TIFFDeferStrileArrayWriting() */
- TIFFSetupStrips(tif);
- }
- else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
- {
- if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
- {
- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
- tif->tif_dir.td_nstrips,
- &tif->tif_dir.td_stripoffset_p))
- {
- goto bad;
- }
- }
- if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
- {
- if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
- tif->tif_dir.td_nstrips,
- &tif->tif_dir.td_stripbytecount_p))
- {
- goto bad;
- }
- }
- }
-
/*
* OJPEG hack:
* - If a) compression is OJPEG, and b) photometric tag is missing,
@@ -4157,6 +4072,95 @@
}
/*
+ * Setup appropriate structures (by strip or by tile)
+ * We do that only after the above OJPEG hack which alters SamplesPerPixel
+ * and thus influences the number of strips in the separate planarconfig.
+ */
+ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+ tif->tif_dir.td_nstrips = TIFFNumberOfStrips(tif);
+ tif->tif_dir.td_tilewidth = tif->tif_dir.td_imagewidth;
+ tif->tif_dir.td_tilelength = tif->tif_dir.td_rowsperstrip;
+ tif->tif_dir.td_tiledepth = tif->tif_dir.td_imagedepth;
+ tif->tif_flags &= ~TIFF_ISTILED;
+ } else {
+ tif->tif_dir.td_nstrips = TIFFNumberOfTiles(tif);
+ tif->tif_flags |= TIFF_ISTILED;
+ }
+ if (!tif->tif_dir.td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Cannot handle zero number of %s",
+ isTiled(tif) ? "tiles" : "strips");
+ goto bad;
+ }
+ if (tif->tif_dir.td_nstrips > INT_MAX) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Cannot handle %u number of %s",
+ tif->tif_dir.td_nstrips,
+ isTiled(tif) ? "tiles" : "strips");
+ goto bad;
+ }
+ tif->tif_dir.td_stripsperimage = tif->tif_dir.td_nstrips;
+ if (tif->tif_dir.td_planarconfig == PLANARCONFIG_SEPARATE)
+ tif->tif_dir.td_stripsperimage /= tif->tif_dir.td_samplesperpixel;
+ if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
+#ifdef OJPEG_SUPPORT
+ if ((tif->tif_dir.td_compression==COMPRESSION_OJPEG) &&
+ (isTiled(tif)==0) &&
+ (tif->tif_dir.td_nstrips==1)) {
+ /*
+ * XXX: OJPEG hack.
+ * If a) compression is OJPEG, b) it's not a tiled TIFF,
+ * and c) the number of strips is 1,
+ * then we tolerate the absence of stripoffsets tag,
+ * because, presumably, all required data is in the
+ * JpegInterchangeFormat stream.
+ */
+ TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+ } else
+#endif
+ {
+ MissingRequired(tif,
+ isTiled(tif) ? "TileOffsets" : "StripOffsets");
+ goto bad;
+ }
+ }
+
+ if( tif->tif_mode == O_RDWR &&
+ tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
+ tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
+ tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
+ tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
+ tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
+ tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
+ tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
+ tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 )
+ {
+ /* Directory typically created with TIFFDeferStrileArrayWriting() */
+ TIFFSetupStrips(tif);
+ }
+ else if( !(tif->tif_flags&TIFF_DEFERSTRILELOAD) )
+ {
+ if( tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 )
+ {
+ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripoffset_entry),
+ tif->tif_dir.td_nstrips,
+ &tif->tif_dir.td_stripoffset_p))
+ {
+ goto bad;
+ }
+ }
+ if( tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 )
+ {
+ if (!TIFFFetchStripThing(tif,&(tif->tif_dir.td_stripbytecount_entry),
+ tif->tif_dir.td_nstrips,
+ &tif->tif_dir.td_stripbytecount_p))
+ {
+ goto bad;
+ }
+ }
+ }
+
+ /*
* Make sure all non-color channels are extrasamples.
* If it's not the case, define them as such.
*/