From a129cef9dd9c661c0e5e0ed0b25834fa629c8141 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 19 Nov 2019 06:47:24 +0000 Subject: [PATCH] add streamo_steal and start converting some old dbuf code --- libvips/foreign/svgload.c | 9 ++-- libvips/include/vips/stream.h | 9 +++- libvips/iofuncs/streamo.c | 89 +++++++++++++++++++++++++++++++---- libvips/iofuncs/vips.c | 40 ++++++++-------- 4 files changed, 111 insertions(+), 36 deletions(-) diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c index 9dbcfa60..06783517 100644 --- a/libvips/foreign/svgload.c +++ b/libvips/foreign/svgload.c @@ -268,8 +268,7 @@ vips_g_input_stream_skip( GInputStream *stream, gsize count, GCancellable *cancellable, GError **error ) { VipsStreami *streami; - goffset start; - goffset end; + gssize position; streami = VIPS_G_INPUT_STREAM( stream )->streami; @@ -278,8 +277,8 @@ vips_g_input_stream_skip( GInputStream *stream, gsize count, if( g_cancellable_set_error_if_cancelled( cancellable, error ) ) return( -1 ); - start = vips_streami_seek( streami, count, SEEK_CUR ); - if( start == -1 ) { + position = vips_streami_seek( streami, count, SEEK_CUR ); + if( position == -1 ) { g_set_error( error, G_IO_ERROR, G_IO_ERROR_FAILED, _( "Error while seeking: %s" ), @@ -287,7 +286,7 @@ vips_g_input_stream_skip( GInputStream *stream, gsize count, return( -1 ); } - return( count ); + return( position ); } static gboolean diff --git a/libvips/include/vips/stream.h b/libvips/include/vips/stream.h index 5781d656..7a617096 100644 --- a/libvips/include/vips/stream.h +++ b/libvips/include/vips/stream.h @@ -241,6 +241,10 @@ typedef struct _VipsStreamo { /*< private >*/ + /* The stream has been finished and can no longer be written. + */ + gboolean finished; + /* Write memory output here. */ GByteArray *memory; @@ -278,16 +282,19 @@ VipsStreamo *vips_streamo_new_to_filename( const char *filename ); VipsStreamo *vips_streamo_new_to_memory( void ); int vips_streamo_write( VipsStreamo *streamo, const void *data, size_t length ); void vips_streamo_finish( VipsStreamo *streamo ); +unsigned char *vips_streamo_steal( VipsStreamo *streamo, size_t *length ); +char *vips_streamo_steal_text( VipsStreamo *streamo ); int vips_streamo_putc( VipsStreamo *streamo, int ch ); #define VIPS_STREAMO_PUTC( S, C ) ( \ - (S)->write_point <= VIPS_STREAMO_BUFFER_SIZE ? \ + (S)->write_point < VIPS_STREAMO_BUFFER_SIZE ? \ ((S)->output_buffer[(S)->write_point++] = (C), 0) : \ vips_streamo_putc( (S), (C) ) \ ) int vips_streamo_writes( VipsStreamo *streamo, const char *str ); int vips_streamo_writef( VipsStreamo *streamo, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); +int vips_streamo_write_amp( VipsStreamo *streamo, const char *str ); #ifdef __cplusplus } diff --git a/libvips/iofuncs/streamo.c b/libvips/iofuncs/streamo.c index 57ca95c3..e5849a5e 100644 --- a/libvips/iofuncs/streamo.c +++ b/libvips/iofuncs/streamo.c @@ -293,6 +293,9 @@ vips_streamo_write_unbuffered( VipsStreamo *streamo, { VipsStreamoClass *class = VIPS_STREAMO_GET_CLASS( streamo ); + if( streamo->finished ) + return( 0 ); + if( streamo->memory ) g_byte_array_append( streamo->memory, data, length ); else @@ -375,7 +378,10 @@ vips_streamo_write( VipsStreamo *streamo, const void *buffer, size_t length ) * @buffer: bytes to write * @length: length of @buffer in bytes * - * Call this at the end of write to make the stream do any cleaning up. + * Call this at the end of write to make the stream do any cleaning up. You + * can call it many times. + * + * After a streamo has been finished, further writes will do nothing. */ void vips_streamo_finish( VipsStreamo *streamo ) @@ -384,6 +390,9 @@ vips_streamo_finish( VipsStreamo *streamo ) VIPS_DEBUG_MSG( "vips_streamo_finish:\n" ); + if( streamo->finished ) + return; + (void) vips_streamo_flush( streamo ); /* Move the stream buffer into the blob so it can be read out. @@ -400,6 +409,69 @@ vips_streamo_finish( VipsStreamo *streamo ) } else class->finish( streamo ); + + streamo->finished = TRUE; +} + +/** + * vips_streamo_steal: + * @streamo: output stream to operate on + * @length: return number of bytes of data + * + * Memory streams only (see vips_streamo_new_to_memory()). Steal all data + * written to the stream so far, and finish it. + * + * You must free the returned pointer with g_free(). + * + * The data is NOT automatically null-terminated. vips_streamo_putc() a '\0' + * before calling this to get a null-terminated string. + * + * Returns: (array length=length) (element-type guint8) (transfer full): the + * data + */ +unsigned char * +vips_streamo_steal( VipsStreamo *streamo, size_t *length ) +{ + unsigned char *data; + + (void) vips_streamo_flush( streamo ); + + if( !streamo->memory || + streamo->finished ) { + if( length ) + *length = streamo->memory->len; + + return( NULL ); + } + + if( length ) + *length = streamo->memory->len; + data = g_byte_array_free( streamo->memory, FALSE ); + streamo->memory = NULL; + + /* We must have a valid byte array or finish will fail. + */ + streamo->memory = g_byte_array_new(); + + vips_streamo_finish( streamo ); + + return( data ); +} + +/** + * vips_streamo_steal_text: + * @streamo: output stream to operate on + * + * As vips_streamo_steal_text(), but return a null-terminated string. + * + * Returns: (transfer full): stream contents as a null-terminated string. + */ +char * +vips_streamo_steal_text( VipsStreamo *streamo ) +{ + vips_streamo_putc( streamo, '\0' ); + + return( (char *) vips_streamo_steal( streamo, NULL ) ); } /** @@ -417,7 +489,7 @@ vips_streamo_putc( VipsStreamo *streamo, int ch ) { VIPS_DEBUG_MSG( "vips_streamo_putc: %d\n", ch ); - if( streamo->write_point > VIPS_STREAMO_BUFFER_SIZE && + if( streamo->write_point >= VIPS_STREAMO_BUFFER_SIZE && vips_streamo_flush( streamo ) ) return( -1 ); @@ -504,27 +576,24 @@ vips_streamo_write_amp( VipsStreamo *streamo, const char *str ) * control characters, so we can use them -- thanks * electroly. */ - if( !vips_streamo_writef( streamo, + if( vips_streamo_writef( streamo, "&#x%04x;", 0x2400 + *p ) ) return( -1 ); } else if( *p == '<' ) { - if( !vips_streamo_write( streamo, - (guchar *) "<", 4 ) ) + if( vips_streamo_writes( streamo, "<" ) ) return( -1 ); } else if( *p == '>' ) { - if( !vips_streamo_write( streamo, - (guchar *) ">", 4 ) ) + if( vips_streamo_writes( streamo, ">" ) ) return( -1 ); } else if( *p == '&' ) { - if( !vips_streamo_write( streamo, - (guchar *) "&", 5 ) ) + if( vips_streamo_writes( streamo, "&" ) ) return( -1 ); } else { - if( !vips_streamo_putc( streamo, *p ) ) + if( VIPS_STREAMO_PUTC( streamo, *p ) ) return( -1 ); } diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index b7f40c10..20702a30 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -912,7 +912,7 @@ static void * vips__xml_properties_meta( VipsImage *image, const char *field, GValue *value, void *a ) { - VipsDbuf *dbuf = (VipsDbuf *) a; + VipsStreamo *streamo = (VipsStreamo *) a; GType type = G_VALUE_TYPE( value ); const char *str; @@ -928,19 +928,19 @@ vips__xml_properties_meta( VipsImage *image, if( !g_value_transform( value, &save_value ) ) { vips_error( "VipsImage", "%s", _( "error transforming to save format" ) ); - return( dbuf ); + return( streamo ); } str = vips_value_get_save_string( &save_value ); - vips_dbuf_writef( dbuf, " \n" ); - vips_dbuf_writef( dbuf, " " ); - vips_dbuf_write_amp( dbuf, field ); - vips_dbuf_writef( dbuf, "\n" ); - vips_dbuf_writef( dbuf, " ", + vips_streamo_writef( streamo, " \n" ); + vips_streamo_writef( streamo, " " ); + vips_streamo_write_amp( streamo, field ); + vips_streamo_writef( streamo, "\n" ); + vips_streamo_writef( streamo, " ", g_type_name( type ) ); - vips_dbuf_write_amp( dbuf, str ); - vips_dbuf_writef( dbuf, "\n" ); - vips_dbuf_writef( dbuf, " \n" ); + vips_streamo_write_amp( streamo, str ); + vips_streamo_writef( streamo, "\n" ); + vips_streamo_writef( streamo, " \n" ); g_value_unset( &save_value ); } @@ -954,31 +954,31 @@ vips__xml_properties_meta( VipsImage *image, char * vips__xml_properties( VipsImage *image ) { - VipsDbuf dbuf; + VipsStreamo *streamo; char *date; date = vips__get_iso8601(); - vips_dbuf_init( &dbuf ); - vips_dbuf_writef( &dbuf, "\n" ); - vips_dbuf_writef( &dbuf, "\n" ); + vips_streamo_writef( streamo, "\n", NAMESPACE_URI, date, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION ); - vips_dbuf_writef( &dbuf, " \n" ); + vips_streamo_writef( streamo, " \n" ); g_free( date ); - if( vips_image_map( image, vips__xml_properties_meta, &dbuf ) ) { - vips_dbuf_destroy( &dbuf ); + if( vips_image_map( image, vips__xml_properties_meta, streamo ) ) { + VIPS_UNREF( streamo ); return( NULL ); } - vips_dbuf_writef( &dbuf, " \n" ); - vips_dbuf_writef( &dbuf, "\n" ); + vips_streamo_writef( streamo, " \n" ); + vips_streamo_writef( streamo, "\n" ); - return( (char *) vips_dbuf_steal( &dbuf, NULL ) ); + return( vips_streamo_steal_text( streamo ) ); } /* Append XML to output fd.