Merge pull request #27679 from sturkmen72:libtiff-4.7.0

libtiff upgrade to version 4.7.0 #27679 
 
### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Suleyman TURKMEN 2025-08-19 13:29:17 +03:00 committed by GitHub
parent 920040d72e
commit d9c0ee234f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 3878 additions and 729 deletions

View File

@ -358,7 +358,7 @@ if(LIBLZMA_LIBRARIES)
endif() endif()
set(LIBTIFF_MAJOR_VERSION "4") set(LIBTIFF_MAJOR_VERSION "4")
set(LIBTIFF_MINOR_VERSION "6") set(LIBTIFF_MINOR_VERSION "7")
set(LIBTIFF_MICRO_VERSION "0") set(LIBTIFF_MICRO_VERSION "0")
set(LIBTIFF_VERSION "${LIBTIFF_MAJOR_VERSION}.${LIBTIFF_MINOR_VERSION}.${LIBTIFF_MICRO_VERSION}") set(LIBTIFF_VERSION "${LIBTIFF_MAJOR_VERSION}.${LIBTIFF_MINOR_VERSION}.${LIBTIFF_MICRO_VERSION}")
file(READ "RELEASE-DATE" LIBTIFF_RELEASE_DATE content) file(READ "RELEASE-DATE" LIBTIFF_RELEASE_DATE content)

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
20230908 20240911

View File

@ -385,53 +385,6 @@ int TIFFGetFieldDefaulted(TIFF *tif, uint32_t tag, ...)
return (ok); return (ok);
} }
struct _Int64Parts
{
int32_t low, high;
};
typedef union
{
struct _Int64Parts part;
int64_t value;
} _Int64;
float _TIFFUInt64ToFloat(uint64_t ui64)
{
_Int64 i;
i.value = ui64;
if (i.part.high >= 0)
{
return (float)i.value;
}
else
{
long double df;
df = (long double)i.value;
df += 18446744073709551616.0; /* adding 2**64 */
return (float)df;
}
}
double _TIFFUInt64ToDouble(uint64_t ui64)
{
_Int64 i;
i.value = ui64;
if (i.part.high >= 0)
{
return (double)i.value;
}
else
{
long double df;
df = (long double)i.value;
df += 18446744073709551616.0; /* adding 2**64 */
return (double)df;
}
}
float _TIFFClampDoubleToFloat(double val) float _TIFFClampDoubleToFloat(double val)
{ {
if (val > FLT_MAX) if (val > FLT_MAX)

View File

@ -110,6 +110,14 @@ void TIFFCleanup(TIFF *tif)
_TIFFfreeExt(tif, tif->tif_fieldscompat); _TIFFfreeExt(tif, tif->tif_fieldscompat);
} }
if (tif->tif_cur_cumulated_mem_alloc != 0)
{
TIFFErrorExtR(tif, "TIFFCleanup",
"tif_cur_cumulated_mem_alloc = %" PRIu64 " whereas it "
"should be 0",
(uint64_t)tif->tif_cur_cumulated_mem_alloc);
}
_TIFFfreeExt(NULL, tif); _TIFFfreeExt(NULL, tif);
} }

View File

@ -89,7 +89,7 @@ void TIFFCIELab16ToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a,
void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z, void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
uint32_t *r, uint32_t *g, uint32_t *b) uint32_t *r, uint32_t *g, uint32_t *b)
{ {
int i; size_t i;
float Yr, Yg, Yb; float Yr, Yg, Yb;
float *matrix = &cielab->display.d_mat[0][0]; float *matrix = &cielab->display.d_mat[0][0];
@ -109,16 +109,16 @@ void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
Yb = TIFFmin(Yb, cielab->display.d_YCB); Yb = TIFFmin(Yb, cielab->display.d_YCB);
/* Turn luminosity to colour value. */ /* Turn luminosity to colour value. */
i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep); i = (size_t)((Yr - cielab->display.d_Y0R) / cielab->rstep);
i = TIFFmin(cielab->range, i); i = TIFFmin((size_t)cielab->range, i);
*r = RINT(cielab->Yr2r[i]); *r = RINT(cielab->Yr2r[i]);
i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep); i = (size_t)((Yg - cielab->display.d_Y0G) / cielab->gstep);
i = TIFFmin(cielab->range, i); i = TIFFmin((size_t)cielab->range, i);
*g = RINT(cielab->Yg2g[i]); *g = RINT(cielab->Yg2g[i]);
i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep); i = (size_t)((Yb - cielab->display.d_Y0B) / cielab->bstep);
i = TIFFmin(cielab->range, i); i = TIFFmin((size_t)cielab->range, i);
*b = RINT(cielab->Yb2b[i]); *b = RINT(cielab->Yb2b[i]);
/* Clip output. */ /* Clip output. */
@ -135,7 +135,7 @@ void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display, int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
float *refWhite) float *refWhite)
{ {
int i; size_t i;
double dfGamma; double dfGamma;
cielab->range = CIELABTORGB_TABLE_RANGE; cielab->range = CIELABTORGB_TABLE_RANGE;
@ -146,7 +146,7 @@ int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
dfGamma = 1.0 / cielab->display.d_gammaR; dfGamma = 1.0 / cielab->display.d_gammaR;
cielab->rstep = cielab->rstep =
(cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
for (i = 0; i <= cielab->range; i++) for (i = 0; i <= (size_t)cielab->range; i++)
{ {
cielab->Yr2r[i] = cielab->display.d_Vrwr * cielab->Yr2r[i] = cielab->display.d_Vrwr *
((float)pow((double)i / cielab->range, dfGamma)); ((float)pow((double)i / cielab->range, dfGamma));
@ -156,7 +156,7 @@ int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
dfGamma = 1.0 / cielab->display.d_gammaG; dfGamma = 1.0 / cielab->display.d_gammaG;
cielab->gstep = cielab->gstep =
(cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
for (i = 0; i <= cielab->range; i++) for (i = 0; i <= (size_t)cielab->range; i++)
{ {
cielab->Yg2g[i] = cielab->display.d_Vrwg * cielab->Yg2g[i] = cielab->display.d_Vrwg *
((float)pow((double)i / cielab->range, dfGamma)); ((float)pow((double)i / cielab->range, dfGamma));
@ -166,7 +166,7 @@ int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
dfGamma = 1.0 / cielab->display.d_gammaB; dfGamma = 1.0 / cielab->display.d_gammaB;
cielab->bstep = cielab->bstep =
(cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range; (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
for (i = 0; i <= cielab->range; i++) for (i = 0; i <= (size_t)cielab->range; i++)
{ {
cielab->Yb2b[i] = cielab->display.d_Vrwb * cielab->Yb2b[i] = cielab->display.d_Vrwb *
((float)pow((double)i / cielab->range, dfGamma)); ((float)pow((double)i / cielab->range, dfGamma));

View File

@ -40,6 +40,18 @@
/* Define to 1 if you have the `getopt' function. */ /* Define to 1 if you have the `getopt' function. */
#cmakedefine HAVE_GETOPT 1 #cmakedefine HAVE_GETOPT 1
/* Define to 1 if you have the <GLUT/glut.h> header file. */
#cmakedefine HAVE_GLUT_GLUT_H 1
/* Define to 1 if you have the <GL/glut.h> header file. */
#cmakedefine HAVE_GL_GLUT_H 1
/* Define to 1 if you have the <GL/glu.h> header file. */
#cmakedefine HAVE_GL_GLU_H 1
/* Define to 1 if you have the <GL/gl.h> header file. */
#cmakedefine HAVE_GL_GL_H 1
/* Define to 1 if you have the <io.h> header file. */ /* Define to 1 if you have the <io.h> header file. */
#cmakedefine HAVE_IO_H 1 #cmakedefine HAVE_IO_H 1
@ -49,6 +61,12 @@
/* Define to 1 if you have the `mmap' function. */ /* Define to 1 if you have the `mmap' function. */
#cmakedefine HAVE_MMAP 1 #cmakedefine HAVE_MMAP 1
/* Define to 1 if you have the <OpenGL/glu.h> header file. */
#cmakedefine HAVE_OPENGL_GLU_H 1
/* Define to 1 if you have the <OpenGL/gl.h> header file. */
#cmakedefine HAVE_OPENGL_GL_H 1
/* Define to 1 if you have the `setmode' function. */ /* Define to 1 if you have the `setmode' function. */
#cmakedefine HAVE_SETMODE 1 #cmakedefine HAVE_SETMODE 1

View File

@ -211,7 +211,7 @@ static uint16_t countInkNamesString(TIFF *tif, uint32_t slen, const char *s)
} }
bad: bad:
TIFFErrorExtR(tif, "TIFFSetField", TIFFErrorExtR(tif, "TIFFSetField",
"%s: Invalid InkNames value; no NUL at given buffer end " "%s: Invalid InkNames value; no null at given buffer end "
"location %" PRIu32 ", after %" PRIu16 " ink", "location %" PRIu32 ", after %" PRIu16 " ink",
tif->tif_name, slen, i); tif->tif_name, slen, i);
return (0); return (0);
@ -1652,6 +1652,17 @@ void TIFFFreeDirectory(TIFF *tif)
_TIFFmemset(&(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry)); _TIFFmemset(&(td->td_stripoffset_entry), 0, sizeof(TIFFDirEntry));
_TIFFmemset(&(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry)); _TIFFmemset(&(td->td_stripbytecount_entry), 0, sizeof(TIFFDirEntry));
/* Reset some internal parameters for IFD data size checking. */
tif->tif_dir.td_dirdatasize_read = 0;
tif->tif_dir.td_dirdatasize_write = 0;
if (tif->tif_dir.td_dirdatasize_offsets != NULL)
{
_TIFFfreeExt(tif, tif->tif_dir.td_dirdatasize_offsets);
tif->tif_dir.td_dirdatasize_offsets = NULL;
tif->tif_dir.td_dirdatasize_Noffsets = 0;
}
tif->tif_dir.td_iswrittentofile = FALSE;
} }
#undef CleanupField #undef CleanupField
@ -1676,18 +1687,23 @@ TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc extender)
*/ */
int TIFFCreateDirectory(TIFF *tif) int TIFFCreateDirectory(TIFF *tif)
{ {
/* Free previously allocated memory and setup default values. */
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif); TIFFDefaultDirectory(tif);
tif->tif_diroff = 0; tif->tif_diroff = 0;
tif->tif_nextdiroff = 0; tif->tif_nextdiroff = 0;
tif->tif_curoff = 0; tif->tif_curoff = 0;
tif->tif_row = (uint32_t)-1; tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1; tif->tif_curstrip = (uint32_t)-1;
tif->tif_dir.td_iswrittentofile = FALSE;
return 0; return 0;
} }
int TIFFCreateCustomDirectory(TIFF *tif, const TIFFFieldArray *infoarray) int TIFFCreateCustomDirectory(TIFF *tif, const TIFFFieldArray *infoarray)
{ {
/* Free previously allocated memory and setup default values. */
TIFFFreeDirectory(tif);
TIFFDefaultDirectory(tif); TIFFDefaultDirectory(tif);
/* /*
@ -1848,7 +1864,9 @@ static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
if (((uint64_t)poffa != poff) || (poffb < poffa) || if (((uint64_t)poffa != poff) || (poffb < poffa) ||
(poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size)) (poffb < (tmsize_t)sizeof(uint16_t)) || (poffb > tif->tif_size))
{ {
TIFFErrorExtR(tif, module, "Error fetching directory count"); TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
*nextdiroff = 0; *nextdiroff = 0;
return (0); return (0);
} }
@ -1877,14 +1895,18 @@ static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
uint16_t dircount16; uint16_t dircount16;
if (poff > (uint64_t)TIFF_TMSIZE_T_MAX - sizeof(uint64_t)) if (poff > (uint64_t)TIFF_TMSIZE_T_MAX - sizeof(uint64_t))
{ {
TIFFErrorExtR(tif, module, "Error fetching directory count"); TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0); return (0);
} }
poffa = (tmsize_t)poff; poffa = (tmsize_t)poff;
poffb = poffa + sizeof(uint64_t); poffb = poffa + sizeof(uint64_t);
if (poffb > tif->tif_size) if (poffb > tif->tif_size)
{ {
TIFFErrorExtR(tif, module, "Error fetching directory count"); TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0); return (0);
} }
_TIFFmemcpy(&dircount64, tif->tif_base + poffa, sizeof(uint64_t)); _TIFFmemcpy(&dircount64, tif->tif_base + poffa, sizeof(uint64_t));
@ -1926,8 +1948,9 @@ static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
if (!SeekOK(tif, *nextdiroff) || if (!SeekOK(tif, *nextdiroff) ||
!ReadOK(tif, &dircount, sizeof(uint16_t))) !ReadOK(tif, &dircount, sizeof(uint16_t)))
{ {
TIFFErrorExtR(tif, module, "%s: Error fetching directory count", TIFFErrorExtR(tif, module,
tif->tif_name); "%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0); return (0);
} }
if (tif->tif_flags & TIFF_SWAB) if (tif->tif_flags & TIFF_SWAB)
@ -1953,15 +1976,18 @@ static int TIFFAdvanceDirectory(TIFF *tif, uint64_t *nextdiroff, uint64_t *off,
if (!SeekOK(tif, *nextdiroff) || if (!SeekOK(tif, *nextdiroff) ||
!ReadOK(tif, &dircount64, sizeof(uint64_t))) !ReadOK(tif, &dircount64, sizeof(uint64_t)))
{ {
TIFFErrorExtR(tif, module, "%s: Error fetching directory count", TIFFErrorExtR(tif, module,
tif->tif_name); "%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0); return (0);
} }
if (tif->tif_flags & TIFF_SWAB) if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&dircount64); TIFFSwabLong8(&dircount64);
if (dircount64 > 0xFFFF) if (dircount64 > 0xFFFF)
{ {
TIFFErrorExtR(tif, module, "Error fetching directory count"); TIFFErrorExtR(tif, module,
"%s:%d: %s: Error fetching directory count",
__FILE__, __LINE__, tif->tif_name);
return (0); return (0);
} }
dircount16 = (uint16_t)dircount64; dircount16 = (uint16_t)dircount64;
@ -2018,6 +2044,8 @@ tdir_t TIFFNumberOfDirectories(TIFF *tif)
{ {
++n; ++n;
} }
/* Update number of main-IFDs in file. */
tif->tif_curdircount = n;
return (n); return (n);
} }
@ -2100,7 +2128,19 @@ int TIFFSetDirectory(TIFF *tif, tdir_t dirn)
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
else else
tif->tif_curdir--; tif->tif_curdir--;
return (TIFFReadDirectory(tif));
tdir_t curdir = tif->tif_curdir;
int retval = TIFFReadDirectory(tif);
if (!retval && tif->tif_curdir == curdir)
{
/* If tif_curdir has not be incremented, TIFFFetchDirectory() in
* TIFFReadDirectory() has failed and tif_curdir shall be set
* specifically. */
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
}
return (retval);
} }
/* /*
@ -2125,8 +2165,11 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
int8_t probablySubIFD = 0; int8_t probablySubIFD = 0;
if (diroff == 0) if (diroff == 0)
{ {
/* Special case to invalidate the tif_lastdiroff member. */ /* Special case to set tif_diroff=0, which is done in
* TIFFReadDirectory() below to indicate that the currently read IFD is
* treated as a new, fresh IFD. */
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
tif->tif_dir.td_iswrittentofile = FALSE;
} }
else else
{ {
@ -2136,32 +2179,40 @@ int TIFFSetSubDirectory(TIFF *tif, uint64_t diroff)
probablySubIFD = 1; probablySubIFD = 1;
} }
/* -1 because TIFFReadDirectory() will increment tif_curdir. */ /* -1 because TIFFReadDirectory() will increment tif_curdir. */
tif->tif_curdir = if (curdir >= 1)
curdir == 0 ? TIFF_NON_EXISTENT_DIR_NUMBER : curdir - 1; tif->tif_curdir = curdir - 1;
else
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
} }
curdir = tif->tif_curdir;
tif->tif_nextdiroff = diroff; tif->tif_nextdiroff = diroff;
retval = TIFFReadDirectory(tif); retval = TIFFReadDirectory(tif);
/* If failed, curdir was not incremented in TIFFReadDirectory(), so set it
* back, but leave it for diroff==0. */ /* tif_curdir is incremented in TIFFReadDirectory(), but if it has not been
if (!retval && diroff != 0) * incremented, TIFFFetchDirectory() has failed there and tif_curdir shall
* be set specifically. */
if (!retval && diroff != 0 && tif->tif_curdir == curdir)
{ {
if (tif->tif_curdir == TIFF_NON_EXISTENT_DIR_NUMBER) tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
tif->tif_curdir = 0;
else
tif->tif_curdir++;
} }
if (retval && probablySubIFD)
if (probablySubIFD)
{ {
/* Reset IFD list to start new one for SubIFD chain and also start if (retval)
* SubIFD chain with tif_curdir=0. */ {
_TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ /* Reset IFD list to start new one for SubIFD chain and also start
tif->tif_curdir = 0; /* first directory of new chain */ * SubIFD chain with tif_curdir=0 for IFD loop checking. */
/* add this offset to new IFD list */ /* invalidate IFD loop lists */
_TIFFCheckDirNumberAndOffset(tif, tif->tif_curdir, diroff); _TIFFCleanupIFDOffsetAndNumberMaps(tif);
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 */ /* To be able to return from SubIFD or custom-IFD to main-IFD */
tif->tif_setdirectory_force_absolute = TRUE; tif->tif_setdirectory_force_absolute = TRUE;
} }
return (retval); return (retval);
} }
@ -2257,9 +2308,11 @@ int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn)
} }
else else
{ {
/* Need local swap because nextdir has to be used unswapped below. */
uint64_t nextdir64 = nextdir;
if (tif->tif_flags & TIFF_SWAB) if (tif->tif_flags & TIFF_SWAB)
TIFFSwabLong8(&nextdir); TIFFSwabLong8(&nextdir64);
if (!WriteOK(tif, &nextdir, sizeof(uint64_t))) if (!WriteOK(tif, &nextdir64, sizeof(uint64_t)))
{ {
TIFFErrorExtR(tif, module, "Error writing directory link"); TIFFErrorExtR(tif, module, "Error writing directory link");
return (0); return (0);
@ -2303,6 +2356,10 @@ int TIFFUnlinkDirectory(TIFF *tif, tdir_t dirn)
tif->tif_row = (uint32_t)-1; tif->tif_row = (uint32_t)-1;
tif->tif_curstrip = (uint32_t)-1; tif->tif_curstrip = (uint32_t)-1;
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER;
if (tif->tif_curdircount > 0)
tif->tif_curdircount--;
else
tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
_TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */ _TIFFCleanupIFDOffsetAndNumberMaps(tif); /* invalidate IFD loop lists */
return (1); return (1);
} }

View File

@ -65,6 +65,12 @@ typedef struct
tif_dirread.c */ tif_dirread.c */
} TIFFDirEntry; } TIFFDirEntry;
typedef struct
{
uint64_t offset;
uint64_t length;
} TIFFEntryOffsetAndLength; /* auxiliary for evaluating size of IFD data */
/* /*
* Internal format of a TIFF directory entry. * Internal format of a TIFF directory entry.
*/ */
@ -115,6 +121,9 @@ typedef struct
#ifdef STRIPBYTECOUNTSORTED_UNUSED #ifdef STRIPBYTECOUNTSORTED_UNUSED
int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */ int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */
#endif #endif
/* Be aware that the parameters of td_stripoffset_entry and
* td_stripbytecount_entry are swapped but tdir_offset is not
* and has to be swapped when used. */
TIFFDirEntry td_stripoffset_entry; /* for deferred loading */ TIFFDirEntry td_stripoffset_entry; /* for deferred loading */
TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */ TIFFDirEntry td_stripbytecount_entry; /* for deferred loading */
uint16_t td_nsubifd; uint16_t td_nsubifd;
@ -135,6 +144,24 @@ typedef struct
unsigned char unsigned char
td_deferstrilearraywriting; /* see TIFFDeferStrileArrayWriting() */ td_deferstrilearraywriting; /* see TIFFDeferStrileArrayWriting() */
unsigned char
td_iswrittentofile; /* indicates if current IFD is present on file */
/* LibTIFF writes all data that does not fit into the IFD entries directly
* after the IFD tag entry part. When reading, only the IFD data directly
* and continuously behind the IFD tags is taken into account for the IFD
* data size.*/
uint64_t td_dirdatasize_write; /* auxiliary for evaluating size of IFD data
to be written */
uint64_t td_dirdatasize_read; /* auxiliary for evaluating size of IFD data
read from file */
uint32_t td_dirdatasize_Noffsets; /* auxiliary counter for
tif_dir.td_dirdatasize_offsets array */
TIFFEntryOffsetAndLength
*td_dirdatasize_offsets; /* auxiliary array for all offsets of IFD tag
entries with data outside the IFD tag
entries. */
} TIFFDirectory; } TIFFDirectory;
/* /*
@ -308,11 +335,10 @@ extern "C"
TIFFDataType field_type; /* type of associated data */ TIFFDataType field_type; /* type of associated data */
uint32_t uint32_t
field_anonymous; /* if true, this is a unknown / anonymous tag */ field_anonymous; /* if true, this is a unknown / anonymous tag */
TIFFSetGetFieldType TIFFSetGetFieldType set_field_type; /* type to be passed to TIFFSetField
set_field_type; /* type to be passed to TIFFSetField */ and TIFFGetField*/
TIFFSetGetFieldType TIFFSetGetFieldType get_field_type; /* not used */
get_field_type; /* type to be passed to TIFFGetField */ unsigned short field_bit; /* bit in fieldsset bit vector */
unsigned short field_bit; /* bit in fieldsset bit vector */
unsigned char field_oktochange; /* if true, can change while writing */ unsigned char field_oktochange; /* if true, can change while writing */
unsigned char field_passcount; /* if true, pass dir count on set */ unsigned char field_passcount; /* if true, pass dir count on set */
char *field_name; /* ASCII name */ char *field_name; /* ASCII name */

