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:
John Cupitt 2021-10-31 14:13:18 +00:00 committed by GitHub
parent 5f101b4f2e
commit 0c70f3dc7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 203 additions and 87 deletions

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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;
}
/*

View File

@ -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.
*

View File

@ -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 ) )

View File

@ -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", &amp;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
*

View File

@ -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.
*

View File

@ -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[];

View File

@ -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.

View File

@ -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 );
}
}

View File

@ -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 );

View File

@ -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 );

View File

@ -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" ),

View File

@ -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;

View File

@ -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 >*/

View File

@ -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;

View File

@ -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()