delay testing stream properties until we have to

This makes stream object creation simpler: you don't need to have
everything set up before build occurs, so you can attach signal handlers
for read and seek later.
This commit is contained in:
John Cupitt 2019-12-04 16:46:00 +00:00
parent ae7aaea077
commit ec7aa1d6b6
4 changed files with 92 additions and 45 deletions

View File

@ -170,14 +170,14 @@ openin_stream_close( thandle_t st )
}
static toff_t
openin_stream_size( thandle_t st )
openin_stream_length( thandle_t st )
{
VipsStreami *streami = VIPS_STREAMI( st );
/* libtiff will use this to get file size if tags like StripByteCounts
* are missing.
*/
return( vips_streami_size( streami ) );
return( vips_streami_length( streami ) );
}
static int
@ -214,7 +214,7 @@ vips__tiff_openin_stream( VipsStreami *streami )
openin_stream_write,
openin_stream_seek,
openin_stream_close,
openin_stream_size,
openin_stream_length,
openin_stream_map,
openin_stream_unmap )) ) {
vips_error( "vips__tiff_openin_stream", "%s",
@ -312,7 +312,7 @@ openout_buffer_seek( thandle_t st, toff_t position, int whence )
}
static toff_t
openout_buffer_size( thandle_t st )
openout_buffer_length( thandle_t st )
{
g_assert_not_reached();
@ -364,7 +364,7 @@ vips__tiff_openout_buffer( VipsImage *image,
openout_buffer_write,
openout_buffer_seek,
openout_buffer_close,
openout_buffer_size,
openout_buffer_length,
openout_buffer_map,
openout_buffer_unmap )) ) {
vips_error( "vips__tiff_openout_buffer", "%s",

View File

@ -132,6 +132,7 @@ typedef struct _VipsStreami {
* get read entirely into memory. Seeks will cause read up to the seek
* point.
*/
gboolean have_tested_seek;
gboolean is_pipe;
/* The current read point and length.
@ -218,7 +219,7 @@ int vips_streami_rewind( VipsStreami *streami );
size_t vips_streami_sniff_at_most( VipsStreami *streami,
unsigned char **data, size_t length );
unsigned char *vips_streami_sniff( VipsStreami *streami, size_t length );
gint64 vips_streami_size( VipsStreami *streami );
gint64 vips_streami_length( VipsStreami *streami );
#define VIPS_TYPE_STREAMIU (vips_streamiu_get_type())
#define VIPS_STREAMIU( obj ) \

View File

@ -38,8 +38,8 @@
/*
#define VIPS_DEBUG
#define TEST_SANITY
*/
#define TEST_SANITY
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -86,6 +86,59 @@
G_DEFINE_TYPE( VipsStreami, vips_streami, VIPS_TYPE_STREAM );
/* We can't test for seekability or length during _build, since the read and
* seek signal handlers may not have been connected yet. Instead, we test
* when we first need to know.
*/
static int
vips_streami_test_features( VipsStreami *streami )
{
VipsStreamiClass *class = VIPS_STREAMI_GET_CLASS( streami );
if( streami->have_tested_seek )
return( 0 );
streami->have_tested_seek = TRUE;
VIPS_DEBUG_MSG( "vips_streami_test_features: testing seek ..\n" );
/* We'll need a descriptor to test.
*/
if( vips_streami_unminimise( streami ) )
return( -1 );
/* Can we seek this input?
*
* We need to call the method directly rather than via
* vips_streami_seek() etc. or we might trigger seek emulation.
*/
if( streami->data ||
class->seek( streami, 0, SEEK_CUR ) != -1 ) {
gint64 length;
VIPS_DEBUG_MSG( " seekable stream\n" );
/* We should be able to get the length of seekable
* objects.
*/
if( (length = vips_streami_length( streami )) == -1 )
return( -1 );
streami->length = length;
/* If we can seek, we won't need to save header bytes.
*/
VIPS_FREEF( g_byte_array_unref, streami->header_bytes );
}
else {
/* Not seekable. This must be some kind of pipe.
*/
VIPS_DEBUG_MSG( " not seekable\n" );
streami->is_pipe = TRUE;
}
return( 0 );
}
#ifdef TEST_SANITY
static void
vips_streami_sanity( VipsStreami *streami )
@ -204,7 +257,6 @@ vips_streami_build( VipsObject *object )
{
VipsStream *stream = VIPS_STREAM( object );
VipsStreami *streami = VIPS_STREAMI( object );
VipsStreamiClass *class = VIPS_STREAMI_GET_CLASS( streami );
VIPS_DEBUG_MSG( "vips_streami_build: %p\n", streami );
@ -237,30 +289,6 @@ vips_streami_build( VipsObject *object )
streami->length = VIPS_MIN( length, G_MAXSSIZE );
}
/* Can we seek this input?
*
* We need to call the method directly rather than via
* vips_streami_seek() etc. or we might trigger seek emulation.
*/
if( streami->data ||
class->seek( streami, 0, SEEK_CUR ) != -1 ) {
VIPS_DEBUG_MSG( " seekable stream\n" );
/* We should be able to get the length of seekable objects.
*/
if( (streami->length = vips_streami_size( streami )) == -1 )
return( -1 );
/* If we can seek, we won't need to save header bytes.
*/
VIPS_FREEF( g_byte_array_unref, streami->header_bytes );
}
else {
/* Not seekable. This must be some kind of pipe.
*/
VIPS_DEBUG_MSG( " not seekable\n" );
streami->is_pipe = TRUE;
}
return( 0 );
}
@ -505,6 +533,8 @@ vips_streami_minimise( VipsStreami *streami )
SANITY( streami );
(void) vips_streami_test_features( streami );
if( stream->filename &&
stream->descriptor != -1 &&
stream->tracked_descriptor == stream->descriptor &&
@ -536,6 +566,9 @@ vips_streami_unminimise( VipsStreami *streami )
VIPS_DEBUG_MSG( "vips_streami_unminimise:\n" );
if( vips_streami_test_features( streami ) )
return( -1 );
if( stream->descriptor == -1 &&
stream->tracked_descriptor == -1 &&
stream->filename ) {
@ -795,7 +828,6 @@ vips_streami_descriptor_to_memory( VipsStreami *streami )
VIPS_DEBUG_MSG( "vips_streami_descriptor_to_memory:\n" );
g_assert( streami->length > 0 );
g_assert( !streami->blob );
g_assert( !streami->mmap_baseaddr );
@ -820,6 +852,9 @@ vips_streami_descriptor_to_memory( VipsStreami *streami )
gboolean
vips_streami_is_mappable( VipsStreami *streami )
{
if( vips_streami_unminimise( streami ) )
return( FALSE );
/* Already a memory object, or there's a filename we can map, or
* there's a seekable descriptor.
*/
@ -853,7 +888,7 @@ vips_streami_map( VipsStreami *streami, size_t *length_out )
return( NULL );
if( !streami->data ) {
/* Seekable descriptors can simply be mmaped. All other sources
/* Seekable descriptors can simply be mapped. All other sources
* must be read into memory.
*/
if( vips_streami_is_mappable( streami ) ) {
@ -895,6 +930,9 @@ vips_streami_seek( VipsStreami *streami, gint64 offset, int whence )
VIPS_DEBUG_MSG( "vips_streami_seek: offset = %" G_GINT64_FORMAT
", whence = %d\n", offset, whence );
if( vips_streami_test_features( streami ) )
return( -1 );
SANITY( streami );
if( vips_streami_unminimise( streami ) )
@ -993,7 +1031,8 @@ vips_streami_rewind( VipsStreami *streami )
SANITY( streami );
if( vips_streami_seek( streami, 0, SEEK_SET ) != 0 )
if( vips_streami_test_features( streami ) ||
vips_streami_seek( streami, 0, SEEK_SET ) != 0 )
return( -1 );
SANITY( streami );
@ -1002,32 +1041,35 @@ vips_streami_rewind( VipsStreami *streami )
}
/**
* vips_streami_size:
* vips_streami_length:
* @streami: input stream to operate on
*
* Return the size in bytes of the stream object. Unseekable streams, for
* example pipes, will have to be read entirely into memory before the size
* Return the length in bytes of the stream object. Unseekable streams, for
* example pipes, will have to be read entirely into memory before the length
* can be found, so this operation can take a long time.
*
* Returns: number of bytes in stream, or -1 on error.
*/
gint64
vips_streami_size( VipsStreami *streami )
vips_streami_length( VipsStreami *streami )
{
gint64 size;
gint64 length;
gint64 read_position;
VIPS_DEBUG_MSG( "vips_streami_size:\n" );
VIPS_DEBUG_MSG( "vips_streami_length:\n" );
SANITY( streami );
if( vips_streami_test_features( streami ) )
return( -1 );
read_position = vips_streami_seek( streami, 0, SEEK_CUR );
size = vips_streami_seek( streami, 0, SEEK_END );
length = vips_streami_seek( streami, 0, SEEK_END );
vips_streami_seek( streami, read_position, SEEK_SET );
SANITY( streami );
return( size );
return( length );
}
/**
@ -1054,7 +1096,8 @@ vips_streami_sniff_at_most( VipsStreami *streami,
SANITY( streami );
if( vips_streami_rewind( streami ) )
if( vips_streami_test_features( streami ) ||
vips_streami_rewind( streami ) )
return( -1 );
g_byte_array_set_size( streami->sniff, length );
@ -1097,6 +1140,9 @@ vips_streami_sniff( VipsStreami *streami, size_t length )
unsigned char *data;
size_t bytes_read;
if( vips_streami_test_features( streami ) )
return( NULL );
bytes_read = vips_streami_sniff_at_most( streami, &data, length );
if( bytes_read < length )
return( NULL );

View File

@ -32,8 +32,8 @@
*/
/*
#define VIPS_DEBUG
*/
#define VIPS_DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>