View File

@ -213,8 +213,6 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL}, {TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, 0, TIFF_SETGET_C16_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CurrentPreProfileMatrix", NULL},
{TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL}, {TIFFTAG_PERSAMPLE, 0, 0, TIFF_SHORT, 0, TIFF_SETGET_UNDEFINED, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "PerSample", NULL},
#if 0 #if 0
/* TODO: revert above #if 0 for TIFF 4.6.0 */
/* begin DNG 1.2.0.0 tags */ /* begin DNG 1.2.0.0 tags */
{TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL}, {TIFFTAG_COLORIMETRICREFERENCE, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ColorimetricReference", NULL},
{TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL}, {TIFFTAG_CAMERACALIBRATIONSIGNATURE, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "CameraCalibrationSignature", NULL},
@ -282,9 +280,11 @@ static const TIFFField tiffFields[] = {
{TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL}, {TIFFTAG_ILLUMINANTDATA2, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData2", NULL},
{TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL}, {TIFFTAG_ILLUMINANTDATA3, -3, -3, TIFF_UNDEFINED, 0, TIFF_SETGET_C32_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "IlluminantData3", NULL},
/* end DNG tags */ /* end DNG tags */
#endif
/* begin TIFF/EP tags */ /* begin TIFF/EP tags */
{TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL}, {TIFFTAG_EP_CFAREPEATPATTERNDIM, 2, 2, TIFF_SHORT, 0, TIFF_SETGET_C0_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP CFARepeatPatternDim", NULL},
{TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL}, {TIFFTAG_EP_CFAPATTERN, -1, -1, TIFF_BYTE, 0, TIFF_SETGET_C16_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 1, "EP CFAPattern", NULL},
#if 0
/* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII. /* TIFFTAG_EP_BATTERYLEVEL can be RATIONAL or ASCII.
* LibTiff defines it as ASCII and converts RATIONAL to an ASCII string. */ * LibTiff defines it as ASCII and converts RATIONAL to an ASCII string. */
{TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL}, {TIFFTAG_EP_BATTERYLEVEL, -1, -1, TIFF_ASCII, 0, TIFF_SETGET_ASCII, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "EP BatteryLevel", NULL},
@ -374,7 +374,7 @@ static const TIFFField exifFields[] = {
{EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL}, {EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "BrightnessValue", NULL},
{EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL}, {EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "ExposureBiasValue", NULL},
{EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL}, {EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "MaxApertureValue", NULL},
/*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance! /*--: EXIFTAG_SUBJECTDISTANCE: LibTiff returns value of "-1" if numerator equals 4294967295 (0xFFFFFFFF) to indicate infinite distance!
* However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values, * However, there are two other EXIF tags where numerator indicates a special value and six other cases where the denominator indicates special values,
* which are not treated within LibTiff!! */ * which are not treated within LibTiff!! */
{EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL}, {EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, 0, TIFF_SETGET_FLOAT, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "SubjectDistance", NULL},
@ -887,7 +887,7 @@ const TIFFField *_TIFFFindOrRegisterField(TIFF *tif, uint32_t tag,
if (fld == NULL) if (fld == NULL)
{ {
fld = _TIFFCreateAnonField(tif, tag, dt); fld = _TIFFCreateAnonField(tif, tag, dt);
if (!_TIFFMergeFields(tif, fld, 1)) if (fld == NULL || !_TIFFMergeFields(tif, fld, 1))
return NULL; return NULL;
} }
@ -1197,12 +1197,24 @@ int TIFFMergeFieldInfo(TIFF *tif, const TIFFFieldInfo info[], uint32_t n)
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
tp->field_tag = info[i].field_tag; tp->field_tag = info[i].field_tag;
if (info[i].field_readcount < TIFF_VARIABLE2 ||
info[i].field_readcount == 0 ||
info[i].field_writecount < TIFF_VARIABLE2 ||
info[i].field_writecount == 0)
{
/* The fields (field_readcount) and (field_writecount) may use the
* values TIFF_VARIABLE (-1), TIFF_SPP (-2), TIFF_VARIABLE2 (-3). */
TIFFErrorExtR(tif, module,
"The value of field_readcount and field_writecount "
"must be greater than or equal to -3 and not zero.");
return -1;
}
tp->field_readcount = info[i].field_readcount; tp->field_readcount = info[i].field_readcount;
tp->field_writecount = info[i].field_writecount; tp->field_writecount = info[i].field_writecount;
tp->field_type = info[i].field_type; tp->field_type = info[i].field_type;
tp->field_anonymous = 0; tp->field_anonymous = 0;
tp->set_field_type = tp->set_field_type =
_TIFFSetGetType(info[i].field_type, info[i].field_readcount, _TIFFSetGetType(info[i].field_type, info[i].field_writecount,
info[i].field_passcount); info[i].field_passcount);
tp->get_field_type = tp->get_field_type =
_TIFFSetGetType(info[i].field_type, info[i].field_readcount, _TIFFSetGetType(info[i].field_type, info[i].field_readcount,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,14 @@
#include "t4.h" #include "t4.h"
#include <stdio.h> #include <stdio.h>
#ifndef EOF_REACHED_COUNT_THRESHOLD
/* Arbitrary threshold to avoid corrupted single-strip files with extremely
* large imageheight to cause apparently endless looping, such as in
* https://gitlab.com/libtiff/libtiff/-/issues/583
*/
#define EOF_REACHED_COUNT_THRESHOLD 8192
#endif
/* /*
* Compression+decompression state blocks are * Compression+decompression state blocks are
* derived from this ``base state'' block. * derived from this ``base state'' block.
@ -77,6 +85,8 @@ typedef struct
uint32_t data; /* current i/o byte/word */ uint32_t data; /* current i/o byte/word */
int bit; /* current i/o bit in byte */ int bit; /* current i/o bit in byte */
int EOLcnt; /* count of EOL codes recognized */ int EOLcnt; /* count of EOL codes recognized */
int eofReachedCount; /* number of times decode has been called with
EOF already reached */
TIFFFaxFillFunc fill; /* fill routine */ TIFFFaxFillFunc fill; /* fill routine */
uint32_t *runs; /* b&w runs for current/previous row */ uint32_t *runs; /* b&w runs for current/previous row */
uint32_t nruns; /* size of the refruns / curruns arrays */ uint32_t nruns; /* size of the refruns / curruns arrays */
@ -120,6 +130,7 @@ typedef struct
int EOLcnt; /* # EOL codes recognized */ \ int EOLcnt; /* # EOL codes recognized */ \
const unsigned char *bitmap = sp->bitmap; /* input data bit reverser */ \ const unsigned char *bitmap = sp->bitmap; /* input data bit reverser */ \
const TIFFFaxTabEnt *TabEnt const TIFFFaxTabEnt *TabEnt
#define DECLARE_STATE_2D(tif, sp, mod) \ #define DECLARE_STATE_2D(tif, sp, mod) \
DECLARE_STATE(tif, sp, mod); \ DECLARE_STATE(tif, sp, mod); \
int b1; /* next change on prev line */ \ int b1; /* next change on prev line */ \
@ -162,6 +173,7 @@ static int Fax3PreDecode(TIFF *tif, uint16_t s)
sp->bit = 0; /* force initial read */ sp->bit = 0; /* force initial read */
sp->data = 0; sp->data = 0;
sp->EOLcnt = 0; /* force initial scan for EOL */ sp->EOLcnt = 0; /* force initial scan for EOL */
sp->eofReachedCount = 0;
/* /*
* Decoder assumes lsb-to-msb bit order. Note that we select * Decoder assumes lsb-to-msb bit order. Note that we select
* this here rather than in Fax3SetupState so that viewers can * this here rather than in Fax3SetupState so that viewers can
@ -232,7 +244,12 @@ static void Fax3PrematureEOF(const char *module, TIFF *tif, uint32_t line,
line, isTiled(tif) ? "tile" : "strip", line, isTiled(tif) ? "tile" : "strip",
(isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0); (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip), a0);
} }
#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0) #define prematureEOF(a0) \
do \
{ \
Fax3PrematureEOF(module, tif, sp->line, a0); \
++sp->eofReachedCount; \
} while (0)
#define Nop #define Nop
@ -252,6 +269,14 @@ static int Fax3Decode1D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s)
TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
return (-1); return (-1);
} }
if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD)
{
TIFFErrorExtR(
tif, module,
"End of file has already been reached %d times within that strip",
sp->eofReachedCount);
return (-1);
}
CACHE_STATE(tif, sp); CACHE_STATE(tif, sp);
thisrun = sp->curruns; thisrun = sp->curruns;
while (occ > 0) while (occ > 0)
@ -302,6 +327,14 @@ static int Fax3Decode2D(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s)
TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
return (-1); return (-1);
} }
if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD)
{
TIFFErrorExtR(
tif, module,
"End of file has already been reached %d times within that strip",
sp->eofReachedCount);
return (-1);
}
CACHE_STATE(tif, sp); CACHE_STATE(tif, sp);
while (occ > 0) while (occ > 0)
{ {
@ -536,7 +569,11 @@ static int Fax3SetupState(TIFF *tif)
TIFFroundup and TIFFSafeMultiply return zero on integer overflow TIFFroundup and TIFFSafeMultiply return zero on integer overflow
*/ */
dsp->runs = (uint32_t *)NULL; if (dsp->runs != NULL)
{
_TIFFfreeExt(tif, dsp->runs);
dsp->runs = (uint32_t *)NULL;
}
dsp->nruns = TIFFroundup_32(rowpixels + 1, 32); dsp->nruns = TIFFroundup_32(rowpixels + 1, 32);
if (needsRefLine) if (needsRefLine)
{ {
@ -578,6 +615,10 @@ static int Fax3SetupState(TIFF *tif)
* is referenced. The reference line must * is referenced. The reference line must
* be initialized to be ``white'' (done elsewhere). * be initialized to be ``white'' (done elsewhere).
*/ */
if (esp->refline != NULL)
{
_TIFFfreeExt(tif, esp->refline);
}
esp->refline = (unsigned char *)_TIFFmallocExt(tif, rowbytes); esp->refline = (unsigned char *)_TIFFmallocExt(tif, rowbytes);
if (esp->refline == NULL) if (esp->refline == NULL)
{ {
@ -1514,7 +1555,16 @@ static int Fax4Decode(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s)
TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
return (-1); return (-1);
} }
if (sp->eofReachedCount >= EOF_REACHED_COUNT_THRESHOLD)
{
TIFFErrorExtR(
tif, module,
"End of file has already been reached %d times within that strip",
sp->eofReachedCount);
return (-1);
}
CACHE_STATE(tif, sp); CACHE_STATE(tif, sp);
int start = sp->line;
while (occ > 0) while (occ > 0)
{ {
a0 = 0; a0 = 0;
@ -1563,7 +1613,9 @@ static int Fax4Decode(TIFF *tif, uint8_t *buf, tmsize_t occ, uint16_t s)
} }
(*sp->fill)(buf, thisrun, pa, lastx); (*sp->fill)(buf, thisrun, pa, lastx);
UNCACHE_STATE(tif, sp); UNCACHE_STATE(tif, sp);
return (sp->line ? 1 : -1); /* don't error on badly-terminated strips */ return (sp->line != start
? 1
: -1); /* don't error on badly-terminated strips */
} }
UNCACHE_STATE(tif, sp); UNCACHE_STATE(tif, sp);
return (1); return (1);

View File

@ -760,6 +760,12 @@ static int gtTileContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
toskew = -(int32_t)(tw - w); toskew = -(int32_t)(tw - w);
} }
if (tw == 0 || th == 0)
{
TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero");
return (0);
}
/* /*
* Leftmost tile is clipped on left side if col_offset > 0. * Leftmost tile is clipped on left side if col_offset > 0.
*/ */
@ -916,6 +922,12 @@ static int gtTileSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
break; break;
} }
if (tw == 0 || th == 0)
{
TIFFErrorExtR(tif, TIFFFileName(tif), "tile width or height is zero");
return (0);
}
/* /*
* Leftmost tile is clipped on left side if col_offset > 0. * Leftmost tile is clipped on left side if col_offset > 0.
*/ */
@ -1092,6 +1104,11 @@ static int gtStripContig(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
} }
TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
if (rowsperstrip == 0)
{
TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
return (0);
}
scanline = TIFFScanlineSize(tif); scanline = TIFFScanlineSize(tif);
fromskew = (w < imagewidth ? imagewidth - w : 0); fromskew = (w < imagewidth ? imagewidth - w : 0);
@ -1216,6 +1233,12 @@ static int gtStripSeparate(TIFFRGBAImage *img, uint32_t *raster, uint32_t w,
} }
TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
if (rowsperstrip == 0)
{
TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
return (0);
}
scanline = TIFFScanlineSize(tif); scanline = TIFFScanlineSize(tif);
fromskew = (w < imagewidth ? imagewidth - w : 0); fromskew = (w < imagewidth ? imagewidth - w : 0);
for (row = 0; row < h; row += nrow) for (row = 0; row < h; row += nrow)
@ -3213,6 +3236,13 @@ int TIFFReadRGBAStripExt(TIFF *tif, uint32_t row, uint32_t *raster,
} }
TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
if (rowsperstrip == 0)
{
TIFFErrorExtR(tif, TIFFFileName(tif), "rowsperstrip is zero");
return (0);
}
if ((row % rowsperstrip) != 0) if ((row % rowsperstrip) != 0)
{ {
TIFFErrorExtR( TIFFErrorExtR(
@ -3224,6 +3254,13 @@ int TIFFReadRGBAStripExt(TIFF *tif, uint32_t row, uint32_t *raster,
if (TIFFRGBAImageOK(tif, emsg) && if (TIFFRGBAImageOK(tif, emsg) &&
TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg)) TIFFRGBAImageBegin(&img, tif, stop_on_error, emsg))
{ {
if (row >= img.height)
{
TIFFErrorExtR(tif, TIFFFileName(tif),
"Invalid row passed to TIFFReadRGBAStrip().");
TIFFRGBAImageEnd(&img);
return (0);
}
img.row_offset = row; img.row_offset = row;
img.col_offset = 0; img.col_offset = 0;
@ -3282,6 +3319,13 @@ int TIFFReadRGBATileExt(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster,
TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize);
TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize);
if (tile_xsize == 0 || tile_ysize == 0)
{
TIFFErrorExtR(tif, TIFFFileName(tif),
"tile_xsize or tile_ysize is zero");
return (0);
}
if ((col % tile_xsize) != 0 || (row % tile_ysize) != 0) if ((col % tile_xsize) != 0 || (row % tile_ysize) != 0)
{ {
TIFFErrorExtR(tif, TIFFFileName(tif), TIFFErrorExtR(tif, TIFFFileName(tif),
@ -3301,6 +3345,14 @@ int TIFFReadRGBATileExt(TIFF *tif, uint32_t col, uint32_t row, uint32_t *raster,
return (0); return (0);
} }
if (col >= img.width || row >= img.height)
{
TIFFErrorExtR(tif, TIFFFileName(tif),
"Invalid row/col passed to TIFFReadRGBATile().");
TIFFRGBAImageEnd(&img);
return (0);
}
/* /*
* The TIFFRGBAImageGet() function doesn't allow us to get off the * The TIFFRGBAImageGet() function doesn't allow us to get off the
* edge of the image, even to fill an otherwise valid tile. So we * edge of the image, even to fill an otherwise valid tile. So we

View File

@ -92,6 +92,7 @@ static int JBIGDecode(TIFF *tif, uint8_t *buffer, tmsize_t size, uint16_t s)
jbg_strerror(decodeStatus) jbg_strerror(decodeStatus)
#endif #endif
); );
memset(buffer, 0, (size_t)size);
jbg_dec_free(&decoder); jbg_dec_free(&decoder);
return 0; return 0;
} }
@ -99,6 +100,7 @@ static int JBIGDecode(TIFF *tif, uint8_t *buffer, tmsize_t size, uint16_t s)
decodedSize = jbg_dec_getsize(&decoder); decodedSize = jbg_dec_getsize(&decoder);
if ((tmsize_t)decodedSize < size) if ((tmsize_t)decodedSize < size)
{ {
memset(buffer + decodedSize, 0, (size_t)(size - decodedSize));
TIFFWarningExtR(tif, "JBIG", TIFFWarningExtR(tif, "JBIG",
"Only decoded %lu bytes, whereas %" TIFF_SSIZE_FORMAT "Only decoded %lu bytes, whereas %" TIFF_SSIZE_FORMAT
" requested", " requested",

View File

@ -73,43 +73,6 @@ int TIFFReInitJPEG_12(TIFF *tif, const JPEGOtherSettings *otherSettings,
int scheme, int is_encode); int scheme, int is_encode);
int TIFFJPEGIsFullStripRequired_12(TIFF *tif); int TIFFJPEGIsFullStripRequired_12(TIFF *tif);
/* We undefine FAR to avoid conflict with JPEG definition */
#ifdef FAR
#undef FAR
#endif
/*
Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
not defined. Unfortunately, the MinGW and Borland compilers include
a typedef for INT32, which causes a conflict. MSVC does not include
a conflicting typedef given the headers which are included.
*/
#if defined(__BORLANDC__) || defined(__MINGW32__)
#define XMD_H 1
#endif
/*
The windows RPCNDR.H file defines boolean, but defines it with the
unsigned char size. You should compile JPEG library using appropriate
definitions in jconfig.h header, but many users compile library in wrong
way. That causes errors of the following type:
"JPEGLib: JPEG parameter struct mismatch: library thinks size is 432,
caller expects 464"
For such users we will fix the problem here. See install.doc file from
the JPEG library distribution for details.
*/
/* Define "boolean" as unsigned char, not int, per Windows custom. */
#if defined(__WIN32__) && !defined(__MINGW32__)
#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
typedef unsigned char boolean;
#endif
#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
#endif
#include "jerror.h" #include "jerror.h"
#include "jpeglib.h" #include "jpeglib.h"
@ -125,18 +88,18 @@ typedef unsigned char boolean;
* 16bit value? * 16bit value?
*/ */
/* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 2.2 which /* HAVE_JPEGTURBO_DUAL_MODE_8_12 is defined for libjpeg-turbo >= 3.0 which
* adds a dual-mode 8/12 bit API in the same library. * adds a dual-mode 8/12 bit API in the same library.
*/ */
#if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12) #if defined(HAVE_JPEGTURBO_DUAL_MODE_8_12)
#define JPEG_DUAL_MODE_8_12 #define JPEG_DUAL_MODE_8_12
/* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo /* Start by undefining BITS_IN_JSAMPLE which is always set to 8 in libjpeg-turbo
* >= 2.2 Cf * >= 3.0 Cf
* https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b * https://github.com/libjpeg-turbo/libjpeg-turbo/commit/8b9bc4b9635a2a047fb23ebe70c9acd728d3f99b
*/ */
#undef BITS_IN_JSAMPLE #undef BITS_IN_JSAMPLE
/* libjpeg-turbo >= 2.2 adds J12xxxx datatypes for the 12-bit mode. */ /* libjpeg-turbo >= 3.0 adds J12xxxx datatypes for the 12-bit mode. */
#if defined(FROM_TIF_JPEG_12) #if defined(FROM_TIF_JPEG_12)
#define BITS_IN_JSAMPLE 12 #define BITS_IN_JSAMPLE 12
#define TIFF_JSAMPLE J12SAMPLE #define TIFF_JSAMPLE J12SAMPLE
@ -182,9 +145,20 @@ typedef unsigned char boolean;
#define LONGJMP(jbuf, code) longjmp(jbuf, code) #define LONGJMP(jbuf, code) longjmp(jbuf, code)
#define JMP_BUF jmp_buf #define JMP_BUF jmp_buf
#ifndef TIFF_jpeg_destination_mgr_defined
#define TIFF_jpeg_destination_mgr_defined
typedef struct jpeg_destination_mgr jpeg_destination_mgr; typedef struct jpeg_destination_mgr jpeg_destination_mgr;
#endif
#ifndef TIFF_jpeg_source_mgr_defined
#define TIFF_jpeg_source_mgr_defined
typedef struct jpeg_source_mgr jpeg_source_mgr; typedef struct jpeg_source_mgr jpeg_source_mgr;
#endif
#ifndef TIFF_jpeg_error_mgr_defined
#define TIFF_jpeg_error_mgr_defined
typedef struct jpeg_error_mgr jpeg_error_mgr; typedef struct jpeg_error_mgr jpeg_error_mgr;
#endif
/* /*
* State block for each open TIFF file using * State block for each open TIFF file using
@ -1241,6 +1215,12 @@ int TIFFJPEGIsFullStripRequired(TIFF *tif)
* For PC 2, scale down the expected strip/tile size * For PC 2, scale down the expected strip/tile size
* to match a downsampled component * to match a downsampled component
*/ */
if (sp->h_sampling == 0 || sp->v_sampling == 0)
{
TIFFErrorExtR(tif, module,
"JPEG horizontal or vertical sampling is zero");
return (0);
}
segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
} }
@ -1471,7 +1451,10 @@ static int JPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc; sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc;
if (sp->bytesperline == 0) if (sp->bytesperline == 0)
{
memset(buf, 0, (size_t)cc);
return 0; return 0;
}
nrows = cc / sp->bytesperline; nrows = cc / sp->bytesperline;
if (cc % sp->bytesperline) if (cc % sp->bytesperline)
@ -1492,7 +1475,10 @@ static int JPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
JSAMPROW bufptr = (JSAMPROW)buf; JSAMPROW bufptr = (JSAMPROW)buf;
if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1) if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1)
{
memset(buf, 0, (size_t)cc);
return (0); return (0);
}
++tif->tif_row; ++tif->tif_row;
buf += sp->bytesperline; buf += sp->bytesperline;
@ -1526,7 +1512,10 @@ static int JPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc; sp->src.bytes_in_buffer = (size_t)tif->tif_rawcc;
if (sp->bytesperline == 0) if (sp->bytesperline == 0)
{
memset(buf, 0, (size_t)cc);
return 0; return 0;
}
nrows = cc / sp->bytesperline; nrows = cc / sp->bytesperline;
if (cc % sp->bytesperline) if (cc % sp->bytesperline)
@ -1562,7 +1551,10 @@ static int JPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
* for 12bit data, which we need to repack. * for 12bit data, which we need to repack.
*/ */
if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1) if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1)
{
memset(buf, 0, (size_t)cc);
return (0); return (0);
}
if (sp->cinfo.d.data_precision == 12) if (sp->cinfo.d.data_precision == 12)
{ {
@ -2190,6 +2182,12 @@ static int JPEGPreEncode(TIFF *tif, uint16_t s)
/* for PC 2, scale down the strip/tile size /* for PC 2, scale down the strip/tile size
* to match a downsampled component * to match a downsampled component
*/ */
if (sp->h_sampling == 0 || sp->v_sampling == 0)
{
TIFFErrorExtR(tif, module,
"JPEG horizontal or vertical sampling is zero");
return (0);
}
segment_width = TIFFhowmany_32(segment_width, sp->h_sampling); segment_width = TIFFhowmany_32(segment_width, sp->h_sampling);
segment_height = TIFFhowmany_32(segment_height, sp->v_sampling); segment_height = TIFFhowmany_32(segment_height, sp->v_sampling);
} }

View File

@ -71,6 +71,9 @@ typedef struct
uint8_t *uncompressed_buffer; uint8_t *uncompressed_buffer;
unsigned int uncompressed_offset; unsigned int uncompressed_offset;
uint8_t *uncompressed_buffer_multiband;
unsigned int uncompressed_buffer_multiband_alloc;
unsigned int mask_size; unsigned int mask_size;
uint8_t *mask_buffer; uint8_t *mask_buffer;
@ -86,9 +89,9 @@ typedef struct
TIFFVSetMethod vsetparent; /* super-class method */ TIFFVSetMethod vsetparent; /* super-class method */
} LERCState; } LERCState;
#define LState(tif) ((LERCState *)(tif)->tif_data) #define GetLERCState(tif) ((LERCState *)(tif)->tif_data)
#define DecoderState(tif) LState(tif) #define LERCDecoderState(tif) GetLERCState(tif)
#define EncoderState(tif) LState(tif) #define LERCEncoderState(tif) GetLERCState(tif)
static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
@ -101,7 +104,7 @@ static int LERCFixupTags(TIFF *tif)
static int LERCSetupDecode(TIFF *tif) static int LERCSetupDecode(TIFF *tif)
{ {
LERCState *sp = DecoderState(tif); LERCState *sp = LERCDecoderState(tif);
assert(sp != NULL); assert(sp != NULL);
@ -168,7 +171,7 @@ static int GetLercDataType(TIFF *tif)
return -1; return -1;
} }
static int SetupUncompressedBuffer(TIFF *tif, LERCState *sp, const char *module) static int SetupBuffers(TIFF *tif, LERCState *sp, const char *module)
{ {
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
uint64_t new_size_64; uint64_t new_size_64;
@ -202,8 +205,9 @@ static int SetupUncompressedBuffer(TIFF *tif, LERCState *sp, const char *module)
sp->uncompressed_size = new_size; sp->uncompressed_size = new_size;
/* add some margin as we are going to use it also to store deflate/zstd /* add some margin as we are going to use it also to store deflate/zstd
* compressed data */ * compressed data. We also need extra margin when writing very small
new_alloc_64 = 100 + new_size_64 + new_size_64 / 3; * rasters with one mask per band. */
new_alloc_64 = 256 + new_size_64 + new_size_64 / 3;
#ifdef ZSTD_SUPPORT #ifdef ZSTD_SUPPORT
{ {
size_t zstd_max = ZSTD_compressBound((size_t)new_size_64); size_t zstd_max = ZSTD_compressBound((size_t)new_size_64);
@ -243,11 +247,17 @@ static int SetupUncompressedBuffer(TIFF *tif, LERCState *sp, const char *module)
td->td_sampleinfo[td->td_extrasamples - 1] == EXTRASAMPLE_UNASSALPHA && td->td_sampleinfo[td->td_extrasamples - 1] == EXTRASAMPLE_UNASSALPHA &&
GetLercDataType(tif) == 1) || GetLercDataType(tif) == 1) ||
(td->td_sampleformat == SAMPLEFORMAT_IEEEFP && (td->td_sampleformat == SAMPLEFORMAT_IEEEFP &&
(td->td_planarconfig == PLANARCONFIG_SEPARATE ||
td->td_samplesperpixel == 1) &&
(td->td_bitspersample == 32 || td->td_bitspersample == 64))) (td->td_bitspersample == 32 || td->td_bitspersample == 64)))
{ {
unsigned int mask_size = sp->segment_width * sp->segment_height; unsigned int mask_size = sp->segment_width * sp->segment_height;
#if LERC_AT_LEAST_VERSION(3, 0, 0)
if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP &&
td->td_planarconfig == PLANARCONFIG_CONTIG)
{
/* We may need one mask per band */
mask_size *= td->td_samplesperpixel;
}
#endif
if (sp->mask_size < mask_size) if (sp->mask_size < mask_size)
{ {
void *mask_buffer = void *mask_buffer =
@ -277,9 +287,9 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
static const char module[] = "LERCPreDecode"; static const char module[] = "LERCPreDecode";
lerc_status lerc_ret; lerc_status lerc_ret;
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
LERCState *sp = DecoderState(tif); LERCState *sp = LERCDecoderState(tif);
int lerc_data_type; int lerc_data_type;
unsigned int infoArray[8]; unsigned int infoArray[9];
unsigned nomask_bands = td->td_samplesperpixel; unsigned nomask_bands = td->td_samplesperpixel;
int ndims; int ndims;
int use_mask = 0; int use_mask = 0;
@ -295,7 +305,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
if (lerc_data_type < 0) if (lerc_data_type < 0)
return 0; return 0;
if (!SetupUncompressedBuffer(tif, sp, module)) if (!SetupBuffers(tif, sp, module))
return 0; return 0;
if (sp->additional_compression != LERC_ADD_COMPRESSION_NONE) if (sp->additional_compression != LERC_ADD_COMPRESSION_NONE)
@ -400,7 +410,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
} }
lerc_ret = lerc_ret =
lerc_getBlobInfo(lerc_data, lerc_data_size, infoArray, NULL, 8, 0); lerc_getBlobInfo(lerc_data, lerc_data_size, infoArray, NULL, 9, 0);
if (lerc_ret != 0) if (lerc_ret != 0)
{ {
TIFFErrorExtR(tif, module, "lerc_getBlobInfo() failed"); TIFFErrorExtR(tif, module, "lerc_getBlobInfo() failed");
@ -418,18 +428,16 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
use_mask = 1; use_mask = 1;
nomask_bands--; nomask_bands--;
} }
else if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && else if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP)
(td->td_planarconfig == PLANARCONFIG_SEPARATE ||
td->td_samplesperpixel == 1) &&
(td->td_bitspersample == 32 || td->td_bitspersample == 64))
{ {
use_mask = 1; use_mask = 1;
} }
ndims = td->td_planarconfig == PLANARCONFIG_CONTIG ? nomask_bands : 1; ndims = td->td_planarconfig == PLANARCONFIG_CONTIG ? nomask_bands : 1;
/* Info returned in infoArray is { version, dataType, nDim, nCols, /* Info returned in infoArray is { version, dataType, nDim/nDepth, nCols,
nRows, nBands, nValidPixels, blobSize } */ nRows, nBands, nValidPixels, blobSize,
and starting with liblerc 3.0 nRequestedMasks } */
if (infoArray[0] != (unsigned)sp->lerc_version) if (infoArray[0] != (unsigned)sp->lerc_version)
{ {
TIFFWarningExtR(tif, module, TIFFWarningExtR(tif, module,
@ -442,12 +450,29 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
infoArray[1], lerc_data_type); infoArray[1], lerc_data_type);
return 0; return 0;
} }
if (infoArray[2] != (unsigned)ndims)
const unsigned nFoundDims = infoArray[2];
#if LERC_AT_LEAST_VERSION(3, 0, 0)
if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP &&
td->td_planarconfig == PLANARCONFIG_CONTIG &&
td->td_samplesperpixel > 1)
{
if (nFoundDims != 1 && nFoundDims != (unsigned)ndims)
{
TIFFErrorExtR(tif, module, "Unexpected nDim: %d. Expected: 1 or %d",
nFoundDims, ndims);
return 0;
}
}
else
#endif
if (nFoundDims != (unsigned)ndims)
{ {
TIFFErrorExtR(tif, module, "Unexpected nDim: %d. Expected: %d", TIFFErrorExtR(tif, module, "Unexpected nDim: %d. Expected: %d",
infoArray[2], ndims); nFoundDims, ndims);
return 0; return 0;
} }
if (infoArray[3] != sp->segment_width) if (infoArray[3] != sp->segment_width)
{ {
TIFFErrorExtR(tif, module, "Unexpected nCols: %d. Expected: %du", TIFFErrorExtR(tif, module, "Unexpected nCols: %d. Expected: %du",
@ -460,12 +485,38 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
infoArray[4], sp->segment_height); infoArray[4], sp->segment_height);
return 0; return 0;
} }
if (infoArray[5] != 1)
const unsigned nFoundBands = infoArray[5];
if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP &&
td->td_planarconfig == PLANARCONFIG_CONTIG &&
td->td_samplesperpixel > 1 && nFoundDims == 1)
{
#if !LERC_AT_LEAST_VERSION(3, 0, 0)
if (nFoundBands == td->td_samplesperpixel)
{
TIFFErrorExtR(
tif, module,
"Unexpected nBands: %d. This file may have been generated with "
"a liblerc version >= 3.0, with one mask per band, and is not "
"supported by this older version of liblerc",
nFoundBands);
return 0;
}
#endif
if (nFoundBands != td->td_samplesperpixel)
{
TIFFErrorExtR(tif, module, "Unexpected nBands: %d. Expected: %d",
nFoundBands, td->td_samplesperpixel);
return 0;
}
}
else if (nFoundBands != 1)
{ {
TIFFErrorExtR(tif, module, "Unexpected nBands: %d. Expected: %d", TIFFErrorExtR(tif, module, "Unexpected nBands: %d. Expected: %d",
infoArray[5], 1); nFoundBands, 1);
return 0; return 0;
} }
if (infoArray[7] != lerc_data_size) if (infoArray[7] != lerc_data_size)
{ {
TIFFErrorExtR(tif, module, "Unexpected blobSize: %d. Expected: %u", TIFFErrorExtR(tif, module, "Unexpected blobSize: %d. Expected: %u",
@ -473,13 +524,75 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
return 0; return 0;
} }
lerc_ret = lerc_decode(lerc_data, lerc_data_size, int nRequestedMasks = use_mask ? 1 : 0;
#if LERC_AT_LEAST_VERSION(3, 0, 0) #if LERC_AT_LEAST_VERSION(3, 0, 0)
use_mask ? 1 : 0, const int nFoundMasks = infoArray[8];
if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP &&
td->td_planarconfig == PLANARCONFIG_CONTIG &&
td->td_samplesperpixel > 1 && nFoundDims == 1)
{
if (nFoundMasks != 0 && nFoundMasks != td->td_samplesperpixel)
{
TIFFErrorExtR(tif, module,
"Unexpected nFoundMasks: %d. Expected: 0 or %d",
nFoundMasks, td->td_samplesperpixel);
return 0;
}
nRequestedMasks = nFoundMasks;
}
else
{
if (nFoundMasks != 0 && nFoundMasks != 1)
{
TIFFErrorExtR(tif, module,
"Unexpected nFoundMasks: %d. Expected: 0 or 1",
nFoundMasks);
return 0;
}
}
if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && nFoundMasks == 0)
{
nRequestedMasks = 0;
use_mask = 0;
}
#endif #endif
use_mask ? sp->mask_buffer : NULL, ndims,
sp->segment_width, sp->segment_height, 1, const unsigned nb_pixels = sp->segment_width * sp->segment_height;
lerc_data_type, sp->uncompressed_buffer);
#if LERC_AT_LEAST_VERSION(3, 0, 0)
if (nRequestedMasks > 1)
{
unsigned int num_bytes_needed =
nb_pixels * td->td_samplesperpixel * (td->td_bitspersample / 8);
if (sp->uncompressed_buffer_multiband_alloc < num_bytes_needed)
{
_TIFFfreeExt(tif, sp->uncompressed_buffer_multiband);
sp->uncompressed_buffer_multiband =
_TIFFmallocExt(tif, num_bytes_needed);
if (!sp->uncompressed_buffer_multiband)
{
sp->uncompressed_buffer_multiband_alloc = 0;
return 0;
}
sp->uncompressed_buffer_multiband_alloc = num_bytes_needed;
}
lerc_ret = lerc_decode(lerc_data, lerc_data_size, nRequestedMasks,
sp->mask_buffer, nFoundDims, sp->segment_width,
sp->segment_height, nFoundBands, lerc_data_type,
sp->uncompressed_buffer_multiband);
}
else
#endif
{
lerc_ret =
lerc_decode(lerc_data, lerc_data_size,
#if LERC_AT_LEAST_VERSION(3, 0, 0)
nRequestedMasks,
#endif
use_mask ? sp->mask_buffer : NULL, nFoundDims,
sp->segment_width, sp->segment_height, nFoundBands,
lerc_data_type, sp->uncompressed_buffer);
}
if (lerc_ret != 0) if (lerc_ret != 0)
{ {
TIFFErrorExtR(tif, module, "lerc_decode() failed"); TIFFErrorExtR(tif, module, "lerc_decode() failed");
@ -515,7 +628,6 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
} }
else if (use_mask && td->td_sampleformat == SAMPLEFORMAT_IEEEFP) else if (use_mask && td->td_sampleformat == SAMPLEFORMAT_IEEEFP)
{ {
const unsigned nb_pixels = sp->segment_width * sp->segment_height;
unsigned i; unsigned i;
#if WORDS_BIGENDIAN #if WORDS_BIGENDIAN
const unsigned char nan_bytes[] = {0x7f, 0xc0, 0, 0}; const unsigned char nan_bytes[] = {0x7f, 0xc0, 0, 0};
@ -525,23 +637,104 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
float nan_float32; float nan_float32;
memcpy(&nan_float32, nan_bytes, 4); memcpy(&nan_float32, nan_bytes, 4);
if (td->td_bitspersample == 32) if (td->td_planarconfig == PLANARCONFIG_SEPARATE ||
td->td_samplesperpixel == 1)
{ {
for (i = 0; i < nb_pixels; i++) if (td->td_bitspersample == 32)
{ {
if (sp->mask_buffer[i] == 0) for (i = 0; i < nb_pixels; i++)
((float *)sp->uncompressed_buffer)[i] = nan_float32; {
if (sp->mask_buffer[i] == 0)
((float *)sp->uncompressed_buffer)[i] = nan_float32;
}
}
else
{
const double nan_float64 = nan_float32;
for (i = 0; i < nb_pixels; i++)
{
if (sp->mask_buffer[i] == 0)
((double *)sp->uncompressed_buffer)[i] = nan_float64;
}
} }
} }
else if (nRequestedMasks == 1)
{
assert(nFoundDims == td->td_samplesperpixel);
assert(nFoundBands == 1);
unsigned k = 0;
if (td->td_bitspersample == 32)
{
for (i = 0; i < nb_pixels; i++)
{
for (int j = 0; j < td->td_samplesperpixel; j++)
{
if (sp->mask_buffer[i] == 0)
((float *)sp->uncompressed_buffer)[k] = nan_float32;
++k;
}
}
}
else
{
const double nan_float64 = nan_float32;
for (i = 0; i < nb_pixels; i++)
{
for (int j = 0; j < td->td_samplesperpixel; j++)
{
if (sp->mask_buffer[i] == 0)
((double *)sp->uncompressed_buffer)[k] =
nan_float64;
++k;
}
}
}
}
#if LERC_AT_LEAST_VERSION(3, 0, 0)
else else
{ {
const double nan_float64 = nan_float32; assert(nRequestedMasks == td->td_samplesperpixel);
for (i = 0; i < nb_pixels; i++) assert(nFoundDims == 1);
assert(nFoundBands == td->td_samplesperpixel);
unsigned k = 0;
if (td->td_bitspersample == 32)
{ {
if (sp->mask_buffer[i] == 0) for (i = 0; i < nb_pixels; i++)
((double *)sp->uncompressed_buffer)[i] = nan_float64; {
for (int j = 0; j < td->td_samplesperpixel; j++)
{
if (sp->mask_buffer[i + j * nb_pixels] == 0)
((float *)sp->uncompressed_buffer)[k] = nan_float32;
else
((float *)sp->uncompressed_buffer)[k] =
((float *)sp->uncompressed_buffer_multiband)
[i + j * nb_pixels];
++k;
}
}
}
else
{
const double nan_float64 = nan_float32;
for (i = 0; i < nb_pixels; i++)
{
for (int j = 0; j < td->td_samplesperpixel; j++)
{
if (sp->mask_buffer[i + j * nb_pixels] == 0)
((double *)sp->uncompressed_buffer)[k] =
nan_float64;
else
((double *)sp->uncompressed_buffer)[k] =
((double *)sp->uncompressed_buffer_multiband)
[i + j * nb_pixels];
++k;
}
}
} }
} }
#endif
} }
return 1; return 1;
@ -553,7 +746,7 @@ static int LERCPreDecode(TIFF *tif, uint16_t s)
static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
static const char module[] = "LERCDecode"; static const char module[] = "LERCDecode";
LERCState *sp = DecoderState(tif); LERCState *sp = LERCDecoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -561,6 +754,7 @@ static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (sp->uncompressed_buffer == 0) if (sp->uncompressed_buffer == 0)
{ {
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, "Uncompressed buffer not allocated"); TIFFErrorExtR(tif, module, "Uncompressed buffer not allocated");
return 0; return 0;
} }
@ -568,6 +762,7 @@ static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if ((uint64_t)sp->uncompressed_offset + (uint64_t)occ > if ((uint64_t)sp->uncompressed_offset + (uint64_t)occ >
sp->uncompressed_size) sp->uncompressed_size)
{ {
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, "Too many bytes read"); TIFFErrorExtR(tif, module, "Too many bytes read");
return 0; return 0;
} }
@ -580,7 +775,7 @@ static int LERCDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
static int LERCSetupEncode(TIFF *tif) static int LERCSetupEncode(TIFF *tif)
{ {
LERCState *sp = EncoderState(tif); LERCState *sp = LERCEncoderState(tif);
assert(sp != NULL); assert(sp != NULL);
if (sp->state & LSTATE_INIT_DECODE) if (sp->state & LSTATE_INIT_DECODE)
@ -599,7 +794,7 @@ static int LERCSetupEncode(TIFF *tif)
static int LERCPreEncode(TIFF *tif, uint16_t s) static int LERCPreEncode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "LERCPreEncode"; static const char module[] = "LERCPreEncode";
LERCState *sp = EncoderState(tif); LERCState *sp = LERCEncoderState(tif);
int lerc_data_type; int lerc_data_type;
(void)s; (void)s;
@ -611,7 +806,7 @@ static int LERCPreEncode(TIFF *tif, uint16_t s)
if (lerc_data_type < 0) if (lerc_data_type < 0)
return 0; return 0;
if (!SetupUncompressedBuffer(tif, sp, module)) if (!SetupBuffers(tif, sp, module))
return 0; return 0;
return 1; return 1;
@ -623,7 +818,7 @@ static int LERCPreEncode(TIFF *tif, uint16_t s)
static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) static int LERCEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
{ {
static const char module[] = "LERCEncode"; static const char module[] = "LERCEncode";
LERCState *sp = EncoderState(tif); LERCState *sp = LERCEncoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -649,8 +844,7 @@ static int LERCPostEncode(TIFF *tif)
{ {
lerc_status lerc_ret; lerc_status lerc_ret;
static const char module[] = "LERCPostEncode"; static const char module[] = "LERCPostEncode";
LERCState *sp = EncoderState(tif); LERCState *sp = LERCEncoderState(tif);
unsigned int numBytes = 0;
unsigned int numBytesWritten = 0; unsigned int numBytesWritten = 0;
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
int use_mask = 0; int use_mask = 0;
@ -662,6 +856,9 @@ static int LERCPostEncode(TIFF *tif)
return 0; return 0;
} }
int mask_count = 1;
const unsigned nb_pixels = sp->segment_width * sp->segment_height;
/* Extract alpha mask (if containing only 0 and 255 values, */ /* Extract alpha mask (if containing only 0 and 255 values, */
/* and compact array of regular bands */ /* and compact array of regular bands */
if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_extrasamples > 0 && if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_extrasamples > 0 &&
@ -673,7 +870,6 @@ static int LERCPostEncode(TIFF *tif)
const unsigned src_stride = const unsigned src_stride =
td->td_samplesperpixel * (td->td_bitspersample / 8); td->td_samplesperpixel * (td->td_bitspersample / 8);
unsigned i = 0; unsigned i = 0;
const unsigned nb_pixels = sp->segment_width * sp->segment_height;
use_mask = 1; use_mask = 1;
for (i = 0; i < nb_pixels; i++) for (i = 0; i < nb_pixels; i++)
@ -710,46 +906,78 @@ static int LERCPostEncode(TIFF *tif)
} }
} }
else if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP && else if (td->td_sampleformat == SAMPLEFORMAT_IEEEFP &&
(td->td_planarconfig == PLANARCONFIG_SEPARATE ||
dst_nbands == 1) &&
(td->td_bitspersample == 32 || td->td_bitspersample == 64)) (td->td_bitspersample == 32 || td->td_bitspersample == 64))
{ {
/* Check for NaN values */ /* Check for NaN values */
unsigned i; unsigned i;
const unsigned nb_pixels = sp->segment_width * sp->segment_height;
if (td->td_bitspersample == 32) if (td->td_bitspersample == 32)
{ {
for (i = 0; i < nb_pixels; i++) if (td->td_planarconfig == PLANARCONFIG_CONTIG && dst_nbands > 1)
{ {
const float val = ((float *)sp->uncompressed_buffer)[i]; unsigned k = 0;
if (val != val) for (i = 0; i < nb_pixels; i++)
{ {
use_mask = 1; int count_nan = 0;
break; for (int j = 0; j < td->td_samplesperpixel; ++j)
{
const float val = ((float *)sp->uncompressed_buffer)[k];
++k;
if (val != val)
{
++count_nan;
}
}
if (count_nan > 0)
{
use_mask = 1;
if (count_nan < td->td_samplesperpixel)
{
mask_count = td->td_samplesperpixel;
break;
}
}
}
}
else
{
for (i = 0; i < nb_pixels; i++)
{
const float val = ((float *)sp->uncompressed_buffer)[i];
if (val != val)
{
use_mask = 1;
break;
}
} }
} }
} }
else else
{ {
for (i = 0; i < nb_pixels; i++) if (td->td_planarconfig == PLANARCONFIG_CONTIG && dst_nbands > 1)
{
const double val = ((double *)sp->uncompressed_buffer)[i];
if (val != val)
{
use_mask = 1;
break;
}
}
}
if (use_mask)
{
if (td->td_bitspersample == 32)
{ {
unsigned k = 0;
for (i = 0; i < nb_pixels; i++) for (i = 0; i < nb_pixels; i++)
{ {
const float val = ((float *)sp->uncompressed_buffer)[i]; int count_nan = 0;
sp->mask_buffer[i] = (val == val) ? 255 : 0; for (int j = 0; j < td->td_samplesperpixel; ++j)
{
const double val =
((double *)sp->uncompressed_buffer)[k];
++k;
if (val != val)
{
++count_nan;
}
}
if (count_nan > 0)
{
use_mask = 1;
if (count_nan < td->td_samplesperpixel)
{
mask_count = td->td_samplesperpixel;
break;
}
}
} }
} }
else else
@ -757,62 +985,168 @@ static int LERCPostEncode(TIFF *tif)
for (i = 0; i < nb_pixels; i++) for (i = 0; i < nb_pixels; i++)
{ {
const double val = ((double *)sp->uncompressed_buffer)[i]; const double val = ((double *)sp->uncompressed_buffer)[i];
sp->mask_buffer[i] = (val == val) ? 255 : 0; if (val != val)
{
use_mask = 1;
break;
}
}
}
}
if (use_mask)
{
if (mask_count > 1)
{
#if LERC_AT_LEAST_VERSION(3, 0, 0)
unsigned int num_bytes_needed =
nb_pixels * dst_nbands * (td->td_bitspersample / 8);
if (sp->uncompressed_buffer_multiband_alloc < num_bytes_needed)
{
_TIFFfreeExt(tif, sp->uncompressed_buffer_multiband);
sp->uncompressed_buffer_multiband =
_TIFFmallocExt(tif, num_bytes_needed);
if (!sp->uncompressed_buffer_multiband)
{
sp->uncompressed_buffer_multiband_alloc = 0;
return 0;
}
sp->uncompressed_buffer_multiband_alloc = num_bytes_needed;
}
unsigned k = 0;
if (td->td_bitspersample == 32)
{
for (i = 0; i < nb_pixels; i++)
{
for (int j = 0; j < td->td_samplesperpixel; ++j)
{
const float val =
((float *)sp->uncompressed_buffer)[k];
((float *)sp->uncompressed_buffer_multiband)
[i + j * nb_pixels] = val;
++k;
sp->mask_buffer[i + j * nb_pixels] =
(val == val) ? 255 : 0;
}
}
}
else
{
for (i = 0; i < nb_pixels; i++)
{
for (int j = 0; j < td->td_samplesperpixel; ++j)
{
const double val =
((double *)sp->uncompressed_buffer)[k];
((double *)sp->uncompressed_buffer_multiband)
[i + j * nb_pixels] = val;
++k;
sp->mask_buffer[i + j * nb_pixels] =
(val == val) ? 255 : 0;
}
}
}
#else
TIFFErrorExtR(tif, module,
"lerc_encode() would need to create one mask per "
"sample, but this requires liblerc >= 3.0");
return 0;
#endif
}
else if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
dst_nbands > 1)
{
if (td->td_bitspersample == 32)
{
for (i = 0; i < nb_pixels; i++)
{
const float val =
((float *)sp->uncompressed_buffer)[i * dst_nbands];
sp->mask_buffer[i] = (val == val) ? 255 : 0;
}
}
else
{
for (i = 0; i < nb_pixels; i++)
{
const double val =
((double *)sp->uncompressed_buffer)[i * dst_nbands];
sp->mask_buffer[i] = (val == val) ? 255 : 0;
}
}
}
else
{
if (td->td_bitspersample == 32)
{
for (i = 0; i < nb_pixels; i++)
{
const float val = ((float *)sp->uncompressed_buffer)[i];
sp->mask_buffer[i] = (val == val) ? 255 : 0;
}
}
else
{
for (i = 0; i < nb_pixels; i++)
{
const double val =
((double *)sp->uncompressed_buffer)[i];
sp->mask_buffer[i] = (val == val) ? 255 : 0;
}
} }
} }
} }
} }
#if 0 unsigned int estimated_compressed_size = sp->uncompressed_alloc;
lerc_ret = lerc_computeCompressedSize( #if LERC_AT_LEAST_VERSION(3, 0, 0)
sp->uncompressed_buffer, if (mask_count > 1)
sp->lerc_version, {
GetLercDataType(tif), estimated_compressed_size += nb_pixels * mask_count / 8;
td->td_planarconfig == PLANARCONFIG_CONTIG ? }
dst_nbands : 1,
sp->segment_width,
sp->segment_height,
1,
use_mask ? sp->mask_buffer : NULL,
sp->maxzerror,
&numBytes);
if( lerc_ret != 0 )
{
TIFFErrorExtR(tif, module,
"lerc_computeCompressedSize() failed");
return 0;
}
#else
numBytes = sp->uncompressed_alloc;
#endif #endif
if (sp->compressed_size < numBytes) if (sp->compressed_size < estimated_compressed_size)
{ {
_TIFFfreeExt(tif, sp->compressed_buffer); _TIFFfreeExt(tif, sp->compressed_buffer);
sp->compressed_buffer = _TIFFmallocExt(tif, numBytes); sp->compressed_buffer = _TIFFmallocExt(tif, estimated_compressed_size);
if (!sp->compressed_buffer) if (!sp->compressed_buffer)
{ {
sp->compressed_size = 0; sp->compressed_size = 0;
return 0; return 0;
} }
sp->compressed_size = numBytes; sp->compressed_size = estimated_compressed_size;
} }
lerc_ret = lerc_encodeForVersion(
sp->uncompressed_buffer, sp->lerc_version, GetLercDataType(tif),
td->td_planarconfig == PLANARCONFIG_CONTIG ? dst_nbands : 1,
sp->segment_width, sp->segment_height, 1,
#if LERC_AT_LEAST_VERSION(3, 0, 0) #if LERC_AT_LEAST_VERSION(3, 0, 0)
use_mask ? 1 : 0, if (mask_count > 1)
{
lerc_ret = lerc_encodeForVersion(
sp->uncompressed_buffer_multiband, sp->lerc_version,
GetLercDataType(tif), 1, sp->segment_width, sp->segment_height,
dst_nbands, dst_nbands, sp->mask_buffer, sp->maxzerror,
sp->compressed_buffer, sp->compressed_size, &numBytesWritten);
}
else
#endif #endif
use_mask ? sp->mask_buffer : NULL, sp->maxzerror, sp->compressed_buffer, {
sp->compressed_size, &numBytesWritten); lerc_ret = lerc_encodeForVersion(
sp->uncompressed_buffer, sp->lerc_version, GetLercDataType(tif),
td->td_planarconfig == PLANARCONFIG_CONTIG ? dst_nbands : 1,
sp->segment_width, sp->segment_height, 1,
#if LERC_AT_LEAST_VERSION(3, 0, 0)
use_mask ? 1 : 0,
#endif
use_mask ? sp->mask_buffer : NULL, sp->maxzerror,
sp->compressed_buffer, sp->compressed_size, &numBytesWritten);
}
if (lerc_ret != 0) if (lerc_ret != 0)
{ {
TIFFErrorExtR(tif, module, "lerc_encode() failed"); TIFFErrorExtR(tif, module, "lerc_encode() failed");
return 0; return 0;
} }
assert(numBytesWritten < numBytes); assert(numBytesWritten < estimated_compressed_size);
if (sp->additional_compression == LERC_ADD_COMPRESSION_DEFLATE) if (sp->additional_compression == LERC_ADD_COMPRESSION_DEFLATE)
{ {
@ -950,7 +1284,7 @@ static int LERCPostEncode(TIFF *tif)
static void LERCCleanup(TIFF *tif) static void LERCCleanup(TIFF *tif)
{ {
LERCState *sp = LState(tif); LERCState *sp = GetLERCState(tif);
assert(sp != 0); assert(sp != 0);
@ -958,6 +1292,7 @@ static void LERCCleanup(TIFF *tif)
tif->tif_tagmethods.vsetfield = sp->vsetparent; tif->tif_tagmethods.vsetfield = sp->vsetparent;
_TIFFfreeExt(tif, sp->uncompressed_buffer); _TIFFfreeExt(tif, sp->uncompressed_buffer);
_TIFFfreeExt(tif, sp->uncompressed_buffer_multiband);
_TIFFfreeExt(tif, sp->compressed_buffer); _TIFFfreeExt(tif, sp->compressed_buffer);
_TIFFfreeExt(tif, sp->mask_buffer); _TIFFfreeExt(tif, sp->mask_buffer);
@ -995,7 +1330,7 @@ static const TIFFField LERCFields[] = {
static int LERCVSetFieldBase(TIFF *tif, uint32_t tag, ...) static int LERCVSetFieldBase(TIFF *tif, uint32_t tag, ...)
{ {
LERCState *sp = LState(tif); LERCState *sp = GetLERCState(tif);
int ret; int ret;
va_list ap; va_list ap;
va_start(ap, tag); va_start(ap, tag);
@ -1007,7 +1342,7 @@ static int LERCVSetFieldBase(TIFF *tif, uint32_t tag, ...)
static int LERCVSetField(TIFF *tif, uint32_t tag, va_list ap) static int LERCVSetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
static const char module[] = "LERCVSetField"; static const char module[] = "LERCVSetField";
LERCState *sp = LState(tif); LERCState *sp = GetLERCState(tif);
switch (tag) switch (tag)
{ {
@ -1115,7 +1450,7 @@ static int LERCVSetField(TIFF *tif, uint32_t tag, va_list ap)
static int LERCVGetField(TIFF *tif, uint32_t tag, va_list ap) static int LERCVGetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
LERCState *sp = LState(tif); LERCState *sp = GetLERCState(tif);
switch (tag) switch (tag)
{ {
@ -1163,7 +1498,7 @@ int TIFFInitLERC(TIFF *tif, int scheme)
tif->tif_data = (uint8_t *)_TIFFcallocExt(tif, 1, sizeof(LERCState)); tif->tif_data = (uint8_t *)_TIFFcallocExt(tif, 1, sizeof(LERCState));
if (tif->tif_data == NULL) if (tif->tif_data == NULL)
goto bad; goto bad;
sp = LState(tif); sp = GetLERCState(tif);
/* /*
* Override parent get/set field methods. * Override parent get/set field methods.

View File

@ -951,7 +951,8 @@ static
int int
uv_encode(double u, double v, int em) /* encode (u',v') coordinates */ uv_encode(double u, double v, int em) /* encode (u',v') coordinates */
{ {
register int vi, ui; unsigned int vi;
int ui;
/* check for NaN */ /* check for NaN */
if (u != u || v != v) if (u != u || v != v)
@ -980,8 +981,9 @@ static
int int
uv_decode(double *up, double *vp, int c) /* decode (u',v') index */ uv_decode(double *up, double *vp, int c) /* decode (u',v') index */
{ {
int upper, lower; unsigned int upper, lower;
register int ui, vi; int ui;
unsigned int vi;
if (c < 0 || c >= UV_NDIVS) if (c < 0 || c >= UV_NDIVS)
return (-1); return (-1);

View File

@ -44,6 +44,8 @@
typedef struct typedef struct
{ {
TIFFPredictorState predict; TIFFPredictorState predict;
int read_error; /* whether a read error has occurred, and which should cause
further reads in the same strip/tile to be aborted */
lzma_stream stream; lzma_stream stream;
lzma_filter filters[LZMA_FILTERS_MAX + 1]; lzma_filter filters[LZMA_FILTERS_MAX + 1];
lzma_options_delta opt_delta; /* delta filter options */ lzma_options_delta opt_delta; /* delta filter options */
@ -58,9 +60,9 @@ typedef struct
TIFFVSetMethod vsetparent; /* super-class method */ TIFFVSetMethod vsetparent; /* super-class method */
} LZMAState; } LZMAState;
#define LState(tif) ((LZMAState *)(tif)->tif_data) #define GetLZMAState(tif) ((LZMAState *)(tif)->tif_data)
#define DecoderState(tif) LState(tif) #define LZMADecoderState(tif) GetLZMAState(tif)
#define EncoderState(tif) LState(tif) #define LZMAEncoderState(tif) GetLZMAState(tif)
static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
@ -106,7 +108,7 @@ static int LZMAFixupTags(TIFF *tif)
static int LZMASetupDecode(TIFF *tif) static int LZMASetupDecode(TIFF *tif)
{ {
LZMAState *sp = DecoderState(tif); LZMAState *sp = LZMADecoderState(tif);
assert(sp != NULL); assert(sp != NULL);
@ -127,7 +129,7 @@ static int LZMASetupDecode(TIFF *tif)
static int LZMAPreDecode(TIFF *tif, uint16_t s) static int LZMAPreDecode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "LZMAPreDecode"; static const char module[] = "LZMAPreDecode";
LZMAState *sp = DecoderState(tif); LZMAState *sp = LZMADecoderState(tif);
lzma_ret ret; lzma_ret ret;
(void)s; (void)s;
@ -156,18 +158,31 @@ static int LZMAPreDecode(TIFF *tif, uint16_t s)
LZMAStrerror(ret)); LZMAStrerror(ret));
return 0; return 0;
} }
sp->read_error = 0;
return 1; return 1;
} }
static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
static const char module[] = "LZMADecode"; static const char module[] = "LZMADecode";
LZMAState *sp = DecoderState(tif); LZMAState *sp = LZMADecoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
assert(sp->state == LSTATE_INIT_DECODE); assert(sp->state == LSTATE_INIT_DECODE);
if (sp->read_error)
{
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module,
"LZMADecode: Scanline %" PRIu32 " cannot be read due to "
"previous error",
tif->tif_row);
return 0;
}
sp->stream.next_in = tif->tif_rawcp; sp->stream.next_in = tif->tif_rawcp;
sp->stream.avail_in = (size_t)tif->tif_rawcc; sp->stream.avail_in = (size_t)tif->tif_rawcc;
@ -175,6 +190,9 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
sp->stream.avail_out = (size_t)occ; sp->stream.avail_out = (size_t)occ;
if ((tmsize_t)sp->stream.avail_out != occ) if ((tmsize_t)sp->stream.avail_out != occ)
{ {
// read_error not set here as this is a usage issue that can be
// recovered in a following call.
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Liblzma cannot deal with buffers this size"); "Liblzma cannot deal with buffers this size");
return 0; return 0;
@ -198,6 +216,8 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0); lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0);
if (r != LZMA_OK) if (r != LZMA_OK)
{ {
sp->read_error = 1;
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Error initializing the stream decoder, %s", "Error initializing the stream decoder, %s",
LZMAStrerror(r)); LZMAStrerror(r));
@ -217,6 +237,8 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
} while (sp->stream.avail_out > 0); } while (sp->stream.avail_out > 0);
if (sp->stream.avail_out != 0) if (sp->stream.avail_out != 0)
{ {
sp->read_error = 1;
memset(sp->stream.next_out, 0, sp->stream.avail_out);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Not enough data at scanline %" PRIu32 "Not enough data at scanline %" PRIu32
" (short %" TIFF_SIZE_FORMAT " bytes)", " (short %" TIFF_SIZE_FORMAT " bytes)",
@ -232,7 +254,7 @@ static int LZMADecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
static int LZMASetupEncode(TIFF *tif) static int LZMASetupEncode(TIFF *tif)
{ {
LZMAState *sp = EncoderState(tif); LZMAState *sp = LZMAEncoderState(tif);
assert(sp != NULL); assert(sp != NULL);
if (sp->state & LSTATE_INIT_DECODE) if (sp->state & LSTATE_INIT_DECODE)
@ -251,7 +273,7 @@ static int LZMASetupEncode(TIFF *tif)
static int LZMAPreEncode(TIFF *tif, uint16_t s) static int LZMAPreEncode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "LZMAPreEncode"; static const char module[] = "LZMAPreEncode";
LZMAState *sp = EncoderState(tif); LZMAState *sp = LZMAEncoderState(tif);
lzma_ret ret; lzma_ret ret;
(void)s; (void)s;
@ -283,7 +305,7 @@ static int LZMAPreEncode(TIFF *tif, uint16_t s)
static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
{ {
static const char module[] = "LZMAEncode"; static const char module[] = "LZMAEncode";
LZMAState *sp = EncoderState(tif); LZMAState *sp = LZMAEncoderState(tif);
assert(sp != NULL); assert(sp != NULL);
assert(sp->state == LSTATE_INIT_ENCODE); assert(sp->state == LSTATE_INIT_ENCODE);
@ -329,7 +351,7 @@ static int LZMAEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
static int LZMAPostEncode(TIFF *tif) static int LZMAPostEncode(TIFF *tif)
{ {
static const char module[] = "LZMAPostEncode"; static const char module[] = "LZMAPostEncode";
LZMAState *sp = EncoderState(tif); LZMAState *sp = LZMAEncoderState(tif);
lzma_ret ret; lzma_ret ret;
sp->stream.avail_in = 0; sp->stream.avail_in = 0;
@ -365,7 +387,7 @@ static int LZMAPostEncode(TIFF *tif)
static void LZMACleanup(TIFF *tif) static void LZMACleanup(TIFF *tif)
{ {
LZMAState *sp = LState(tif); LZMAState *sp = GetLZMAState(tif);
assert(sp != 0); assert(sp != 0);
@ -388,7 +410,7 @@ static void LZMACleanup(TIFF *tif)
static int LZMAVSetField(TIFF *tif, uint32_t tag, va_list ap) static int LZMAVSetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
static const char module[] = "LZMAVSetField"; static const char module[] = "LZMAVSetField";
LZMAState *sp = LState(tif); LZMAState *sp = GetLZMAState(tif);
switch (tag) switch (tag)
{ {
@ -414,7 +436,7 @@ static int LZMAVSetField(TIFF *tif, uint32_t tag, va_list ap)
static int LZMAVGetField(TIFF *tif, uint32_t tag, va_list ap) static int LZMAVGetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
LZMAState *sp = LState(tif); LZMAState *sp = GetLZMAState(tif);
switch (tag) switch (tag)
{ {
@ -457,7 +479,7 @@ int TIFFInitLZMA(TIFF *tif, int scheme)
tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZMAState)); tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZMAState));
if (tif->tif_data == NULL) if (tif->tif_data == NULL)
goto bad; goto bad;
sp = LState(tif); sp = GetLZMAState(tif);
memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream)); memcpy(&sp->stream, &tmp_stream, sizeof(lzma_stream));
/* /*

View File

@ -161,8 +161,8 @@ typedef struct
} LZWCodecState; } LZWCodecState;
#define LZWState(tif) ((LZWBaseState *)(tif)->tif_data) #define LZWState(tif) ((LZWBaseState *)(tif)->tif_data)
#define DecoderState(tif) ((LZWCodecState *)LZWState(tif)) #define LZWDecoderState(tif) ((LZWCodecState *)LZWState(tif))
#define EncoderState(tif) ((LZWCodecState *)LZWState(tif)) #define LZWEncoderState(tif) ((LZWCodecState *)LZWState(tif))
static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s); static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s);
#ifdef LZW_COMPAT #ifdef LZW_COMPAT
@ -183,7 +183,7 @@ static int LZWFixupTags(TIFF *tif)
static int LZWSetupDecode(TIFF *tif) static int LZWSetupDecode(TIFF *tif)
{ {
static const char module[] = "LZWSetupDecode"; static const char module[] = "LZWSetupDecode";
LZWCodecState *sp = DecoderState(tif); LZWCodecState *sp = LZWDecoderState(tif);
int code; int code;
if (sp == NULL) if (sp == NULL)
@ -199,7 +199,7 @@ static int LZWSetupDecode(TIFF *tif)
return (0); return (0);
} }
sp = DecoderState(tif); sp = LZWDecoderState(tif);
sp->dec_codetab = NULL; sp->dec_codetab = NULL;
sp->dec_decode = NULL; sp->dec_decode = NULL;
@ -245,7 +245,7 @@ static int LZWSetupDecode(TIFF *tif)
static int LZWPreDecode(TIFF *tif, uint16_t s) static int LZWPreDecode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "LZWPreDecode"; static const char module[] = "LZWPreDecode";
LZWCodecState *sp = DecoderState(tif); LZWCodecState *sp = LZWDecoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -329,10 +329,7 @@ static int LZWPreDecode(TIFF *tif, uint16_t s)
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
#define GetNextData(nextdata, bp) memcpy(&nextdata, bp, sizeof(nextdata)) #define GetNextData(nextdata, bp) memcpy(&nextdata, bp, sizeof(nextdata))
#elif SIZEOF_WORDTYPE == 8 #elif SIZEOF_WORDTYPE == 8
#if defined(__GNUC__) && defined(__x86_64__) #if defined(_M_X64)
#define GetNextData(nextdata, bp) \
nextdata = __builtin_bswap64(*(uint64_t *)(bp))
#elif defined(_M_X64)
#define GetNextData(nextdata, bp) nextdata = _byteswap_uint64(*(uint64_t *)(bp)) #define GetNextData(nextdata, bp) nextdata = _byteswap_uint64(*(uint64_t *)(bp))
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define GetNextData(nextdata, bp) \ #define GetNextData(nextdata, bp) \
@ -346,10 +343,7 @@ static int LZWPreDecode(TIFF *tif, uint16_t s)
(((uint64_t)bp[6]) << 8) | (((uint64_t)bp[7])) (((uint64_t)bp[6]) << 8) | (((uint64_t)bp[7]))
#endif #endif
#elif SIZEOF_WORDTYPE == 4 #elif SIZEOF_WORDTYPE == 4
#if defined(__GNUC__) && defined(__i386__) #if defined(_M_X86)
#define GetNextData(nextdata, bp) \
nextdata = __builtin_bswap32(*(uint32_t *)(bp))
#elif defined(_M_X86)
#define GetNextData(nextdata, bp) \ #define GetNextData(nextdata, bp) \
nextdata = _byteswap_ulong(*(unsigned long *)(bp)) nextdata = _byteswap_ulong(*(unsigned long *)(bp))
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -409,7 +403,7 @@ static int LZWPreDecode(TIFF *tif, uint16_t s)
static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s) static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s)
{ {
static const char module[] = "LZWDecode"; static const char module[] = "LZWDecode";
LZWCodecState *sp = DecoderState(tif); LZWCodecState *sp = LZWDecoderState(tif);
uint8_t *op = (uint8_t *)op0; uint8_t *op = (uint8_t *)op0;
tmsize_t occ = occ0; tmsize_t occ = occ0;
uint8_t *bp; uint8_t *bp;
@ -423,6 +417,7 @@ static int LZWDecode(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s)
if (sp->read_error) if (sp->read_error)
{ {
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"LZWDecode: Scanline %" PRIu32 " cannot be read due to " "LZWDecode: Scanline %" PRIu32 " cannot be read due to "
"previous error", "previous error",
@ -737,6 +732,7 @@ after_loop:
if (occ > 0) if (occ > 0)
{ {
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Not enough data at scanline %" PRIu32 " (short %" PRIu64 "Not enough data at scanline %" PRIu32 " (short %" PRIu64
" bytes)", " bytes)",
@ -746,12 +742,14 @@ after_loop:
return (1); return (1);
no_eoi: no_eoi:
memset(op, 0, (size_t)occ);
sp->read_error = 1; sp->read_error = 1;
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"LZWDecode: Strip %" PRIu32 " not terminated with EOI code", "LZWDecode: Strip %" PRIu32 " not terminated with EOI code",
tif->tif_curstrip); tif->tif_curstrip);
return 0; return 0;
error_code: error_code:
memset(op, 0, (size_t)occ);
sp->read_error = 1; sp->read_error = 1;
TIFFErrorExtR(tif, tif->tif_name, "Using code not yet in table"); TIFFErrorExtR(tif, tif->tif_name, "Using code not yet in table");
return 0; return 0;
@ -800,7 +798,7 @@ error_code:
static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s) static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s)
{ {
static const char module[] = "LZWDecodeCompat"; static const char module[] = "LZWDecodeCompat";
LZWCodecState *sp = DecoderState(tif); LZWCodecState *sp = LZWDecoderState(tif);
uint8_t *op = (uint8_t *)op0; uint8_t *op = (uint8_t *)op0;
tmsize_t occ = occ0; tmsize_t occ = occ0;
uint8_t *tp; uint8_t *tp;
@ -1026,7 +1024,7 @@ static int LZWDecodeCompat(TIFF *tif, uint8_t *op0, tmsize_t occ0, uint16_t s)
static int LZWSetupEncode(TIFF *tif) static int LZWSetupEncode(TIFF *tif)
{ {
static const char module[] = "LZWSetupEncode"; static const char module[] = "LZWSetupEncode";
LZWCodecState *sp = EncoderState(tif); LZWCodecState *sp = LZWEncoderState(tif);
assert(sp != NULL); assert(sp != NULL);
sp->enc_hashtab = (hash_t *)_TIFFmallocExt(tif, HSIZE * sizeof(hash_t)); sp->enc_hashtab = (hash_t *)_TIFFmallocExt(tif, HSIZE * sizeof(hash_t));
@ -1043,7 +1041,7 @@ static int LZWSetupEncode(TIFF *tif)
*/ */
static int LZWPreEncode(TIFF *tif, uint16_t s) static int LZWPreEncode(TIFF *tif, uint16_t s)
{ {
LZWCodecState *sp = EncoderState(tif); LZWCodecState *sp = LZWEncoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -1114,7 +1112,7 @@ static int LZWPreEncode(TIFF *tif, uint16_t s)
*/ */
static int LZWEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) static int LZWEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
{ {
register LZWCodecState *sp = EncoderState(tif); register LZWCodecState *sp = LZWEncoderState(tif);
register long fcode; register long fcode;
register hash_t *hp; register hash_t *hp;
register int h, c; register int h, c;
@ -1299,7 +1297,7 @@ static int LZWEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
*/ */
static int LZWPostEncode(TIFF *tif) static int LZWPostEncode(TIFF *tif)
{ {
register LZWCodecState *sp = EncoderState(tif); register LZWCodecState *sp = LZWEncoderState(tif);
uint8_t *op = tif->tif_rawcp; uint8_t *op = tif->tif_rawcp;
long nextbits = sp->lzw_nextbits; long nextbits = sp->lzw_nextbits;
WordType nextdata = sp->lzw_nextdata; WordType nextdata = sp->lzw_nextdata;
@ -1381,11 +1379,11 @@ static void LZWCleanup(TIFF *tif)
assert(tif->tif_data != 0); assert(tif->tif_data != 0);
if (DecoderState(tif)->dec_codetab) if (LZWDecoderState(tif)->dec_codetab)
_TIFFfreeExt(tif, DecoderState(tif)->dec_codetab); _TIFFfreeExt(tif, LZWDecoderState(tif)->dec_codetab);
if (EncoderState(tif)->enc_hashtab) if (LZWEncoderState(tif)->enc_hashtab)
_TIFFfreeExt(tif, EncoderState(tif)->enc_hashtab); _TIFFfreeExt(tif, LZWEncoderState(tif)->enc_hashtab);
_TIFFfreeExt(tif, tif->tif_data); _TIFFfreeExt(tif, tif->tif_data);
tif->tif_data = NULL; tif->tif_data = NULL;
@ -1404,9 +1402,9 @@ int TIFFInitLZW(TIFF *tif, int scheme)
tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZWCodecState)); tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(LZWCodecState));
if (tif->tif_data == NULL) if (tif->tif_data == NULL)
goto bad; goto bad;
DecoderState(tif)->dec_codetab = NULL; LZWDecoderState(tif)->dec_codetab = NULL;
DecoderState(tif)->dec_decode = NULL; LZWDecoderState(tif)->dec_decode = NULL;
EncoderState(tif)->enc_hashtab = NULL; LZWEncoderState(tif)->enc_hashtab = NULL;
LZWState(tif)->rw_mode = tif->tif_mode; LZWState(tif)->rw_mode = tif->tif_mode;
/* /*

View File

@ -207,37 +207,21 @@ static const TIFFField ojpegFields[] = {
#include <setjmp.h> #include <setjmp.h>
#endif #endif
/* We undefine FAR to avoid conflict with JPEG definition */
#ifdef FAR
#undef FAR
#endif
/*
Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
not defined. Unfortunately, the MinGW and Borland compilers include
a typedef for INT32, which causes a conflict. MSVC does not include
a conflicting typedef given the headers which are included.
*/
#if defined(__BORLANDC__) || defined(__MINGW32__)
#define XMD_H 1
#endif
/* Define "boolean" as unsigned char, not int, per Windows custom. */
#if defined(__WIN32__) && !defined(__MINGW32__)
#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
typedef unsigned char boolean;
#endif
#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
#endif
#include "jerror.h" #include "jerror.h"
#include "jpeglib.h" #include "jpeglib.h"
#ifndef TIFF_jpeg_source_mgr_defined
#define TIFF_jpeg_source_mgr_defined
typedef struct jpeg_source_mgr jpeg_source_mgr;
#endif
#ifndef TIFF_jpeg_error_mgr_defined
#define TIFF_jpeg_error_mgr_defined
typedef struct jpeg_error_mgr jpeg_error_mgr; typedef struct jpeg_error_mgr jpeg_error_mgr;
#endif
typedef struct jpeg_common_struct jpeg_common_struct; typedef struct jpeg_common_struct jpeg_common_struct;
typedef struct jpeg_decompress_struct jpeg_decompress_struct; typedef struct jpeg_decompress_struct jpeg_decompress_struct;
typedef struct jpeg_source_mgr jpeg_source_mgr;
typedef enum typedef enum
{ {
@ -771,6 +755,9 @@ static int OJPEGPreDecode(TIFF *tif, uint16_t s)
if (OJPEGWriteHeaderInfo(tif) == 0) if (OJPEGWriteHeaderInfo(tif) == 0)
return (0); return (0);
} }
sp->subsampling_convert_state = 0;
while (sp->write_curstrile < m) while (sp->write_curstrile < m)
{ {
if (sp->libjpeg_jpeg_query_style == 0) if (sp->libjpeg_jpeg_query_style == 0)
@ -856,12 +843,14 @@ static int OJPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
(void)s; (void)s;
if (!sp->decoder_ok) if (!sp->decoder_ok)
{ {
memset(buf, 0, (size_t)cc);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Cannot decode: decoder not correctly initialized"); "Cannot decode: decoder not correctly initialized");
return 0; return 0;
} }
if (sp->libjpeg_session_active == 0) if (sp->libjpeg_session_active == 0)
{ {
memset(buf, 0, (size_t)cc);
/* This should normally not happen, except that it does when */ /* This should normally not happen, except that it does when */
/* using TIFFReadScanline() which calls OJPEGPostDecode() for */ /* using TIFFReadScanline() which calls OJPEGPostDecode() for */
/* each scanline, which assumes that a whole strile was read */ /* each scanline, which assumes that a whole strile was read */
@ -875,17 +864,24 @@ static int OJPEGDecode(TIFF *tif, uint8_t *buf, tmsize_t cc, uint16_t s)
} }
if (sp->error_in_raw_data_decoding) if (sp->error_in_raw_data_decoding)
{ {
memset(buf, 0, (size_t)cc);
return 0; return 0;
} }
if (sp->libjpeg_jpeg_query_style == 0) if (sp->libjpeg_jpeg_query_style == 0)
{ {
if (OJPEGDecodeRaw(tif, buf, cc) == 0) if (OJPEGDecodeRaw(tif, buf, cc) == 0)
{
memset(buf, 0, (size_t)cc);
return (0); return (0);
}
} }
else else
{ {
if (OJPEGDecodeScanlines(tif, buf, cc) == 0) if (OJPEGDecodeScanlines(tif, buf, cc) == 0)
{
memset(buf, 0, (size_t)cc);
return (0); return (0);
}
} }
return (1); return (1);
} }

View File

@ -25,7 +25,13 @@
/* /*
* TIFF Library. * TIFF Library.
*/ */
#ifdef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
#undef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
#endif
#include "tiffiop.h" #include "tiffiop.h"
#include <assert.h>
#include <limits.h> #include <limits.h>
/* /*
@ -81,8 +87,9 @@ TIFFOpenOptions *TIFFOpenOptionsAlloc()
void TIFFOpenOptionsFree(TIFFOpenOptions *opts) { _TIFFfree(opts); } void TIFFOpenOptionsFree(TIFFOpenOptions *opts) { _TIFFfree(opts); }
/** Define a limit in bytes for a single memory allocation done by libtiff. /** Define a limit in bytes for a single memory allocation done by libtiff.
* If max_single_mem_alloc is set to 0, no other limit that the underlying * If max_single_mem_alloc is set to 0, which is the default, no other limit
* _TIFFmalloc() will be applied, which is the default. * that the underlying _TIFFmalloc() or
* TIFFOpenOptionsSetMaxCumulatedMemAlloc() will be applied.
*/ */
void TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, void TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts,
tmsize_t max_single_mem_alloc) tmsize_t max_single_mem_alloc)
@ -90,6 +97,18 @@ void TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts,
opts->max_single_mem_alloc = max_single_mem_alloc; opts->max_single_mem_alloc = max_single_mem_alloc;
} }
/** Define a limit in bytes for the cumulated memory allocations done by libtiff
* on a given TIFF handle.
* If max_cumulated_mem_alloc is set to 0, which is the default, no other limit
* that the underlying _TIFFmalloc() or
* TIFFOpenOptionsSetMaxSingleMemAlloc() will be applied.
*/
void TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts,
tmsize_t max_cumulated_mem_alloc)
{
opts->max_cumulated_mem_alloc = max_cumulated_mem_alloc;
}
void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, void TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts,
TIFFErrorHandlerExtR handler, TIFFErrorHandlerExtR handler,
void *errorhandler_user_data) void *errorhandler_user_data)
@ -117,6 +136,30 @@ static void _TIFFEmitErrorAboveMaxSingleMemAlloc(TIFF *tif,
(uint64_t)s, (uint64_t)tif->tif_max_single_mem_alloc); (uint64_t)s, (uint64_t)tif->tif_max_single_mem_alloc);
} }
static void _TIFFEmitErrorAboveMaxCumulatedMemAlloc(TIFF *tif,
const char *pszFunction,
tmsize_t s)
{
TIFFErrorExtR(tif, pszFunction,
"Cumulated memory allocation of %" PRIu64 " + %" PRIu64
" bytes is beyond the %" PRIu64
" cumulated byte limit defined in open options",
(uint64_t)tif->tif_cur_cumulated_mem_alloc, (uint64_t)s,
(uint64_t)tif->tif_max_cumulated_mem_alloc);
}
/* When allocating memory, we write at the beginning of the buffer it size.
* This allows us to keep track of the total memory allocated when we
* malloc/calloc/realloc and free. In theory we need just SIZEOF_SIZE_T bytes
* for that, but on x86_64, allocations of more than 16 bytes are aligned on
* 16 bytes. Hence using 2 * SIZEOF_SIZE_T.
* It is critical that _TIFFmallocExt/_TIFFcallocExt/_TIFFreallocExt are
* paired with _TIFFfreeExt.
* CMakeLists.txt defines TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS, which in
* turn disables the definition of the non Ext version in tiffio.h
*/
#define LEADING_AREA_TO_STORE_ALLOC_SIZE (2 * SIZEOF_SIZE_T)
/** malloc() version that takes into account memory-specific open options */ /** malloc() version that takes into account memory-specific open options */
void *_TIFFmallocExt(TIFF *tif, tmsize_t s) void *_TIFFmallocExt(TIFF *tif, tmsize_t s)
{ {
@ -126,16 +169,32 @@ void *_TIFFmallocExt(TIFF *tif, tmsize_t s)
_TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFmallocExt", s); _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFmallocExt", s);
return NULL; return NULL;
} }
if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
{
if (s > tif->tif_max_cumulated_mem_alloc -
tif->tif_cur_cumulated_mem_alloc ||
s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE)
{
_TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFmallocExt", s);
return NULL;
}
void *ptr = _TIFFmalloc(LEADING_AREA_TO_STORE_ALLOC_SIZE + s);
if (!ptr)
return NULL;
tif->tif_cur_cumulated_mem_alloc += s;
memcpy(ptr, &s, sizeof(s));
return (char *)ptr + LEADING_AREA_TO_STORE_ALLOC_SIZE;
}
return _TIFFmalloc(s); return _TIFFmalloc(s);
} }
/** calloc() version that takes into account memory-specific open options */ /** calloc() version that takes into account memory-specific open options */
void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz) void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz)
{ {
if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz)
return NULL;
if (tif != NULL && tif->tif_max_single_mem_alloc > 0) if (tif != NULL && tif->tif_max_single_mem_alloc > 0)
{ {
if (nmemb <= 0 || siz <= 0 || nmemb > TIFF_TMSIZE_T_MAX / siz)
return NULL;
if (nmemb * siz > tif->tif_max_single_mem_alloc) if (nmemb * siz > tif->tif_max_single_mem_alloc)
{ {
_TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFcallocExt", _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFcallocExt",
@ -143,6 +202,23 @@ void *_TIFFcallocExt(TIFF *tif, tmsize_t nmemb, tmsize_t siz)
return NULL; return NULL;
} }
} }
if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
{
const tmsize_t s = nmemb * siz;
if (s > tif->tif_max_cumulated_mem_alloc -
tif->tif_cur_cumulated_mem_alloc ||
s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE)
{
_TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFcallocExt", s);
return NULL;
}
void *ptr = _TIFFcalloc(LEADING_AREA_TO_STORE_ALLOC_SIZE + s, 1);
if (!ptr)
return NULL;
tif->tif_cur_cumulated_mem_alloc += s;
memcpy(ptr, &s, sizeof(s));
return (char *)ptr + LEADING_AREA_TO_STORE_ALLOC_SIZE;
}
return _TIFFcalloc(nmemb, siz); return _TIFFcalloc(nmemb, siz);
} }
@ -155,13 +231,49 @@ void *_TIFFreallocExt(TIFF *tif, void *p, tmsize_t s)
_TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFreallocExt", s); _TIFFEmitErrorAboveMaxSingleMemAlloc(tif, "_TIFFreallocExt", s);
return NULL; return NULL;
} }
if (tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
{
void *oldPtr = p;
tmsize_t oldSize = 0;
if (p)
{
oldPtr = (char *)p - LEADING_AREA_TO_STORE_ALLOC_SIZE;
memcpy(&oldSize, oldPtr, sizeof(oldSize));
assert(oldSize <= tif->tif_cur_cumulated_mem_alloc);
}
if (s > oldSize &&
(s > tif->tif_max_cumulated_mem_alloc -
(tif->tif_cur_cumulated_mem_alloc - oldSize) ||
s > TIFF_TMSIZE_T_MAX - LEADING_AREA_TO_STORE_ALLOC_SIZE))
{
_TIFFEmitErrorAboveMaxCumulatedMemAlloc(tif, "_TIFFreallocExt",
s - oldSize);
return NULL;
}
void *newPtr =
_TIFFrealloc(oldPtr, LEADING_AREA_TO_STORE_ALLOC_SIZE + s);
if (newPtr == NULL)
return NULL;
tif->tif_cur_cumulated_mem_alloc -= oldSize;
tif->tif_cur_cumulated_mem_alloc += s;
memcpy(newPtr, &s, sizeof(s));
return (char *)newPtr + LEADING_AREA_TO_STORE_ALLOC_SIZE;
}
return _TIFFrealloc(p, s); return _TIFFrealloc(p, s);
} }
/** free() version that takes into account memory-specific open options */ /** free() version that takes into account memory-specific open options */
void _TIFFfreeExt(TIFF *tif, void *p) void _TIFFfreeExt(TIFF *tif, void *p)
{ {
(void)tif; if (p != NULL && tif != NULL && tif->tif_max_cumulated_mem_alloc > 0)
{
void *oldPtr = (char *)p - LEADING_AREA_TO_STORE_ALLOC_SIZE;
tmsize_t oldSize;
memcpy(&oldSize, oldPtr, sizeof(oldSize));
assert(oldSize <= tif->tif_cur_cumulated_mem_alloc);
tif->tif_cur_cumulated_mem_alloc -= oldSize;
p = oldPtr;
}
_TIFFfree(p); _TIFFfree(p);
} }
@ -231,6 +343,17 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
(uint64_t)opts->max_single_mem_alloc); (uint64_t)opts->max_single_mem_alloc);
goto bad2; goto bad2;
} }
if (opts && opts->max_cumulated_mem_alloc > 0 &&
size_to_alloc > opts->max_cumulated_mem_alloc)
{
_TIFFErrorEarly(opts, clientdata, module,
"%s: Memory allocation of %" PRIu64
" bytes is beyond the %" PRIu64
" cumulated byte limit defined in open options",
name, (uint64_t)size_to_alloc,
(uint64_t)opts->max_cumulated_mem_alloc);
goto bad2;
}
tif = (TIFF *)_TIFFmallocExt(NULL, size_to_alloc); tif = (TIFF *)_TIFFmallocExt(NULL, size_to_alloc);
if (tif == NULL) if (tif == NULL)
{ {
@ -243,6 +366,7 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
strcpy(tif->tif_name, name); strcpy(tif->tif_name, name);
tif->tif_mode = m & ~(O_CREAT | O_TRUNC); tif->tif_mode = m & ~(O_CREAT | O_TRUNC);
tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; /* non-existent directory */ tif->tif_curdir = TIFF_NON_EXISTENT_DIR_NUMBER; /* non-existent directory */
tif->tif_curdircount = TIFF_NON_EXISTENT_DIR_NUMBER;
tif->tif_curoff = 0; tif->tif_curoff = 0;
tif->tif_curstrip = (uint32_t)-1; /* invalid strip */ tif->tif_curstrip = (uint32_t)-1; /* invalid strip */
tif->tif_row = (uint32_t)-1; /* read/write pre-increment */ tif->tif_row = (uint32_t)-1; /* read/write pre-increment */
@ -261,6 +385,7 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
tif->tif_warnhandler = opts->warnhandler; tif->tif_warnhandler = opts->warnhandler;
tif->tif_warnhandler_user_data = opts->warnhandler_user_data; tif->tif_warnhandler_user_data = opts->warnhandler_user_data;
tif->tif_max_single_mem_alloc = opts->max_single_mem_alloc; tif->tif_max_single_mem_alloc = opts->max_single_mem_alloc;
tif->tif_max_cumulated_mem_alloc = opts->max_cumulated_mem_alloc;
} }
if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc)
@ -423,9 +548,9 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
TIFFErrorExtR(tif, name, "Cannot read TIFF header"); TIFFErrorExtR(tif, name, "Cannot read TIFF header");
goto bad; goto bad;
} }
/* /*
* Setup header and write. * Setup header and write.
*/ */
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
tif->tif_header.common.tiff_magic = tif->tif_header.common.tiff_magic =
(tif->tif_flags & TIFF_SWAB) ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN; (tif->tif_flags & TIFF_SWAB) ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN;
@ -433,13 +558,17 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
tif->tif_header.common.tiff_magic = tif->tif_header.common.tiff_magic =
(tif->tif_flags & TIFF_SWAB) ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN; (tif->tif_flags & TIFF_SWAB) ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN;
#endif #endif
TIFFHeaderUnion tif_header_swapped;
if (!(tif->tif_flags & TIFF_BIGTIFF)) if (!(tif->tif_flags & TIFF_BIGTIFF))
{ {
tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC; tif->tif_header.common.tiff_version = TIFF_VERSION_CLASSIC;
tif->tif_header.classic.tiff_diroff = 0; tif->tif_header.classic.tiff_diroff = 0;
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&tif->tif_header.common.tiff_version);
tif->tif_header_size = sizeof(TIFFHeaderClassic); tif->tif_header_size = sizeof(TIFFHeaderClassic);
/* Swapped copy for writing */
_TIFFmemcpy(&tif_header_swapped, &tif->tif_header,
sizeof(TIFFHeaderUnion));
if (tif->tif_flags & TIFF_SWAB)
TIFFSwabShort(&tif_header_swapped.common.tiff_version);
} }
else else
{ {
@ -447,12 +576,15 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
tif->tif_header.big.tiff_offsetsize = 8; tif->tif_header.big.tiff_offsetsize = 8;
tif->tif_header.big.tiff_unused = 0; tif->tif_header.big.tiff_unused = 0;
tif->tif_header.big.tiff_diroff = 0; tif->tif_header.big.tiff_diroff = 0;
tif->tif_header_size = sizeof(TIFFHeaderBig);
/* Swapped copy for writing */
_TIFFmemcpy(&tif_header_swapped, &tif->tif_header,
sizeof(TIFFHeaderUnion));
if (tif->tif_flags & TIFF_SWAB) if (tif->tif_flags & TIFF_SWAB)
{ {
TIFFSwabShort(&tif->tif_header.common.tiff_version); TIFFSwabShort(&tif_header_swapped.common.tiff_version);
TIFFSwabShort(&tif->tif_header.big.tiff_offsetsize); TIFFSwabShort(&tif_header_swapped.big.tiff_offsetsize);
} }
tif->tif_header_size = sizeof(TIFFHeaderBig);
} }
/* /*
* The doc for "fopen" for some STD_C_LIBs says that if you * The doc for "fopen" for some STD_C_LIBs says that if you
@ -462,26 +594,12 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
* on Solaris. * on Solaris.
*/ */
TIFFSeekFile(tif, 0, SEEK_SET); TIFFSeekFile(tif, 0, SEEK_SET);
if (!WriteOK(tif, &tif->tif_header, (tmsize_t)(tif->tif_header_size))) if (!WriteOK(tif, &tif_header_swapped,
(tmsize_t)(tif->tif_header_size)))
{ {
TIFFErrorExtR(tif, name, "Error writing TIFF header"); TIFFErrorExtR(tif, name, "Error writing TIFF header");
goto bad; goto bad;
} }
/*
* Setup the byte order handling.
*/
if (tif->tif_header.common.tiff_magic == TIFF_BIGENDIAN)
{
#ifndef WORDS_BIGENDIAN
tif->tif_flags |= TIFF_SWAB;
#endif
}
else
{
#ifdef WORDS_BIGENDIAN
tif->tif_flags |= TIFF_SWAB;
#endif
}
/* /*
* Setup default directory. * Setup default directory.
*/ */
@ -490,10 +608,14 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
tif->tif_diroff = 0; tif->tif_diroff = 0;
tif->tif_lastdiroff = 0; tif->tif_lastdiroff = 0;
tif->tif_setdirectory_force_absolute = FALSE; tif->tif_setdirectory_force_absolute = FALSE;
/* tif_curdircount = 0 means 'empty file opened for writing, but no IFD
* written yet' */
tif->tif_curdircount = 0;
return (tif); return (tif);
} }
/* /*
* Setup the byte order handling. * Setup the byte order handling according to the opened file for reading.
*/ */
if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN && if (tif->tif_header.common.tiff_magic != TIFF_BIGENDIAN &&
tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN tif->tif_header.common.tiff_magic != TIFF_LITTLEENDIAN
@ -619,9 +741,17 @@ TIFF *TIFFClientOpenExt(const char *name, const char *mode,
* example, it may be broken) and want to proceed to other * example, it may be broken) and want to proceed to other
* directories. I this case we use the TIFF_HEADERONLY flag to open * directories. I this case we use the TIFF_HEADERONLY flag to open
* file and return immediately after reading TIFF header. * file and return immediately after reading TIFF header.
* However, the pointer to TIFFSetField() and TIFFGetField()
* (i.e. tif->tif_tagmethods.vsetfield and
* tif->tif_tagmethods.vgetfield) need to be initialized, which is
* done in TIFFDefaultDirectory().
*/ */
if (tif->tif_flags & TIFF_HEADERONLY) if (tif->tif_flags & TIFF_HEADERONLY)
{
if (!TIFFDefaultDirectory(tif))
goto bad;
return (tif); return (tif);
}
/* /*
* Setup initial directory. * Setup initial directory.
@ -764,10 +894,7 @@ int TIFFIsBigEndian(TIFF *tif)
/* /*
* Return nonzero if given file is BigTIFF style. * Return nonzero if given file is BigTIFF style.
*/ */
int TIFFIsBigTIFF(TIFF *tif) int TIFFIsBigTIFF(TIFF *tif) { return ((tif->tif_flags & TIFF_BIGTIFF) != 0); }
{
return (tif->tif_header.common.tiff_version == TIFF_VERSION_BIG);
}
/* /*
* Return pointer to file read method. * Return pointer to file read method.

View File

@ -300,6 +300,7 @@ static int PackBitsDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
tif->tif_rawcc = cc; tif->tif_rawcc = cc;
if (occ > 0) if (occ > 0)
{ {
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, "Not enough data for scanline %" PRIu32, TIFFErrorExtR(tif, module, "Not enough data for scanline %" PRIu32,
tif->tif_row); tif->tif_row);
return (0); return (0);

View File

@ -670,8 +670,8 @@ static int PixarLogMakeTables(TIFF *tif, PixarLogState *sp)
return 1; return 1;
} }
#define DecoderState(tif) ((PixarLogState *)(tif)->tif_data) #define PixarLogDecoderState(tif) ((PixarLogState *)(tif)->tif_data)
#define EncoderState(tif) ((PixarLogState *)(tif)->tif_data) #define PixarLogEncoderState(tif) ((PixarLogState *)(tif)->tif_data)
static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
@ -740,7 +740,7 @@ static int PixarLogSetupDecode(TIFF *tif)
{ {
static const char module[] = "PixarLogSetupDecode"; static const char module[] = "PixarLogSetupDecode";
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
PixarLogState *sp = DecoderState(tif); PixarLogState *sp = PixarLogDecoderState(tif);
tmsize_t tbuf_size; tmsize_t tbuf_size;
uint32_t strip_height; uint32_t strip_height;
@ -813,7 +813,7 @@ static int PixarLogSetupDecode(TIFF *tif)
static int PixarLogPreDecode(TIFF *tif, uint16_t s) static int PixarLogPreDecode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "PixarLogPreDecode"; static const char module[] = "PixarLogPreDecode";
PixarLogState *sp = DecoderState(tif); PixarLogState *sp = PixarLogDecoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -835,7 +835,7 @@ static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
static const char module[] = "PixarLogDecode"; static const char module[] = "PixarLogDecode";
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
PixarLogState *sp = DecoderState(tif); PixarLogState *sp = PixarLogDecoderState(tif);
tmsize_t i; tmsize_t i;
tmsize_t nsamples; tmsize_t nsamples;
int llen; int llen;
@ -859,6 +859,7 @@ static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"%" PRIu16 " bit input not supported in PixarLog", "%" PRIu16 " bit input not supported in PixarLog",
td->td_bitspersample); td->td_bitspersample);
memset(op, 0, (size_t)occ);
return 0; return 0;
} }
@ -879,12 +880,14 @@ static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (sp->stream.avail_out != nsamples * sizeof(uint16_t)) if (sp->stream.avail_out != nsamples * sizeof(uint16_t))
{ {
TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size"); TIFFErrorExtR(tif, module, "ZLib cannot deal with buffers this size");
memset(op, 0, (size_t)occ);
return (0); return (0);
} }
/* Check that we will not fill more than what was allocated */ /* Check that we will not fill more than what was allocated */
if ((tmsize_t)sp->stream.avail_out > sp->tbuf_size) if ((tmsize_t)sp->stream.avail_out > sp->tbuf_size)
{ {
TIFFErrorExtR(tif, module, "sp->stream.avail_out > sp->tbuf_size"); TIFFErrorExtR(tif, module, "sp->stream.avail_out > sp->tbuf_size");
memset(op, 0, (size_t)occ);
return (0); return (0);
} }
do do
@ -899,12 +902,14 @@ static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
TIFFErrorExtR( TIFFErrorExtR(
tif, module, "Decoding error at scanline %" PRIu32 ", %s", tif, module, "Decoding error at scanline %" PRIu32 ", %s",
tif->tif_row, sp->stream.msg ? sp->stream.msg : "(null)"); tif->tif_row, sp->stream.msg ? sp->stream.msg : "(null)");
memset(op, 0, (size_t)occ);
return (0); return (0);
} }
if (state != Z_OK) if (state != Z_OK)
{ {
TIFFErrorExtR(tif, module, "ZLib error: %s", TIFFErrorExtR(tif, module, "ZLib error: %s",
sp->stream.msg ? sp->stream.msg : "(null)"); sp->stream.msg ? sp->stream.msg : "(null)");
memset(op, 0, (size_t)occ);
return (0); return (0);
} }
} while (sp->stream.avail_out > 0); } while (sp->stream.avail_out > 0);
@ -916,6 +921,7 @@ static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
"Not enough data at scanline %" PRIu32 "Not enough data at scanline %" PRIu32
" (short %u bytes)", " (short %u bytes)",
tif->tif_row, sp->stream.avail_out); tif->tif_row, sp->stream.avail_out);
memset(op, 0, (size_t)occ);
return (0); return (0);
} }
@ -977,6 +983,7 @@ static int PixarLogDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
default: default:
TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16, TIFFErrorExtR(tif, module, "Unsupported bits/sample: %" PRIu16,
td->td_bitspersample); td->td_bitspersample);
memset(op, 0, (size_t)occ);
return (0); return (0);
} }
} }
@ -988,7 +995,7 @@ static int PixarLogSetupEncode(TIFF *tif)
{ {
static const char module[] = "PixarLogSetupEncode"; static const char module[] = "PixarLogSetupEncode";
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
PixarLogState *sp = EncoderState(tif); PixarLogState *sp = PixarLogEncoderState(tif);
tmsize_t tbuf_size; tmsize_t tbuf_size;
assert(sp != NULL); assert(sp != NULL);
@ -1038,7 +1045,7 @@ static int PixarLogSetupEncode(TIFF *tif)
static int PixarLogPreEncode(TIFF *tif, uint16_t s) static int PixarLogPreEncode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "PixarLogPreEncode"; static const char module[] = "PixarLogPreEncode";
PixarLogState *sp = EncoderState(tif); PixarLogState *sp = PixarLogEncoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -1294,7 +1301,7 @@ static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
{ {
static const char module[] = "PixarLogEncode"; static const char module[] = "PixarLogEncode";
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
PixarLogState *sp = EncoderState(tif); PixarLogState *sp = PixarLogEncoderState(tif);
tmsize_t i; tmsize_t i;
tmsize_t n; tmsize_t n;
int llen; int llen;
@ -1401,7 +1408,7 @@ static int PixarLogEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
static int PixarLogPostEncode(TIFF *tif) static int PixarLogPostEncode(TIFF *tif)
{ {
static const char module[] = "PixarLogPostEncode"; static const char module[] = "PixarLogPostEncode";
PixarLogState *sp = EncoderState(tif); PixarLogState *sp = PixarLogEncoderState(tif);
int state; int state;
sp->stream.avail_in = 0; sp->stream.avail_in = 0;

View File

@ -105,8 +105,8 @@ static int TIFFReadAndRealloc(TIFF *tif, tmsize_t size, tmsize_t rawdata_offset,
TIFFErrorExtR(tif, module, "Invalid buffer size"); TIFFErrorExtR(tif, module, "Invalid buffer size");
return 0; return 0;
} }
new_rawdata = new_rawdata = (uint8_t *)_TIFFreallocExt(tif, tif->tif_rawdata,
(uint8_t *)_TIFFrealloc(tif->tif_rawdata, tif->tif_rawdatasize); tif->tif_rawdatasize);
if (new_rawdata == 0) if (new_rawdata == 0)
{ {
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
@ -464,6 +464,10 @@ int TIFFReadScanline(TIFF *tif, void *buf, uint32_t row, uint16_t sample)
if (e) if (e)
(*tif->tif_postdecode)(tif, (uint8_t *)buf, tif->tif_scanlinesize); (*tif->tif_postdecode)(tif, (uint8_t *)buf, tif->tif_scanlinesize);
} }
else
{
memset(buf, 0, (size_t)tif->tif_scanlinesize);
}
return (e > 0 ? 1 : -1); return (e > 0 ? 1 : -1);
} }
@ -495,6 +499,11 @@ static tmsize_t TIFFReadEncodedStripGetStripSize(TIFF *tif, uint32_t strip,
rowsperstrip = td->td_rowsperstrip; rowsperstrip = td->td_rowsperstrip;
if (rowsperstrip > td->td_imagelength) if (rowsperstrip > td->td_imagelength)
rowsperstrip = td->td_imagelength; rowsperstrip = td->td_imagelength;
if (rowsperstrip == 0)
{
TIFFErrorExtR(tif, module, "rowsperstrip is zero");
return ((tmsize_t)(-1));
}
stripsperplane = stripsperplane =
TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip); TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
stripinplane = (strip % stripsperplane); stripinplane = (strip % stripsperplane);
@ -544,7 +553,10 @@ tmsize_t TIFFReadEncodedStrip(TIFF *tif, uint32_t strip, void *buf,
if ((size != (tmsize_t)(-1)) && (size < stripsize)) if ((size != (tmsize_t)(-1)) && (size < stripsize))
stripsize = size; stripsize = size;
if (!TIFFFillStrip(tif, strip)) if (!TIFFFillStrip(tif, strip))
{
memset(buf, 0, (size_t)stripsize);
return ((tmsize_t)(-1)); return ((tmsize_t)(-1));
}
if ((*tif->tif_decodestrip)(tif, buf, stripsize, plane) <= 0) if ((*tif->tif_decodestrip)(tif, buf, stripsize, plane) <= 0)
return ((tmsize_t)(-1)); return ((tmsize_t)(-1));
(*tif->tif_postdecode)(tif, buf, stripsize); (*tif->tif_postdecode)(tif, buf, stripsize);
@ -962,9 +974,13 @@ tmsize_t TIFFReadEncodedTile(TIFF *tif, uint32_t tile, void *buf, tmsize_t size)
size = tilesize; size = tilesize;
else if (size > tilesize) else if (size > tilesize)
size = tilesize; size = tilesize;
if (TIFFFillTile(tif, tile) && if (!TIFFFillTile(tif, tile))
(*tif->tif_decodetile)(tif, (uint8_t *)buf, size, {
(uint16_t)(tile / td->td_stripsperimage))) memset(buf, 0, (size_t)size);
return ((tmsize_t)(-1));
}
else if ((*tif->tif_decodetile)(tif, (uint8_t *)buf, size,
(uint16_t)(tile / td->td_stripsperimage)))
{ {
(*tif->tif_postdecode)(tif, (uint8_t *)buf, size); (*tif->tif_postdecode)(tif, (uint8_t *)buf, size);
return (size); return (size);
@ -1449,6 +1465,11 @@ static int TIFFStartTile(TIFF *tif, uint32_t tile)
tif->tif_flags |= TIFF_CODERSETUP; tif->tif_flags |= TIFF_CODERSETUP;
} }
tif->tif_curtile = tile; tif->tif_curtile = tile;
if (td->td_tilewidth == 0)
{
TIFFErrorExtR(tif, module, "Zero tilewidth");
return 0;
}
howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth); howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
if (howmany32 == 0) if (howmany32 == 0)
{ {
@ -1545,9 +1566,14 @@ int TIFFReadFromUserBuffer(TIFF *tif, uint32_t strile, void *inbuf,
if (TIFFIsTiled(tif)) if (TIFFIsTiled(tif))
{ {
if (!TIFFStartTile(tif, strile) || if (!TIFFStartTile(tif, strile))
!(*tif->tif_decodetile)(tif, (uint8_t *)outbuf, outsize, {
(uint16_t)(strile / td->td_stripsperimage))) ret = 0;
memset(outbuf, 0, (size_t)outsize);
}
else if (!(*tif->tif_decodetile)(
tif, (uint8_t *)outbuf, outsize,
(uint16_t)(strile / td->td_stripsperimage)))
{ {
ret = 0; ret = 0;
} }
@ -1558,14 +1584,27 @@ int TIFFReadFromUserBuffer(TIFF *tif, uint32_t strile, void *inbuf,
uint32_t stripsperplane; uint32_t stripsperplane;
if (rowsperstrip > td->td_imagelength) if (rowsperstrip > td->td_imagelength)
rowsperstrip = td->td_imagelength; rowsperstrip = td->td_imagelength;
stripsperplane = if (rowsperstrip == 0)
TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
if (!TIFFStartStrip(tif, strile) ||
!(*tif->tif_decodestrip)(tif, (uint8_t *)outbuf, outsize,
(uint16_t)(strile / stripsperplane)))
{ {
TIFFErrorExtR(tif, module, "rowsperstrip is zero");
ret = 0; ret = 0;
} }
else
{
stripsperplane =
TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
if (!TIFFStartStrip(tif, strile))
{
ret = 0;
memset(outbuf, 0, (size_t)outsize);
}
else if (!(*tif->tif_decodestrip)(
tif, (uint8_t *)outbuf, outsize,
(uint16_t)(strile / stripsperplane)))
{
ret = 0;
}
}
} }
if (ret) if (ret)
{ {

View File

@ -38,6 +38,11 @@ uint32_t TIFFComputeStrip(TIFF *tif, uint32_t row, uint16_t sample)
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
uint32_t strip; uint32_t strip;
if (td->td_rowsperstrip == 0)
{
TIFFErrorExtR(tif, module, "Cannot compute strip: RowsPerStrip is zero");
return 0;
}
strip = row / td->td_rowsperstrip; strip = row / td->td_rowsperstrip;
if (td->td_planarconfig == PLANARCONFIG_SEPARATE) if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
{ {
@ -61,6 +66,11 @@ uint32_t TIFFNumberOfStrips(TIFF *tif)
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
uint32_t nstrips; uint32_t nstrips;
if (td->td_rowsperstrip == 0)
{
TIFFWarningExtR(tif, "TIFFNumberOfStrips", "RowsPerStrip is zero");
return 0;
}
nstrips = (td->td_rowsperstrip == (uint32_t)-1 nstrips = (td->td_rowsperstrip == (uint32_t)-1
? 1 ? 1
: TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip)); : TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip));
@ -107,7 +117,8 @@ uint64_t TIFFVStripSize64(TIFF *tif, uint32_t nrows)
if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 && if ((ycbcrsubsampling[0] != 1 && ycbcrsubsampling[0] != 2 &&
ycbcrsubsampling[0] != 4) || ycbcrsubsampling[0] != 4) ||
(ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 && (ycbcrsubsampling[1] != 1 && ycbcrsubsampling[1] != 2 &&
ycbcrsubsampling[1] != 4)) ycbcrsubsampling[1] != 4) ||
(ycbcrsubsampling[0] == 0 || ycbcrsubsampling[1] == 0))
{ {
TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling (%dx%d)", TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling (%dx%d)",
ycbcrsubsampling[0], ycbcrsubsampling[1]); ycbcrsubsampling[0], ycbcrsubsampling[1]);
@ -267,7 +278,8 @@ uint64_t TIFFScanlineSize64(TIFF *tif)
if (((ycbcrsubsampling[0] != 1) && (ycbcrsubsampling[0] != 2) && if (((ycbcrsubsampling[0] != 1) && (ycbcrsubsampling[0] != 2) &&
(ycbcrsubsampling[0] != 4)) || (ycbcrsubsampling[0] != 4)) ||
((ycbcrsubsampling[1] != 1) && (ycbcrsubsampling[1] != 2) && ((ycbcrsubsampling[1] != 1) && (ycbcrsubsampling[1] != 2) &&
(ycbcrsubsampling[1] != 4))) (ycbcrsubsampling[1] != 4)) ||
((ycbcrsubsampling[0] == 0) || (ycbcrsubsampling[1] == 0)))
{ {
TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling"); TIFFErrorExtR(tif, module, "Invalid YCbCr subsampling");
return 0; return 0;
@ -287,7 +299,25 @@ uint64_t TIFFScanlineSize64(TIFF *tif)
else else
{ {
uint64_t scanline_samples; uint64_t scanline_samples;
scanline_samples = _TIFFMultiply64(tif, td->td_imagewidth, uint32_t scanline_width = td->td_imagewidth;
#if 0
// Tries to fix https://gitlab.com/libtiff/libtiff/-/merge_requests/564
// but causes regression when decoding legit files with tiffcp -c none
// Cf https://gitlab.com/libtiff/libtiff/-/merge_requests/644
if (td->td_photometric == PHOTOMETRIC_YCBCR)
{
uint16_t subsampling_hor;
uint16_t ignored;
TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING,
&subsampling_hor, &ignored);
if (subsampling_hor > 1) // roundup width for YCbCr
scanline_width =
TIFFroundup_32(scanline_width, subsampling_hor);
}
#endif
scanline_samples = _TIFFMultiply64(tif, scanline_width,
td->td_samplesperpixel, module); td->td_samplesperpixel, module);
scanline_size = scanline_size =
TIFFhowmany_64(_TIFFMultiply64(tif, scanline_samples, TIFFhowmany_64(_TIFFMultiply64(tif, scanline_samples,

View File

@ -82,13 +82,14 @@ static int ThunderSetupDecode(TIFF *tif)
return (1); return (1);
} }
static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels) static int ThunderDecode(TIFF *tif, uint8_t *op0, tmsize_t maxpixels)
{ {
static const char module[] = "ThunderDecode"; static const char module[] = "ThunderDecode";
register unsigned char *bp; register unsigned char *bp;
register tmsize_t cc; register tmsize_t cc;
unsigned int lastpixel; unsigned int lastpixel;
tmsize_t npixels; tmsize_t npixels;
uint8_t *op = op0;
bp = (unsigned char *)tif->tif_rawcp; bp = (unsigned char *)tif->tif_rawcp;
cc = tif->tif_rawcc; cc = tif->tif_rawcc;
@ -107,6 +108,8 @@ static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels)
* Replicate the last pixel n times, * Replicate the last pixel n times,
* where n is the lower-order 6 bits. * where n is the lower-order 6 bits.
*/ */
if (n == 0)
break;
if (npixels & 1) if (npixels & 1)
{ {
op[0] |= lastpixel; op[0] |= lastpixel;
@ -117,11 +120,10 @@ static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels)
else else
lastpixel |= lastpixel << 4; lastpixel |= lastpixel << 4;
npixels += n; npixels += n;
if (npixels < maxpixels) if (npixels > maxpixels)
{ break;
for (; n > 0; n -= 2) for (; n > 0; n -= 2)
*op++ = (uint8_t)lastpixel; *op++ = (uint8_t)lastpixel;
}
if (n == -1) if (n == -1)
*--op &= 0xf0; *--op &= 0xf0;
lastpixel &= 0xf; lastpixel &= 0xf;
@ -154,6 +156,8 @@ static int ThunderDecode(TIFF *tif, uint8_t *op, tmsize_t maxpixels)
tif->tif_rawcc = cc; tif->tif_rawcc = cc;
if (npixels != maxpixels) if (npixels != maxpixels)
{ {
uint8_t *op_end = op0 + (maxpixels + 1) / 2;
memset(op, 0, (size_t)(op_end - op));
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"%s data at scanline %lu (%" PRIu64 " != %" PRIu64 ")", "%s data at scanline %lu (%" PRIu64 " != %" PRIu64 ")",
npixels < maxpixels ? "Not enough" : "Too much", npixels < maxpixels ? "Not enough" : "Too much",

View File

@ -27,6 +27,10 @@
* Windows Common RunTime Library. * Windows Common RunTime Library.
*/ */
#ifdef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
#undef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
#endif
#include "tif_config.h" #include "tif_config.h"
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
@ -79,6 +83,8 @@ static tmsize_t _tiffReadProc(thandle_t fd, void *buf, tmsize_t size)
size_t io_size = bytes_total - bytes_read; size_t io_size = bytes_total - bytes_read;
if (io_size > TIFF_IO_MAX) if (io_size > TIFF_IO_MAX)
io_size = TIFF_IO_MAX; io_size = TIFF_IO_MAX;
/* Below is an obvious false positive of Coverity Scan */
/* coverity[overflow_sink] */
count = read(fdh.fd, buf_offset, (TIFFIOSize_t)io_size); count = read(fdh.fd, buf_offset, (TIFFIOSize_t)io_size);
if (count <= 0) if (count <= 0)
break; break;
@ -106,6 +112,8 @@ static tmsize_t _tiffWriteProc(thandle_t fd, void *buf, tmsize_t size)
size_t io_size = bytes_total - bytes_written; size_t io_size = bytes_total - bytes_written;
if (io_size > TIFF_IO_MAX) if (io_size > TIFF_IO_MAX)
io_size = TIFF_IO_MAX; io_size = TIFF_IO_MAX;
/* Below is an obvious false positive of Coverity Scan */
/* coverity[overflow_sink] */
count = write(fdh.fd, buf_offset, (TIFFIOSize_t)io_size); count = write(fdh.fd, buf_offset, (TIFFIOSize_t)io_size);
if (count <= 0) if (count <= 0)
break; break;
@ -258,7 +266,7 @@ TIFF *TIFFOpenExt(const char *name, const char *mode, TIFFOpenOptions *opts)
return tif; return tif;
} }
#ifdef __WIN32__ #ifdef _WIN32
#include <windows.h> #include <windows.h>
/* /*
* Open a TIFF file with a Unicode filename, for read/writing. * Open a TIFF file with a Unicode filename, for read/writing.

View File

@ -47,7 +47,9 @@ typedef struct
{ {
uint16_t nSamples; /* number of samples per pixel */ uint16_t nSamples; /* number of samples per pixel */
int lossless; /* lossy/lossless compression */ int read_error; /* whether a read error has occurred, and which should cause
further reads in the same strip/tile to be aborted */
int lossless; /* lossy/lossless compression */
int lossless_exact; /* lossless exact mode. If TRUE, R,G,B values in areas int lossless_exact; /* lossless exact mode. If TRUE, R,G,B values in areas
with alpha = 0 will be preserved */ with alpha = 0 will be preserved */
int quality_level; /* compression level */ int quality_level; /* compression level */
@ -133,6 +135,16 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
assert(sp != NULL); assert(sp != NULL);
assert(sp->state == LSTATE_INIT_DECODE); assert(sp->state == LSTATE_INIT_DECODE);
if (sp->read_error)
{
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module,
"ZIPDecode: Scanline %" PRIu32 " cannot be read due to "
"previous error",
tif->tif_row);
return 0;
}
if (sp->psDecoder == NULL) if (sp->psDecoder == NULL)
{ {
TIFFDirectory *td = &tif->tif_dir; TIFFDirectory *td = &tif->tif_dir;
@ -158,12 +170,16 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
: (uint32_t)tif->tif_rawcc, : (uint32_t)tif->tif_rawcc,
&webp_width, &webp_height)) &webp_width, &webp_height))
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, "WebPGetInfo() failed"); TIFFErrorExtR(tif, module, "WebPGetInfo() failed");
return 0; return 0;
} }
if ((uint32_t)webp_width != segment_width || if ((uint32_t)webp_width != segment_width ||
(uint32_t)webp_height != segment_height) (uint32_t)webp_height != segment_height)
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR( TIFFErrorExtR(
tif, module, "WebP blob dimension is %dx%d. Expected %ux%u", tif, module, "WebP blob dimension is %dx%d. Expected %ux%u",
webp_width, webp_height, segment_width, segment_height); webp_width, webp_height, segment_width, segment_height);
@ -174,6 +190,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
WebPDecoderConfig config; WebPDecoderConfig config;
if (!WebPInitDecoderConfig(&config)) if (!WebPInitDecoderConfig(&config))
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed"); TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
return 0; return 0;
} }
@ -189,6 +207,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (!bWebPGetFeaturesOK) if (!bWebPGetFeaturesOK)
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed"); TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
return 0; return 0;
} }
@ -202,6 +222,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
*/ */
!(webp_bands == 3 && sp->nSamples == 4)) !(webp_bands == 3 && sp->nSamples == 4))
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"WebP blob band count is %d. Expected %d", webp_bands, "WebP blob band count is %d. Expected %d", webp_bands,
sp->nSamples); sp->nSamples);
@ -228,6 +250,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (!sp->pBuffer) if (!sp->pBuffer)
{ {
TIFFErrorExtR(tif, module, "Cannot allocate buffer"); TIFFErrorExtR(tif, module, "Cannot allocate buffer");
memset(op, 0, (size_t)occ);
sp->read_error = 1;
return 0; return 0;
} }
sp->buffer_size = buffer_size; sp->buffer_size = buffer_size;
@ -257,6 +281,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (sp->psDecoder == NULL) if (sp->psDecoder == NULL)
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, "Unable to allocate WebP decoder."); TIFFErrorExtR(tif, module, "Unable to allocate WebP decoder.");
return 0; return 0;
} }
@ -264,6 +290,10 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (occ % sp->sDecBuffer.u.RGBA.stride) if (occ % sp->sDecBuffer.u.RGBA.stride)
{ {
// read_error not set here as this is a usage issue that can be
// recovered in a following call.
memset(op, 0, (size_t)occ);
/* Do not set read_error as could potentially be recovered */
TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read"); TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
return 0; return 0;
} }
@ -284,6 +314,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
TIFFErrorExtR(tif, module, "Unrecognized error."); TIFFErrorExtR(tif, module, "Unrecognized error.");
} }
memset(op, 0, (size_t)occ);
sp->read_error = 1;
return 0; return 0;
} }
else else
@ -303,6 +335,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
if (current_y != numberOfExpectedLines) if (current_y != numberOfExpectedLines)
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Unable to decode WebP data: less lines than " "Unable to decode WebP data: less lines than "
"expected."); "expected.");
@ -332,6 +366,8 @@ static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
} }
else else
{ {
memset(op, 0, (size_t)occ);
sp->read_error = 1;
TIFFErrorExtR(tif, module, "Unable to decode WebP data."); TIFFErrorExtR(tif, module, "Unable to decode WebP data.");
return 0; return 0;
} }
@ -451,6 +487,8 @@ static int TWebPPreDecode(TIFF *tif, uint16_t s)
sp->psDecoder = NULL; sp->psDecoder = NULL;
} }
sp->read_error = 0;
return 1; return 1;
} }

