revise heifload EOF detection

VipsSource used a unix-style model where read() returns 0 to mean EOF.
libheif uses a model where a separate call to wait_for_file_size()
beforehand is used to check thaht the read will be OK, and then the
read() is expected to never fail.

We were trying to put EOF detection into libheif read(), but that's not
the right way to do it. Instead, test for EOF in wait_for_file_size().

see https://github.com/libvips/libvips/pull/1833
This commit is contained in:
John Cupitt 2020-09-26 13:00:52 +01:00
parent 7829518847
commit 237604bb07
2 changed files with 22 additions and 28 deletions

View File

@ -9,6 +9,7 @@
- allow gaussblur sigma zero, meaning no blur - allow gaussblur sigma zero, meaning no blur
- better heif signature detection [lovell] - better heif signature detection [lovell]
- fix vips_fractsurf() typo [kleisauke] - fix vips_fractsurf() typo [kleisauke]
- better heif EOF detection [lovell]
9/8/20 started 8.10.1 9/8/20 started 8.10.1
- fix markdown -> xml conversion in doc generation - fix markdown -> xml conversion in doc generation

View File

@ -173,10 +173,6 @@ typedef struct _VipsForeignLoadHeif {
*/ */
struct heif_reader *reader; struct heif_reader *reader;
/* When we see EOF from read(), record the source length here.
*/
gint64 length;
} VipsForeignLoadHeif; } VipsForeignLoadHeif;
typedef struct _VipsForeignLoadHeifClass { typedef struct _VipsForeignLoadHeifClass {
@ -920,6 +916,11 @@ vips_foreign_load_heif_get_position( void *userdata )
return( vips_source_seek( heif->source, 0L, SEEK_CUR ) ); return( vips_source_seek( heif->source, 0L, SEEK_CUR ) );
} }
/* libheif read() does not work like unix read().
*
* This method is cannot return EOF. Instead, the separate wait_for_file_size()
* is called beforehand to make sure that there's enough data there.
*/
static int static int
vips_foreign_load_heif_read( void *data, size_t size, void *userdata ) vips_foreign_load_heif_read( void *data, size_t size, void *userdata )
{ {
@ -928,16 +929,6 @@ vips_foreign_load_heif_read( void *data, size_t size, void *userdata )
gint64 result; gint64 result;
result = vips_source_read( heif->source, data, size ); result = vips_source_read( heif->source, data, size );
/* On EOF, make a note of the file length.
*
* libheif can sometimes ask for zero bytes, be careful not to
* interpret that as EOF.
*/
if( size > 0 &&
result == 0 &&
heif->length == -1 )
result = heif->length =
vips_source_seek( heif->source, 0L, SEEK_CUR );
if( result < 0 ) if( result < 0 )
return( -1 ); return( -1 );
@ -954,30 +945,33 @@ vips_foreign_load_heif_seek( gint64 position, void *userdata )
return( 0 ); return( 0 );
} }
/* libheif calls this to mean "I intend to read() to this position, please
* check it is OK".
*/
static enum heif_reader_grow_status static enum heif_reader_grow_status
vips_foreign_load_heif_wait_for_file_size( gint64 target_size, void *userdata ) vips_foreign_load_heif_wait_for_file_size( gint64 target_size, void *userdata )
{ {
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata; VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata;
gint64 old_position;
gint64 result;
enum heif_reader_grow_status status; enum heif_reader_grow_status status;
if( heif->source->data != NULL && target_size > heif->source->length ) /* We seek the VipsSource to the position and check for errors.
/* Target size is beyond known buffer length */
old_position = vips_source_seek( heif->source, 0L, SEEK_CUR );
result = vips_source_seek( heif->source, target_size, SEEK_SET );
vips_source_seek( heif->source, old_position, SEEK_SET );
if( result < 0 )
/* Unable to seek to this point, so it's beyond EOF.
*/ */
status = heif_reader_grow_status_size_beyond_eof; status = heif_reader_grow_status_size_beyond_eof;
else if( heif->length == -1 )
/* We've not seen EOF yet, so seeking to any point is fine (as
* far as we know).
*/
status = heif_reader_grow_status_size_reached;
else if( target_size <= heif->length )
/* We've seen EOF, and this target is less than that.
*/
status = heif_reader_grow_status_size_reached;
else else
/* We've seen EOF, we know the length, and this is too far. /* Successfully read to the requested point, but the requested
* point is not necessarily EOF.
*/ */
status = heif_reader_grow_status_size_beyond_eof; status = heif_reader_grow_status_size_reached;
return( status ); return( status );
} }
@ -986,7 +980,6 @@ static void
vips_foreign_load_heif_init( VipsForeignLoadHeif *heif ) vips_foreign_load_heif_init( VipsForeignLoadHeif *heif )
{ {
heif->n = 1; heif->n = 1;
heif->length = -1;
heif->reader = VIPS_ARRAY( NULL, 1, struct heif_reader ); heif->reader = VIPS_ARRAY( NULL, 1, struct heif_reader );