more revision

This commit is contained in:
John Cupitt 2019-10-21 15:04:30 +01:00
parent d49e816641
commit 72cbaa9ea3
7 changed files with 117 additions and 97 deletions

View File

@ -627,10 +627,10 @@ static void *
vips_foreign_find_load_stream_sub( void *item, void *a, void *b )
{
VipsForeignLoadClass *load_class = VIPS_FOREIGN_LOAD_CLASS( item );
VipsStreamInput *input = VIPS_STREAM_INPUT( a );
VipsStreami *streami = VIPS_STREAMI( a );
if( load_class->is_a_stream &&
load_class->is_a_stream( input ) )
load_class->is_a_stream( streami ) )
return( load_class );
return( NULL );
@ -638,7 +638,7 @@ vips_foreign_find_load_stream_sub( void *item, void *a, void *b )
/**
* vips_foreign_find_load_stream:
* @input: stream to load from
* @streami: stream to load from
*
* Searches for an operation you could use to load a stream. To see the
* range of buffer loaders supported by your vips, try something like:
@ -651,14 +651,14 @@ vips_foreign_find_load_stream_sub( void *item, void *a, void *b )
* error.
*/
const char *
vips_foreign_find_load_stream( VipsStreamInput *input )
vips_foreign_find_load_stream( VipsStreami *streami )
{
VipsForeignLoadClass *load_class;
if( !(load_class = (VipsForeignLoadClass *) vips_foreign_map(
"VipsForeignLoad",
vips_foreign_find_load_stream_sub,
input, NULL )) ) {
streami, NULL )) ) {
vips_error( "VipsForeignLoad",
"%s", _( "stream is not in a known format" ) );
return( NULL );
@ -723,15 +723,15 @@ vips_foreign_is_a_buffer( const char *loader, const void *data, size_t size )
/**
* vips_foreign_is_a_stream:
* @loader: name of loader to use for test
* @input: stream to test
* @streami: stream to test
*
* Return %TRUE if @input can be loaded by @loader. @loader is something
* Return %TRUE if @streami can be loaded by @loader. @loader is something
* like "tiffload_stream" or "VipsForeignLoadTiffStream".
*
* Returns: %TRUE if @data can be loaded by @stream.
*/
gboolean
vips_foreign_is_a_stream( const char *loader, VipsStreamInput *input )
vips_foreign_is_a_stream( const char *loader, VipsStreami *streami )
{
const VipsObjectClass *class;
VipsForeignLoadClass *load_class;
@ -740,7 +740,7 @@ vips_foreign_is_a_stream( const char *loader, VipsStreamInput *input )
return( FALSE );
load_class = VIPS_FOREIGN_LOAD_CLASS( class );
if( load_class->is_a_stream &&
load_class->is_a_stream( input ) )
load_class->is_a_stream( streami ) )
return( TRUE );
return( FALSE );

View File

@ -79,11 +79,11 @@ int vips__tiff_write_buf( VipsImage *in,
VipsRegionShrink region_shrink,
int level, gboolean lossless );
gboolean vips__istiff_stream( VipsStreamInput *input );
gboolean vips__istifftiled_stream( VipsStreamInput *input );
int vips__tiff_read_header_stream( VipsStreamInput *input, VipsImage *out,
gboolean vips__istiff_stream( VipsStreami *streami );
gboolean vips__istifftiled_stream( VipsStreami *streami );
int vips__tiff_read_header_stream( VipsStreami *streami, VipsImage *out,
int page, int n, gboolean autorotate );
int vips__tiff_read_stream( VipsStreamInput *input, VipsImage *out,
int vips__tiff_read_stream( VipsStreami *streami, VipsImage *out,
int page, int n, gboolean autorotate );
extern const char *vips__foreign_tiff_suffs[];
@ -163,25 +163,25 @@ extern const char *vips__rad_suffs[];
extern const char *vips__jpeg_suffs[];
int vips__jpeg_write_stream( VipsImage *in, VipsStreamOutput *output,
int vips__jpeg_write_stream( VipsImage *in, VipsStreamo *streamo,
int Q, const char *profile,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans,
int quant_table );
int vips__jpeg_read_stream( VipsStreamInput *input, VipsImage *out,
int vips__jpeg_read_stream( VipsStreami *streami, VipsImage *out,
gboolean header_only, int shrink, int fail, gboolean autorotate );
int vips__isjpeg_stream( VipsStreamInput *input );
int vips__isjpeg_stream( VipsStreami *streami );
int vips__png_ispng_stream( VipsStreamInput *input );
int vips__png_header_stream( VipsStreamInput *input, VipsImage *out );
int vips__png_read_stream( VipsStreamInput *input, VipsImage *out,
int vips__png_ispng_stream( VipsStreami *streami );
int vips__png_header_stream( VipsStreami *streami, VipsImage *out );
int vips__png_read_stream( VipsStreami *streami, VipsImage *out,
gboolean fail );
gboolean vips__png_isinterlaced_stream( VipsStreamInput *input );
gboolean vips__png_isinterlaced_stream( VipsStreami *streami );
extern const char *vips__png_suffs[];
int vips__png_write_stream( VipsImage *in, VipsStreamOutput *output,
int vips__png_write_stream( VipsImage *in, VipsStreamo *streamo,
int compress, int interlace, const char *profile,
VipsForeignPngFilter filter, gboolean strip,
gboolean palette, int colours, int Q, double dither );
@ -198,14 +198,14 @@ extern const VipsWebPNames vips__webp_names[];
extern const int vips__n_webp_names;
extern const char *vips__webp_suffs[];
int vips__iswebp_stream( VipsStreamInput *input );
int vips__iswebp_stream( VipsStreami *streami );
int vips__webp_read_header_stream( VipsStreamInput *input, VipsImage *out,
int vips__webp_read_header_stream( VipsStreami *streami, VipsImage *out,
int page, int n, double scale );
int vips__webp_read_stream( VipsStreamInput *input, VipsImage *out,
int vips__webp_read_stream( VipsStreami *streami, VipsImage *out,
int page, int n, double scale );
int vips__webp_write_stream( VipsImage *image, VipsStreamOutput *output,
int vips__webp_write_stream( VipsImage *image, VipsStreamo *streamo,
int Q, gboolean lossless, VipsForeignWebpPreset preset,
gboolean smart_subsample, gboolean near_lossless,
int alpha_q, int reduction_effort,

View File

@ -57,7 +57,7 @@ typedef struct _VipsForeignLoadPngStream {
/* Load from a stream.
*/
VipsStreamInput *input;
VipsStreami *input;
} VipsForeignLoadPngStream;
@ -153,7 +153,7 @@ G_DEFINE_TYPE( VipsForeignLoadPng, vips_foreign_load_png,
static gboolean
vips_foreign_load_png_is_a( const char *filename )
{
VipsStreamInput *input;
VipsStreami *input;
gboolean result;
if( !(input = vips_stream_input_new_from_filename( filename )) )
@ -167,7 +167,7 @@ vips_foreign_load_png_is_a( const char *filename )
static VipsForeignFlags
vips_foreign_load_png_get_flags_filename( const char *filename )
{
VipsStreamInput *input;
VipsStreami *input;
VipsForeignFlags flags;
if( !(input = vips_stream_input_new_from_filename( filename )) )
@ -197,7 +197,7 @@ vips_foreign_load_png_header( VipsForeignLoad *load )
{
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
VipsStreamInput *input;
VipsStreami *input;
if( !(input = vips_stream_input_new_from_filename( png->filename )) )
return( -1 );
@ -215,7 +215,7 @@ vips_foreign_load_png_load( VipsForeignLoad *load )
{
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
VipsStreamInput *input;
VipsStreami *input;
if( !(input = vips_stream_input_new_from_filename( png->filename )) )
return( -1 );
@ -285,7 +285,7 @@ G_DEFINE_TYPE( VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer,
static gboolean
vips_foreign_load_png_buffer_is_a_buffer( const void *buf, size_t len )
{
VipsStreamInput *input;
VipsStreami *input;
gboolean result;
if( !(input = vips_stream_input_new_from_memory( buf, len )) )
@ -301,7 +301,7 @@ vips_foreign_load_png_buffer_get_flags( VipsForeignLoad *load )
{
VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) load;
VipsStreamInput *input;
VipsStreami *input;
VipsForeignFlags flags;
if( !(input = vips_stream_input_new_from_memory( buffer->buf->data,
@ -324,7 +324,7 @@ vips_foreign_load_png_buffer_header( VipsForeignLoad *load )
{
VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) load;
VipsStreamInput *input;
VipsStreami *input;
if( !(input = vips_stream_input_new_from_memory( buffer->buf->data,
buffer->buf->length )) )
@ -343,7 +343,7 @@ vips_foreign_load_png_buffer_load( VipsForeignLoad *load )
{
VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) load;
VipsStreamInput *input;
VipsStreami *input;
if( !(input = vips_stream_input_new_from_memory( buffer->buf->data,
buffer->buf->length )) )
@ -469,7 +469,7 @@ vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
* Returns: 0 on success, -1 on error.
*/
int
vips_pngload_stream( VipsStreamInput *input, VipsImage **out, ... )
vips_pngload_stream( VipsStreami *input, VipsImage **out, ... )
{
va_list ap;
int result;

View File

@ -189,7 +189,7 @@ typedef struct _VipsForeignLoadClass {
* This function should return %TRUE if the stream contains an image of
* this type.
*/
gboolean (*is_a_stream)( VipsStreamInput *stream );
gboolean (*is_a_stream)( VipsStreami *streami );
/* Get the flags from a filename.
*
@ -240,14 +240,14 @@ GType vips_foreign_load_get_type(void);
const char *vips_foreign_find_load( const char *filename );
const char *vips_foreign_find_load_buffer( const void *data, size_t size );
const char *vips_foreign_find_load_stream( VipsStreamInput *stream );
const char *vips_foreign_find_load_stream( VipsStreami *streami );
VipsForeignFlags vips_foreign_flags( const char *loader, const char *filename );
gboolean vips_foreign_is_a( const char *loader, const char *filename );
gboolean vips_foreign_is_a_buffer( const char *loader,
const void *data, size_t size );
gboolean vips_foreign_is_a_stream( const char *loader,
VipsStreamInput *stream );
VipsStreami *streami );
void vips_foreign_load_invalidate( VipsImage *image );
@ -369,7 +369,7 @@ int vips_jpegload( const char *filename, VipsImage **out, ... )
int vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jpegsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
int vips_jpegsave_stream( VipsImage *in, VipsStreamo *streamo, ... )
__attribute__((sentinel));
int vips_jpegsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
@ -399,14 +399,14 @@ typedef enum {
VIPS_FOREIGN_WEBP_PRESET_LAST
} VipsForeignWebpPreset;
int vips_webpload_stream( VipsStreamInput *input, VipsImage **out, ... )
int vips_webpload_stream( VipsStreami *streami, VipsImage **out, ... )
__attribute__((sentinel));
int vips_webpload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_webpload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_webpsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
int vips_webpsave_stream( VipsImage *in, VipsStreamo *streamo, ... )
__attribute__((sentinel));
int vips_webpsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
@ -481,7 +481,7 @@ int vips_tiffload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_tiffload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_tiffload_stream( VipsStreamInput *input, VipsImage **out, ... )
int vips_tiffload_stream( VipsStreami *streami, VipsImage **out, ... )
__attribute__((sentinel));
int vips_tiffsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
@ -549,13 +549,13 @@ typedef enum /*< flags >*/ {
VIPS_FOREIGN_PNG_FILTER_ALL = 0xF8
} VipsForeignPngFilter;
int vips_pngload_stream( VipsStreamInput *input, VipsImage **out, ... )
int vips_pngload_stream( VipsStreami *streami, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pngload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pngsave_stream( VipsImage *in, VipsStreamOutput *output, ... )
int vips_pngsave_stream( VipsImage *in, VipsStreamo *streamo, ... )
__attribute__((sentinel));
int vips_pngsave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));

View File

@ -447,7 +447,7 @@ VipsImage *vips_image_new_from_memory_copy( const void *data, size_t size,
VipsImage *vips_image_new_from_buffer( const void *buf, size_t len,
const char *option_string, ... )
__attribute__((sentinel));
VipsImage *vips_image_new_from_stream( VipsStreamInput *input,
VipsImage *vips_image_new_from_stream( VipsStreami *streami,
const char *option_string, ... ) __attribute__((sentinel));
VipsImage *vips_image_new_matrix( int width, int height );
VipsImage *vips_image_new_matrixv( int width, int height, ... );
@ -471,7 +471,7 @@ int vips_image_write_to_buffer( VipsImage *in,
const char *suffix, void **buf, size_t *size, ... )
__attribute__((sentinel));
int vips_image_write_to_stream( VipsImage *in,
const char *suffix, VipsStreamOutput *output, ... )
const char *suffix, VipsStreamo *streamo, ... )
__attribute__((sentinel));
void *vips_image_write_to_memory( VipsImage *in, size_t *size );

View File

@ -79,7 +79,7 @@ int vips_thumbnail_buffer( void *buf, size_t len, VipsImage **out,
__attribute__((sentinel));
int vips_thumbnail_image( VipsImage *in, VipsImage **out, int width, ... )
__attribute__((sentinel));
int vips_thumbnail_stream( VipsStreamInput *input, VipsImage **out,
int vips_thumbnail_stream( VipsStreami *streami, VipsImage **out,
int width, ... )
__attribute__((sentinel));

View File

@ -33,17 +33,15 @@
/* TODO
*
* - catch out of range seeks
* - some sanity thing to prevent endless streams filling memory?
* - filename encoding
* - seek END and _size need thinking about with pipes ... perhaps we should
* force-read the whole thing in
* - are we detecting EOF correctly? what about interrupted reads? perhaps
* we should check errno as well
* - _size() needs to be a vfunc too (libtiff needs it)
* - _miminize() is a vfunc, so _open() must be as well
* + perhaps minimise should not be a vfunc? is it really useful for
* subclasses?
* + perhaps make _open() / _close() into vfuncs and don't expose minimise
* - only fetch length once
* + perhaps make _open() / _close() into vfuncs on stream (not streami) and
* don't expose minimise
* - need to be able to set is_pipe via constructor
* - test we can really change all behaviour in the subclass ... add callbacks
* as well to make it simpler for language bindings
@ -592,7 +590,7 @@ vips_streami_read( VipsStreami *streami, void *buffer, size_t length )
VIPS_DEBUG_MSG( " %zd bytes from cache\n", available );
}
/* Any more bytes required? Call the read() vfunc.
/* Any more bytes requested? Call the read() vfunc.
*/
if( length > 0 ) {
ssize_t n;
@ -626,30 +624,63 @@ vips_streami_read( VipsStreami *streami, void *buffer, size_t length )
return( bytes_read );
}
/* Read the entire pipe into memory and turn this into a memory source stream.
/* Read a pipe to at least a position. -1 means read to end of stream. Does
* not chenge read_position.
*/
static int
vips_streami_read_whole_pipe( VipsStreami *streami )
vips_streami_pipe_read_to_position( VipsStreami *streami, gint64 target )
{
gint64 old_read_position;
unsigned char buffer[4096];
unsigned char *data;
VIPS_DEBUG_MSG( "vips_streami_read_whole_pipe:\n" );
VIPS_DEBUG_MSG( "vips_streami_pipe_read_position:\n" );
vips_streami_sanity( streami );
if( streami->decode ) {
vips_error( vips_stream_name( VIPS_STREAM( streami ) ),
"%s", _( "can't seek pipe after "
"pixel decode begins" ) );
return( -1 );
}
old_read_position = streami->read_position;
if( vips_streami_rewind( streami ) )
return( -1 );
/* TODO ... add something to prevent unbounded streams filling memory.
*/
while( vips_streami_read( streami, buffer, 4096 ) > 0 )
;
while( target == -1 ||
streami->read_position < target ) {
ssize_t read;
read = vips_streami_read( streami, buffer, 4096 );
if( read == -1 )
return( -1 );
if( read == 0 )
break;
}
streami->read_position = old_read_position;
vips_streami_sanity( streami );
return( 0 );
}
/* Read the entire pipe into memory and turn this into a memory source stream.
*/
static int
vips_streami_pipe_to_memory( VipsStreami *streami )
{
unsigned char *data;
VIPS_DEBUG_MSG( "vips_streami_pipe_to_memory:\n" );
vips_streami_sanity( streami );
if( vips_streami_pipe_read_to_position( streami, -1 ) )
return( -1 );
/* Move header_bytes into the memory blob and set up as a memory
* source.
*/
@ -678,6 +709,12 @@ vips_streami_map( VipsStreami *streami, size_t *length_out )
vips_streami_sanity( streami );
/* Pipes need to be converted to memory streams.
*/
if( streami->is_pipe &&
vips_streami_pipe_to_memory( streami ) )
return( NULL );
/* Memory source ... easy!
*/
if( streami->blob ) {
@ -685,12 +722,6 @@ vips_streami_map( VipsStreami *streami, size_t *length_out )
data = vips_blob_get( streami->blob, &length );
}
else if( streami->is_pipe ) {
if( vips_streami_read_whole_pipe( streami ) )
return( NULL );
data = vips_blob_get( streami->blob, &length );
}
else {
/* A streami that supports mmap.
*/
@ -734,7 +765,8 @@ vips_streami_seek( VipsStreami *streami, gint64 offset, int whence )
case SEEK_END:
if( streami->length == -1 &&
vips_streami_read_whole_pipe( streami ) )
streami->is_pipe &&
vips_streami_pipe_to_memory( streami ) )
return( -1 );
new_pos = streami->length + offset;
@ -747,29 +779,18 @@ vips_streami_seek( VipsStreami *streami, gint64 offset, int whence )
break;
}
/* Don't allow out of range seeks.
*/
if( new_pos < 0 ||
(streami->length != -1 && new_pos >= streami->length) ) {
vips_error( vips_stream_name( VIPS_STREAM( streami ) ),
_( "bad seek to %" G_GINT64_FORMAT ), new_pos );
return( -1 );
}
if( streami->is_pipe ) {
/* We can seek on non-seekable streams during the header phase.
*/
if( streami->decode ) {
vips_error( STREAM_NAME( streami ),
"%s", _( "can't rewind after decode begins" ) );
if( vips_streami_pipe_read_to_position( streami, new_pos ) )
return( -1 );
}
g_assert( streami->header_bytes );
/* We may not have read up to the new position.
*/
while( streami->read_position < new_pos ) {
unsigned char buffer[4096];
ssize_t read;
read = vips_streami_read( streami, buffer, 4096 );
if( read < 0 )
return( -1 );
if( read == 0 ) {
}
}
}
else {
if( (new_pos = class->seek( streami, offset, whence )) == -1 )
@ -877,13 +898,12 @@ vips_streami_size( VipsStreami *streami )
vips_streami_sanity( streami );
if( stream->descriptor >= 0 &&
(size = vips_file_length( stream->descriptor )) >= 0 )
return( size );
else if( streami->blob )
return( VIPS_AREA( streami->blob )->length );
else if( streami->header_bytes )
return( streami->header_bytes->len );
else
if( streami->length == -1 &&
streami->is_pipe &&
vips_streami_pipe_to_memory( streami ) )
return( -1 );
vips_streami_sanity( streami );
return( streami->length );
}