Creation: use SHORT type when possible for StripByteCounts/TileByteCounts

This follows the same logic as previous commit.
This commit is contained in:
Even Rouault 2019-05-10 11:08:01 +02:00
parent 116cf67f4c
commit 458c211ae2
No known key found for this signature in database
GPG Key ID: 33EBBFC47B3DD87D
2 changed files with 126 additions and 43 deletions

View File

@ -1651,12 +1651,12 @@ TIFFWriteDirectoryTagShortLong(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint1
return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value)); return(TIFFWriteDirectoryTagCheckedLong(tif,ndir,dir,tag,value));
} }
static int WriteAsLong8(TIFF* tif, uint64 strile_size) static int _WriteAsType(TIFF* tif, uint64 strile_size, uint64 uncompressed_threshold)
{ {
const uint16 compression = tif->tif_dir.td_compression; const uint16 compression = tif->tif_dir.td_compression;
if ( compression == COMPRESSION_NONE ) if ( compression == COMPRESSION_NONE )
{ {
return strile_size >= 0xFFFFFFFFU; return strile_size > uncompressed_threshold;
} }
else if ( compression == COMPRESSION_JPEG || else if ( compression == COMPRESSION_JPEG ||
compression == COMPRESSION_LZW || compression == COMPRESSION_LZW ||
@ -1669,27 +1669,34 @@ static int WriteAsLong8(TIFF* tif, uint64 strile_size)
/* For a few select compression types, we assume that in the worst */ /* For a few select compression types, we assume that in the worst */
/* case the compressed size will be 10 times the uncompressed size */ /* case the compressed size will be 10 times the uncompressed size */
/* This is overly pessismistic ! */ /* This is overly pessismistic ! */
return strile_size >= 0xFFFFFFFFU / 10; return strile_size >= uncompressed_threshold / 10;
} }
return 1; return 1;
} }
static int WriteAsLong8(TIFF* tif, uint64 strile_size)
{
return _WriteAsType(tif, strile_size, 0xFFFFFFFFU);
}
static int WriteAsLong4(TIFF* tif, uint64 strile_size)
{
return _WriteAsType(tif, strile_size, 0xFFFFU);
}
/************************************************************************/ /************************************************************************/
/* TIFFWriteDirectoryTagLongLong8Array() */ /* TIFFWriteDirectoryTagLongLong8Array() */
/* */ /* */
/* Write out LONG8 array as LONG8 for BigTIFF or LONG for */ /* Write out LONG8 array and write a SHORT/LONG/LONG8 depending */
/* Classic TIFF with some checking. */ /* on strile size and Classic/BigTIFF mode. */
/************************************************************************/ /************************************************************************/
static int static int
TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value) TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir, uint16 tag, uint32 count, uint64* value)
{ {
static const char module[] = "TIFFWriteDirectoryTagLongLong8Array"; static const char module[] = "TIFFWriteDirectoryTagLongLong8Array";
uint64* ma;
uint32 mb;
uint32* p;
uint32* q;
int o; int o;
int write_aslong4;
/* is this just a counting pass? */ /* is this just a counting pass? */
if (dir==NULL) if (dir==NULL)
@ -1721,32 +1728,77 @@ TIFFWriteDirectoryTagLongLong8Array(TIFF* tif, uint32* ndir, TIFFDirEntry* dir,
} }
} }
/* write_aslong4 = 1;
** For classic tiff we want to verify everything is in range for LONG if( count > 1 && tag == TIFFTAG_STRIPBYTECOUNTS )
** and convert to long format.
*/
p = _TIFFmalloc(count*sizeof(uint32));
if (p==NULL)
{ {
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory"); write_aslong4 = WriteAsLong4(tif, TIFFStripSize64(tif));
return(0);
} }
else if( count > 1 && tag == TIFFTAG_TILEBYTECOUNTS )
for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
{ {
if (*ma>0xFFFFFFFF) write_aslong4 = WriteAsLong4(tif, TIFFTileSize64(tif));
}
if( write_aslong4 )
{
/*
** For classic tiff we want to verify everything is in range for LONG
** and convert to long format.
*/
uint32* p = _TIFFmalloc(count*sizeof(uint32));
uint32* q;
uint64* ma;
uint32 mb;
if (p==NULL)
{ {
TIFFErrorExt(tif->tif_clientdata,module, TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
"Attempt to write value larger than 0xFFFFFFFF in Classic TIFF file.");
_TIFFfree(p);
return(0); return(0);
} }
*q= (uint32)(*ma);
}
o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p); for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
_TIFFfree(p); {
if (*ma>0xFFFFFFFF)
{
TIFFErrorExt(tif->tif_clientdata,module,
"Attempt to write value larger than 0xFFFFFFFF in LONG array.");
_TIFFfree(p);
return(0);
}
*q= (uint32)(*ma);
}
o=TIFFWriteDirectoryTagCheckedLongArray(tif,ndir,dir,tag,count,p);
_TIFFfree(p);
}
else
{
uint16* p = _TIFFmalloc(count*sizeof(uint16));
uint16* q;
uint64* ma;
uint32 mb;
if (p==NULL)
{
TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
return(0);
}
for (q=p, ma=value, mb=0; mb<count; ma++, mb++, q++)
{
if (*ma>0xFFFF)
{
/* Should not happen normally given the check we did before */
TIFFErrorExt(tif->tif_clientdata,module,
"Attempt to write value larger than 0xFFFF in SHORT array.");
_TIFFfree(p);
return(0);
}
*q= (uint16)(*ma);
}
o=TIFFWriteDirectoryTagCheckedShortArray(tif,ndir,dir,tag,count,p);
_TIFFfree(p);
}
return(o); return(o);
} }
@ -2859,7 +2911,7 @@ _TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype,
if( TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags&TIFF_BIGTIFF) ) if( TIFFDataWidth(in_datatype) == 8 && !(tif->tif_flags&TIFF_BIGTIFF) )
{ {
if( in_datatype == TIFF_LONG8 ) if( in_datatype == TIFF_LONG8 )
datatype = TIFF_LONG; datatype = entry_type == TIFF_SHORT ? TIFF_SHORT : TIFF_LONG;
else if( in_datatype == TIFF_SLONG8 ) else if( in_datatype == TIFF_SLONG8 )
datatype = TIFF_SLONG; datatype = TIFF_SLONG;
else if( in_datatype == TIFF_IFD8 ) else if( in_datatype == TIFF_IFD8 )
@ -2870,7 +2922,8 @@ _TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype,
else else
{ {
if( in_datatype == TIFF_LONG8 && if( in_datatype == TIFF_LONG8 &&
(entry_type == TIFF_LONG || entry_type == TIFF_LONG8 ) ) (entry_type == TIFF_SHORT || entry_type == TIFF_LONG ||
entry_type == TIFF_LONG8 ) )
datatype = entry_type; datatype = entry_type;
else if( in_datatype == TIFF_SLONG8 && else if( in_datatype == TIFF_SLONG8 &&
(entry_type == TIFF_SLONG || entry_type == TIFF_SLONG8 ) ) (entry_type == TIFF_SLONG || entry_type == TIFF_SLONG8 ) )
@ -2929,6 +2982,23 @@ _TIFFRewriteField(TIFF* tif, uint16 tag, TIFFDataType in_datatype,
} }
} }
} }
else if( datatype == TIFF_SHORT && in_datatype == TIFF_LONG8 )
{
tmsize_t i;
for( i = 0; i < count; i++ )
{
((uint16 *) buf_to_write)[i] =
(uint16) ((uint64 *) data)[i];
if( (uint64) ((uint16 *) buf_to_write)[i] != ((uint64 *) data)[i] )
{
_TIFFfree( buf_to_write );
TIFFErrorExt( tif->tif_clientdata, module,
"Value exceeds 16bit range of output type." );
return 0;
}
}
}
else else
{ {
TIFFErrorExt( tif->tif_clientdata, module, TIFFErrorExt( tif->tif_clientdata, module,

View File

@ -30,6 +30,7 @@
#include "tif_config.h" #include "tif_config.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
@ -38,7 +39,6 @@
#include "tiffio.h" #include "tiffio.h"
#include "tiffiop.h" #include "tiffiop.h"
const uint32 width = 10;
const uint32 length = 40; const uint32 length = 40;
const uint32 rows_per_strip = 1; const uint32 rows_per_strip = 1;
@ -49,6 +49,7 @@ int test_packbits()
int i; int i;
unsigned char buf[10] = {0,0,0,0,0,0,0,0,0,0}; unsigned char buf[10] = {0,0,0,0,0,0,0,0,0,0};
uint32 width = 10;
int length = 20; int length = 20;
const char *filename = "test_packbits.tif"; const char *filename = "test_packbits.tif";
@ -136,17 +137,20 @@ int test_packbits()
/************************************************************************/ /************************************************************************/
/* rewrite_test() */ /* rewrite_test() */
/************************************************************************/ /************************************************************************/
int rewrite_test( const char *filename, int length, int bigtiff, int rewrite_test( const char *filename, uint32 width, int length, int bigtiff,
uint64 base_value ) uint64 base_value )
{ {
TIFF *tif; TIFF *tif;
int i; int i;
unsigned char buf[10] = {5,6,7,8,9,10,11,12,13,14}; unsigned char *buf;
uint64 *rowoffset, *rowbytes; uint64 *rowoffset, *rowbytes;
uint64 *upd_rowoffset; uint64 *upd_rowoffset;
uint64 *upd_bytecount; uint64 *upd_bytecount;
buf = calloc(1, width);
assert(buf);
/* Test whether we can write tags. */ /* Test whether we can write tags. */
if( bigtiff ) if( bigtiff )
tif = TIFFOpen(filename, "w8"); tif = TIFFOpen(filename, "w8");
@ -155,6 +159,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
if (!tif) { if (!tif) {
fprintf (stderr, "Can't create test TIFF file %s.\n", filename); fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
free(buf);
return 1; return 1;
} }
@ -202,6 +207,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
tif = TIFFOpen(filename, "r+"); tif = TIFFOpen(filename, "r+");
if (!tif) { if (!tif) {
fprintf (stderr, "Can't open test TIFF file %s.\n", filename); fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
free(buf);
return 1; return 1;
} }
@ -219,7 +225,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
upd_rowoffset = (uint64 *) _TIFFmalloc(sizeof(uint64) * length); upd_rowoffset = (uint64 *) _TIFFmalloc(sizeof(uint64) * length);
for( i = 0; i < length; i++ ) for( i = 0; i < length; i++ )
upd_rowoffset[i] = base_value + i*10; upd_rowoffset[i] = base_value + i*width;
if( !_TIFFRewriteField( tif, TIFFTAG_STRIPOFFSETS, TIFF_LONG8, if( !_TIFFRewriteField( tif, TIFFTAG_STRIPOFFSETS, TIFF_LONG8,
length, upd_rowoffset ) ) length, upd_rowoffset ) )
@ -232,7 +238,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
upd_bytecount = (uint64 *) _TIFFmalloc(sizeof(uint64) * length); upd_bytecount = (uint64 *) _TIFFmalloc(sizeof(uint64) * length);
for( i = 0; i < length; i++ ) for( i = 0; i < length; i++ )
upd_bytecount[i] = 100 + i*10; upd_bytecount[i] = 100 + i*width;
if( !_TIFFRewriteField( tif, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG8, if( !_TIFFRewriteField( tif, TIFFTAG_STRIPBYTECOUNTS, TIFF_LONG8,
length, upd_bytecount ) ) length, upd_bytecount ) )
@ -250,6 +256,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
tif = TIFFOpen(filename, "r"); tif = TIFFOpen(filename, "r");
if (!tif) { if (!tif) {
fprintf (stderr, "Can't open test TIFF file %s.\n", filename); fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
free(buf);
return 1; return 1;
} }
@ -261,7 +268,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
for( i = 0; i < length; i++ ) for( i = 0; i < length; i++ )
{ {
uint64 expect = base_value + i*10; uint64 expect = base_value + i*width;
if( rowoffset[i] != expect ) if( rowoffset[i] != expect )
{ {
@ -284,7 +291,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
for( i = 0; i < length; i++ ) for( i = 0; i < length; i++ )
{ {
uint64 expect = 100 + i*10; uint64 expect = 100 + i*width;
if( rowbytes[i] != expect ) if( rowbytes[i] != expect )
{ {
@ -300,6 +307,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
} }
TIFFClose( tif ); TIFFClose( tif );
free(buf);
/* All tests passed; delete file and exit with success status. */ /* All tests passed; delete file and exit with success status. */
unlink(filename); unlink(filename);
@ -308,6 +316,7 @@ int rewrite_test( const char *filename, int length, int bigtiff,
failure: failure:
/* Something goes wrong; close file and return unsuccessful status. */ /* Something goes wrong; close file and return unsuccessful status. */
TIFFClose(tif); TIFFClose(tif);
free(buf);
/* unlink(filename); */ /* unlink(filename); */
return 1; return 1;
@ -325,16 +334,20 @@ main(void)
failure |= test_packbits(); failure |= test_packbits();
/* test fairly normal use */ /* test fairly normal use */
failure |= rewrite_test( "rewrite1.tif", 10, 0, 100 ); failure |= rewrite_test( "rewrite1.tif", 10, 10, 0, 100 );
failure |= rewrite_test( "rewrite2.tif", 10, 1, 100 ); failure |= rewrite_test( "rewrite2.tif", 10, 10, 1, 100 );
/* test case of fitting all in directory entry */ /* test case of fitting all in directory entry */
failure |= rewrite_test( "rewrite3.tif", 1, 0, 100 ); failure |= rewrite_test( "rewrite3.tif", 10, 1, 0, 100 );
failure |= rewrite_test( "rewrite4.tif", 1, 1, 100 ); failure |= rewrite_test( "rewrite4.tif", 10, 1, 1, 100 );
/* test with very large values that don't fit in 4bytes (bigtiff only) */ /* test with very large values that don't fit in 4bytes (bigtiff only) */
failure |= rewrite_test( "rewrite5.tif", 1000, 1, 0x6000000000ULL ); failure |= rewrite_test( "rewrite5.tif", 10, 1000, 1, 0x6000000000ULL );
failure |= rewrite_test( "rewrite6.tif", 1, 1, 0x6000000000ULL ); failure |= rewrite_test( "rewrite6.tif", 10, 1, 1, 0x6000000000ULL );
/* StripByteCounts on LONG */
failure |= rewrite_test( "rewrite7.tif", 65536, 1, 0, 100 );
failure |= rewrite_test( "rewrite8.tif", 65536, 2, 0, 100 );
return failure; return failure;
} }