move buf writers on top of dbuf

tiff and webp not moved
This commit is contained in:
John Cupitt 2017-02-28 13:40:34 +00:00
parent 40294bb85c
commit f2a178e98f
6 changed files with 196 additions and 167 deletions

22
TODO
View File

@ -1,25 +1,3 @@
- use VipsDbuf for tiffsave_buffer etc.
$ grep -l save_buffer *.c
dzsave.c
jpegsave.c
pngsave.c
radsave.c
tiffsave.c
webpsave.c
done png, jpg
tiff needs seek ... perhaps add this to dbuf?
dzsave uses gsf
rad and webp left to do
vips2jpeg term_destination() needs some kind of truncate call for dbuf
- verify xml data against master for vips save and dzsave - verify xml data against master for vips save and dzsave

View File

@ -17,6 +17,8 @@
* readers * readers
* 23/5/16 * 23/5/16
* - add buffer save functions * - add buffer save functions
* 28/2/17
* - use dbuf for buffer output
*/ */
/* /*
@ -1172,9 +1174,7 @@ typedef struct {
char *filename; char *filename;
FILE *fout; FILE *fout;
char *buf; VipsDbuf dbuf;
size_t len;
size_t alloc;
char format[256]; char format[256];
double expos; double expos;
@ -1189,7 +1189,7 @@ write_destroy( Write *write )
{ {
VIPS_FREE( write->filename ); VIPS_FREE( write->filename );
VIPS_FREEF( fclose, write->fout ); VIPS_FREEF( fclose, write->fout );
VIPS_FREE( write->buf ); vips_dbuf_destroy( &write->dbuf );
vips_free( write ); vips_free( write );
} }
@ -1208,9 +1208,7 @@ write_new( VipsImage *in )
write->filename = NULL; write->filename = NULL;
write->fout = NULL; write->fout = NULL;
write->buf = NULL; vips_dbuf_init( &write->dbuf );
write->len = 0;
write->alloc = 0;
strcpy( write->format, COLRFMT ); strcpy( write->format, COLRFMT );
write->expos = 1.0; write->expos = 1.0;
@ -1346,91 +1344,30 @@ vips__rad_save( VipsImage *in, const char *filename )
return( 0 ); return( 0 );
} }
static void
write_buf_grow( Write *write, size_t grow_len )
{
size_t new_len = write->len + grow_len;
if( new_len > write->alloc ) {
size_t proposed_alloc = (16 + write->alloc) * 3 / 2;
write->alloc = VIPS_MAX( proposed_alloc, new_len );
/* Our caller must free with g_free(), so we must use
* g_realloc().
*/
write->buf = g_realloc( write->buf, write->alloc );
VIPS_DEBUG_MSG( "write_buf_grow: grown to %zd bytes\n",
write->alloc );
}
}
static void
bprintf( Write *write, const char *fmt, ... )
{
int length;
char *write_start;
va_list ap;
/* Determine required size.
*/
va_start( ap, fmt );
length = vsnprintf( NULL, 0, fmt, ap );
va_end( ap );
write_buf_grow( write, length + 1 );
write_start = write->buf + write->len;
va_start( ap, fmt );
length = vsnprintf( write_start, length + 1, fmt, ap );
va_end( ap );
write->len += length;
g_assert( write->len <= write->alloc );
}
#define bputformat( write, s ) \
bprintf( write, "%s%s\n", FMTSTR, s )
#define bputexpos( write, ex ) \
bprintf( write, "%s%e\n", EXPOSSTR, ex )
#define bputcolcor( write, cc ) \
bprintf( write, "%s %f %f %f\n", \
COLCORSTR, (cc)[RED], (cc)[GRN], (cc)[BLU] )
#define bputaspect( write, pa ) \
bprintf( write, "%s%f\n", ASPECTSTR, pa )
#define bputprims( write, p ) \
bprintf( write, "%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n", \
PRIMARYSTR, \
(p)[RED][CIEX], (p)[RED][CIEY], \
(p)[GRN][CIEX], (p)[GRN][CIEY], \
(p)[BLU][CIEX], (p)[BLU][CIEY], \
(p)[WHT][CIEX], (p)[WHT][CIEY] )
#define bputsresolu( write, rs ) \
bprintf( write, "%s", resolu2str( resolu_buf, rs ) )
static int static int
vips2rad_put_header_buf( Write *write ) vips2rad_put_header_buf( Write *write )
{ {
vips2rad_make_header( write ); vips2rad_make_header( write );
bprintf( write, "#?RADIANCE\n" ); vips_dbuf_appendf( &write->dbuf, "#?RADIANCE\n" );
vips_dbuf_appendf( &write->dbuf, "%s%s\n", FMTSTR, write->format );
bputformat( write, write->format ); vips_dbuf_appendf( &write->dbuf, "%s%e\n", EXPOSSTR, write->expos );
bputexpos( write, write->expos ); vips_dbuf_appendf( &write->dbuf, "%s %f %f %f\n",
bputcolcor( write, write->colcor ); COLCORSTR,
bprintf( write, "SOFTWARE=vips %s\n", vips_version_string() ); write->colcor[RED], write->colcor[GRN], write->colcor[BLU] );
bputaspect( write, write->aspect ); vips_dbuf_appendf( &write->dbuf, "SOFTWARE=vips %s\n",
bputprims( write, write->prims ); vips_version_string() );
bprintf( write, "\n" ); vips_dbuf_appendf( &write->dbuf, "%s%f\n", ASPECTSTR, write->aspect );
bputsresolu( write, &write->rs ); vips_dbuf_appendf( &write->dbuf,
"%s %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f\n",
PRIMARYSTR,
write->prims[RED][CIEX], write->prims[RED][CIEY],
write->prims[GRN][CIEX], write->prims[GRN][CIEY],
write->prims[BLU][CIEX], write->prims[BLU][CIEY],
write->prims[WHT][CIEX], write->prims[WHT][CIEY] );
vips_dbuf_appendf( &write->dbuf, "\n" );
vips_dbuf_appendf( &write->dbuf, "%s",
resolu2str( resolu_buf, &write->rs ) );
return( 0 ); return( 0 );
} }
@ -1441,25 +1378,25 @@ static int
scanline_write_buf( Write *write, COLR *scanline, int width ) scanline_write_buf( Write *write, COLR *scanline, int width )
{ {
unsigned char *buffer; unsigned char *buffer;
size_t size;
int length;
write_buf_grow( write, MAX_LINE ); vips_dbuf_allocate( &write->dbuf, MAX_LINE );
buffer = (unsigned char *) write->buf + write->len; buffer = vips_dbuf_get_write( &write->dbuf, &size );
if( width < MINELEN || if( width < MINELEN ||
width > MAXELEN ) { width > MAXELEN ) {
/* Write as a flat scanline. /* Write as a flat scanline.
*/ */
memcpy( buffer, scanline, sizeof( COLR ) * width ); length = sizeof( COLR ) * width;
write->len += sizeof( COLR ) * width; memcpy( buffer, scanline, length );
} }
else { else
int length;
/* An RLE scanline. /* An RLE scanline.
*/ */
rle_scanline_write( scanline, width, buffer, &length ); rle_scanline_write( scanline, width, buffer, &length );
write->len += length;
} vips_dbuf_seek( &write->dbuf, length - size, SEEK_CUR );
return( 0 ); return( 0 );
} }
@ -1510,10 +1447,7 @@ vips__rad_save_buf( VipsImage *in, void **obuf, size_t *olen )
return( -1 ); return( -1 );
} }
*obuf = write->buf; *obuf = vips_dbuf_steal( &write->dbuf, olen );
write->buf = NULL;
if( olen )
*olen = write->len;
write_destroy( write ); write_destroy( write );