View File

@ -27,6 +27,10 @@
* Scott Wagner (wagner@itek.com), Itek Graphix, Rochester, NY USA * Scott Wagner (wagner@itek.com), Itek Graphix, Rochester, NY USA
*/ */
#ifdef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
#undef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
#endif
#include "tiffiop.h" #include "tiffiop.h"
#include <stdlib.h> #include <stdlib.h>

View File

@ -67,6 +67,8 @@ typedef struct
{ {
TIFFPredictorState predict; TIFFPredictorState predict;
z_stream stream; z_stream stream;
int read_error; /* whether a read error has occurred, and which should cause
further reads in the same strip/tile to be aborted */
int zipquality; /* compression level */ int zipquality; /* compression level */
int state; /* state flags */ int state; /* state flags */
int subcodec; /* DEFLATE_SUBCODEC_ZLIB or DEFLATE_SUBCODEC_LIBDEFLATE */ int subcodec; /* DEFLATE_SUBCODEC_ZLIB or DEFLATE_SUBCODEC_LIBDEFLATE */
@ -83,9 +85,9 @@ typedef struct
TIFFVSetMethod vsetparent; /* super-class method */ TIFFVSetMethod vsetparent; /* super-class method */
} ZIPState; } ZIPState;
#define ZState(tif) ((ZIPState *)(tif)->tif_data) #define GetZIPState(tif) ((ZIPState *)(tif)->tif_data)
#define DecoderState(tif) ZState(tif) #define ZIPDecoderState(tif) GetZIPState(tif)
#define EncoderState(tif) ZState(tif) #define ZIPEncoderState(tif) GetZIPState(tif)
static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
@ -99,7 +101,7 @@ static int ZIPFixupTags(TIFF *tif)
static int ZIPSetupDecode(TIFF *tif) static int ZIPSetupDecode(TIFF *tif)
{ {
static const char module[] = "ZIPSetupDecode"; static const char module[] = "ZIPSetupDecode";
ZIPState *sp = DecoderState(tif); ZIPState *sp = ZIPDecoderState(tif);
assert(sp != NULL); assert(sp != NULL);
@ -131,7 +133,7 @@ static int ZIPSetupDecode(TIFF *tif)
*/ */
static int ZIPPreDecode(TIFF *tif, uint16_t s) static int ZIPPreDecode(TIFF *tif, uint16_t s)
{ {
ZIPState *sp = DecoderState(tif); ZIPState *sp = ZIPDecoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -150,18 +152,33 @@ static int ZIPPreDecode(TIFF *tif, uint16_t s)
sp->stream.avail_in = (uint64_t)tif->tif_rawcc < 0xFFFFFFFFU sp->stream.avail_in = (uint64_t)tif->tif_rawcc < 0xFFFFFFFFU
? (uInt)tif->tif_rawcc ? (uInt)tif->tif_rawcc
: 0xFFFFFFFFU; : 0xFFFFFFFFU;
return (inflateReset(&sp->stream) == Z_OK); if (inflateReset(&sp->stream) == Z_OK)
{
sp->read_error = 0;
return 1;
}
return 0;
} }
static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
static const char module[] = "ZIPDecode"; static const char module[] = "ZIPDecode";
ZIPState *sp = DecoderState(tif); ZIPState *sp = ZIPDecoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
assert(sp->state == ZSTATE_INIT_DECODE); assert(sp->state == ZSTATE_INIT_DECODE);
if (sp->read_error)
{
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module,
"ZIPDecode: Scanline %" PRIu32 " cannot be read due to "
"previous error",
tif->tif_row);
return 0;
}
#if LIBDEFLATE_SUPPORT #if LIBDEFLATE_SUPPORT
if (sp->libdeflate_state == 1) if (sp->libdeflate_state == 1)
return 0; return 0;
@ -227,8 +244,10 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (res != LIBDEFLATE_SUCCESS && if (res != LIBDEFLATE_SUCCESS &&
res != LIBDEFLATE_INSUFFICIENT_SPACE) res != LIBDEFLATE_INSUFFICIENT_SPACE)
{ {
memset(op, 0, (size_t)occ);
TIFFErrorExtR(tif, module, "Decoding error at scanline %lu", TIFFErrorExtR(tif, module, "Decoding error at scanline %lu",
(unsigned long)tif->tif_row); (unsigned long)tif->tif_row);
sp->read_error = 1;
return 0; return 0;
} }
@ -263,13 +282,17 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
break; break;
if (state == Z_DATA_ERROR) if (state == Z_DATA_ERROR)
{ {
memset(sp->stream.next_out, 0, sp->stream.avail_out);
TIFFErrorExtR(tif, module, "Decoding error at scanline %lu, %s", TIFFErrorExtR(tif, module, "Decoding error at scanline %lu, %s",
(unsigned long)tif->tif_row, SAFE_MSG(sp)); (unsigned long)tif->tif_row, SAFE_MSG(sp));
sp->read_error = 1;
return (0); return (0);
} }
if (state != Z_OK) if (state != Z_OK)
{ {
memset(sp->stream.next_out, 0, sp->stream.avail_out);
TIFFErrorExtR(tif, module, "ZLib error: %s", SAFE_MSG(sp)); TIFFErrorExtR(tif, module, "ZLib error: %s", SAFE_MSG(sp));
sp->read_error = 1;
return (0); return (0);
} }
} while (occ > 0); } while (occ > 0);
@ -279,6 +302,8 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
"Not enough data at scanline %lu (short %" PRIu64 "Not enough data at scanline %lu (short %" PRIu64
" bytes)", " bytes)",
(unsigned long)tif->tif_row, (uint64_t)occ); (unsigned long)tif->tif_row, (uint64_t)occ);
memset(sp->stream.next_out, 0, sp->stream.avail_out);
sp->read_error = 1;
return (0); return (0);
} }
@ -290,7 +315,7 @@ static int ZIPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
static int ZIPSetupEncode(TIFF *tif) static int ZIPSetupEncode(TIFF *tif)
{ {
static const char module[] = "ZIPSetupEncode"; static const char module[] = "ZIPSetupEncode";
ZIPState *sp = EncoderState(tif); ZIPState *sp = ZIPEncoderState(tif);
int cappedQuality; int cappedQuality;
assert(sp != NULL); assert(sp != NULL);
@ -321,7 +346,7 @@ static int ZIPSetupEncode(TIFF *tif)
*/ */
static int ZIPPreEncode(TIFF *tif, uint16_t s) static int ZIPPreEncode(TIFF *tif, uint16_t s)
{ {
ZIPState *sp = EncoderState(tif); ZIPState *sp = ZIPEncoderState(tif);
(void)s; (void)s;
assert(sp != NULL); assert(sp != NULL);
@ -348,7 +373,7 @@ static int ZIPPreEncode(TIFF *tif, uint16_t s)
static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
{ {
static const char module[] = "ZIPEncode"; static const char module[] = "ZIPEncode";
ZIPState *sp = EncoderState(tif); ZIPState *sp = ZIPEncoderState(tif);
assert(sp != NULL); assert(sp != NULL);
assert(sp->state == ZSTATE_INIT_ENCODE); assert(sp->state == ZSTATE_INIT_ENCODE);
@ -487,7 +512,7 @@ static int ZIPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
static int ZIPPostEncode(TIFF *tif) static int ZIPPostEncode(TIFF *tif)
{ {
static const char module[] = "ZIPPostEncode"; static const char module[] = "ZIPPostEncode";
ZIPState *sp = EncoderState(tif); ZIPState *sp = ZIPEncoderState(tif);
int state; int state;
#if LIBDEFLATE_SUPPORT #if LIBDEFLATE_SUPPORT
@ -526,7 +551,7 @@ static int ZIPPostEncode(TIFF *tif)
static void ZIPCleanup(TIFF *tif) static void ZIPCleanup(TIFF *tif)
{ {
ZIPState *sp = ZState(tif); ZIPState *sp = GetZIPState(tif);
assert(sp != 0); assert(sp != 0);
@ -562,7 +587,7 @@ static void ZIPCleanup(TIFF *tif)
static int ZIPVSetField(TIFF *tif, uint32_t tag, va_list ap) static int ZIPVSetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
static const char module[] = "ZIPVSetField"; static const char module[] = "ZIPVSetField";
ZIPState *sp = ZState(tif); ZIPState *sp = GetZIPState(tif);
switch (tag) switch (tag)
{ {
@ -628,7 +653,7 @@ static int ZIPVSetField(TIFF *tif, uint32_t tag, va_list ap)
static int ZIPVGetField(TIFF *tif, uint32_t tag, va_list ap) static int ZIPVGetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
ZIPState *sp = ZState(tif); ZIPState *sp = GetZIPState(tif);
switch (tag) switch (tag)
{ {
@ -680,7 +705,7 @@ int TIFFInitZIP(TIFF *tif, int scheme)
tif->tif_data = (uint8_t *)_TIFFcallocExt(tif, sizeof(ZIPState), 1); tif->tif_data = (uint8_t *)_TIFFcallocExt(tif, sizeof(ZIPState), 1);
if (tif->tif_data == NULL) if (tif->tif_data == NULL)
goto bad; goto bad;
sp = ZState(tif); sp = GetZIPState(tif);
sp->stream.zalloc = NULL; sp->stream.zalloc = NULL;
sp->stream.zfree = NULL; sp->stream.zfree = NULL;
sp->stream.opaque = NULL; sp->stream.opaque = NULL;

View File

@ -54,9 +54,9 @@ typedef struct
TIFFVSetMethod vsetparent; /* super-class method */ TIFFVSetMethod vsetparent; /* super-class method */
} ZSTDState; } ZSTDState;
#define LState(tif) ((ZSTDState *)(tif)->tif_data) #define GetZSTDState(tif) ((ZSTDState *)(tif)->tif_data)
#define DecoderState(tif) LState(tif) #define ZSTDDecoderState(tif) GetZSTDState(tif)
#define EncoderState(tif) LState(tif) #define ZSTDEncoderState(tif) GetZSTDState(tif)
static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s); static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s); static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
@ -69,7 +69,7 @@ static int ZSTDFixupTags(TIFF *tif)
static int ZSTDSetupDecode(TIFF *tif) static int ZSTDSetupDecode(TIFF *tif)
{ {
ZSTDState *sp = DecoderState(tif); ZSTDState *sp = ZSTDDecoderState(tif);
assert(sp != NULL); assert(sp != NULL);
@ -91,7 +91,7 @@ static int ZSTDSetupDecode(TIFF *tif)
static int ZSTDPreDecode(TIFF *tif, uint16_t s) static int ZSTDPreDecode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "ZSTDPreDecode"; static const char module[] = "ZSTDPreDecode";
ZSTDState *sp = DecoderState(tif); ZSTDState *sp = ZSTDDecoderState(tif);
size_t zstd_ret; size_t zstd_ret;
(void)s; (void)s;
@ -124,7 +124,7 @@ static int ZSTDPreDecode(TIFF *tif, uint16_t s)
static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s) static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
{ {
static const char module[] = "ZSTDDecode"; static const char module[] = "ZSTDDecode";
ZSTDState *sp = DecoderState(tif); ZSTDState *sp = ZSTDDecoderState(tif);
ZSTD_inBuffer in_buffer; ZSTD_inBuffer in_buffer;
ZSTD_outBuffer out_buffer; ZSTD_outBuffer out_buffer;
size_t zstd_ret; size_t zstd_ret;
@ -146,6 +146,7 @@ static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
zstd_ret = ZSTD_decompressStream(sp->dstream, &out_buffer, &in_buffer); zstd_ret = ZSTD_decompressStream(sp->dstream, &out_buffer, &in_buffer);
if (ZSTD_isError(zstd_ret)) if (ZSTD_isError(zstd_ret))
{ {
memset(op + out_buffer.pos, 0, out_buffer.size - out_buffer.pos);
TIFFErrorExtR(tif, module, "Error in ZSTD_decompressStream(): %s", TIFFErrorExtR(tif, module, "Error in ZSTD_decompressStream(): %s",
ZSTD_getErrorName(zstd_ret)); ZSTD_getErrorName(zstd_ret));
return 0; return 0;
@ -155,6 +156,7 @@ static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
if (out_buffer.pos < (size_t)occ) if (out_buffer.pos < (size_t)occ)
{ {
memset(op + out_buffer.pos, 0, out_buffer.size - out_buffer.pos);
TIFFErrorExtR(tif, module, TIFFErrorExtR(tif, module,
"Not enough data at scanline %lu (short %lu bytes)", "Not enough data at scanline %lu (short %lu bytes)",
(unsigned long)tif->tif_row, (unsigned long)tif->tif_row,
@ -170,7 +172,7 @@ static int ZSTDDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
static int ZSTDSetupEncode(TIFF *tif) static int ZSTDSetupEncode(TIFF *tif)
{ {
ZSTDState *sp = EncoderState(tif); ZSTDState *sp = ZSTDEncoderState(tif);
assert(sp != NULL); assert(sp != NULL);
if (sp->state & LSTATE_INIT_DECODE) if (sp->state & LSTATE_INIT_DECODE)
@ -190,7 +192,7 @@ static int ZSTDSetupEncode(TIFF *tif)
static int ZSTDPreEncode(TIFF *tif, uint16_t s) static int ZSTDPreEncode(TIFF *tif, uint16_t s)
{ {
static const char module[] = "ZSTDPreEncode"; static const char module[] = "ZSTDPreEncode";
ZSTDState *sp = EncoderState(tif); ZSTDState *sp = ZSTDEncoderState(tif);
size_t zstd_ret; size_t zstd_ret;
(void)s; (void)s;
@ -229,7 +231,7 @@ static int ZSTDPreEncode(TIFF *tif, uint16_t s)
static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s) static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
{ {
static const char module[] = "ZSTDEncode"; static const char module[] = "ZSTDEncode";
ZSTDState *sp = EncoderState(tif); ZSTDState *sp = ZSTDEncoderState(tif);
ZSTD_inBuffer in_buffer; ZSTD_inBuffer in_buffer;
size_t zstd_ret; size_t zstd_ret;
@ -271,7 +273,7 @@ static int ZSTDEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
static int ZSTDPostEncode(TIFF *tif) static int ZSTDPostEncode(TIFF *tif)
{ {
static const char module[] = "ZSTDPostEncode"; static const char module[] = "ZSTDPostEncode";
ZSTDState *sp = EncoderState(tif); ZSTDState *sp = ZSTDEncoderState(tif);
size_t zstd_ret; size_t zstd_ret;
do do
@ -297,7 +299,7 @@ static int ZSTDPostEncode(TIFF *tif)
static void ZSTDCleanup(TIFF *tif) static void ZSTDCleanup(TIFF *tif)
{ {
ZSTDState *sp = LState(tif); ZSTDState *sp = GetZSTDState(tif);
assert(sp != 0); assert(sp != 0);
@ -325,7 +327,7 @@ static void ZSTDCleanup(TIFF *tif)
static int ZSTDVSetField(TIFF *tif, uint32_t tag, va_list ap) static int ZSTDVSetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
static const char module[] = "ZSTDVSetField"; static const char module[] = "ZSTDVSetField";
ZSTDState *sp = LState(tif); ZSTDState *sp = GetZSTDState(tif);
switch (tag) switch (tag)
{ {
@ -347,7 +349,7 @@ static int ZSTDVSetField(TIFF *tif, uint32_t tag, va_list ap)
static int ZSTDVGetField(TIFF *tif, uint32_t tag, va_list ap) static int ZSTDVGetField(TIFF *tif, uint32_t tag, va_list ap)
{ {
ZSTDState *sp = LState(tif); ZSTDState *sp = GetZSTDState(tif);
switch (tag) switch (tag)
{ {
@ -389,7 +391,7 @@ int TIFFInitZSTD(TIFF *tif, int scheme)
tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(ZSTDState)); tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(ZSTDState));
if (tif->tif_data == NULL) if (tif->tif_data == NULL)
goto bad; goto bad;
sp = LState(tif); sp = GetZSTDState(tif);
/* /*
* Override parent get/set field methods. * Override parent get/set field methods.

View File

@ -77,10 +77,6 @@ typedef tstrile_t ttile_t; /* tile number */
typedef tmsize_t tsize_t; /* i/o size in bytes */ typedef tmsize_t tsize_t; /* i/o size in bytes */
typedef void *tdata_t; /* image data ref */ typedef void *tdata_t; /* image data ref */
#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32))
#define __WIN32__
#endif
/* /*
* On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c
* or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c).
@ -88,7 +84,7 @@ typedef void *tdata_t; /* image data ref */
* By default tif_unix.c is assumed. * By default tif_unix.c is assumed.
*/ */
#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows) #if defined(_WIN32)
#if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && \ #if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && \
!defined(USE_WIN32_FILEIO) !defined(USE_WIN32_FILEIO)
#define AVOID_WIN32_FILEIO #define AVOID_WIN32_FILEIO
@ -98,11 +94,11 @@ typedef void *tdata_t; /* image data ref */
#if defined(USE_WIN32_FILEIO) #if defined(USE_WIN32_FILEIO)
#define VC_EXTRALEAN #define VC_EXTRALEAN
#include <windows.h> #include <windows.h>
#ifdef __WIN32__ #ifdef _WIN32
DECLARE_HANDLE(thandle_t); /* Win32 file handle */ DECLARE_HANDLE(thandle_t); /* Win32 file handle */
#else #else
typedef HFILE thandle_t; /* client data handle */ typedef HFILE thandle_t; /* client data handle */
#endif /* __WIN32__ */ #endif /* _WIN32 */
#else #else
typedef void *thandle_t; /* client data handle */ typedef void *thandle_t; /* client data handle */
#endif /* USE_WIN32_FILEIO */ #endif /* USE_WIN32_FILEIO */
@ -311,14 +307,15 @@ extern "C"
/* /*
* Auxiliary functions. * Auxiliary functions.
*/ */
#ifndef TIFF_DO_NOT_USE_NON_EXT_ALLOC_FUNCTIONS
extern void *_TIFFmalloc(tmsize_t s); extern void *_TIFFmalloc(tmsize_t s);
extern void *_TIFFcalloc(tmsize_t nmemb, tmsize_t siz); extern void *_TIFFcalloc(tmsize_t nmemb, tmsize_t siz);
extern void *_TIFFrealloc(void *p, tmsize_t s); extern void *_TIFFrealloc(void *p, tmsize_t s);
extern void _TIFFfree(void *p);
#endif
extern void _TIFFmemset(void *p, int v, tmsize_t c); extern void _TIFFmemset(void *p, int v, tmsize_t c);
extern void _TIFFmemcpy(void *d, const void *s, tmsize_t c); extern void _TIFFmemcpy(void *d, const void *s, tmsize_t c);
extern int _TIFFmemcmp(const void *p1, const void *p2, tmsize_t c); extern int _TIFFmemcmp(const void *p1, const void *p2, tmsize_t c);
extern void _TIFFfree(void *p);
/* /*
** Stuff, related to tag handling and creating custom tags. ** Stuff, related to tag handling and creating custom tags.
@ -508,6 +505,9 @@ extern int TIFFReadRGBAImageOriented(TIFF *, uint32_t, uint32_t, uint32_t *,
TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts,
tmsize_t max_single_mem_alloc); tmsize_t max_single_mem_alloc);
extern void extern void
TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts,
tmsize_t max_cumulated_mem_alloc);
extern void
TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts,
TIFFErrorHandlerExtR handler, TIFFErrorHandlerExtR handler,
void *errorhandler_user_data); void *errorhandler_user_data);
@ -518,11 +518,11 @@ extern int TIFFReadRGBAImageOriented(TIFF *, uint32_t, uint32_t, uint32_t *,
extern TIFF *TIFFOpen(const char *, const char *); extern TIFF *TIFFOpen(const char *, const char *);
extern TIFF *TIFFOpenExt(const char *, const char *, TIFFOpenOptions *opts); extern TIFF *TIFFOpenExt(const char *, const char *, TIFFOpenOptions *opts);
#ifdef __WIN32__ #ifdef _WIN32
extern TIFF *TIFFOpenW(const wchar_t *, const char *); extern TIFF *TIFFOpenW(const wchar_t *, const char *);
extern TIFF *TIFFOpenWExt(const wchar_t *, const char *, extern TIFF *TIFFOpenWExt(const wchar_t *, const char *,
TIFFOpenOptions *opts); TIFFOpenOptions *opts);
#endif /* __WIN32__ */ #endif /* _WIN32 */
extern TIFF *TIFFFdOpen(int, const char *, const char *); extern TIFF *TIFFFdOpen(int, const char *, const char *);
extern TIFF *TIFFFdOpenExt(int, const char *, const char *, extern TIFF *TIFFFdOpenExt(int, const char *, const char *,
TIFFOpenOptions *opts); TIFFOpenOptions *opts);

View File

@ -102,6 +102,13 @@ struct TIFFOffsetAndDirNumber
}; };
typedef struct TIFFOffsetAndDirNumber TIFFOffsetAndDirNumber; typedef struct TIFFOffsetAndDirNumber TIFFOffsetAndDirNumber;
typedef union
{
TIFFHeaderCommon common;
TIFFHeaderClassic classic;
TIFFHeaderBig big;
} TIFFHeaderUnion;
struct tiff struct tiff
{ {
char *tif_name; /* name of open file */ char *tif_name; /* name of open file */
@ -153,20 +160,35 @@ struct tiff
TIFFDirectory tif_dir; /* internal rep of current directory */ TIFFDirectory tif_dir; /* internal rep of current directory */
TIFFDirectory TIFFDirectory
tif_customdir; /* custom IFDs are separated from the main ones */ tif_customdir; /* custom IFDs are separated from the main ones */
union TIFFHeaderUnion tif_header; /* file's header block Classic/BigTIFF union */
{ uint16_t tif_header_size; /* file's header block and its length */
TIFFHeaderCommon common; uint32_t tif_row; /* current scanline */
TIFFHeaderClassic classic;
TIFFHeaderBig big; /* There are IFDs in the file and an "active" IFD in memory,
} tif_header; * from which fields are "set" and "get".
uint16_t tif_header_size; /* file's header block and its length */ * tif_curdir is set to:
uint32_t tif_row; /* current scanline */ * a) TIFF_NON_EXISTENT_DIR_NUMBER if there is no IFD in the file
tdir_t tif_curdir; /* current directory (index) */ * or the state is unknown,
* or the last read (i.e. TIFFFetchDirectory()) failed,
* or a custom directory was written.
* b) IFD index of last IFD written in the file. In this case the
* active IFD is a new (empty) one and tif_diroff is zero.
* If writing fails, tif_curdir is not changed.
* c) IFD index of IFD read from file into memory (=active IFD),
* even if IFD is corrupt and TIFFReadDirectory() returns 0.
* Then tif_diroff contains the offset of the IFD in the file.
* d) IFD index 0, whenever a custom directory or an unchained SubIFD
* was read. */
tdir_t tif_curdir; /* current directory (index) */
/* tif_curdircount: number of directories (main-IFDs) in file:
* - TIFF_NON_EXISTENT_DIR_NUMBER means 'dont know number of IFDs'.
* - 0 means 'empty file opened for writing, but no IFD written yet' */
tdir_t tif_curdircount;
uint32_t tif_curstrip; /* current strip for read/write */ uint32_t tif_curstrip; /* current strip for read/write */
uint64_t tif_curoff; /* current offset for read/write */ uint64_t tif_curoff; /* current offset for read/write */
uint64_t tif_lastvalidoff; /* last valid offset allowed for rewrite in uint64_t tif_lastvalidoff; /* last valid offset allowed for rewrite in
place. Used only by TIFFAppendToStrip() */ place. Used only by TIFFAppendToStrip() */
uint64_t tif_dataoff; /* current offset for writing dir */ uint64_t tif_dataoff; /* current offset for writing dir (IFD) */
/* SubIFD support */ /* SubIFD support */
uint16_t tif_nsubifd; /* remaining subifds to write */ uint16_t tif_nsubifd; /* remaining subifds to write */
uint64_t tif_subifdoff; /* offset for patching SubIFD link */ uint64_t tif_subifdoff; /* offset for patching SubIFD link */
@ -233,7 +255,9 @@ struct tiff
void *tif_errorhandler_user_data; void *tif_errorhandler_user_data;
TIFFErrorHandlerExtR tif_warnhandler; TIFFErrorHandlerExtR tif_warnhandler;
void *tif_warnhandler_user_data; void *tif_warnhandler_user_data;
tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */ tmsize_t tif_max_single_mem_alloc; /* in bytes. 0 for unlimited */
tmsize_t tif_max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */
tmsize_t tif_cur_cumulated_mem_alloc; /* in bytes */
}; };
struct TIFFOpenOptions struct TIFFOpenOptions
@ -243,6 +267,7 @@ struct TIFFOpenOptions
TIFFErrorHandlerExtR warnhandler; /* may be NULL */ TIFFErrorHandlerExtR warnhandler; /* may be NULL */
void *warnhandler_user_data; /* may be NULL */ void *warnhandler_user_data; /* may be NULL */
tmsize_t max_single_mem_alloc; /* in bytes. 0 for unlimited */ tmsize_t max_single_mem_alloc; /* in bytes. 0 for unlimited */
tmsize_t max_cumulated_mem_alloc; /* in bytes. 0 for unlimited */
}; };
#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */ #define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */
@ -331,7 +356,7 @@ struct TIFFOpenOptions
#define ftell(stream, offset, whence) ftello(stream, offset, whence) #define ftell(stream, offset, whence) ftello(stream, offset, whence)
#endif #endif
#endif #endif
#if defined(__WIN32__) && !(defined(_MSC_VER) && _MSC_VER < 1400) && \ #if defined(_WIN32) && \
!(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x800) !(defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x800)
typedef unsigned int TIFFIOSize_t; typedef unsigned int TIFFIOSize_t;
#define _TIFF_lseek_f(fildes, offset, whence) \ #define _TIFF_lseek_f(fildes, offset, whence) \
@ -437,9 +462,6 @@ extern "C"
extern void *_TIFFCheckRealloc(TIFF *, void *, tmsize_t, tmsize_t, extern void *_TIFFCheckRealloc(TIFF *, void *, tmsize_t, tmsize_t,
const char *); const char *);
extern double _TIFFUInt64ToDouble(uint64_t);
extern float _TIFFUInt64ToFloat(uint64_t);
extern float _TIFFClampDoubleToFloat(double); extern float _TIFFClampDoubleToFloat(double);
extern uint32_t _TIFFClampDoubleToUInt32(double); extern uint32_t _TIFFClampDoubleToUInt32(double);