better header sniffing for small files

vips__get_bytes() used to fail if the file was too small for the
allocated buffer, which was a problem for svg, since files can be extremely
small.

This change makes vips__get_bytes() return the number of bytes read, so
the is_a testers can work on files smaller than the max header size.
This commit is contained in:
John Cupitt 2018-03-22 12:08:39 +00:00
parent 5a1ab5968b
commit 5176b4a17e
14 changed files with 28 additions and 30 deletions

View File

@ -8,6 +8,7 @@
- add vips_sobel() and vips_canny() edge detectors
- add vips_rotate() ... a convenience method for vips_similarity()
- svgload was missing is_a [lovell]
- better header sniffing for small files
12/3/18 started 8.6.4
- better fitting of fonts with overhanging edges, thanks Adrià

View File

@ -383,7 +383,7 @@ vips_foreign_load_gif_is_a( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) &&
if( vips__get_bytes( filename, buf, 4 ) == 4 &&
vips_foreign_load_gif_is_a_buffer( buf, 4 ) )
return( 1 );

View File

@ -968,7 +968,7 @@ vips__isjpeg( const char *filename )
{
unsigned char buf[2];
if( vips__get_bytes( filename, buf, 2 ) &&
if( vips__get_bytes( filename, buf, 2 ) == 2 &&
vips__isjpeg_buffer( buf, 2 ) )
return( 1 );

View File

@ -323,7 +323,7 @@ vips__mat_ismat( const char *filename )
{
unsigned char buf[15];
if( vips__get_bytes( filename, buf, 10 ) &&
if( vips__get_bytes( filename, buf, 10 ) == 10 &&
vips_isprefix( "MATLAB 5.0", (char *) buf ) )
return( 1 );

View File

@ -107,7 +107,7 @@ vips__openexr_isexr( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) )
if( vips__get_bytes( filename, buf, 4 ) == 4 )
if( buf[0] == 0x76 && buf[1] == 0x2f &&
buf[2] == 0x31 && buf[3] == 0x01 )
return( TRUE );

View File

@ -165,7 +165,7 @@ vips_foreign_load_pdf_is_a( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) &&
if( vips__get_bytes( filename, buf, 4 ) == 4 &&
vips_foreign_load_pdf_is_a_buffer( buf, 4 ) )
return( 1 );

View File

@ -514,7 +514,7 @@ vips__ppm_isppm( const char *filename )
{
VipsPel buf[3];
if( vips__get_bytes( filename, buf, 2 ) ) {
if( vips__get_bytes( filename, buf, 2 ) == 2 ) {
int i;
buf[2] = '\0';

View File

@ -458,9 +458,10 @@ static gboolean
vips_foreign_load_svg_file_is_a( const char *filename )
{
unsigned char buf[300];
guint64 bytes;
return( vips__get_bytes( filename, buf, 300 ) &&
vips_foreign_load_svg_is_a( buf, 300 ) );
return( (bytes = vips__get_bytes( filename, buf, 300 )) > 0 &&
vips_foreign_load_svg_is_a( buf, bytes ) );
}
static int

View File

@ -2362,7 +2362,7 @@ vips__istiff( const char *filename )
{
unsigned char buf[4];
if( vips__get_bytes( filename, buf, 4 ) &&
if( vips__get_bytes( filename, buf, 4 ) == 4 &&
vips__istiff_buffer( buf, 4 ) )
return( TRUE );

View File

@ -677,7 +677,7 @@ vips__png_ispng( const char *filename )
{
unsigned char buf[8];
return( vips__get_bytes( filename, buf, 8 ) &&
return( vips__get_bytes( filename, buf, 8 ) == 8 &&
vips__png_ispng_buffer( buf, 8 ) );
}

View File

@ -119,7 +119,7 @@ vips__iswebp( const char *filename )
*/
unsigned char header[12];
if( vips__get_bytes( filename, header, 12 ) &&
if( vips__get_bytes( filename, header, 12 ) == 12 &&
vips__iswebp_buffer( header, 12 ) )
return( 1 );

View File

@ -266,7 +266,8 @@ char *vips__file_read( FILE *fp, const char *name, size_t *length_out );
char *vips__file_read_name( const char *name, const char *fallback_dir,
size_t *length_out );
int vips__file_write( void *data, size_t size, size_t nmemb, FILE *stream );
int vips__get_bytes( const char *filename, unsigned char buf[], int len );
guint64 vips__get_bytes( const char *filename,
unsigned char buf[], guint64 len );
int vips__fgetc( FILE *fp );
GValue *vips__gvalue_ref_string_new( const char *text );

View File

@ -844,33 +844,28 @@ vips__file_write( void *data, size_t size, size_t nmemb, FILE *stream )
return( 0 );
}
/* Read a few bytes from the start of a file. For sniffing file types.
* Filename may contain a mode.
/* Read a few bytes from the start of a file. This is used for sniffing file
* types, so we must read binary.
*
* Return the number of bytes actually read (the file might be shorter than
* len), or 0 for error.
*/
int
vips__get_bytes( const char *filename, unsigned char buf[], int len )
guint64
vips__get_bytes( const char *filename, unsigned char buf[], guint64 len )
{
char name[FILENAME_MAX];
char mode[FILENAME_MAX];
int fd;
/* Split off the mode part.
*/
im_filename_split( filename, name, mode );
guint64 bytes_read;
/* File may not even exist (for tmp images for example!)
* so no hasty messages. And the file might be truncated, so no error
* on read either.
*/
if( (fd = vips__open_read( name )) == -1 )
if( (fd = vips__open_read( filename )) == -1 )
return( 0 );
if( read( fd, buf, len ) != len ) {
close( fd );
return( 0 );
}
bytes_read = read( fd, buf, len );
close( fd );
return( 1 );
return( bytes_read );
}
/* We try to support stupid DOS files too. These have \r\n (13, 10) as line

View File

@ -255,9 +255,9 @@ vips__file_magic( const char *filename )
{
guint32 magic;
if( vips__get_bytes( filename, (unsigned char *) &magic, 4 ) &&
if( vips__get_bytes( filename, (unsigned char *) &magic, 4 ) == 4 &&
(magic == VIPS_MAGIC_INTEL ||
magic == VIPS_MAGIC_SPARC ) )
magic == VIPS_MAGIC_SPARC) )
return( magic );
return( 0 );