rename VipsStreamib as VipsBufis

The VipsStreamib (stream input buffered) was misleading -- it was
implemented on top of VipsStreami, but was not a subclass.

Rename as VipsBufis (buffered input stream). It's a silly name, but
easy to remember and reflects the purpose better,
This commit is contained in:
John Cupitt 2019-11-18 13:09:04 +00:00
parent 6b5035c160
commit 09325600ee
10 changed files with 328 additions and 291 deletions

View File

@ -147,7 +147,6 @@ extern const char *vips__ppm_suffs[];
int vips__ppm_save_stream( VipsImage *in, VipsStreamo *streamo,
gboolean ascii, gboolean squash );
int vips__rad_israd( VipsStreami *streami );
int vips__rad_header( VipsStreami *streami, VipsImage *out );
int vips__rad_load( VipsStreami *streami, VipsImage *out );

View File

@ -88,10 +88,10 @@
typedef struct _VipsForeignLoadPpm {
VipsForeignLoad parent_object;
/* The stream we load from, and the buffered wrapper.
/* The stream we load from, and the buffered wrapper for it.
*/
VipsStreami *streami;
VipsStreamib *streamib;
VipsBufis *bufis;
/* Properties of this ppm, from the header.
*/
@ -103,7 +103,7 @@ typedef struct _VipsForeignLoadPpm {
float scale;
int max_value;
int index; /* ppm type .. index in magic_names[] */
int bits; /* 1, 8 or 32 */
int bits; /* 1, 8, 16 or 32 */
gboolean ascii; /* TRUE for ascii encoding */
gboolean msb_first; /* TRUE if most sig byte is first */
@ -150,12 +150,12 @@ vips_foreign_load_ppm_is_a_stream( VipsStreami *streami )
}
static int
get_int( VipsStreamib *streamib, int *i )
get_int( VipsBufis *bufis, int *i )
{
const char *txt;
if( vips_streamib_skip_whitespace( streamib ) ||
!(txt = vips_streamib_get_non_whitespace( streamib )) )
if( vips_bufis_skip_whitespace( bufis ) ||
!(txt = vips_bufis_get_non_whitespace( bufis )) )
return( -1 );
*i = atoi( txt );
@ -164,12 +164,12 @@ get_int( VipsStreamib *streamib, int *i )
}
static int
get_float( VipsStreamib *streamib, float *f )
get_float( VipsBufis *bufis, float *f )
{
const char *txt;
if( vips_streamib_skip_whitespace( streamib ) ||
!(txt = vips_streamib_get_non_whitespace( streamib )) )
if( vips_bufis_skip_whitespace( bufis ) ||
!(txt = vips_bufis_get_non_whitespace( bufis )) )
return( -1 );
/* We don't want the locale str -> float conversion.
@ -184,7 +184,7 @@ vips_foreign_load_ppm_dispose( GObject *gobject )
{
VipsForeignLoadPpm *ppm = (VipsForeignLoadPpm *) gobject;
VIPS_UNREF( ppm->streamib );
VIPS_UNREF( ppm->bufis );
VIPS_UNREF( ppm->streami );
G_OBJECT_CLASS( vips_foreign_load_ppm_parent_class )->
@ -218,8 +218,8 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
/* Read in the magic number.
*/
buf[0] = VIPS_STREAMIB_GETC( ppm->streamib );
buf[1] = VIPS_STREAMIB_GETC( ppm->streamib );
buf[0] = VIPS_BUFIS_GETC( ppm->bufis );
buf[1] = VIPS_BUFIS_GETC( ppm->bufis );
for( i = 0; i < VIPS_NUMBER( magic_names ); i++ )
if( vips_isprefix( magic_names[i], buf ) )
@ -239,8 +239,8 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
/* Read in size.
*/
if( get_int( ppm->streamib, &ppm->width ) ||
get_int( ppm->streamib, &ppm->height ) )
if( get_int( ppm->bufis, &ppm->width ) ||
get_int( ppm->bufis, &ppm->height ) )
return( -1 );
/* Read in max value / scale for >1 bit images.
@ -248,7 +248,7 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
if( ppm->bits > 1 ) {
if( ppm->index == 6 ||
ppm->index == 7 ) {
if( get_float( ppm->streamib, &ppm->scale ) )
if( get_float( ppm->bufis, &ppm->scale ) )
return( -1 );
/* Scale > 0 means big-endian.
@ -256,7 +256,7 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
ppm->msb_first = ppm->scale > 0;
}
else {
if( get_int( ppm->streamib, &ppm->max_value ) )
if( get_int( ppm->bufis, &ppm->max_value ) )
return( -1 );
if( ppm->max_value > 255 )
@ -270,7 +270,7 @@ vips_foreign_load_ppm_parse_header( VipsForeignLoadPpm *ppm )
* character before the data starts.
*/
if( !ppm->ascii &&
!isspace( VIPS_STREAMIB_GETC( ppm->streamib ) ) ) {
!isspace( VIPS_BUFIS_GETC( ppm->bufis ) ) ) {
vips_error( class->nickname, "%s",
_( "no whitespace before start of binary data" ) );
return( -1 );
@ -368,7 +368,7 @@ vips_foreign_load_ppm_set_image( VipsForeignLoadPpm *ppm, VipsImage *image )
"ppm-max-value", VIPS_FABS( ppm->max_value ) );
VIPS_SETSTR( image->filename,
vips_stream_filename( VIPS_STREAM( ppm->streamib->streami ) ) );
vips_stream_filename( VIPS_STREAM( ppm->bufis->streami ) ) );
}
static int
@ -399,7 +399,7 @@ vips_foreign_load_ppm_map( VipsForeignLoadPpm *ppm, VipsImage *image )
size_t length;
const void *data;
vips_streamib_unbuffer( ppm->streamib );
vips_bufis_unbuffer( ppm->bufis );
header_offset = vips_streami_seek( ppm->streami, 0, SEEK_CUR );
data = vips_streami_map( ppm->streami, &length );
if( header_offset < 0 ||
@ -462,7 +462,7 @@ vips_foreign_load_ppm_generate_1bit_ascii( VipsRegion *or,
for( x = 0; x < image->Xsize; x++ ) {
int val;
if( get_int( ppm->streamib, &val ) )
if( get_int( ppm->bufis, &val ) )
return( -1 );
if( val )
@ -486,7 +486,7 @@ vips_foreign_load_ppm_generate_1bit_binary( VipsRegion *or,
int x, y;
int bits;
bits = VIPS_STREAMIB_GETC( ppm->streamib );
bits = VIPS_BUFIS_GETC( ppm->bufis );
for( y = 0; y < r->height; y++ ) {
VipsPel *q = VIPS_REGION_ADDR( or, 0, r->top + y );
@ -494,13 +494,13 @@ vips_foreign_load_ppm_generate_1bit_binary( VipsRegion *or,
q[x] = (bits & 128) ? 0 : 255;
bits = VIPS_LSHIFT_INT( bits, 1 );
if( (x & 7) == 7 )
bits = VIPS_STREAMIB_GETC( ppm->streamib );
bits = VIPS_BUFIS_GETC( ppm->bufis );
}
/* Skip any unaligned bits at end of line.
*/
if( (x & 7) != 0 )
bits = VIPS_STREAMIB_GETC( ppm->streamib );
bits = VIPS_BUFIS_GETC( ppm->bufis );
}
return( 0 );
@ -523,7 +523,7 @@ vips_foreign_load_ppm_generate_ascii_int( VipsRegion *or,
for( i = 0; i < n_elements; i++ ) {
int val;
if( get_int( ppm->streamib, &val ) )
if( get_int( ppm->bufis, &val ) )
return( -1 );
switch( image->BandFmt ) {
@ -581,7 +581,7 @@ vips_foreign_load_ppm_load( VipsForeignLoad *load )
/* The binary loader does not use the buffered IO
* object.
*/
vips_streamib_unbuffer( ppm->streamib );
vips_bufis_unbuffer( ppm->bufis );
}
else if( !ppm->ascii && ppm->bits == 1 )
generate = vips_foreign_load_ppm_generate_1bit_binary;
@ -674,7 +674,7 @@ vips_foreign_load_ppm_file_build( VipsObject *object )
if( !(ppm->streami =
vips_streami_new_from_filename( file->filename )) )
return( -1 );
ppm->streamib = vips_streamib_new( ppm->streami );
ppm->bufis = vips_bufis_new_from_streami( ppm->streami );
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_ppm_file_parent_class )->

View File

@ -4,7 +4,6 @@
* - wrap a class around the ppm writer
* 13/11/19
* - redone with streams
* - faster plus lower memory use
*/
/*

View File

@ -500,7 +500,7 @@ formatval( /* get format value (return true if format) */
static int
getheader( /* get header from file */
VipsStreamib *streamib,
VipsBufis *bufis,
gethfunc *f,
void *p
)
@ -508,7 +508,7 @@ getheader( /* get header from file */
for(;;) {
const char *line;
if( !(line = vips_streamib_get_line( streamib )) )
if( !(line = vips_bufis_get_line( bufis )) )
return( -1 );
if( strcmp( line, "" ) == 0 )
/* Blank line. We've parsed the header successfully.
@ -526,20 +526,20 @@ getheader( /* get header from file */
/* Read a single scanline, encoded in the old style.
*/
static int
scanline_read_old( VipsStreamib *streamib, COLR *scanline, int width )
scanline_read_old( VipsBufis *bufis, COLR *scanline, int width )
{
int rshift;
rshift = 0;
while( width > 0 ) {
if( VIPS_STREAMIB_REQUIRE( streamib, 4 ) )
if( VIPS_BUFIS_REQUIRE( bufis, 4 ) )
return( -1 );
scanline[0][RED] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][GRN] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][BLU] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][EXP] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][RED] = VIPS_BUFIS_FETCH( bufis );
scanline[0][GRN] = VIPS_BUFIS_FETCH( bufis );
scanline[0][BLU] = VIPS_BUFIS_FETCH( bufis );
scanline[0][EXP] = VIPS_BUFIS_FETCH( bufis );
if( scanline[0][RED] == 1 &&
scanline[0][GRN] == 1 &&
@ -568,7 +568,7 @@ scanline_read_old( VipsStreamib *streamib, COLR *scanline, int width )
/* Read a single encoded scanline.
*/
static int
scanline_read( VipsStreamib *streamib, COLR *scanline, int width )
scanline_read( VipsBufis *bufis, COLR *scanline, int width )
{
int i, j;
@ -576,21 +576,21 @@ scanline_read( VipsStreamib *streamib, COLR *scanline, int width )
*/
if( width < MINELEN ||
width > MAXELEN )
return( scanline_read_old( streamib, scanline, width ) );
return( scanline_read_old( bufis, scanline, width ) );
if( VIPS_STREAMIB_REQUIRE( streamib, 4 ) )
if( VIPS_BUFIS_REQUIRE( bufis, 4 ) )
return( -1 );
if( VIPS_STREAMIB_PEEK( streamib )[0] != 2 )
return( scanline_read_old( streamib, scanline, width ) );
if( VIPS_BUFIS_PEEK( bufis )[0] != 2 )
return( scanline_read_old( bufis, scanline, width ) );
scanline[0][RED] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][GRN] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][BLU] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][EXP] = VIPS_STREAMIB_FETCH( streamib );
scanline[0][RED] = VIPS_BUFIS_FETCH( bufis );
scanline[0][GRN] = VIPS_BUFIS_FETCH( bufis );
scanline[0][BLU] = VIPS_BUFIS_FETCH( bufis );
scanline[0][EXP] = VIPS_BUFIS_FETCH( bufis );
if( scanline[0][GRN] != 2 ||
scanline[0][BLU] & 128 )
return( scanline_read_old( streamib,
return( scanline_read_old( bufis,
scanline + 1, width - 1 ) );
if( ((scanline[0][BLU] << 8) | scanline[0][EXP]) != width ) {
@ -603,10 +603,10 @@ scanline_read( VipsStreamib *streamib, COLR *scanline, int width )
int code, len;
gboolean run;
if( VIPS_STREAMIB_REQUIRE( streamib, 2 ) )
if( VIPS_BUFIS_REQUIRE( bufis, 2 ) )
return( -1 );
code = VIPS_STREAMIB_FETCH( streamib );
code = VIPS_BUFIS_FETCH( bufis );
run = code > 128;
len = run ? code & 127 : code;
@ -618,16 +618,16 @@ scanline_read( VipsStreamib *streamib, COLR *scanline, int width )
if( run ) {
int val;
val = VIPS_STREAMIB_FETCH( streamib );
val = VIPS_BUFIS_FETCH( bufis );
while( len-- )
scanline[j++][i] = val;
}
else {
if( VIPS_STREAMIB_REQUIRE( streamib, len ) )
if( VIPS_BUFIS_REQUIRE( bufis, len ) )
return( -1 );
while( len-- )
scanline[j++][i] =
VIPS_STREAMIB_FETCH( streamib );
VIPS_BUFIS_FETCH( bufis );
}
}
@ -710,7 +710,7 @@ rle_scanline_write( COLR *scanline, int width,
/* What we track during radiance file read.
*/
typedef struct {
VipsStreamib *streamib;
VipsBufis *bufis;
VipsImage *out;
char format[256];
@ -724,16 +724,16 @@ typedef struct {
int
vips__rad_israd( VipsStreami *streami )
{
VipsStreamib *streamib;
VipsBufis *bufis;
const char *line;
int result;
/* Just test that the first line is the magic string.
*/
streamib = vips_streamib_new( streami );
result = (line = vips_streamib_get_line( streamib )) &&
bufis = vips_bufis_new_from_streami( streami );
result = (line = vips_bufis_get_line( bufis )) &&
strcmp( line, "#?RADIANCE" ) == 0;
VIPS_UNREF( streamib );
VIPS_UNREF( bufis );
return( result );
}
@ -741,14 +741,14 @@ vips__rad_israd( VipsStreami *streami )
static void
read_destroy( VipsObject *object, Read *read )
{
VIPS_UNREF( read->streamib );
VIPS_UNREF( read->bufis );
}
static void
read_minimise_cb( VipsObject *object, Read *read )
{
if( read->streamib )
vips_streami_minimise( read->streamib->streami );
if( read->bufis )
vips_streami_minimise( read->bufis->streami );
}
static Read *
@ -763,7 +763,7 @@ read_new( VipsStreami *streami, VipsImage *out )
if( !(read = VIPS_NEW( out, Read )) )
return( NULL );
read->streamib = vips_streamib_new( streami );
read->bufis = vips_bufis_new_from_streami( streami );
read->out = out;
strcpy( read->format, COLRFMT );
read->expos = 1.0;
@ -837,9 +837,9 @@ rad2vips_get_header( Read *read, VipsImage *out )
int height;
int i, j;
if( getheader( read->streamib,
if( getheader( read->bufis,
(gethfunc *) rad2vips_process_line, read ) ||
!(line = vips_streamib_get_line( read->streamib )) ||
!(line = vips_bufis_get_line( read->bufis )) ||
!str2resolu( &read->rs, line ) ) {
vips_error( "rad2vips", "%s",
_( "error reading radiance header" ) );
@ -870,7 +870,7 @@ rad2vips_get_header( Read *read, VipsImage *out )
VIPS_SETSTR( out->filename,
vips_stream_filename(
VIPS_STREAM( read->streamib->streami ) ) );
VIPS_STREAM( read->bufis->streami ) ) );
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
@ -926,7 +926,7 @@ rad2vips_generate( VipsRegion *or,
COLR *buf = (COLR *)
VIPS_REGION_ADDR( or, 0, r->top + y );
if( scanline_read( read->streamib, buf, or->im->Xsize ) ) {
if( scanline_read( read->bufis, buf, or->im->Xsize ) ) {
vips_error( "rad2vips",
_( "read error line %d" ), r->top + y );
VIPS_GATE_STOP( "rad2vips_generate: work" );

View File

@ -1,5 +1,6 @@
pkginclude_HEADERS = \
stream.h \
bufis.h \
basic.h \
type.h \
gate.h \

View File

@ -0,0 +1,130 @@
/* Buffered inputput from a VipsStreami
*
* J.Cupitt, 18/11/19
*/
/*
This file is part of VIPS.
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifndef VIPS_BUFIS_H
#define VIPS_BUFIS_H
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
#define VIPS_TYPE_BUFIS (vips_bufis_get_type())
#define VIPS_BUFIS( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_BUFIS, VipsBufis ))
#define VIPS_BUFIS_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_BUFIS, VipsBufisClass))
#define VIPS_IS_BUFIS( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_BUFIS ))
#define VIPS_IS_BUFIS_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_BUFIS ))
#define VIPS_BUFIS_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_BUFIS, VipsBufisClass ))
#define VIPS_BUFIS_BUFFER_SIZE (4096)
/* Layer over streami: read with an input buffer.
*
* Libraries like libjpeg do their own input buffering and need raw IO, but
* others, like radiance, need to parse the input into lines. A buffered read
* class is very convenient.
*/
typedef struct _VipsBufis {
VipsObject parent_object;
/*< private >*/
/* The VipsStreami we wrap.
*/
VipsStreami *streami;
/* The +1 means there's always a \0 byte at the end.
*
* Unsigned char, since we don't want >127 to be -ve.
*
* chars_in_buffer is how many chars we have in input_buffer,
* read_point is the current read position in that buffer.
*/
unsigned char input_buffer[VIPS_BUFIS_BUFFER_SIZE + 1];
int chars_in_buffer;
int read_point;
/* Build lines of text here.
*/
unsigned char line[VIPS_BUFIS_BUFFER_SIZE + 1];
} VipsBufis;
typedef struct _VipsBufisClass {
VipsObjectClass parent_class;
} VipsBufisClass;
GType vips_bufis_get_type( void );
VipsBufis *vips_bufis_new_from_streami( VipsStreami *streami );
void vips_bufis_unbuffer( VipsBufis *streamib );
int vips_bufis_getc( VipsBufis *streamib );
#define VIPS_BUFIS_GETC( S ) ( \
(S)->read_point < (S)->chars_in_buffer ? \
(S)->input_buffer[(S)->read_point++] : \
vips_bufis_getc( S ) \
)
void vips_bufis_ungetc( VipsBufis *streamib );
#define VIPS_BUFIS_UNGETC( S ) { \
if( (S)->read_point > 0 ) \
(S)->read_point -= 1; \
}
int vips_bufis_require( VipsBufis *streamib, int require );
#define VIPS_BUFIS_REQUIRE( S, R ) ( \
(S)->read_point + (R) <= (S)->chars_in_buffer ? \
0 : \
vips_bufis_require( (S), (R) ) \
)
#define VIPS_BUFIS_PEEK( S ) ((S)->input_buffer + (S)->read_point)
#define VIPS_BUFIS_FETCH( S ) ((S)->input_buffer[(S)->read_point++])
const char *vips_bufis_get_line( VipsBufis *streamib );
char *vips_bufis_get_line_copy( VipsBufis *streamib );
const char *vips_bufis_get_non_whitespace( VipsBufis *streamib );
int vips_bufis_skip_whitespace( VipsBufis *streamib );
#ifdef __cplusplus
}
#endif /*__cplusplus*/
#endif /*VIPS_BUFIS_H*/

View File

@ -217,92 +217,6 @@ size_t vips_streami_sniff_at_most( VipsStreami *streami,
unsigned char *vips_streami_sniff( VipsStreami *streami, size_t length );
gint64 vips_streami_size( VipsStreami *streami );
#define VIPS_TYPE_STREAMIB (vips_streamib_get_type())
#define VIPS_STREAMIB( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_STREAMIB, VipsStreamib ))
#define VIPS_STREAMIB_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_STREAMIB, VipsStreamibClass))
#define VIPS_IS_STREAMIB( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_STREAMIB ))
#define VIPS_IS_STREAMIB_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_STREAMIB ))
#define VIPS_STREAMIB_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_STREAMIB, VipsStreamibClass ))
#define VIPS_STREAMIB_BUFFER_SIZE (4096)
/* Layer over streami: read with an input buffer.
*
* Libraries like libjpeg do their own input buffering and need raw IO, but
* others, like radiance, need to parse the input into lines. A buffered read
* class is very convenient.
*/
typedef struct _VipsStreamib {
VipsObject parent_object;
/*< private >*/
/* The VipsStreami we wrap.
*/
VipsStreami *streami;
/* The +1 means there's always a \0 byte at the end.
*
* Unsigned char, since we don't want >127 to be -ve.
*
* chars_in_buffer is how many chars we have in input_buffer,
* read_point is the current read position in that buffer.
*/
unsigned char input_buffer[VIPS_STREAMIB_BUFFER_SIZE + 1];
int chars_in_buffer;
int read_point;
/* Build lines of text here.
*/
unsigned char line[VIPS_STREAMIB_BUFFER_SIZE + 1];
} VipsStreamib;
typedef struct _VipsStreamibClass {
VipsObjectClass parent_class;
} VipsStreamibClass;
GType vips_streamib_get_type( void );
VipsStreamib *vips_streamib_new( VipsStreami *streami );
void vips_streamib_unbuffer( VipsStreamib *streamib );
int vips_streamib_getc( VipsStreamib *streamib );
#define VIPS_STREAMIB_GETC( S ) ( \
(S)->read_point < (S)->chars_in_buffer ? \
(S)->input_buffer[(S)->read_point++] : \
vips_streamib_getc( S ) \
)
void vips_streamib_ungetc( VipsStreamib *streamib );
#define VIPS_STREAMIB_UNGETC( S ) { \
if( (S)->read_point > 0 ) \
(S)->read_point -= 1; \
}
int vips_streamib_require( VipsStreamib *streamib, int require );
#define VIPS_STREAMIB_REQUIRE( S, R ) ( \
(S)->read_point + (R) <= (S)->chars_in_buffer ? \
0 : \
vips_streamib_require( (S), (R) ) \
)
#define VIPS_STREAMIB_PEEK( S ) ((S)->input_buffer + (S)->read_point)
#define VIPS_STREAMIB_FETCH( S ) ((S)->input_buffer[(S)->read_point++])
const char *vips_streamib_get_line( VipsStreamib *streamib );
char *vips_streamib_get_line_copy( VipsStreamib *streamib );
const char *vips_streamib_get_non_whitespace( VipsStreamib *streamib );
int vips_streamib_skip_whitespace( VipsStreamib *streamib );
#define VIPS_TYPE_STREAMIW (vips_streamiw_get_type())
#define VIPS_STREAMIW( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \

View File

@ -115,6 +115,7 @@ extern "C" {
#include <vips/type.h>
#include <vips/gate.h>
#include <vips/stream.h>
#include <vips/bufis.h>
#include <vips/version.h>
#include <vips/rect.h>

View File

@ -3,9 +3,9 @@ noinst_LTLIBRARIES = libiofuncs.la
libiofuncs_la_SOURCES = \
stream.c \
streami.c \
streamib.c \
streamiw.c \
streamo.c \
bufis.c \
dbuf.c \
reorder.c \
vipsmarshal.h \

View File

@ -1,6 +1,6 @@
/* A layer over streami to provide buffered and line-based input.
*
* J.Cupitt, 19/6/14
/* Buffered input from a stream.
*
* J.Cupitt, 18/11/19
*/
/*
@ -30,13 +30,6 @@
*/
/* TODO
*
* - can we map and then close the fd? how about on Windows?
* - make a subclass that lets you set vfuncs as params, inc. close(),
* is_pipe etc.
*/
/*
#define VIPS_DEBUG
*/
@ -63,10 +56,10 @@
#include <vips/internal.h>
#include <vips/debug.h>
G_DEFINE_TYPE( VipsStreamib, vips_streamib, VIPS_TYPE_OBJECT );
G_DEFINE_TYPE( VipsBufis, vips_bufis, VIPS_TYPE_OBJECT );
static void
vips_streamib_class_init( VipsStreamibClass *class )
vips_bufis_class_init( VipsBufisClass *class )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
@ -74,160 +67,160 @@ vips_streamib_class_init( VipsStreamibClass *class )
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "streamib";
object_class->nickname = "bufis";
object_class->description = _( "buffered input stream" );
VIPS_ARG_OBJECT( class, "input", 1,
_( "Input" ),
_( "Stream to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsStreamib, streami ),
G_STRUCT_OFFSET( VipsBufis, streami ),
VIPS_TYPE_STREAMI );
}
static void
vips_streamib_init( VipsStreamib *streamib )
vips_bufis_init( VipsBufis *bufis )
{
streamib->read_point = 0;
streamib->chars_in_buffer = 0;
streamib->input_buffer[0] = '\0';
bufis->read_point = 0;
bufis->chars_in_buffer = 0;
bufis->input_buffer[0] = '\0';
}
/**
* vips_streamib_new:
* vips_bufis_new_from_streami:
* @streami: stream to operate on
*
* Create a streamib wrapping a streami.
* Create a bufis wrapping a streami.
*
* Returns: a new #VipsStreamib
* Returns: a new #VipsBufis
*/
VipsStreamib *
vips_streamib_new( VipsStreami *streami )
VipsBufis *
vips_bufis_new_from_streami( VipsStreami *streami )
{
VipsStreamib *streamib;
VipsBufis *bufis;
streamib = VIPS_STREAMIB( g_object_new( VIPS_TYPE_STREAMIB,
bufis = VIPS_BUFIS( g_object_new( VIPS_TYPE_BUFIS,
"input", streami,
NULL ) );
if( vips_object_build( VIPS_OBJECT( streamib ) ) ) {
VIPS_UNREF( streamib );
if( vips_object_build( VIPS_OBJECT( bufis ) ) ) {
VIPS_UNREF( bufis );
return( NULL );
}
return( streamib );
return( bufis );
}
/**
* vips_streamib_unbuffer:
* @streamib: stream to operate on
* vips_bufis_unbuffer:
* @bufis: stream to operate on
*
* Discard the input buffer and reset the read point. You must call this
* before using read or seek on the underlying #VipsStreami class.
*/
void
vips_streamib_unbuffer( VipsStreamib *streamib )
vips_bufis_unbuffer( VipsBufis *bufis )
{
/* We'd read ahead a little way -- seek backwards by that amount.
*/
vips_streami_seek( streamib->streami,
streamib->read_point - streamib->chars_in_buffer, SEEK_CUR );
streamib->read_point = 0;
streamib->chars_in_buffer = 0;
vips_streami_seek( bufis->streami,
bufis->read_point - bufis->chars_in_buffer, SEEK_CUR );
bufis->read_point = 0;
bufis->chars_in_buffer = 0;
}
/* Returns -1 on error, 0 on EOF, otherwise bytes read.
*/
static ssize_t
vips_streamib_refill( VipsStreamib *streamib )
vips_bufis_refill( VipsBufis *bufis )
{
ssize_t bytes_read;
VIPS_DEBUG_MSG( "vips_streamib_refill:\n" );
VIPS_DEBUG_MSG( "vips_bufis_refill:\n" );
/* We should not discard any unread bytes.
*/
g_assert( streamib->read_point == streamib->chars_in_buffer );
g_assert( bufis->read_point == bufis->chars_in_buffer );
bytes_read = vips_streami_read( streamib->streami,
streamib->input_buffer, VIPS_STREAMIB_BUFFER_SIZE );
bytes_read = vips_streami_read( bufis->streami,
bufis->input_buffer, VIPS_BUFIS_BUFFER_SIZE );
if( bytes_read == -1 )
return( -1 );
streamib->read_point = 0;
streamib->chars_in_buffer = bytes_read;
bufis->read_point = 0;
bufis->chars_in_buffer = bytes_read;
/* Always add a null byte so we can use strchr() etc. on lines. This is
* safe because input_buffer is VIPS_STREAMIB_BUFFER_SIZE + 1 bytes.
* safe because input_buffer is VIPS_BUFIS_BUFFER_SIZE + 1 bytes.
*/
streamib->input_buffer[bytes_read] = '\0';
bufis->input_buffer[bytes_read] = '\0';
return( bytes_read );
}
/**
* vips_streamib_getc:
* @streamib: stream to operate on
* vips_bufis_getc:
* @bufis: stream to operate on
*
* Fetch the next character from the stream.
*
* If you can, use the macro VIPS_STREAMIB_GETC() instead for speed.
* If you can, use the macro VIPS_BUFIS_GETC() instead for speed.
*
* Returns: the next char from @streamib, -1 on read error or EOF.
* Returns: the next char from @bufis, -1 on read error or EOF.
*/
int
vips_streamib_getc( VipsStreamib *streamib )
vips_bufis_getc( VipsBufis *bufis )
{
if( streamib->read_point == streamib->chars_in_buffer &&
vips_streamib_refill( streamib ) <= 0 )
if( bufis->read_point == bufis->chars_in_buffer &&
vips_bufis_refill( bufis ) <= 0 )
return( -1 );
g_assert( streamib->read_point < streamib->chars_in_buffer );
g_assert( bufis->read_point < bufis->chars_in_buffer );
return( streamib->input_buffer[streamib->read_point++] );
return( bufis->input_buffer[bufis->read_point++] );
}
/**
* VIPS_STREAMIB_GETC:
* @streamib: stream to operate on
* VIPS_BUFIS_GETC:
* @bufis: stream to operate on
*
* Fetch the next character from the stream.
*
* Returns: the next char from @streamib, -1 on read error or EOF.
* Returns: the next char from @bufis, -1 on read error or EOF.
*/
/**
* vips_streamib_ungetc:
* @streamib: stream to operate on
* vips_bufis_ungetc:
* @bufis: stream to operate on
*
* The opposite of vips_streamib_getc(): undo the previous getc.
* The opposite of vips_bufis_getc(): undo the previous getc.
*
* unget more than one character is undefined. Unget at the start of the file
* does nothing.
*
* If you can, use the macro VIPS_STREAMIB_UNGETC() instead for speed.
* If you can, use the macro VIPS_BUFIS_UNGETC() instead for speed.
*/
void
vips_streamib_ungetc( VipsStreamib *streamib )
vips_bufis_ungetc( VipsBufis *bufis )
{
if( streamib->read_point > 0 )
streamib->read_point -= 1;
if( bufis->read_point > 0 )
bufis->read_point -= 1;
}
/**
* VIPS_STREAMIB_UNGETC:
* @streamib: stream to operate on
* VIPS_BUFIS_UNGETC:
* @bufis: stream to operate on
*
* The opposite of vips_streamib_getc(): undo the previous getc.
* The opposite of vips_bufis_getc(): undo the previous getc.
*
* unget more than one character is undefined. Unget at the start of the file
* does nothing.
*/
/**
* vips_streamib_require:
* @streamib: stream to operate on
* vips_bufis_require:
* @bufis: stream to operate on
* @require: make sure we have at least this many chars available
*
* Make sure there are at least @require bytes of readahead available.
@ -235,46 +228,46 @@ vips_streamib_ungetc( VipsStreamib *streamib )
* Returns: 0 on success, -1 on error or EOF.
*/
int
vips_streamib_require( VipsStreamib *streamib, int require )
vips_bufis_require( VipsBufis *bufis, int require )
{
g_assert( require < VIPS_STREAMIB_BUFFER_SIZE );
g_assert( streamib->chars_in_buffer >= 0 );
g_assert( streamib->chars_in_buffer <= VIPS_STREAMIB_BUFFER_SIZE );
g_assert( streamib->read_point >= 0 );
g_assert( streamib->read_point <= streamib->chars_in_buffer );
g_assert( require < VIPS_BUFIS_BUFFER_SIZE );
g_assert( bufis->chars_in_buffer >= 0 );
g_assert( bufis->chars_in_buffer <= VIPS_BUFIS_BUFFER_SIZE );
g_assert( bufis->read_point >= 0 );
g_assert( bufis->read_point <= bufis->chars_in_buffer );
VIPS_DEBUG_MSG( "vips_streamib_require: %d\n", require );
VIPS_DEBUG_MSG( "vips_bufis_require: %d\n", require );
if( streamib->read_point + require > streamib->chars_in_buffer ) {
if( bufis->read_point + require > bufis->chars_in_buffer ) {
/* Areas can overlap, so we must memmove().
*/
memmove( streamib->input_buffer,
streamib->input_buffer + streamib->read_point,
streamib->chars_in_buffer - streamib->read_point );
streamib->chars_in_buffer -= streamib->read_point;
streamib->read_point = 0;
memmove( bufis->input_buffer,
bufis->input_buffer + bufis->read_point,
bufis->chars_in_buffer - bufis->read_point );
bufis->chars_in_buffer -= bufis->read_point;
bufis->read_point = 0;
while( require > streamib->chars_in_buffer ) {
unsigned char *to = streamib->input_buffer +
streamib->chars_in_buffer;
while( require > bufis->chars_in_buffer ) {
unsigned char *to = bufis->input_buffer +
bufis->chars_in_buffer;
int space_available =
VIPS_STREAMIB_BUFFER_SIZE -
streamib->chars_in_buffer;
VIPS_BUFIS_BUFFER_SIZE -
bufis->chars_in_buffer;
size_t bytes_read;
if( (bytes_read = vips_streami_read( streamib->streami,
if( (bytes_read = vips_streami_read( bufis->streami,
to, space_available )) == -1 )
return( -1 );
if( bytes_read == 0 ) {
vips_error(
vips_stream_nick( VIPS_STREAM(
streamib->streami ) ),
bufis->streami ) ),
"%s", _( "end of file" ) );
return( -1 );
}
to[bytes_read] = '\0';
streamib->chars_in_buffer += bytes_read;
bufis->chars_in_buffer += bytes_read;
}
}
@ -282,41 +275,41 @@ vips_streamib_require( VipsStreamib *streamib, int require )
}
/**
* VIPS_STREAMIB_REQUIRE:
* @streamib: stream to operate on
* VIPS_BUFIS_REQUIRE:
* @bufis: stream to operate on
* @require: need this many characters
*
* Make sure at least @require characters are available for
* VIPS_STREAMIB_PEEK() and VIPS_STREAMIB_FETCH().
* VIPS_BUFIS_PEEK() and VIPS_BUFIS_FETCH().
*
* Returns: 0 on success, -1 on read error or EOF.
*/
/**
* VIPS_STREAMIB_PEEK:
* @streamib: stream to operate on
* VIPS_BUFIS_PEEK:
* @bufis: stream to operate on
*
* After a successful VIPS_STREAMIB_REQUIRE(), you can index this to get
* After a successful VIPS_BUFIS_REQUIRE(), you can index this to get
* require characters of input.
*
* Returns: a pointer to the next requre characters of input.
*/
/**
* VIPS_STREAMIB_FETCH:
* @streamib: stream to operate on
* VIPS_BUFIS_FETCH:
* @bufis: stream to operate on
*
* After a successful VIPS_STREAMIB_REQUIRE(), you can use this require times
* After a successful VIPS_BUFIS_REQUIRE(), you can use this require times
* to fetch characters of input.
*
* Returns: the next input character.
*/
/**
* vips_streamib_get_line:
* @streamib: stream to operate on
* vips_bufis_get_line:
* @bufis: stream to operate on
*
* Fetch the next line of text from @streamib and return it. The end of
* Fetch the next line of text from @bufis and return it. The end of
* line character (or characters, for DOS files) are removed, and the string
* is terminated with a null (`\0` character).
*
@ -324,33 +317,33 @@ vips_streamib_require( VipsStreamib *streamib, int require )
*
* If the line is longer than some arbitrary (but large) limit, is is
* truncated. If you need to be able to read very long lines, use the
* slower vips_streamib_get_line_copy().
* slower vips_bufis_get_line_copy().
*
* The return value is owned by @streamib and must not be freed. It
* is valid until the next get call @streamib.
* The return value is owned by @bufis and must not be freed. It
* is valid until the next get call @bufis.
*
* Returns: the next line of text, or NULL on EOF or read error.
*/
const char *
vips_streamib_get_line( VipsStreamib *streamib )
vips_bufis_get_line( VipsBufis *bufis )
{
int write_point;
int space_remaining;
int ch;
VIPS_DEBUG_MSG( "vips_streamib_get_line:\n" );
VIPS_DEBUG_MSG( "vips_bufis_get_line:\n" );
write_point = 0;
space_remaining = VIPS_STREAMIB_BUFFER_SIZE;
space_remaining = VIPS_BUFIS_BUFFER_SIZE;
while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 &&
while( (ch = VIPS_BUFIS_GETC( bufis )) != -1 &&
ch != '\n' &&
space_remaining > 0 ) {
streamib->line[write_point] = ch;
bufis->line[write_point] = ch;
write_point += 1;
space_remaining -= 1;
}
streamib->line[write_point] = '\0';
bufis->line[write_point] = '\0';
/* If we hit EOF immediately, return EOF.
*/
@ -365,27 +358,27 @@ vips_streamib_get_line( VipsStreamib *streamib )
* lines, but ignore this.
*/
if( write_point > 0 &&
streamib->line[write_point - 1] == '\r' )
streamib->line[write_point - 1] = '\0';
bufis->line[write_point - 1] == '\r' )
bufis->line[write_point - 1] = '\0';
/* If we filled the output line without seeing \n, keep going to the
* next \n.
*/
if( ch != '\n' &&
space_remaining == 0 ) {
while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 &&
while( (ch = VIPS_BUFIS_GETC( bufis )) != -1 &&
ch != '\n' )
;
}
VIPS_DEBUG_MSG( " %s\n", streamib->line );
VIPS_DEBUG_MSG( " %s\n", bufis->line );
return( (const char *) streamib->line );
return( (const char *) bufis->line );
}
/**
* vips_streamib_get_line_copy:
* @streamib: stream to operate on
* vips_bufis_get_line_copy:
* @bufis: stream to operate on
*
* Return the next line of text from the stream. The newline character (or
* characters) are removed, and and the string is terminated with a null
@ -393,17 +386,17 @@ vips_streamib_get_line( VipsStreamib *streamib )
*
* The return result must be freed with g_free().
*
* This is slower than vips_streamib_get_line(), but can work with lines of
* This is slower than vips_bufis_get_line(), but can work with lines of
* any length.
*
* Returns: the next line of text, or NULL on EOF or read error.
*/
char *
vips_streamib_get_line_copy( VipsStreamib *streamib )
vips_bufis_get_line_copy( VipsBufis *bufis )
{
static const unsigned char null = '\0';
VIPS_DEBUG_MSG( "vips_streamib_get_line_copy:\n" );
VIPS_DEBUG_MSG( "vips_bufis_get_line_copy:\n" );
GByteArray *buffer;
int ch;
@ -411,7 +404,7 @@ vips_streamib_get_line_copy( VipsStreamib *streamib )
buffer = g_byte_array_new();
while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 &&
while( (ch = VIPS_BUFIS_GETC( bufis )) != -1 &&
ch != '\n' ) {
unsigned char c = ch;
@ -444,8 +437,8 @@ vips_streamib_get_line_copy( VipsStreamib *streamib )
}
/**
* vips_streamib_get_non_whitespace:
* @streamib: stream to operate on
* vips_bufis_get_non_whitespace:
* @bufis: stream to operate on
*
* Fetch the next chunk of non-whitespace text from the stream, and
* null-terminate it.
@ -459,28 +452,28 @@ vips_streamib_get_line_copy( VipsStreamib *streamib )
* If the item is longer than some arbitrary (but large) limit, it is
* truncated.
*
* The return value is owned by @streamib and must not be freed. It
* is valid until the next get call @streamib.
* The return value is owned by @bufis and must not be freed. It
* is valid until the next get call @bufis.
*
* Returns: the next block of non-whitespace, or NULL on EOF or read error.
*/
const char *
vips_streamib_get_non_whitespace( VipsStreamib *streamib )
vips_bufis_get_non_whitespace( VipsBufis *bufis )
{
int ch;
int i;
for( i = 0; i < VIPS_STREAMIB_BUFFER_SIZE &&
!isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) &&
for( i = 0; i < VIPS_BUFIS_BUFFER_SIZE &&
!isspace( ch = VIPS_BUFIS_GETC( bufis ) ) &&
ch != EOF; i++ )
streamib->line[i] = ch;
streamib->line[i] = '\0';
bufis->line[i] = ch;
bufis->line[i] = '\0';
/* If we stopped before seeing any whitespace, skip to the end of the
* block of non-whitespace.
*/
if( !isspace( ch ) )
while( !isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) &&
while( !isspace( ch = VIPS_BUFIS_GETC( bufis ) ) &&
ch != EOF )
;
@ -488,14 +481,14 @@ vips_streamib_get_non_whitespace( VipsStreamib *streamib )
* will be whitespace (or EOF).
*/
if( isspace( ch ) )
VIPS_STREAMIB_UNGETC( streamib );
VIPS_BUFIS_UNGETC( bufis );
return( (const char *) streamib->line );
return( (const char *) bufis->line );
}
/**
* vips_streamib_skip_whitespace:
* @streamib: stream to operate on
* vips_bufis_skip_whitespace:
* @bufis: stream to operate on
*
* After this, the next getc will be the first char of the next block of
* non-whitespace (or EOF).
@ -503,19 +496,19 @@ vips_streamib_get_non_whitespace( VipsStreamib *streamib )
* Returns: 0 on success, -1 on error.
*/
int
vips_streamib_skip_whitespace( VipsStreamib *streamib )
vips_bufis_skip_whitespace( VipsBufis *bufis )
{
int ch;
while( isspace( ch = VIPS_STREAMIB_GETC( streamib ) ) )
while( isspace( ch = VIPS_BUFIS_GETC( bufis ) ) )
;
VIPS_STREAMIB_UNGETC( streamib );
VIPS_BUFIS_UNGETC( bufis );
/* # skip comments too.
*/
if( ch == '#' &&
(!vips_streamib_get_line( streamib ) ||
vips_streamib_skip_whitespace( streamib )) )
(!vips_bufis_get_line( bufis ) ||
vips_bufis_skip_whitespace( bufis )) )
return( -1 );
return( 0 );