Cherry-pick libtiff commit to revise handling of TIFFTAG_INKNAMES. Apply [1] and resolve all the merge conflicts. [1] https://gitlab.com/libtiff/libtiff/-/commit/e813112545942107551433d61afd16ac094ff246 Bug: chromium:1399080 Change-Id: Id5f5c078016fb3a302de41aa431b10fdfd1d2b3d Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/102230 Reviewed-by: Tom Sepez <tsepez@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/libtiff/0039-handling-of-tifftag-inknames.patch b/third_party/libtiff/0039-handling-of-tifftag-inknames.patch new file mode 100644 index 0000000..5ffd695 --- /dev/null +++ b/third_party/libtiff/0039-handling-of-tifftag-inknames.patch
@@ -0,0 +1,192 @@ +diff --git a/third_party/libtiff/tif_dir.c b/third_party/libtiff/tif_dir.c +index 347b7115c..ac7097c22 100644 +--- a/third_party/libtiff/tif_dir.c ++++ b/third_party/libtiff/tif_dir.c +@@ -138,32 +138,30 @@ setExtraSamples(TIFF* tif, va_list ap, uint32* v) + } + + /* +- * Confirm we have "samplesperpixel" ink names separated by \0. Returns ++ * Count ink names separated by \0. Returns + * zero if the ink names are not as expected. + */ +-static uint32 +-checkInkNamesString(TIFF* tif, uint32 slen, const char* s) ++static uint16 ++countInkNamesString(TIFF *tif, uint32 slen, const char *s) + { +- TIFFDirectory* td = &tif->tif_dir; +- uint16 i = td->td_samplesperpixel; ++ uint16 i = 0; ++ const char *ep = s + slen; ++ const char *cp = s; + + if (slen > 0) { +- const char* ep = s+slen; +- const char* cp = s; +- for (; i > 0; i--) { ++ do { + for (; cp < ep && *cp != '\0'; cp++) {} + if (cp >= ep) + goto bad; + cp++; /* skip \0 */ +- } +- return ((uint32)(cp-s)); ++ i++; ++ } while (cp < ep); ++ return (i); + } + bad: + TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", +- "%s: Invalid InkNames value; expecting %d names, found %d", +- tif->tif_name, +- td->td_samplesperpixel, +- td->td_samplesperpixel-i); ++ "%s: Invalid InkNames value; no NUL at given buffer end location %u, after %u ink", ++ tif->tif_name, slen, i); + return (0); + } + +@@ -477,13 +475,61 @@ _TIFFVSetField(TIFF* tif, uint32 tag, va_list ap) + _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6); + break; + case TIFFTAG_INKNAMES: +- v = (uint16) va_arg(ap, uint16_vap); +- s = va_arg(ap, char*); +- v = checkInkNamesString(tif, v, s); +- status = v > 0; +- if( v > 0 ) { +- _TIFFsetNString(&td->td_inknames, s, v); +- td->td_inknameslen = v; ++ { ++ v = (uint16) va_arg(ap, uint16_vap); ++ s = va_arg(ap, char*); ++ uint16 ninksinstring; ++ ninksinstring = countInkNamesString(tif, v, s); ++ status = ninksinstring > 0; ++ if(ninksinstring > 0 ) { ++ _TIFFsetNString(&td->td_inknames, s, v); ++ td->td_inknameslen = v; ++ /* Set NumberOfInks to the value ninksinstring */ ++ if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) ++ { ++ if (td->td_numberofinks != ninksinstring) { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Warning %s; Tag %s:\n Value %u of NumberOfInks is different from the number of inks %u.\n -> NumberOfInks value adapted to %u", ++ tif->tif_name, fip->field_name, td->td_numberofinks, ninksinstring, ninksinstring); ++ td->td_numberofinks = ninksinstring; ++ } ++ } else { ++ td->td_numberofinks = ninksinstring; ++ TIFFSetFieldBit(tif, FIELD_NUMBEROFINKS); ++ } ++ if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) ++ { ++ if (td->td_numberofinks != td->td_samplesperpixel) { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Warning %s; Tag %s:\n Value %u of NumberOfInks is different from the SamplesPerPixel value %u", ++ tif->tif_name, fip->field_name, td->td_numberofinks, td->td_samplesperpixel); ++ } ++ } ++ } ++ } ++ break; ++ case TIFFTAG_NUMBEROFINKS: ++ v = (uint16)va_arg(ap, uint16_vap); ++ /* If InkNames already set also NumberOfInks is set accordingly and should be equal */ ++ if (TIFFFieldSet(tif, FIELD_INKNAMES)) ++ { ++ if (v != td->td_numberofinks) { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Error %s; Tag %s:\n It is not possible to set the value %u for NumberOfInks\n which is different from the number of inks in the InkNames tag (%u)", ++ tif->tif_name, fip->field_name, v, td->td_numberofinks); ++ /* Do not set / overwrite number of inks already set by InkNames case accordingly. */ ++ status = 0; ++ } ++ } else { ++ td->td_numberofinks = (uint16)v; ++ if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) ++ { ++ if (td->td_numberofinks != td->td_samplesperpixel) { ++ TIFFErrorExt(tif->tif_clientdata, module, ++ "Warning %s; Tag %s:\n Value %u of NumberOfInks is different from the SamplesPerPixel value %u", ++ tif->tif_name, fip->field_name, v, td->td_samplesperpixel); ++ } ++ } + } + break; + case TIFFTAG_PERSAMPLE: +@@ -1114,6 +1160,9 @@ _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap) + case TIFFTAG_INKNAMES: + *va_arg(ap, const char**) = td->td_inknames; + break; ++ case TIFFTAG_NUMBEROFINKS: ++ *va_arg(ap, uint16_t *) = td->td_numberofinks; ++ break; + default: + { + int i; +diff --git a/third_party/libtiff/tif_dir.h b/third_party/libtiff/tif_dir.h +index f608dd713..399a35ab3 100644 +--- a/third_party/libtiff/tif_dir.h ++++ b/third_party/libtiff/tif_dir.h +@@ -117,6 +117,7 @@ typedef struct { + /* CMYK parameters */ + int td_inknameslen; + char* td_inknames; ++ uint16_t td_numberofinks; /* number of inks in InkNames string */ + + int td_customValueCount; + TIFFTagValue *td_customValues; +@@ -174,6 +175,7 @@ typedef struct { + #define FIELD_TRANSFERFUNCTION 44 + #define FIELD_INKNAMES 46 + #define FIELD_SUBIFD 49 ++#define FIELD_NUMBEROFINKS 50 + /* FIELD_CUSTOM (see tiffio.h) 65 */ + /* end of support for well-known tags; codec-private tags follow */ + #define FIELD_CODEC 66 /* base of codec-private tags */ +diff --git a/third_party/libtiff/tif_dirinfo.c b/third_party/libtiff/tif_dirinfo.c +index 7217042c2..ea3b0c20f 100644 +--- a/third_party/libtiff/tif_dirinfo.c ++++ b/third_party/libtiff/tif_dirinfo.c +@@ -114,7 +114,7 @@ tiffFields[] = { + { TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_SUBIFD, 1, 1, "SubIFD", (TIFFFieldArray*) &tiffFieldArray }, + { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL }, + { TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL }, +- { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NumberOfInks", NULL }, ++ { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_NUMBEROFINKS, 1, 0, "NumberOfInks", NULL }, + { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL }, + { TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL }, + { TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL }, +diff --git a/third_party/libtiff/tif_dirwrite.c b/third_party/libtiff/tif_dirwrite.c +index f481250e3..fe6d6558a 100644 +--- a/third_party/libtiff/tif_dirwrite.c ++++ b/third_party/libtiff/tif_dirwrite.c +@@ -692,6 +692,11 @@ TIFFWriteDirectorySec(TIFF* tif, int isimage, int imagedone, uint64* pdiroff) + if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames)) + goto bad; + } ++ if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) ++ { ++ if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir, TIFFTAG_NUMBEROFINKS, tif->tif_dir.td_numberofinks)) ++ goto bad; ++ } + if (TIFFFieldSet(tif,FIELD_SUBIFD)) + { + if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir)) +diff --git a/third_party/libtiff/tif_print.c b/third_party/libtiff/tif_print.c +index a0737941f..a9f05a7ec 100644 +--- a/third_party/libtiff/tif_print.c ++++ b/third_party/libtiff/tif_print.c +@@ -402,6 +402,10 @@ TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags) + } + fputs("\n", fd); + } ++ if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) { ++ fprintf(fd, " NumberOfInks: %d\n", ++ td->td_numberofinks); ++ } + if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) { + fprintf(fd, " Thresholding: "); + switch (td->td_threshholding) {
diff --git a/third_party/libtiff/README.pdfium b/third_party/libtiff/README.pdfium index 08bbe37..11547b7 100644 --- a/third_party/libtiff/README.pdfium +++ b/third_party/libtiff/README.pdfium
@@ -22,3 +22,4 @@ 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. +0039-handling-of-tifftag-inknames.patch: Revised handling of TIFFTAG_INKNAMES and related TIFFTAG_NUMBEROFINKS value.
diff --git a/third_party/libtiff/tif_dir.c b/third_party/libtiff/tif_dir.c index 347b711..ac7097c 100644 --- a/third_party/libtiff/tif_dir.c +++ b/third_party/libtiff/tif_dir.c
@@ -138,32 +138,30 @@ } /* - * Confirm we have "samplesperpixel" ink names separated by \0. Returns + * Count ink names separated by \0. Returns * zero if the ink names are not as expected. */ -static uint32 -checkInkNamesString(TIFF* tif, uint32 slen, const char* s) +static uint16 +countInkNamesString(TIFF *tif, uint32 slen, const char *s) { - TIFFDirectory* td = &tif->tif_dir; - uint16 i = td->td_samplesperpixel; + uint16 i = 0; + const char *ep = s + slen; + const char *cp = s; if (slen > 0) { - const char* ep = s+slen; - const char* cp = s; - for (; i > 0; i--) { + do { for (; cp < ep && *cp != '\0'; cp++) {} if (cp >= ep) goto bad; cp++; /* skip \0 */ - } - return ((uint32)(cp-s)); + i++; + } while (cp < ep); + return (i); } bad: TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", - "%s: Invalid InkNames value; expecting %d names, found %d", - tif->tif_name, - td->td_samplesperpixel, - td->td_samplesperpixel-i); + "%s: Invalid InkNames value; no NUL at given buffer end location %u, after %u ink", + tif->tif_name, slen, i); return (0); } @@ -477,13 +475,61 @@ _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6); break; case TIFFTAG_INKNAMES: - v = (uint16) va_arg(ap, uint16_vap); - s = va_arg(ap, char*); - v = checkInkNamesString(tif, v, s); - status = v > 0; - if( v > 0 ) { - _TIFFsetNString(&td->td_inknames, s, v); - td->td_inknameslen = v; + { + v = (uint16) va_arg(ap, uint16_vap); + s = va_arg(ap, char*); + uint16 ninksinstring; + ninksinstring = countInkNamesString(tif, v, s); + status = ninksinstring > 0; + if(ninksinstring > 0 ) { + _TIFFsetNString(&td->td_inknames, s, v); + td->td_inknameslen = v; + /* Set NumberOfInks to the value ninksinstring */ + if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) + { + if (td->td_numberofinks != ninksinstring) { + TIFFErrorExt(tif->tif_clientdata, module, + "Warning %s; Tag %s:\n Value %u of NumberOfInks is different from the number of inks %u.\n -> NumberOfInks value adapted to %u", + tif->tif_name, fip->field_name, td->td_numberofinks, ninksinstring, ninksinstring); + td->td_numberofinks = ninksinstring; + } + } else { + td->td_numberofinks = ninksinstring; + TIFFSetFieldBit(tif, FIELD_NUMBEROFINKS); + } + if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) + { + if (td->td_numberofinks != td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, module, + "Warning %s; Tag %s:\n Value %u of NumberOfInks is different from the SamplesPerPixel value %u", + tif->tif_name, fip->field_name, td->td_numberofinks, td->td_samplesperpixel); + } + } + } + } + break; + case TIFFTAG_NUMBEROFINKS: + v = (uint16)va_arg(ap, uint16_vap); + /* If InkNames already set also NumberOfInks is set accordingly and should be equal */ + if (TIFFFieldSet(tif, FIELD_INKNAMES)) + { + if (v != td->td_numberofinks) { + TIFFErrorExt(tif->tif_clientdata, module, + "Error %s; Tag %s:\n It is not possible to set the value %u for NumberOfInks\n which is different from the number of inks in the InkNames tag (%u)", + tif->tif_name, fip->field_name, v, td->td_numberofinks); + /* Do not set / overwrite number of inks already set by InkNames case accordingly. */ + status = 0; + } + } else { + td->td_numberofinks = (uint16)v; + if (TIFFFieldSet(tif, FIELD_SAMPLESPERPIXEL)) + { + if (td->td_numberofinks != td->td_samplesperpixel) { + TIFFErrorExt(tif->tif_clientdata, module, + "Warning %s; Tag %s:\n Value %u of NumberOfInks is different from the SamplesPerPixel value %u", + tif->tif_name, fip->field_name, v, td->td_samplesperpixel); + } + } } break; case TIFFTAG_PERSAMPLE: @@ -1114,6 +1160,9 @@ case TIFFTAG_INKNAMES: *va_arg(ap, const char**) = td->td_inknames; break; + case TIFFTAG_NUMBEROFINKS: + *va_arg(ap, uint16_t *) = td->td_numberofinks; + break; default: { int i;
diff --git a/third_party/libtiff/tif_dir.h b/third_party/libtiff/tif_dir.h index f608dd7..399a35a 100644 --- a/third_party/libtiff/tif_dir.h +++ b/third_party/libtiff/tif_dir.h
@@ -117,6 +117,7 @@ /* CMYK parameters */ int td_inknameslen; char* td_inknames; + uint16_t td_numberofinks; /* number of inks in InkNames string */ int td_customValueCount; TIFFTagValue *td_customValues; @@ -174,6 +175,7 @@ #define FIELD_TRANSFERFUNCTION 44 #define FIELD_INKNAMES 46 #define FIELD_SUBIFD 49 +#define FIELD_NUMBEROFINKS 50 /* FIELD_CUSTOM (see tiffio.h) 65 */ /* end of support for well-known tags; codec-private tags follow */ #define FIELD_CODEC 66 /* base of codec-private tags */
diff --git a/third_party/libtiff/tif_dirinfo.c b/third_party/libtiff/tif_dirinfo.c index 7217042..ea3b0c2 100644 --- a/third_party/libtiff/tif_dirinfo.c +++ b/third_party/libtiff/tif_dirinfo.c
@@ -114,7 +114,7 @@ { TIFFTAG_SUBIFD, -1, -1, TIFF_IFD8, 0, TIFF_SETGET_C16_IFD8, TIFF_SETGET_UNDEFINED, FIELD_SUBIFD, 1, 1, "SubIFD", (TIFFFieldArray*) &tiffFieldArray }, { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "InkSet", NULL }, { TIFFTAG_INKNAMES, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_C16_ASCII, TIFF_SETGET_UNDEFINED, FIELD_INKNAMES, 1, 1, "InkNames", NULL }, - { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "NumberOfInks", NULL }, + { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_NUMBEROFINKS, 1, 0, "NumberOfInks", NULL }, { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_UINT16_PAIR, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, "DotRange", NULL }, { TIFFTAG_TARGETPRINTER, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "TargetPrinter", NULL }, { TIFFTAG_EXTRASAMPLES, -1, -1, TIFF_SHORT, 0, TIFF_SETGET_C16_UINT16, TIFF_SETGET_UNDEFINED, FIELD_EXTRASAMPLES, 0, 1, "ExtraSamples", NULL },
diff --git a/third_party/libtiff/tif_dirwrite.c b/third_party/libtiff/tif_dirwrite.c index f481250..fe6d655 100644 --- a/third_party/libtiff/tif_dirwrite.c +++ b/third_party/libtiff/tif_dirwrite.c
@@ -692,6 +692,11 @@ if (!TIFFWriteDirectoryTagAscii(tif,&ndir,dir,TIFFTAG_INKNAMES,tif->tif_dir.td_inknameslen,tif->tif_dir.td_inknames)) goto bad; } + if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) + { + if (!TIFFWriteDirectoryTagShort(tif, &ndir, dir, TIFFTAG_NUMBEROFINKS, tif->tif_dir.td_numberofinks)) + goto bad; + } if (TIFFFieldSet(tif,FIELD_SUBIFD)) { if (!TIFFWriteDirectoryTagSubifd(tif,&ndir,dir))
diff --git a/third_party/libtiff/tif_print.c b/third_party/libtiff/tif_print.c index a073794..a9f05a7 100644 --- a/third_party/libtiff/tif_print.c +++ b/third_party/libtiff/tif_print.c
@@ -402,6 +402,10 @@ } fputs("\n", fd); } + if (TIFFFieldSet(tif, FIELD_NUMBEROFINKS)) { + fprintf(fd, " NumberOfInks: %d\n", + td->td_numberofinks); + } if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) { fprintf(fd, " Thresholding: "); switch (td->td_threshholding) {