add fail-on : better control over loader error handling (#2360)
Instead of a simple fail/don't-fail boolean switch, add fail-on, an enum which sets the sensitivity of loaders to errors. There's a new sensitivity level which tries to detect truncated images, but ignores other types of error.
This commit is contained in:
parent
5f101b4f2e
commit
0c70f3dc7d
@ -75,8 +75,8 @@ im_tiff_read_header( const char *filename, VipsImage *out,
|
||||
|
||||
if( !(source = vips_source_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__tiff_read_header_source( source,
|
||||
out, page, n, autorotate, -1 ) ) {
|
||||
if( vips__tiff_read_header_source( source, out,
|
||||
page, n, autorotate, -1, VIPS_FAIL_ON_ERROR ) ) {
|
||||
VIPS_UNREF( source );
|
||||
return( -1 );
|
||||
}
|
||||
@ -93,7 +93,8 @@ im_tiff_read( const char *filename, VipsImage *out,
|
||||
|
||||
if( !(source = vips_source_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__tiff_read_source( source, out, page, n, autorotate, -1 ) ) {
|
||||
if( vips__tiff_read_source( source, out,
|
||||
page, n, autorotate, -1, VIPS_FAIL_ON_ERROR ) ) {
|
||||
VIPS_UNREF( source );
|
||||
return( -1 );
|
||||
}
|
||||
|
@ -421,12 +421,17 @@ vips_foreign_load_csv_load( VipsForeignLoad *load )
|
||||
*/
|
||||
ch = EOF;
|
||||
|
||||
/* Some lines may be shorter.
|
||||
*/
|
||||
memset( csv->linebuf, 0, load->real->Xsize * sizeof( double ) );
|
||||
|
||||
for( x = 0; x < load->real->Xsize; x++ ) {
|
||||
double value;
|
||||
|
||||
csv->colno += 1;
|
||||
ch = vips_foreign_load_csv_read_double( csv, &value );
|
||||
if( ch == EOF ) {
|
||||
if( ch == EOF &&
|
||||
load->fail_on >= VIPS_FAIL_ON_TRUNCATED ) {
|
||||
vips_error( class->nickname,
|
||||
"%s", _( "unexpected end of file" ) );
|
||||
return( -1 );
|
||||
@ -436,7 +441,9 @@ vips_foreign_load_csv_load( VipsForeignLoad *load )
|
||||
vips_error( class->nickname,
|
||||
_( "line %d has only %d columns" ),
|
||||
csv->lineno, csv->colno );
|
||||
if( load->fail )
|
||||
/* Unequal length lines, but no EOF.
|
||||
*/
|
||||
if( load->fail_on >= VIPS_FAIL_ON_ERROR )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
@ -671,7 +678,7 @@ vips_foreign_load_csv_source_init( VipsForeignLoadCsvSource *source )
|
||||
* * @lines: read this many lines from file
|
||||
* * @whitespace: set of whitespace characters
|
||||
* * @separator: set of separator characters
|
||||
* * @fail: %gboolean, fail on errors
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Load a CSV (comma-separated values) file. The output image is always 1
|
||||
* band (monochrome), #VIPS_FORMAT_DOUBLE. Use vips_bandfold() to turn
|
||||
@ -695,7 +702,8 @@ vips_foreign_load_csv_source_init( VipsForeignLoadCsvSource *source )
|
||||
* @separator sets the characters that separate fields.
|
||||
* Default ;,<emphasis>tab</emphasis>. Separators are never run together.
|
||||
*
|
||||
* Setting @fail to %TRUE makes the reader fail on any errors.
|
||||
* Use @fail_on to set the type of error that will cause load to fail. By
|
||||
* default, loaders are permissive, that is, #VIPS_FAIL_ON_NONE.
|
||||
*
|
||||
* See also: vips_image_new_from_file(), vips_bandfold().
|
||||
*
|
||||
@ -726,7 +734,7 @@ vips_csvload( const char *filename, VipsImage **out, ... )
|
||||
* * @lines: read this many lines from file
|
||||
* * @whitespace: set of whitespace characters
|
||||
* * @separator: set of separator characters
|
||||
* * @fail: %gboolean, fail on errors
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Exactly as vips_csvload(), but read from a source.
|
||||
*
|
||||
@ -747,6 +755,3 @@ vips_csvload_source( VipsSource *source, VipsImage **out, ... )
|
||||
return( result );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
* - block _start if one start fails, see #893
|
||||
* 1/4/18
|
||||
* - drop incompatible ICC profiles before save
|
||||
* 24/7/21
|
||||
* - add fail-on
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -1061,6 +1063,13 @@ vips_foreign_load_build( VipsObject *object )
|
||||
if( sequential )
|
||||
load->nocache = TRUE;
|
||||
|
||||
/* The deprecated "fail" field sets fail_on warning.
|
||||
*/
|
||||
if( vips_object_argument_isset( object, "fail" ) &&
|
||||
!vips_object_argument_isset( object, "fail_on" ) )
|
||||
load->fail_on = load->fail ?
|
||||
VIPS_FAIL_ON_WARNING : VIPS_FAIL_ON_NONE;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_foreign_load_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
@ -1184,21 +1193,28 @@ vips_foreign_load_class_init( VipsForeignLoadClass *class )
|
||||
G_STRUCT_OFFSET( VipsForeignLoad, access ),
|
||||
VIPS_TYPE_ACCESS, VIPS_ACCESS_RANDOM );
|
||||
|
||||
VIPS_ARG_BOOL( class, "sequential", 109,
|
||||
VIPS_ARG_ENUM( class, "fail-on", 109,
|
||||
_( "Fail on" ),
|
||||
_( "Error level to fail on" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoad, fail_on ),
|
||||
VIPS_TYPE_FAIL_ON, VIPS_FAIL_ON_NONE );
|
||||
|
||||
VIPS_ARG_BOOL( class, "sequential", 110,
|
||||
_( "Sequential" ),
|
||||
_( "Sequential read only" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
|
||||
G_STRUCT_OFFSET( VipsForeignLoad, sequential ),
|
||||
FALSE );
|
||||
|
||||
VIPS_ARG_BOOL( class, "fail", 110,
|
||||
VIPS_ARG_BOOL( class, "fail", 111,
|
||||
_( "Fail" ),
|
||||
_( "Fail on first error" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
_( "Fail on first warning" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
|
||||
G_STRUCT_OFFSET( VipsForeignLoad, fail ),
|
||||
FALSE );
|
||||
|
||||
VIPS_ARG_BOOL( class, "disc", 111,
|
||||
VIPS_ARG_BOOL( class, "disc", 112,
|
||||
_( "Disc" ),
|
||||
_( "Open to disc" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
|
||||
@ -1212,6 +1228,7 @@ vips_foreign_load_init( VipsForeignLoad *load )
|
||||
{
|
||||
load->disc = TRUE;
|
||||
load->access = VIPS_ACCESS_RANDOM;
|
||||
load->fail_on = VIPS_FAIL_ON_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -827,7 +827,10 @@ vips_foreign_load_jp2k_generate( VipsRegion *out,
|
||||
y += hit.height;
|
||||
}
|
||||
|
||||
if( load->fail &&
|
||||
/* jp2k files can't be truncated (they fail to open), so all we can
|
||||
* spot is errors.
|
||||
*/
|
||||
if( load->fail_on >= VIPS_FAIL_ON_ERROR &&
|
||||
jp2k->n_errors > 0 )
|
||||
return( -1 );
|
||||
|
||||
@ -1280,20 +1283,21 @@ vips__foreign_load_jp2k_decompress( VipsImage *out,
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @page: %gint, load this page
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Read a JPEG2000 image. The loader supports 8, 16 and 32-bit int pixel
|
||||
* values, signed and unsigned.
|
||||
* It supports greyscale, RGB, YCC, CMYK and
|
||||
* multispectral colour spaces.
|
||||
* It will read any ICC profile on
|
||||
* the image.
|
||||
* values, signed and unsigned. It supports greyscale, RGB, YCC, CMYK and
|
||||
* multispectral colour spaces. It will read any ICC profile on the image.
|
||||
*
|
||||
* It will only load images where all channels are the same format.
|
||||
* It will only load images where all channels have the same format.
|
||||
*
|
||||
* Use @page to set the page to load, where page 0 is the base resolution
|
||||
* image and higher-numbered pages are x2 reductions. Use the metadata item
|
||||
* "n-pages" to find the number of pyramid layers.
|
||||
*
|
||||
* Use @fail_on to set the type of error that will cause load to fail. By
|
||||
* default, loaders are permissive, that is, #VIPS_FAIL_ON_NONE.
|
||||
*
|
||||
* See also: vips_image_new_from_file().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
@ -1321,8 +1325,12 @@ vips_jp2kload( const char *filename, VipsImage **out, ... )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @page: %gint, load this page
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Exactly as vips_jp2kload(), but read from a source.
|
||||
* Exactly as vips_jp2kload(), but read from a buffer.
|
||||
*
|
||||
* You must not free the buffer while @out is active. The
|
||||
* #VipsObject::postclose signal on @out is a good place to free.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
@ -1355,6 +1363,7 @@ vips_jp2kload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @page: %gint, load this page
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Exactly as vips_jp2kload(), but read from a source.
|
||||
*
|
||||
|
@ -110,6 +110,8 @@
|
||||
* - better handling of JFIF res unit 0
|
||||
* 13/9/20
|
||||
* - set resolution unit from JFIF
|
||||
* 24/7/21
|
||||
* - add fail-on support
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -171,9 +173,9 @@ typedef struct _ReadJpeg {
|
||||
*/
|
||||
int shrink;
|
||||
|
||||
/* Fail on warning.
|
||||
/* Types of error to cause failure.
|
||||
*/
|
||||
gboolean fail;
|
||||
VipsFailOn fail_on;
|
||||
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
ErrorManager eman;
|
||||
@ -249,7 +251,7 @@ source_fill_input_buffer( j_decompress_ptr cinfo )
|
||||
src->pub.bytes_in_buffer = read;
|
||||
}
|
||||
else {
|
||||
if( src->jpeg->fail )
|
||||
if( src->jpeg->fail_on >= VIPS_FAIL_ON_TRUNCATED )
|
||||
ERREXIT( cinfo, JERR_INPUT_EOF );
|
||||
else
|
||||
WARNMS( cinfo, JWRN_JPEG_EOF );
|
||||
@ -355,7 +357,7 @@ readjpeg_minimise_cb( VipsImage *image, ReadJpeg *jpeg )
|
||||
|
||||
static ReadJpeg *
|
||||
readjpeg_new( VipsSource *source, VipsImage *out,
|
||||
int shrink, gboolean fail, gboolean autorotate )
|
||||
int shrink, VipsFailOn fail_on, gboolean autorotate )
|
||||
{
|
||||
ReadJpeg *jpeg;
|
||||
|
||||
@ -365,7 +367,7 @@ readjpeg_new( VipsSource *source, VipsImage *out,
|
||||
jpeg->source = source;
|
||||
g_object_ref( source );
|
||||
jpeg->shrink = shrink;
|
||||
jpeg->fail = fail;
|
||||
jpeg->fail_on = fail_on;
|
||||
jpeg->cinfo.err = jpeg_std_error( &jpeg->eman.pub );
|
||||
jpeg->eman.pub.error_exit = vips__new_error_exit;
|
||||
jpeg->eman.pub.output_message = vips__new_output_message;
|
||||
@ -805,13 +807,8 @@ read_jpeg_generate( VipsRegion *or,
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* If --fail is set, we make read fail on any warnings. This
|
||||
* will stop on any errors from the previous jpeg_read_scanlines().
|
||||
* libjpeg warnings are used for serious image corruption, like
|
||||
* truncated files.
|
||||
*/
|
||||
if( jpeg->eman.pub.num_warnings > 0 &&
|
||||
jpeg->fail ) {
|
||||
jpeg->fail_on >= VIPS_FAIL_ON_WARNING ) {
|
||||
VIPS_GATE_STOP( "read_jpeg_generate: work" );
|
||||
|
||||
/* Only fail once.
|
||||
@ -952,11 +949,13 @@ vips__jpeg_read( ReadJpeg *jpeg, VipsImage *out, gboolean header_only )
|
||||
|
||||
int
|
||||
vips__jpeg_read_source( VipsSource *source, VipsImage *out,
|
||||
gboolean header_only, int shrink, int fail, gboolean autorotate )
|
||||
gboolean header_only, int shrink, VipsFailOn fail_on,
|
||||
gboolean autorotate )
|
||||
{
|
||||
ReadJpeg *jpeg;
|
||||
|
||||
if( !(jpeg = readjpeg_new( source, out, shrink, fail, autorotate )) )
|
||||
if( !(jpeg = readjpeg_new( source, out, shrink, fail_on,
|
||||
autorotate )) )
|
||||
return( -1 );
|
||||
|
||||
if( setjmp( jpeg->eman.jmp ) )
|
||||
|
@ -4,6 +4,8 @@
|
||||
* - wrap a class around the jpeg writer
|
||||
* 29/11/11
|
||||
* - split to make load, load from buffer and load from file
|
||||
* 24/7/21
|
||||
* - add fail-on support
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -137,7 +139,8 @@ vips_foreign_load_jpeg_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
|
||||
|
||||
if( vips__jpeg_read_source( jpeg->source,
|
||||
load->out, TRUE, jpeg->shrink, load->fail, jpeg->autorotate ) )
|
||||
load->out, TRUE, jpeg->shrink, load->fail_on,
|
||||
jpeg->autorotate ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -149,7 +152,7 @@ vips_foreign_load_jpeg_load( VipsForeignLoad *load )
|
||||
VipsForeignLoadJpeg *jpeg = (VipsForeignLoadJpeg *) load;
|
||||
|
||||
if( vips__jpeg_read_source( jpeg->source,
|
||||
load->real, FALSE, jpeg->shrink, load->fail,
|
||||
load->real, FALSE, jpeg->shrink, load->fail_on,
|
||||
jpeg->autorotate ) )
|
||||
return( -1 );
|
||||
|
||||
@ -435,7 +438,7 @@ vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @shrink: %gint, shrink by this much on load
|
||||
* * @fail: %gboolean, fail on errors
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
* * @autorotate: %gboolean, rotate image upright during load
|
||||
*
|
||||
* Read a JPEG file into a VIPS image. It can read most 8-bit JPEG images,
|
||||
@ -445,9 +448,8 @@ vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer )
|
||||
* are 1, 2, 4 and 8. Shrinking during read is very much faster than
|
||||
* decompressing the whole image and then shrinking later.
|
||||
*
|
||||
* Setting @fail to %TRUE makes the JPEG reader fail on any errors.
|
||||
* This can be useful for detecting truncated files, for example. Normally
|
||||
* reading these produces a warning, but no fatal error.
|
||||
* Use @fail_on to set the type of error that will cause load to fail. By
|
||||
* default, loaders are permissive, that is, #VIPS_FAIL_ON_NONE.
|
||||
*
|
||||
* Setting @autorotate to %TRUE will make the loader interpret the
|
||||
* orientation tag and automatically rotate the image appropriately during
|
||||
@ -465,7 +467,7 @@ vips_foreign_load_jpeg_buffer_init( VipsForeignLoadJpegBuffer *buffer )
|
||||
* |[
|
||||
* vips_jpegload( "fred.jpg", &out,
|
||||
* "shrink", 8,
|
||||
* "fail", TRUE,
|
||||
* "fail-on", VIPS_FAIL_ON_TRUNCATED,
|
||||
* NULL );
|
||||
* ]|
|
||||
*
|
||||
@ -517,7 +519,7 @@ vips_jpegload( const char *filename, VipsImage **out, ... )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @shrink: %gint, shrink by this much on load
|
||||
* * @fail: %gboolean, fail on errors
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
* * @autorotate: %gboolean, use exif Orientation tag to rotate the image
|
||||
* during load
|
||||
*
|
||||
@ -560,7 +562,7 @@ vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @shrink: %gint, shrink by this much on load
|
||||
* * @fail: %gboolean, fail on errors
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
* * @autorotate: %gboolean, use exif Orientation tag to rotate the image
|
||||
* during load
|
||||
*
|
||||
|
@ -384,7 +384,7 @@ vips_foreign_load_nsgif_header( VipsForeignLoad *load )
|
||||
return( -1 );
|
||||
}
|
||||
else if( result == GIF_INSUFFICIENT_FRAME_DATA &&
|
||||
load->fail ) {
|
||||
load->fail_on >= VIPS_FAIL_ON_TRUNCATED ) {
|
||||
vips_error( class->nickname, "%s", _( "truncated GIF" ) );
|
||||
return( -1 );
|
||||
}
|
||||
@ -887,6 +887,7 @@ vips_foreign_load_nsgif_source_init( VipsForeignLoadNsgifSource *source )
|
||||
*
|
||||
* * @page: %gint, page (frame) to read
|
||||
* * @n: %gint, load this many pages
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Read a GIF file into a libvips image.
|
||||
*
|
||||
@ -896,6 +897,9 @@ vips_foreign_load_nsgif_source_init( VipsForeignLoadNsgifSource *source )
|
||||
* rendered in a vertical column. Set to -1 to mean "until the end of the
|
||||
* document". Use vips_grid() to change page layout.
|
||||
*
|
||||
* Use @fail_on to set the type of error that will cause load to fail. By
|
||||
* default, loaders are permissive, that is, #VIPS_FAIL_ON_NONE.
|
||||
*
|
||||
* The output image is RGBA for GIFs containing transparent elements, RGB
|
||||
* otherwise.
|
||||
*
|
||||
@ -927,9 +931,9 @@ vips_gifload( const char *filename, VipsImage **out, ... )
|
||||
*
|
||||
* * @page: %gint, page (frame) to read
|
||||
* * @n: %gint, load this many pages
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Read a GIF-formatted memory block into a VIPS image. Exactly as
|
||||
* vips_gifload(), but read from a memory buffer.
|
||||
* Exactly as vips_gifload(), but read from a memory buffer.
|
||||
*
|
||||
* You must not free the buffer while @out is active. The
|
||||
* #VipsObject::postclose signal on @out is a good place to free.
|
||||
@ -968,6 +972,7 @@ vips_gifload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
*
|
||||
* * @page: %gint, page (frame) to read
|
||||
* * @n: %gint, load this many pages
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
*
|
||||
* Exactly as vips_gifload(), but read from a source.
|
||||
*
|
||||
|
@ -96,9 +96,9 @@ int vips__tiff_write_buf( VipsImage *in,
|
||||
gboolean vips__istiff_source( VipsSource *source );
|
||||
gboolean vips__istifftiled_source( VipsSource *source );
|
||||
int vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate, int subifd );
|
||||
int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on );
|
||||
int vips__tiff_read_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate, int subifd );
|
||||
int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on );
|
||||
|
||||
extern const char *vips__foreign_tiff_suffs[];
|
||||
|
||||
@ -108,16 +108,6 @@ int vips__analyze_read( const char *filename, VipsImage *out );
|
||||
|
||||
extern const char *vips__foreign_csv_suffs[];
|
||||
|
||||
int vips__csv_read( const char *filename, VipsImage *out,
|
||||
int skip, int lines, const char *whitespace, const char *separator,
|
||||
gboolean fail );
|
||||
int vips__csv_read_header( const char *filename, VipsImage *out,
|
||||
int skip, int lines, const char *whitespace, const char *separator,
|
||||
gboolean fail );
|
||||
|
||||
int vips__csv_write( VipsImage *in, const char *filename,
|
||||
const char *separator );
|
||||
|
||||
int vips__matrix_read_header( const char *filename,
|
||||
int *width, int *height, double *scale, double *offset );
|
||||
int vips__matrix_ismatrix( const char *filename );
|
||||
@ -183,13 +173,15 @@ int vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
|
||||
VipsForeignSubsample subsample_mode, int restart_interval );
|
||||
|
||||
int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
|
||||
gboolean header_only, int shrink, int fail, gboolean autorotate );
|
||||
gboolean header_only, int shrink, VipsFailOn fail_on,
|
||||
gboolean autorotate );
|
||||
int vips__isjpeg_source( VipsSource *source );
|
||||
|
||||
int vips__png_ispng_source( VipsSource *source );
|
||||
int vips__png_header_source( VipsSource *source, VipsImage *out, gboolean unlimited );
|
||||
int vips__png_header_source( VipsSource *source, VipsImage *out,
|
||||
gboolean unlimited );
|
||||
int vips__png_read_source( VipsSource *source, VipsImage *out,
|
||||
gboolean fail, gboolean unlimited );
|
||||
VipsFailOn fail_on, gboolean unlimited );
|
||||
gboolean vips__png_isinterlaced_source( VipsSource *source );
|
||||
extern const char *vips__png_suffs[];
|
||||
|
||||
|
@ -136,7 +136,7 @@ vips_foreign_load_png_load( VipsForeignLoad *load )
|
||||
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||
|
||||
if( vips__png_read_source( png->source, load->real,
|
||||
load->fail, png->unlimited ) )
|
||||
load->fail_on, png->unlimited ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -412,6 +412,7 @@ vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *buffer )
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
* * @unlimited: %gboolean, remove all denial of service limits
|
||||
*
|
||||
* Read a PNG file into a VIPS image. It can read all png images, including 8-
|
||||
@ -420,6 +421,9 @@ vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *buffer )
|
||||
* Any ICC profile is read and attached to the VIPS image. It also supports
|
||||
* XMP metadata.
|
||||
*
|
||||
* Use @fail_on to set the type of error that will cause load to fail. By
|
||||
* default, loaders are permissive, that is, #VIPS_FAIL_ON_NONE.
|
||||
*
|
||||
* By default, the PNG loader limits the number of text and data chunks to
|
||||
* block some denial of service attacks. Set @unlimited to disable these
|
||||
* limits.
|
||||
@ -450,6 +454,7 @@ vips_pngload( const char *filename, VipsImage **out, ... )
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
* * @unlimited: %gboolean, Remove all denial of service limits
|
||||
*
|
||||
* Exactly as vips_pngload(), but read from a PNG-formatted memory block.
|
||||
@ -489,6 +494,7 @@ vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @fail_on: #VipsFailOn, types of read error to fail on
|
||||
* * @unlimited: %gboolean, Remove all denial of service limits
|
||||
*
|
||||
* Exactly as vips_pngload(), but read from a source.
|
||||
|
@ -342,10 +342,10 @@ vips_foreign_load_png_header( VipsForeignLoad *load )
|
||||
/* In non-fail mode, ignore CRC errors.
|
||||
*/
|
||||
flags = 0;
|
||||
if( !load->fail )
|
||||
if( load->fail_on >= VIPS_FAIL_ON_ERROR )
|
||||
flags |= SPNG_CTX_IGNORE_ADLER32;
|
||||
png->ctx = spng_ctx_new( flags );
|
||||
if( !load->fail )
|
||||
if( load->fail_on >= VIPS_FAIL_ON_ERROR )
|
||||
/* Ignore and don't calculate checksums.
|
||||
*/
|
||||
spng_set_crc_action( png->ctx, SPNG_CRC_USE, SPNG_CRC_USE );
|
||||
@ -557,11 +557,11 @@ vips_foreign_load_png_generate( VipsRegion *or,
|
||||
g_warning( "%s: %s",
|
||||
class->nickname, spng_strerror( error ) );
|
||||
|
||||
/* And bail if fail is on.
|
||||
/* And bail if trunc is on.
|
||||
*/
|
||||
if( load->fail ) {
|
||||
if( load->fail_on >= VIPS_FAIL_ON_TRUNCATED ) {
|
||||
vips_error( class->nickname,
|
||||
"%s", _( "libpng read error" ) );
|
||||
"%s", _( "libspng read error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
|
@ -203,6 +203,8 @@
|
||||
* - support 2 and 4 bit greyscale load
|
||||
* 27/3/21
|
||||
* - add jp2k decompresion
|
||||
* 24/7/21
|
||||
* - add fail_on
|
||||
* 30/9/21
|
||||
* - fix tiled + packed formats
|
||||
*/
|
||||
@ -361,6 +363,7 @@ typedef struct _Rtiff {
|
||||
int n;
|
||||
gboolean autorotate;
|
||||
int subifd;
|
||||
VipsFailOn fail_on;
|
||||
|
||||
/* The TIFF we read.
|
||||
*/
|
||||
@ -574,7 +577,7 @@ rtiff_minimise_cb( VipsImage *image, Rtiff *rtiff )
|
||||
|
||||
static Rtiff *
|
||||
rtiff_new( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate, int subifd )
|
||||
int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on )
|
||||
{
|
||||
Rtiff *rtiff;
|
||||
|
||||
@ -588,6 +591,7 @@ rtiff_new( VipsSource *source, VipsImage *out,
|
||||
rtiff->n = n;
|
||||
rtiff->autorotate = autorotate;
|
||||
rtiff->subifd = subifd;
|
||||
rtiff->fail_on = fail_on;
|
||||
rtiff->tiff = NULL;
|
||||
rtiff->n_pages = 0;
|
||||
rtiff->current_page = -1;
|
||||
@ -2863,13 +2867,14 @@ vips__istifftiled_source( VipsSource *source )
|
||||
|
||||
int
|
||||
vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate, int subifd )
|
||||
int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on )
|
||||
{
|
||||
Rtiff *rtiff;
|
||||
|
||||
vips__tiff_init();
|
||||
|
||||
if( !(rtiff = rtiff_new( source, out, page, n, autorotate, subifd )) ||
|
||||
if( !(rtiff = rtiff_new( source, out,
|
||||
page, n, autorotate, subifd, fail_on )) ||
|
||||
rtiff_header_read_all( rtiff ) )
|
||||
return( -1 );
|
||||
|
||||
@ -2892,7 +2897,7 @@ vips__tiff_read_header_source( VipsSource *source, VipsImage *out,
|
||||
|
||||
int
|
||||
vips__tiff_read_source( VipsSource *source, VipsImage *out,
|
||||
int page, int n, gboolean autorotate, int subifd )
|
||||
int page, int n, gboolean autorotate, int subifd, VipsFailOn fail_on )
|
||||
{
|
||||
Rtiff *rtiff;
|
||||
|
||||
@ -2902,7 +2907,8 @@ vips__tiff_read_source( VipsSource *source, VipsImage *out,
|
||||
|
||||
vips__tiff_init();
|
||||
|
||||
if( !(rtiff = rtiff_new( source, out, page, n, autorotate, subifd )) ||
|
||||
if( !(rtiff = rtiff_new( source, out,
|
||||
page, n, autorotate, subifd, fail_on )) ||
|
||||
rtiff_header_read_all( rtiff ) )
|
||||
return( -1 );
|
||||
|
||||
|
@ -137,7 +137,8 @@ vips_foreign_load_tiff_header( VipsForeignLoad *load )
|
||||
VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
|
||||
|
||||
if( vips__tiff_read_header_source( tiff->source, load->out,
|
||||
tiff->page, tiff->n, tiff->autorotate, tiff->subifd ) )
|
||||
tiff->page, tiff->n, tiff->autorotate, tiff->subifd,
|
||||
load->fail_on ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -149,7 +150,8 @@ vips_foreign_load_tiff_load( VipsForeignLoad *load )
|
||||
VipsForeignLoadTiff *tiff = (VipsForeignLoadTiff *) load;
|
||||
|
||||
if( vips__tiff_read_source( tiff->source, load->real,
|
||||
tiff->page, tiff->n, tiff->autorotate, tiff->subifd ) )
|
||||
tiff->page, tiff->n, tiff->autorotate, tiff->subifd,
|
||||
load->fail_on ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
|
@ -174,7 +174,7 @@ user_warning_function( png_structp png_ptr, png_const_charp warning_msg )
|
||||
typedef struct {
|
||||
char *name;
|
||||
VipsImage *out;
|
||||
gboolean fail;
|
||||
VipsFailOn fail_on;
|
||||
gboolean unlimited;
|
||||
|
||||
int y_pos;
|
||||
@ -259,7 +259,7 @@ vips_png_read_source( png_structp pPng, png_bytep data, png_size_t length )
|
||||
|
||||
static Read *
|
||||
read_new( VipsSource *source, VipsImage *out,
|
||||
gboolean fail, gboolean unlimited )
|
||||
VipsFailOn fail_on, gboolean unlimited )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
@ -267,7 +267,7 @@ read_new( VipsSource *source, VipsImage *out,
|
||||
return( NULL );
|
||||
|
||||
read->name = NULL;
|
||||
read->fail = fail;
|
||||
read->fail_on = fail_on;
|
||||
read->out = out;
|
||||
read->y_pos = 0;
|
||||
read->pPng = NULL;
|
||||
@ -727,7 +727,7 @@ png2vips_generate( VipsRegion *or,
|
||||
* message, since the handler we install just does
|
||||
* g_warning().
|
||||
*/
|
||||
if( read->fail ) {
|
||||
if( read->fail_on >= VIPS_FAIL_ON_TRUNCATED ) {
|
||||
vips_error( "vipspng",
|
||||
"%s", _( "libpng read error" ) );
|
||||
return( -1 );
|
||||
@ -805,11 +805,11 @@ vips__png_header_source( VipsSource *source, VipsImage *out,
|
||||
|
||||
int
|
||||
vips__png_read_source( VipsSource *source, VipsImage *out,
|
||||
gboolean fail, gboolean unlimited )
|
||||
VipsFailOn fail_on, gboolean unlimited )
|
||||
{
|
||||
Read *read;
|
||||
|
||||
if( !(read = read_new( source, out, fail, unlimited )) ||
|
||||
if( !(read = read_new( source, out, fail_on, unlimited )) ||
|
||||
png2vips_image( read, out ) ||
|
||||
vips_source_decode( source ) ) {
|
||||
vips_error( "png2vips", _( "unable to read source %s" ),
|
||||
|
@ -56,6 +56,8 @@ GType vips_combine_mode_get_type (void) G_GNUC_CONST;
|
||||
/* enumerations from "../../../libvips/include/vips/foreign.h" */
|
||||
GType vips_foreign_flags_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_FOREIGN_FLAGS (vips_foreign_flags_get_type())
|
||||
GType vips_fail_on_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_FAIL_ON (vips_fail_on_get_type())
|
||||
GType vips_saveable_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_SAVEABLE (vips_saveable_get_type())
|
||||
GType vips_foreign_subsample_get_type (void) G_GNUC_CONST;
|
||||
|
@ -100,6 +100,27 @@ typedef enum /*< flags >*/ {
|
||||
VIPS_FOREIGN_ALL = 7 /* All flags set */
|
||||
} VipsForeignFlags;
|
||||
|
||||
/**
|
||||
* VipsFailOn:
|
||||
* @VIPS_FAIL_ON_NONE: never stop
|
||||
* @VIPS_FAIL_ON_TRUNCATED: stop on image truncated, nothing else
|
||||
* @VIPS_FAIL_ON_ERROR: stop on serious error or truncation
|
||||
* @VIPS_FAIL_ON_WARNING: stop on anything, even warnings
|
||||
*
|
||||
* How sensitive loaders are to errors, from never stop (very insensitive), to
|
||||
* stop on the smallest warning (very sensitive).
|
||||
*
|
||||
* Each one implies the ones before it, so #VIPS_FAIL_ON_ERROR implies
|
||||
* #VIPS_FAIL_ON_TRUNCATED.
|
||||
*/
|
||||
typedef enum {
|
||||
VIPS_FAIL_ON_NONE,
|
||||
VIPS_FAIL_ON_TRUNCATED,
|
||||
VIPS_FAIL_ON_ERROR,
|
||||
VIPS_FAIL_ON_WARNING,
|
||||
VIPS_FAIL_ON_LAST
|
||||
} VipsFailOn;
|
||||
|
||||
#define VIPS_TYPE_FOREIGN_LOAD (vips_foreign_load_get_type())
|
||||
#define VIPS_FOREIGN_LOAD( obj ) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
|
||||
@ -131,12 +152,13 @@ typedef struct _VipsForeignLoad {
|
||||
*/
|
||||
VipsForeignFlags flags;
|
||||
|
||||
/* Stop load on first warning.
|
||||
/* Behaviour on error.
|
||||
*/
|
||||
VipsFailOn fail_on;
|
||||
|
||||
/* Deprecated and unused. Just here for compat.
|
||||
*/
|
||||
gboolean fail;
|
||||
|
||||
/* Deprecated and unused, just here for compat.
|
||||
*/
|
||||
gboolean sequential;
|
||||
|
||||
/*< public >*/
|
||||
|
@ -479,6 +479,26 @@ vips_foreign_flags_get_type( void )
|
||||
return( etype );
|
||||
}
|
||||
GType
|
||||
vips_fail_on_get_type( void )
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
||||
if( etype == 0 ) {
|
||||
static const GEnumValue values[] = {
|
||||
{VIPS_FAIL_ON_NONE, "VIPS_FAIL_ON_NONE", "none"},
|
||||
{VIPS_FAIL_ON_TRUNCATED, "VIPS_FAIL_ON_TRUNCATED", "truncated"},
|
||||
{VIPS_FAIL_ON_ERROR, "VIPS_FAIL_ON_ERROR", "error"},
|
||||
{VIPS_FAIL_ON_WARNING, "VIPS_FAIL_ON_WARNING", "warning"},
|
||||
{VIPS_FAIL_ON_LAST, "VIPS_FAIL_ON_LAST", "last"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
etype = g_enum_register_static( "VipsFailOn", values );
|
||||
}
|
||||
|
||||
return( etype );
|
||||
}
|
||||
GType
|
||||
vips_saveable_get_type( void )
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
@ -1277,5 +1277,33 @@ class TestForeign:
|
||||
assert x1.get("page-height") == x2.get("page-height")
|
||||
assert x1.get("loop") == x2.get("loop")
|
||||
|
||||
def test_fail_on(self):
|
||||
# csvload should spot trunc correctly
|
||||
target = pyvips.Target.new_to_memory()
|
||||
self.mono.write_to_target(target, ".csv")
|
||||
buf = target.get("blob")
|
||||
|
||||
source = pyvips.Source.new_from_memory(buf)
|
||||
im = pyvips.Image.csvload_source(source)
|
||||
assert im.avg() > 0
|
||||
|
||||
# truncation should be OK by default
|
||||
buf_trunc = buf[:-100]
|
||||
source = pyvips.Source.new_from_memory(buf_trunc)
|
||||
im = pyvips.Image.csvload_source(source)
|
||||
assert im.avg() > 0
|
||||
|
||||
# set trunc should make it fail
|
||||
with pytest.raises(Exception) as e_info:
|
||||
im = pyvips.Image.csvload_source(source, fail_on="truncated")
|
||||
# this will now force parsing of the whole file, which should
|
||||
# trigger an error
|
||||
im.avg() > 0
|
||||
|
||||
# warn should fail too, since trunc implies warn
|
||||
with pytest.raises(Exception) as e_info:
|
||||
im = pyvips.Image.csvload_source(source, fail_on="warning")
|
||||
im.avg() > 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user