View File

@ -734,10 +734,12 @@ term_destination( j_compress_ptr cinfo )
size_t size; size_t size;
/* This can be called before the output area fills. We need to chop /* We probably won't have filled the area that was last allocated in
* size down to the number of bytes actually written. * empty_output_buffer(). Chop the data size down to the length that
* was actually written.
*/ */
buf->dbuf.write_point = buf->dbuf.max_size - buf->pub.free_in_buffer; vips_dbuf_seek( &buf->dbuf, -buf->pub.free_in_buffer, SEEK_END );
vips_dbuf_truncate( &buf->dbuf );
*(buf->obuf) = vips_dbuf_steal( &buf->dbuf, &size ); *(buf->obuf) = vips_dbuf_steal( &buf->dbuf, &size );
*(buf->olen) = size; *(buf->olen) = size;

View File

@ -49,11 +49,17 @@ typedef struct _VipsDbuf {
/* The current base, and the size of the allocated memory area. /* The current base, and the size of the allocated memory area.
*/ */
unsigned char *data; unsigned char *data;
size_t max_size; size_t allocated_size;
/* And the write point. /* The size of the actual data that's been written. This will usually
* be <= allocated_size, but always >= write_point.
*/
size_t data_size;
/* The write point.
*/ */
size_t write_point; size_t write_point;
} VipsDbuf; } VipsDbuf;
void vips_dbuf_destroy( VipsDbuf *buf ); void vips_dbuf_destroy( VipsDbuf *buf );
@ -63,8 +69,10 @@ unsigned char *vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size );
gboolean vips_dbuf_append( VipsDbuf *dbuf, gboolean vips_dbuf_append( VipsDbuf *dbuf,
const unsigned char *data, size_t size ); const unsigned char *data, size_t size );
gboolean vips_dbuf_appendf( VipsDbuf *dbuf, const char *fmt, ... ); gboolean vips_dbuf_appendf( VipsDbuf *dbuf, const char *fmt, ... );
void vips_dbuf_rewind( VipsDbuf *dbuf ); void vips_dbuf_reset( VipsDbuf *dbuf );
void vips_dbuf_destroy( VipsDbuf *dbuf ); void vips_dbuf_destroy( VipsDbuf *dbuf );
gboolean vips_dbuf_seek( VipsDbuf *dbuf, off_t offset, int whence );
void vips_dbuf_truncate( VipsDbuf *dbuf );
unsigned char *vips_dbuf_string( VipsDbuf *dbuf, size_t *size ); unsigned char *vips_dbuf_string( VipsDbuf *dbuf, size_t *size );
unsigned char *vips_dbuf_steal( VipsDbuf *dbuf, size_t *size ); unsigned char *vips_dbuf_steal( VipsDbuf *dbuf, size_t *size );

