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,
"%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.