diff --git a/ChangeLog b/ChangeLog index 354b9f2b..691a770e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +25/6/14 started 7.40.2 +- dzsave write to zip stops at 4gb, thanks bgilbert + 24/6/14 started 7.40.1 - revise man.1 pages - fix vips_guess_prefix() diff --git a/configure.ac b/configure.ac index ef6da63d..6552b539 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # also update the version number in the m4 macros below -AC_INIT([vips], [7.40.1], [vipsip@jiscmail.ac.uk]) +AC_INIT([vips], [7.40.2], [vipsip@jiscmail.ac.uk]) # required for gobject-introspection AC_PREREQ(2.62) @@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4]) # user-visible library versioning m4_define([vips_major_version], [7]) m4_define([vips_minor_version], [40]) -m4_define([vips_micro_version], [1]) +m4_define([vips_micro_version], [2]) m4_define([vips_version], [vips_major_version.vips_minor_version.vips_micro_version]) @@ -38,7 +38,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date` # binary interface changes not backwards compatible?: reset age to 0 LIBRARY_CURRENT=37 -LIBRARY_REVISION=5 +LIBRARY_REVISION=6 LIBRARY_AGE=0 # patched into include/vips/version.h diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 6b9ece9d..f63d1956 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -42,6 +42,8 @@ * 8/5/14 * - set Type on strips so we can convert for save correctly, thanks * philipgiuliani + * 25/6/14 + * - stop on zip write >4gb, thanks bgilbert */ /* @@ -163,6 +165,7 @@ typedef struct _VipsGsfDirectory { * this on cleanup. */ GsfOutput *container; + } VipsGsfDirectory; /* Close all dirs, non-NULL on error. @@ -417,6 +420,11 @@ struct _VipsForeignSaveDz { * becomes ".jpg". */ char *file_suffix; + + /* libgsf can't write zip files larger than 4gb. Track bytes written + * here and try to guess when we'll go over. + */ + size_t bytes_written; }; typedef VipsForeignSaveClass VipsForeignSaveDzClass; @@ -997,12 +1005,14 @@ strip_work( VipsThreadState *state, void *a ) Strip *strip = (Strip *) a; Layer *layer = strip->layer; VipsForeignSaveDz *dz = layer->dz; + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz ); VipsImage *x; VipsImage *t; void *buf; size_t len; GsfOutput *out; + gboolean status; #ifdef DEBUG_VERBOSE printf( "strip_work\n" ); @@ -1073,14 +1083,37 @@ strip_work( VipsThreadState *state, void *a ) out = tile_name( layer, state->x / dz->tile_size, state->y / dz->tile_size ); - gsf_output_write( out, len, buf ); + status = gsf_output_write( out, len, buf ); + dz->bytes_written += len; + gsf_output_close( out ); g_object_unref( out ); - g_mutex_unlock( vips__global_lock ); - g_free( buf ); + if( !status ) { + g_mutex_unlock( vips__global_lock ); + + vips_error( class->nickname, + "%s", gsf_output_error( out )->message ); + return( -1 ); + } + + /* Allow a 100,000 byte margin. This probably isn't enough: we don't + * include the space zip needs for the index nor anything we are + * outputting apart from the gsf_output_write() above. + */ + if( dz->container == VIPS_FOREIGN_DZ_CONTAINER_ZIP && + dz->bytes_written > (size_t) UINT_MAX - 100000 ) { + g_mutex_unlock( vips__global_lock ); + + vips_error( class->nickname, + "%s", _( "output file too large" ) ); + return( -1 ); + } + + g_mutex_unlock( vips__global_lock ); + #ifdef DEBUG_VERBOSE printf( "strip_work: success\n" ); #endif /*DEBUG_VERBOSE*/ @@ -1364,7 +1397,7 @@ pyramid_strip( VipsRegion *region, VipsRect *area, void *a ) */ if( layer->write_y == VIPS_RECT_BOTTOM( to ) || layer->write_y == layer->height ) { - if( strip_arrived( layer ) ) + if( strip_arrived( layer ) ) return( -1 ); } }