View File

@ -51,37 +51,74 @@ void
vips_dbuf_init( VipsDbuf *dbuf ) vips_dbuf_init( VipsDbuf *dbuf )
{ {
dbuf->data = NULL; dbuf->data = NULL;
dbuf->max_size = 0; dbuf->allocated_size = 0;
dbuf->data_size = 0;
dbuf->write_point = 0; dbuf->write_point = 0;
} }
/**
* vips_dbuf_minimum_size:
* @dbuf: the buffer
* @size: the minimum size
*
* Make sure @dbuf is at least @size bytes.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/
gboolean
vips_dbuf_minimum_size( VipsDbuf *dbuf, size_t size )
{
if( size > dbuf->allocated_size ) {
size_t new_allocated_size = 3 * (16 + size) / 2;
unsigned char *new_data;
if( !(new_data =
g_try_realloc( dbuf->data, new_allocated_size )) ) {
vips_error( "VipsDbuf", "%s", _( "out of memory" ) );
return( FALSE );
}
dbuf->data = new_data;
dbuf->allocated_size = new_allocated_size;
}
return( TRUE );
}
/** /**
* vips_dbuf_allocate: * vips_dbuf_allocate:
* @dbuf: the buffer * @dbuf: the buffer
* @size: the size to allocate * @size: the size to allocate
* *
* Make sure @dbuf has at least @size bytes available for writing. * Make sure @dbuf has at least @size bytes available after the write point.
* *
* Returns: %FALSE on out of memory, %TRUE otherwise. * Returns: %FALSE on out of memory, %TRUE otherwise.
*/ */
gboolean gboolean
vips_dbuf_allocate( VipsDbuf *dbuf, size_t size ) vips_dbuf_allocate( VipsDbuf *dbuf, size_t size )
{ {
size_t new_write_point = dbuf->write_point + size; return( vips_dbuf_minimum_size( dbuf, dbuf->write_point + size ) );
}
if( new_write_point > dbuf->max_size ) { /**
size_t new_max_size = 3 * (16 + new_write_point) / 2; * vips_dbuf_null_terminate:
* @dbuf: the buffer
unsigned char *new_data; *
* Make sure the byte after the last data byte is `\0`. This extra byte is not
if( !(new_data = g_try_realloc( dbuf->data, new_max_size )) ) { * included in the data size and the write point is not moved.
vips_error( "VipsDbuf", "%s", _( "out of memory" ) ); *
* This makes it safe to treat the dbuf contents as a C string.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/
static gboolean
vips_dbuf_null_terminate( VipsDbuf *dbuf )
{
if( !vips_dbuf_minimum_size( dbuf, dbuf->data_size + 1 ) )
return( FALSE ); return( FALSE );
}
dbuf->data = new_data; dbuf->data[dbuf->data_size] = 0;
dbuf->max_size = new_max_size;
}
return( TRUE ); return( TRUE );
} }
@ -92,21 +129,28 @@ vips_dbuf_allocate( VipsDbuf *dbuf, size_t size )
* @size: (allow-none): optionally return length in bytes here * @size: (allow-none): optionally return length in bytes here
* *
* Return a pointer to an area you can write to, return length of area in * Return a pointer to an area you can write to, return length of area in
* @size. Use vips_dbuf_allocate() before this call to make the space. * @size. Use vips_dbuf_allocate() before this call to set a minimum amount of
* space to have available.
*
* The write point moves to just beyond the returned block. Use
* vips_dbuf_seek() to move it back again.
* *
* Returns: (transfer none): start of write area. * Returns: (transfer none): start of write area.
*/ */
unsigned char * unsigned char *
vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size ) vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size )
{ {
unsigned char *data = dbuf->data + dbuf->write_point; unsigned char *write = dbuf->data + dbuf->write_point;
size_t length = dbuf->data + dbuf->allocated_size - write;
memset( write, 0, length );
dbuf->write_point = dbuf->allocated_size;
dbuf->data_size = dbuf->allocated_size;
if( size ) if( size )
*size = dbuf->max_size - dbuf->write_point; *size = length;
dbuf->write_point = dbuf->max_size; return( write );
return( data );
} }
/** /**
@ -115,7 +159,7 @@ vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size )
* @data: the data to append to the buffer * @data: the data to append to the buffer
* @size: the size of the len to append * @size: the size of the len to append
* *
* Append len bytes from @data to the buffer. The buffer expands if necessary. * Append @size bytes from @data. @dbuf expands if necessary.
* *
* Returns: %FALSE on out of memory, %TRUE otherwise. * Returns: %FALSE on out of memory, %TRUE otherwise.
*/ */
@ -127,6 +171,7 @@ vips_dbuf_append( VipsDbuf *dbuf, const unsigned char *data, size_t size )
memcpy( dbuf->data + dbuf->write_point, data, size ); memcpy( dbuf->data + dbuf->write_point, data, size );
dbuf->write_point += size; dbuf->write_point += size;
dbuf->data_size = VIPS_MAX( dbuf->data_size, dbuf->write_point );
return( TRUE ); return( TRUE );
} }
@ -161,16 +206,17 @@ vips_dbuf_appendf( VipsDbuf *dbuf, const char *fmt, ... )
} }
/** /**
* vips_dbuf_rewind: * vips_dbuf_reset:
* @dbuf: the buffer * @dbuf: the buffer
* *
* Reset the buffer to empty. No memory is freed, just the write pointer is * Reset the buffer to empty. No memory is freed, just the data size and
* reset. * write point are reset.
*/ */
void void
vips_dbuf_rewind( VipsDbuf *dbuf ) vips_dbuf_reset( VipsDbuf *dbuf )
{ {
dbuf->write_point = 0; dbuf->write_point = 0;
dbuf->data_size = 0;
} }
/** /**
@ -182,9 +228,73 @@ vips_dbuf_rewind( VipsDbuf *dbuf )
void void
vips_dbuf_destroy( VipsDbuf *dbuf ) vips_dbuf_destroy( VipsDbuf *dbuf )
{ {
vips_dbuf_reset( dbuf );
VIPS_FREE( dbuf->data ); VIPS_FREE( dbuf->data );
dbuf->max_size = 0; dbuf->allocated_size = 0;
dbuf->write_point = 0; }
/**
* vips_dbuf_seek:
* @dbuf: the buffer
* @offset: how to move the write point
* @whence: from start, from end, from current
*
* Move the write point. @whence can be %SEEK_SET, %SEEK_CUR, %SEEK_END, with
* the usual meaning.
*/
gboolean
vips_dbuf_seek( VipsDbuf *dbuf, off_t offset, int whence )
{
off_t new_write_point;
switch( whence ) {
case SEEK_SET:
new_write_point = offset;
break;
case SEEK_END:
new_write_point = dbuf->data_size + offset;
break;
case SEEK_CUR:
new_write_point = dbuf->write_point + offset;
break;
default:
g_assert( 0 );
new_write_point = dbuf->write_point;
break;
}
if( new_write_point < 0 ) {
vips_error( "VipsDbuf", "%s", "negative seek" );
return( FALSE );
}
/* Possibly need to grow the buffer
*/
if( !vips_dbuf_minimum_size( dbuf, new_write_point ) )
return( FALSE );
dbuf->write_point = new_write_point;
if( dbuf->data_size < dbuf->write_point ) {
memset( dbuf->data, 0, dbuf->write_point - dbuf->data_size );
dbuf->data_size = dbuf->write_point;
}
return( TRUE );
}
/**
* vips_dbuf_truncate:
* @dbuf: the buffer
*
* Truncate the data so that it ends at the write point. No memory is freed.
*/
void
vips_dbuf_truncate( VipsDbuf *dbuf )
{
dbuf->data_size = dbuf->write_point;
} }
/** /**
@ -205,17 +315,15 @@ vips_dbuf_steal( VipsDbuf *dbuf, size_t *size )
{ {
unsigned char *data; unsigned char *data;
vips_dbuf_append( dbuf, (unsigned char *) "", 1 ); vips_dbuf_null_terminate( dbuf );
dbuf->write_point -= 1;
data = dbuf->data; data = dbuf->data;
if( size ) if( size )
*size = dbuf->write_point; *size = dbuf->data_size;
dbuf->data = NULL; dbuf->data = NULL;
dbuf->max_size = 0; vips_dbuf_destroy( dbuf );
dbuf->write_point = 0;
return( data ); return( data );
} }
@ -235,11 +343,10 @@ vips_dbuf_steal( VipsDbuf *dbuf, size_t *size )
unsigned char * unsigned char *
vips_dbuf_string( VipsDbuf *dbuf, size_t *size ) vips_dbuf_string( VipsDbuf *dbuf, size_t *size )
{ {
vips_dbuf_append( dbuf, (unsigned char *) "", 1 ); vips_dbuf_null_terminate( dbuf );
dbuf->write_point -= 1;
if( size ) if( size )
*size = dbuf->write_point; *size = dbuf->data_size;
return( dbuf->data ); return( dbuf->data );
} }

View File

@ -536,7 +536,7 @@ parser_element_start_handler( void *user_data,
vips_strncpy( vep->type, p[1], MAX_PARSE_ATTR ); vips_strncpy( vep->type, p[1], MAX_PARSE_ATTR );
} }
vips_dbuf_rewind( &vep->dbuf ); vips_dbuf_reset( &vep->dbuf );
} }
else if( strcmp( name, "header" ) == 0 ) else if( strcmp( name, "header" ) == 0 )
vep->header = TRUE; vep->header = TRUE;
@ -545,7 +545,7 @@ parser_element_start_handler( void *user_data,
else if( strcmp( name, "root" ) == 0 ) { else if( strcmp( name, "root" ) == 0 ) {
for( p = atts; *p; p += 2 ) for( p = atts; *p; p += 2 )
if( strcmp( p[0], "xmlns" ) == 0 && if( strcmp( p[0], "xmlns" ) == 0 &&
!vips_isprefix( NAMESPACE_URI "/vips", p[1] ) ) { !vips_isprefix( NAMESPACE_URI "vips", p[1] ) ) {
vips_error( "VipsImage", "%s", vips_error( "VipsImage", "%s",
_( "incorrect namespace in XML" ) ); _( "incorrect namespace in XML" ) );
vep->error = TRUE; vep->error = TRUE;
@ -812,7 +812,7 @@ build_xml( VipsImage *image )
vips_dbuf_init( &dbuf ); vips_dbuf_init( &dbuf );
vips_dbuf_appendf( &dbuf, "<?xml version=\"1.0\"?>\n" ); vips_dbuf_appendf( &dbuf, "<?xml version=\"1.0\"?>\n" );
vips_dbuf_appendf( &dbuf, "<root xmlns=\"%s/vips/%d.%d.%d\">\n", vips_dbuf_appendf( &dbuf, "<root xmlns=\"%svips/%d.%d.%d\">\n",
NAMESPACE_URI, NAMESPACE_URI,
VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION ); VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION );
vips_dbuf_appendf( &dbuf, " <header>\n" ); vips_dbuf_appendf( &dbuf, " <header>\n" );