fix pyr tiff write to buffer

now we have a test for it heh
This commit is contained in:
John Cupitt 2017-08-27 11:03:34 +01:00
parent 7cf7a6335e
commit c0bfa4e70b
3 changed files with 145 additions and 116 deletions

View File

@ -1,4 +1,4 @@
/* Some shared TIFF utilities. /* Some shared TIFF utilities.
* *
* 14/10/16 * 14/10/16
* - from vips2tiff.c * - from vips2tiff.c
@ -10,7 +10,7 @@
/* /*
This file is part of VIPS. This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
@ -34,7 +34,7 @@
*/ */
/* /*
#define DEBUG #define DEBUG
*/ */
@ -62,7 +62,7 @@
/* Handle TIFF errors here. Shared with vips2tiff.c. These can be called from /* Handle TIFF errors here. Shared with vips2tiff.c. These can be called from
* more than one thread. * more than one thread.
*/ */
static void static void
vips__thandler_error( const char *module, const char *fmt, va_list ap ) vips__thandler_error( const char *module, const char *fmt, va_list ap )
{ {
vips_verror( module, fmt, ap ); vips_verror( module, fmt, ap );
@ -71,7 +71,7 @@ vips__thandler_error( const char *module, const char *fmt, va_list ap )
/* It'd be nice to be able to support the @fail option for the tiff loader, but /* It'd be nice to be able to support the @fail option for the tiff loader, but
* there's no easy way to do this, since libtiff has a global warning handler. * there's no easy way to do this, since libtiff has a global warning handler.
*/ */
static void static void
vips__thandler_warning( const char *module, const char *fmt, va_list ap ) vips__thandler_warning( const char *module, const char *fmt, va_list ap )
{ {
g_logv( G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap ); g_logv( G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, fmt, ap );
@ -106,22 +106,22 @@ vips__tiff_openout( const char *path, gboolean bigtiff )
GError *error = NULL; GError *error = NULL;
wchar_t *path16; wchar_t *path16;
if( !(path16 = (wchar_t *) if( !(path16 = (wchar_t *)
g_utf8_to_utf16( path, -1, NULL, NULL, &error )) ) { g_utf8_to_utf16( path, -1, NULL, NULL, &error )) ) {
vips_g_error( &error ); vips_g_error( &error );
return( NULL ); return( NULL );
} }
tif = TIFFOpenW( path16, mode ); tif = TIFFOpenW( path16, mode );
g_free( path16 ); g_free( path16 );
} }
#else /*!OS_WIN32*/ #else /*!OS_WIN32*/
tif = TIFFOpen( path, mode ); tif = TIFFOpen( path, mode );
#endif /*OS_WIN32*/ #endif /*OS_WIN32*/
if( !tif ) { if( !tif ) {
vips_error( "tiff", vips_error( "tiff",
_( "unable to open \"%s\" for output" ), path ); _( "unable to open \"%s\" for output" ), path );
return( NULL ); return( NULL );
} }
@ -129,7 +129,7 @@ vips__tiff_openout( const char *path, gboolean bigtiff )
return( tif ); return( tif );
} }
/* Open TIFF for input from a file. /* Open TIFF for input from a file.
*/ */
TIFF * TIFF *
vips__tiff_openin( const char *path ) vips__tiff_openin( const char *path )
@ -142,7 +142,7 @@ vips__tiff_openin( const char *path )
TIFF *tif; TIFF *tif;
#ifdef DEBUG #ifdef DEBUG
printf( "vips__tiff_openin( \"%s\" )\n", path ); printf( "vips__tiff_openin( \"%s\" )\n", path );
#endif /*DEBUG*/ #endif /*DEBUG*/
/* Need the utf-16 version on Windows. /* Need the utf-16 version on Windows.
@ -152,22 +152,22 @@ vips__tiff_openin( const char *path )
GError *error = NULL; GError *error = NULL;
wchar_t *path16; wchar_t *path16;
if( !(path16 = (wchar_t *) if( !(path16 = (wchar_t *)
g_utf8_to_utf16( path, -1, NULL, NULL, &error )) ) { g_utf8_to_utf16( path, -1, NULL, NULL, &error )) ) {
vips_g_error( &error ); vips_g_error( &error );
return( NULL ); return( NULL );
} }
tif = TIFFOpenW( path16, mode ); tif = TIFFOpenW( path16, mode );
g_free( path16 ); g_free( path16 );
} }
#else /*!OS_WIN32*/ #else /*!OS_WIN32*/
tif = TIFFOpen( path, mode ); tif = TIFFOpen( path, mode );
#endif /*OS_WIN32*/ #endif /*OS_WIN32*/
if( !tif ) { if( !tif ) {
vips_error( "tiff", vips_error( "tiff",
_( "unable to open \"%s\" for input" ), path ); _( "unable to open \"%s\" for input" ), path );
return( NULL ); return( NULL );
} }
@ -175,7 +175,7 @@ vips__tiff_openin( const char *path )
return( tif ); return( tif );
} }
/* TIFF input from a memory buffer. /* TIFF input from a memory buffer.
*/ */
typedef struct _VipsTiffOpeninBuffer { typedef struct _VipsTiffOpeninBuffer {
@ -184,7 +184,7 @@ typedef struct _VipsTiffOpeninBuffer {
size_t length; size_t length;
} VipsTiffOpeninBuffer; } VipsTiffOpeninBuffer;
static tsize_t static tsize_t
openin_buffer_read( thandle_t st, tdata_t data, tsize_t size ) openin_buffer_read( thandle_t st, tdata_t data, tsize_t size )
{ {
VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st; VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st;
@ -193,38 +193,38 @@ openin_buffer_read( thandle_t st, tdata_t data, tsize_t size )
size_t copied; size_t copied;
if( buffer->position > buffer->length ) { if( buffer->position > buffer->length ) {
vips_error( "openin_buffer_read", vips_error( "openin_buffer_read",
"%s", _( "read beyond end of buffer" ) ); "%s", _( "read beyond end of buffer" ) );
return( 0 ); return( 0 );
} }
available = buffer->length - buffer->position; available = buffer->length - buffer->position;
copied = VIPS_MIN( size, available ); copied = VIPS_MIN( size, available );
memcpy( data, memcpy( data,
(unsigned char *) buffer->data + buffer->position, copied ); (unsigned char *) buffer->data + buffer->position, copied );
buffer->position += copied; buffer->position += copied;
return( copied ); return( copied );
} }
static tsize_t static tsize_t
openin_buffer_write( thandle_t st, tdata_t buffer, tsize_t size ) openin_buffer_write( thandle_t st, tdata_t buffer, tsize_t size )
{ {
g_assert_not_reached(); g_assert_not_reached();
return( 0 ); return( 0 );
} }
static int static int
openin_buffer_close( thandle_t st ) openin_buffer_close( thandle_t st )
{ {
return( 0 ); return( 0 );
} }
/* After calling this, ->pos is not bound by the size of the buffer, it can /* After calling this, ->pos is not bound by the size of the buffer, it can
* have any positive value. * have any positive value.
*/ */
static toff_t static toff_t
openin_buffer_seek( thandle_t st, toff_t position, int whence ) openin_buffer_seek( thandle_t st, toff_t position, int whence )
{ {
VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st; VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st;
@ -236,31 +236,31 @@ openin_buffer_seek( thandle_t st, toff_t position, int whence )
else if( whence == SEEK_END ) else if( whence == SEEK_END )
buffer->position = buffer->length + position; buffer->position = buffer->length + position;
else else
g_assert_not_reached(); g_assert_not_reached();
return( buffer->position ); return( buffer->position );
} }
static toff_t static toff_t
openin_buffer_size( thandle_t st ) openin_buffer_size( thandle_t st )
{ {
VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st; VipsTiffOpeninBuffer *buffer = (VipsTiffOpeninBuffer *) st;
return( buffer->length ); return( buffer->length );
} }
static int static int
openin_buffer_map( thandle_t st, tdata_t *start, toff_t *len ) openin_buffer_map( thandle_t st, tdata_t *start, toff_t *len )
{ {
g_assert_not_reached(); g_assert_not_reached();
return( 0 ); return( 0 );
} }
static void static void
openin_buffer_unmap( thandle_t st, tdata_t start, toff_t len ) openin_buffer_unmap( thandle_t st, tdata_t start, toff_t len )
{ {
g_assert_not_reached(); g_assert_not_reached();
return; return;
} }
@ -272,7 +272,7 @@ vips__tiff_openin_buffer( VipsImage *image, const void *data, size_t length )
TIFF *tiff; TIFF *tiff;
#ifdef DEBUG #ifdef DEBUG
printf( "vips__tiff_openin_buffer:\n" ); printf( "vips__tiff_openin_buffer:\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
buffer = VIPS_NEW( image, VipsTiffOpeninBuffer ); buffer = VIPS_NEW( image, VipsTiffOpeninBuffer );
@ -282,26 +282,26 @@ vips__tiff_openin_buffer( VipsImage *image, const void *data, size_t length )
if( !(tiff = TIFFClientOpen( "memory input", "rm", if( !(tiff = TIFFClientOpen( "memory input", "rm",
(thandle_t) buffer, (thandle_t) buffer,
openin_buffer_read, openin_buffer_read,
openin_buffer_write, openin_buffer_write,
openin_buffer_seek, openin_buffer_seek,
openin_buffer_close, openin_buffer_close,
openin_buffer_size, openin_buffer_size,
openin_buffer_map, openin_buffer_map,
openin_buffer_unmap )) ) { openin_buffer_unmap )) ) {
vips_error( "vips__tiff_openin_buffer", "%s", vips_error( "vips__tiff_openin_buffer", "%s",
_( "unable to open memory buffer for input" ) ); _( "unable to open memory buffer for input" ) );
return( NULL ); return( NULL );
} }
return( tiff ); return( tiff );
} }
/* TIFF output to a memory buffer. /* TIFF output to a memory buffer.
*/ */
typedef struct _VipsTiffOpenoutBuffer { typedef struct _VipsTiffOpenoutBuffer {
VipsDbuf dbuf; VipsDbuf dbuf;
/* On close, consolidate and write the output here. /* On close, consolidate and write the output here.
*/ */
@ -309,91 +309,96 @@ typedef struct _VipsTiffOpenoutBuffer {
size_t *out_length; size_t *out_length;
} VipsTiffOpenoutBuffer; } VipsTiffOpenoutBuffer;
static tsize_t static tsize_t
openout_buffer_read( thandle_t st, tdata_t data, tsize_t size ) openout_buffer_read( thandle_t st, tdata_t data, tsize_t size )
{ {
VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st; VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
off_t write_point; #ifdef DEBUG
size_t available; printf( "openout_buffer_read: %zd bytes\n", size );
unsigned char *from; #endif /*DEBUG*/
write_point = vips_dbuf_tell( &buffer->dbuf ); return( vips_dbuf_read( &buffer->dbuf, data, size ) );
from = vips_dbuf_get_write( &buffer->dbuf, &available );
vips_dbuf_seek( &buffer->dbuf, write_point, SEEK_SET );
if( available < size ) {
vips_error( "openout_buffer_read",
"%s", _( "read beyond end of buffer" ) );
return( 0 );
}
memcpy( data, from, size );
vips_dbuf_seek( &buffer->dbuf, size, SEEK_CUR );
return( size );
} }
static tsize_t static tsize_t
openout_buffer_write( thandle_t st, tdata_t data, tsize_t size ) openout_buffer_write( thandle_t st, tdata_t data, tsize_t size )
{ {
VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st; VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
#ifdef DEBUG #ifdef DEBUG
printf( "openout_buffer_write: %zd bytes\n", size ); printf( "openout_buffer_write: %zd bytes\n", size );
#endif /*DEBUG*/ #endif /*DEBUG*/
vips_dbuf_write( &buffer->dbuf, data, size ); vips_dbuf_write( &buffer->dbuf, data, size );
return( size ); return( size );
} }
static int static int
openout_buffer_close( thandle_t st ) openout_buffer_close( thandle_t st )
{ {
VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st; VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
*(buffer->out_data) = vips_dbuf_steal( &buffer->dbuf, *(buffer->out_data) = vips_dbuf_steal( &buffer->dbuf,
buffer->out_length); buffer->out_length);
return( 0 ); return( 0 );
} }
static toff_t static toff_t
openout_buffer_seek( thandle_t st, toff_t position, int whence ) openout_buffer_seek( thandle_t st, toff_t position, int whence )
{ {
VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st; VipsTiffOpenoutBuffer *buffer = (VipsTiffOpenoutBuffer *) st;
#ifdef DEBUG #ifdef DEBUG
printf( "openout_buffer_seek: position %zd, whence %d\n", printf( "openout_buffer_seek: position %zd, whence %d ",
position, whence ); position, whence );
switch( whence ) {
case SEEK_SET:
printf( "set" );
break;
case SEEK_END:
printf( "end" );
break;
case SEEK_CUR:
printf( "cur" );
break;
default:
printf( "unknown" );
break;
}
printf( "\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
vips_dbuf_seek( &buffer->dbuf, position, whence ); vips_dbuf_seek( &buffer->dbuf, position, whence );
return( vips_dbuf_tell( &buffer->dbuf ) ); return( vips_dbuf_tell( &buffer->dbuf ) );
} }
static toff_t static toff_t
openout_buffer_size( thandle_t st ) openout_buffer_size( thandle_t st )
{ {
g_assert_not_reached(); g_assert_not_reached();
return( 0 );
}
static int
openout_buffer_map( thandle_t st, tdata_t *start, toff_t *len )
{
g_assert_not_reached();
return( 0 ); return( 0 );
} }
static void static int
openout_buffer_map( thandle_t st, tdata_t *start, toff_t *len )
{
g_assert_not_reached();
return( 0 );
}
static void
openout_buffer_unmap( thandle_t st, tdata_t start, toff_t len ) openout_buffer_unmap( thandle_t st, tdata_t start, toff_t len )
{ {
g_assert_not_reached(); g_assert_not_reached();
return; return;
} }
@ -401,7 +406,7 @@ openout_buffer_unmap( thandle_t st, tdata_t start, toff_t len )
/* On TIFFClose(), @data and @length are set to point to the output buffer. /* On TIFFClose(), @data and @length are set to point to the output buffer.
*/ */
TIFF * TIFF *
vips__tiff_openout_buffer( VipsImage *image, vips__tiff_openout_buffer( VipsImage *image,
gboolean bigtiff, void **out_data, size_t *out_length ) gboolean bigtiff, void **out_data, size_t *out_length )
{ {
const char *mode = bigtiff ? "w8" : "w"; const char *mode = bigtiff ? "w8" : "w";
@ -410,29 +415,29 @@ vips__tiff_openout_buffer( VipsImage *image,
TIFF *tiff; TIFF *tiff;
#ifdef DEBUG #ifdef DEBUG
printf( "vips__tiff_openout_buffer:\n" ); printf( "vips__tiff_openout_buffer:\n" );
#endif /*DEBUG*/ #endif /*DEBUG*/
buffer = VIPS_NEW( image, VipsTiffOpenoutBuffer ); buffer = VIPS_NEW( image, VipsTiffOpenoutBuffer );
vips_dbuf_init( &buffer->dbuf ); vips_dbuf_init( &buffer->dbuf );
buffer->out_data = out_data; buffer->out_data = out_data;
buffer->out_length = out_length; buffer->out_length = out_length;
if( !(tiff = TIFFClientOpen( "memory output", mode, if( !(tiff = TIFFClientOpen( "memory output", mode,
(thandle_t) buffer, (thandle_t) buffer,
openout_buffer_read, openout_buffer_read,
openout_buffer_write, openout_buffer_write,
openout_buffer_seek, openout_buffer_seek,
openout_buffer_close, openout_buffer_close,
openout_buffer_size, openout_buffer_size,
openout_buffer_map, openout_buffer_map,
openout_buffer_unmap )) ) { openout_buffer_unmap )) ) {
vips_error( "vips__tiff_openout_buffer", "%s", vips_error( "vips__tiff_openout_buffer", "%s",
_( "unable to open memory buffer for output" ) ); _( "unable to open memory buffer for output" ) );
return( NULL ); return( NULL );
} }
return( tiff ); return( tiff );
} }
#endif /*HAVE_TIFF*/ #endif /*HAVE_TIFF*/

View File

@ -64,6 +64,7 @@ typedef struct _VipsDbuf {
void vips_dbuf_destroy( VipsDbuf *buf ); void vips_dbuf_destroy( VipsDbuf *buf );
void vips_dbuf_init( VipsDbuf *buf ); void vips_dbuf_init( VipsDbuf *buf );
gboolean vips_dbuf_allocate( VipsDbuf *dbuf, size_t size ); gboolean vips_dbuf_allocate( VipsDbuf *dbuf, size_t size );
size_t vips_dbuf_read( VipsDbuf *dbuf, unsigned char *data, size_t size );
unsigned char *vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size ); unsigned char *vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size );
gboolean vips_dbuf_write( VipsDbuf *dbuf, gboolean vips_dbuf_write( VipsDbuf *dbuf,
const unsigned char *data, size_t size ); const unsigned char *data, size_t size );

View File

@ -69,7 +69,7 @@ gboolean
vips_dbuf_minimum_size( VipsDbuf *dbuf, size_t size ) vips_dbuf_minimum_size( VipsDbuf *dbuf, size_t size )
{ {
if( size > dbuf->allocated_size ) { if( size > dbuf->allocated_size ) {
size_t new_allocated_size = 3 * (16 + size) / 2; const size_t new_allocated_size = 3 * (16 + size) / 2;
unsigned char *new_data; unsigned char *new_data;
@ -102,25 +102,26 @@ vips_dbuf_allocate( VipsDbuf *dbuf, size_t size )
} }
/** /**
* vips_dbuf_null_terminate: * vips_dbuf_read:
* @dbuf: the buffer * @dbuf: the buffer
* @data: read to this area
* @size: read up to this many bytes
* *
* Make sure the byte after the last data byte is `\0`. This extra byte is not * Up to @size bytes are read from the buffer and copied to @data. The number
* included in the data size and the write point is not moved. * of bytes transferred is returned.
* *
* This makes it safe to treat the dbuf contents as a C string. * Returns: the number of bytes transferred.
*
* Returns: %FALSE on out of memory, %TRUE otherwise.
*/ */
static gboolean size_t
vips_dbuf_null_terminate( VipsDbuf *dbuf ) vips_dbuf_read( VipsDbuf *dbuf, unsigned char *data, size_t size )
{ {
if( !vips_dbuf_minimum_size( dbuf, dbuf->data_size + 1 ) ) const size_t available = dbuf->data_size - dbuf->write_point;
return( FALSE ); const size_t copied = VIPS_MIN( size, available );
dbuf->data[dbuf->data_size] = 0; memcpy( data, dbuf->data + dbuf->write_point, copied );
dbuf->write_point += copied;
return( TRUE ); return( copied );
} }
/** /**
@ -141,14 +142,14 @@ unsigned char *
vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size ) vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size )
{ {
unsigned char *write = dbuf->data + dbuf->write_point; unsigned char *write = dbuf->data + dbuf->write_point;
size_t length = dbuf->data + dbuf->allocated_size - write; const size_t available = dbuf->allocated_size - dbuf->write_point;
memset( write, 0, length ); memset( write, 0, available );
dbuf->write_point = dbuf->allocated_size; dbuf->write_point = dbuf->allocated_size;
dbuf->data_size = dbuf->allocated_size; dbuf->data_size = dbuf->allocated_size;
if( size ) if( size )
*size = length; *size = available;
return( write ); return( write );
} }
@ -310,6 +311,28 @@ vips_dbuf_tell( VipsDbuf *dbuf )
return( dbuf->write_point ); return( dbuf->write_point );
} }
/**
* vips_dbuf_null_terminate:
* @dbuf: the buffer
*
* Make sure the byte after the last data byte is `\0`. This extra byte is not
* included in the data size and the write point is not moved.
*
* 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 );
dbuf->data[dbuf->data_size] = 0;
return( TRUE );
}
/** /**
* vips_dbuf_steal: * vips_dbuf_steal:
* @dbuf: the buffer * @dbuf: the buffer