buffered input compiles

This commit is contained in:
John Cupitt 2019-11-01 23:24:48 +00:00
parent 805da46670
commit 37049af140
2 changed files with 137 additions and 98 deletions

View File

@ -270,6 +270,14 @@ VipsStreamib *vips_streamib_new_from_blob( VipsBlob *blob );
VipsStreamib *vips_streamib_new_from_memory( const void *data, size_t size ); VipsStreamib *vips_streamib_new_from_memory( const void *data, size_t size );
VipsStreamib *vips_streamib_new_from_options( const char *options ); VipsStreamib *vips_streamib_new_from_options( const char *options );
int vips_streamib_getc( VipsStreamib *streamib );
void vips_streamib_ungetc( VipsStreamib *streamib );
#define VIPS_STREAMIB_GETC( S ) ( \
(S)->bytes_remaining > 0 ? \
((S)->bytes_remaining--, ((S)->read_point++)[0]) : \
vips_streamib_getc( S ))
int vips_streamib_get_line( VipsStreamib *streamib, const char **line ); int vips_streamib_get_line( VipsStreamib *streamib, const char **line );
int vips_streamib_get_line_copy( VipsStreamib *streamib, char **line ); int vips_streamib_get_line_copy( VipsStreamib *streamib, char **line );

View File

@ -314,7 +314,7 @@ vips_streami_class_init( VipsStreamiClass *class )
gobject_class->get_property = vips_object_get_property; gobject_class->get_property = vips_object_get_property;
object_class->nickname = "streami"; object_class->nickname = "streami";
object_class->description = _( "streami stream" ); object_class->description = _( "input stream" );
object_class->build = vips_streami_build; object_class->build = vips_streami_build;
@ -1046,43 +1046,13 @@ vips_streami_sniff( VipsStreami *streami, size_t length )
G_DEFINE_TYPE( VipsStreamib, vips_streamib, VIPS_TYPE_STREAMI ); G_DEFINE_TYPE( VipsStreamib, vips_streamib, VIPS_TYPE_STREAMI );
static void
vips_streamib_finalize( GObject *gobject )
{
VipsStreamib *streamib = VIPS_STREAMIB( gobject );
G_OBJECT_CLASS( vips_streamib_parent_class )->finalize( gobject );
}
static int
vips_streamib_build( VipsObject *object )
{
VipsStream *stream = VIPS_STREAM( object );
VipsStreamib *streamib = VIPS_STREAMIB( object );
VipsStreamibClass *class = VIPS_STREAMIB_GET_CLASS( streamib );
VIPS_DEBUG_MSG( "vips_streamib_build: %p\n", streamib );
if( VIPS_OBJECT_CLASS( vips_streamib_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static void static void
vips_streamib_class_init( VipsStreamibClass *class ) vips_streamib_class_init( VipsStreamibClass *class )
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class ); VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
gobject_class->finalize = vips_streamib_finalize;
object_class->nickname = "streamib"; object_class->nickname = "streamib";
object_class->description = _( "streamib stream" ); object_class->description = _( "buffered input stream" );
object_class->build = vips_streamib_build;
} }
static void static void
@ -1090,9 +1060,12 @@ vips_streamib_init( VipsStreamib *streamib )
{ {
streamib->read_point = streamib->input_buffer; streamib->read_point = streamib->input_buffer;
streamib->bytes_remaining = 0; streamib->bytes_remaining = 0;
streamib->read_point[streamib->bytes_remaining] = '\0';
} }
static int /* Returns -1 on error, 0 on EOF, otherwise bytes read.
*/
static ssize_t
vips_streamib_refill( VipsStreamib *streamib ) vips_streamib_refill( VipsStreamib *streamib )
{ {
ssize_t bytes_read; ssize_t bytes_read;
@ -1101,33 +1074,75 @@ vips_streamib_refill( VipsStreamib *streamib )
*/ */
g_assert( streamib->bytes_remaining == 0 ); g_assert( streamib->bytes_remaining == 0 );
streamib->read_postion = streamib->input_buffer; bytes_read = vips_streami_read( VIPS_STREAMI( streamib ),
streamib->bytes_remaining = 0; streamib->input_buffer, VIPS_STREAMIB_BUFFER_SIZE );
if( (bytes_read = vips_streami_read( VIPS_STREAMI( streamib ), if( bytes_read == -1 )
streamib->read_postion, VIPS_STREAMIB_BUFFER_SIZE )) == -1 )
return( -1 ); return( -1 );
streamib->read_point = streamib->input_buffer;
streamib->bytes_remaining = bytes_read; streamib->bytes_remaining = bytes_read;
/* Always add a nul byte so we can use strchr() etc. on lines. This is /* 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_STREAMIB_BUFFER_SIZE + 1 bytes.
*/ */
streamib->read_postion[bytes_read] = '\0'; streamib->read_point[bytes_read] = '\0';
if( bytes_read == 0 ) return( bytes_read );
streamib->eof = TRUE; }
return( 0 ); /**
* vips_streamib_getc:
* @streamib: stream to operate on
*
* Fetch the next character from the stream.
*
* Use VIPS_STREAMIB_GETC() for speed.
*
* Returns: the next char from @streamib, -1 on read error or EOF.
*/
int
vips_streamib_getc( VipsStreamib *streamib )
{
int ch;
if( streamib->bytes_remaining == 0 &&
vips_streamib_refill( streamib ) <= 0 )
return( -1 );
ch = streamib->read_point[0];
streamib->read_point += 1;
streamib->bytes_remaining -= 1;
return( ch );
}
/**
* vips_streamib_ungetc:
* @streamib: stream to operate on
*
* The opposite of vips_streamib_getc: undo the previous getc.
*
* unget more than one character is undefined. Unget at the start of the file
* does nothing.
*/
void
vips_streamib_ungetc( VipsStreamib *streamib )
{
if( streamib->read_point > streamib->input_buffer ) {
streamib->read_point -= 1;
streamib->bytes_remaining += 1;
}
} }
/** /**
* vips_streamib_get_line: * vips_streamib_get_line:
* @streamib: stream to fetch the line from * @streamib: stream to operate on
* @line: return the next line of text here * @line: return the next line of text here
* *
* Fetch the next line of text from @streamib and return in @line. The end of * Fetch the next line of text from @streamib and return in @line. The end of
* line character (or characters, for DOS files) are removed, and and the * line character (or characters, for DOS files) are removed, and @line
* string is terminated with a null (`\0` character). * is terminated with a null (`\0` character).
* *
* @line is set to NULL on end of file. * @line is set to NULL on end of file.
* *
@ -1144,67 +1159,53 @@ int
vips_streamib_get_line( VipsStreamib *streamib, const char **line ) vips_streamib_get_line( VipsStreamib *streamib, const char **line )
{ {
char *write_point; char *write_point;
int bytes_available; int space_remaining;
int ch;
write_point = streamib->line; write_point = streamib->line;
bytes_available = VIPS_STREAMIB_BUFFER_SIZE; space_remaining = VIPS_STREAMIB_BUFFER_SIZE;
for(;;) { while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 &&
/* Is there a \n in the current buffer? It's always nul ch != '\n' &&
* terminated, so strchr() is safe. space_remaining > 0 ) {
*/ write_point[0] = ch;
if( (p = strchr( streamib->read_position, '\n' )) ) { write_point += 1;
int bytes_to_copy = p - streamib->read_position; space_remaining -= 1;
memcpy( write_point, streamib->read_position,
bytes_to_copy );
write_point[bytes_to_copy] = '\0';
/* Leave input pointing at the \n.
*/
streamib->read_position += bytes_to_copy;
streamib->bytes_remaining -= bytes_to_copy;
return( vips_streamib_next_line( streamib ) );
}
else {
/* No newline, so copy what we have, refill, and try
* again.
*/
int bytes_to_copy = VIPS_MIN( bytes_available,
streamib->bytes_remaining );
memcpy( write_point, streamib->read_position,
bytes_to_copy );
write_point[bytes_to_copy] = '\0';
write_point += bytes_to_copy;
bytes_available -= bytes_to_copy;
streamib->read_position += bytes_to_copy;
streamib->bytes_remaining -= bytes_to_copy;
/* If the line has filled, just skip to the next line.
*/
if( bytes_available <= 0 )
return( vips_streamib_next_line( streamib ) );
/* We must have exhausted the buffer. Refill and
* retry.
*/
if( vips_streamib_refill( streamib ) )
return( -1 );
if( streamib->eof )
break;
}
} }
write_point[0] = '\0';
/* If we hit EOF immediately, return EOF.
*/
if( write_point == streamib->line ) {
*line = NULL;
return( 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 &&
ch != '\n' )
;
}
/* If we stopped on \n, try to skip any \r too.
*/
if( ch == '\n' ) {
if( VIPS_STREAMIB_GETC( streamib ) != '\r' )
vips_streamib_ungetc( streamib );
}
*line = streamib->line;
return( 0 ); return( 0 );
} }
/** /**
* vips_streamib_get_line_copy: * vips_streamib_get_line_copy:
* @streamib: stream to fetch the line from * @streamib: stream to operate on
* *
* Return the next line of text from the stream. The newline character (or * 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 * characters) are removed, and and the string is terminated with a null
@ -1218,8 +1219,38 @@ vips_streamib_get_line( VipsStreamib *streamib, const char **line )
* Returns: the next line from the file, or NULL on EOF. * Returns: the next line from the file, or NULL on EOF.
* *
*/ */
char * int
vips_streamib_get_line_copy( VipsStreamib *streamib ) vips_streamib_get_line_copy( VipsStreamib *streamib, char **line )
{ {
const unsigned char null = '\0';
GByteArray *buffer;
int ch;
buffer = g_byte_array_new();
while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 &&
ch != '\n' ) {
unsigned char c = ch;
g_byte_array_append( buffer, &c, 1 );
}
if( ch == -1 ) {
VIPS_FREEF( g_byte_array_unref, buffer );
return( -1 );
}
g_byte_array_append( buffer, &null, 1 );
/* If we stopped on \n, try to skip any \r too.
*/
if( ch == '\n' ) {
if( VIPS_STREAMIB_GETC( streamib ) != '\r' )
vips_streamib_ungetc( streamib );
}
*line = (char *) g_byte_array_free( buffer, FALSE );
return( 0 );
} }