revise buffered input

rad load works now
This commit is contained in:
John Cupitt 2019-11-06 16:35:19 +00:00
parent de94a725aa
commit edca486f19
4 changed files with 60 additions and 56 deletions

View File

@ -17,7 +17,7 @@
- nifti load/save uses double for all floating point metadata - nifti load/save uses double for all floating point metadata
- add vips_error_buffer_copy() - add vips_error_buffer_copy()
- add VipsStream: a universal IO class for loaders and savers - add VipsStream: a universal IO class for loaders and savers
- jpeg, png, tiff and webp use the new IO class - jpeg, png, tiff (though not tiffsave), rad and webp use the new IO class
- add @no_strip option to dzsave [kalozka1] - add @no_strip option to dzsave [kalozka1]
31/8/19 started 8.8.3 31/8/19 started 8.8.3

View File

@ -27,6 +27,8 @@
* 23/7/18 * 23/7/18
* - fix a buffer overflow for incorrectly coded old-style RLE * - fix a buffer overflow for incorrectly coded old-style RLE
* [HongxuChen] * [HongxuChen]
* 6/11/19
* - revise for VipsStream
*/ */
/* /*
@ -608,8 +610,6 @@ scanline_read( VipsStreamib *streamib, COLR *scanline, int width )
run = code > 128; run = code > 128;
len = run ? code & 127 : code; len = run ? code & 127 : code;
printf( "len = %d\n", len );
if( j + len > width ) { if( j + len > width ) {
vips_error( "rad2vips", "%s", _( "overrun" ) ); vips_error( "rad2vips", "%s", _( "overrun" ) );
return( -1 ); return( -1 );
@ -953,6 +953,9 @@ vips__rad_load( VipsStreami *streami, VipsImage *out )
vips_image_write( t[1], out ) ) vips_image_write( t[1], out ) )
return( -1 ); return( -1 );
if( vips_streami_decode( streami ) )
return( -1 );
return( 0 ); return( 0 );
} }

View File

@ -251,10 +251,13 @@ typedef struct _VipsStreamib {
/* The +1 means there's always a \0 byte at the end. /* The +1 means there's always a \0 byte at the end.
* *
* Unsigned char, since we don't want >127 to be -ve. * 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]; unsigned char input_buffer[VIPS_STREAMIB_BUFFER_SIZE + 1];
unsigned char *read_point; int chars_in_buffer;
int chars_unread; int read_point;
/* Build lines of text here. /* Build lines of text here.
*/ */
@ -275,20 +278,20 @@ void vips_streamib_unbuffer( VipsStreamib *streamib );
int vips_streamib_getc( VipsStreamib *streamib ); int vips_streamib_getc( VipsStreamib *streamib );
#define VIPS_STREAMIB_GETC( S ) ( \ #define VIPS_STREAMIB_GETC( S ) ( \
(S)->chars_unread > 0 ? \ (S)->read_point < (S)->chars_in_buffer ? \
((S)->chars_unread--, ((S)->read_point++)[0]) : \ (S)->input_buffer[(S)->read_point++] : \
vips_streamib_getc( S ) \ vips_streamib_getc( S ) \
) )
void vips_streamib_ungetc( VipsStreamib *streamib ); void vips_streamib_ungetc( VipsStreamib *streamib );
int vips_streamib_require( VipsStreamib *streamib, int require ); int vips_streamib_require( VipsStreamib *streamib, int require );
#define VIPS_STREAMIB_REQUIRE( S, R ) ( \ #define VIPS_STREAMIB_REQUIRE( S, R ) ( \
(R) > (S)->chars_unread ? \ (S)->read_point + (R) <= (S)->chars_in_buffer ? \
0 : \ 0 : \
vips_streamib_require( (S), (R) ) \ vips_streamib_require( (S), (R) ) \
) )
#define VIPS_STREAMIB_PEEK( S ) ((S)->read_point) #define VIPS_STREAMIB_PEEK( S ) ((S)->input_buffer + (S)->read_point)
#define VIPS_STREAMIB_FETCH( S ) ((S)->chars_unread--, ((S)->read_point++)[0]) #define VIPS_STREAMIB_FETCH( S ) ((S)->input_buffer[(S)->read_point++])
const unsigned char *vips_streamib_get_line( VipsStreamib *streamib ); const unsigned char *vips_streamib_get_line( VipsStreamib *streamib );
unsigned char *vips_streamib_get_line_copy( VipsStreamib *streamib ); unsigned char *vips_streamib_get_line_copy( VipsStreamib *streamib );

View File

@ -90,9 +90,9 @@ vips_streamib_class_init( VipsStreamibClass *class )
static void static void
vips_streamib_init( VipsStreamib *streamib ) vips_streamib_init( VipsStreamib *streamib )
{ {
streamib->read_point = streamib->input_buffer; streamib->read_point = 0;
streamib->chars_unread = 0; streamib->chars_in_buffer = 0;
streamib->read_point[streamib->chars_unread] = '\0'; streamib->input_buffer[0] = '\0';
} }
/** /**
@ -130,12 +130,12 @@ vips_streamib_new( VipsStreami *streami )
void void
vips_streamib_unbuffer( VipsStreamib *streamib ) vips_streamib_unbuffer( VipsStreamib *streamib )
{ {
int bytes_in_buffer = streamib->read_point - streamib->input_buffer; /* We'd read ahead a little way -- seek backwards by that amount.
*/
streamib->read_point = streamib->input_buffer;
streamib->chars_unread = 0;
vips_streami_seek( streamib->streami, vips_streami_seek( streamib->streami,
-bytes_in_buffer, SEEK_SET ); streamib->read_point - streamib->chars_in_buffer, SEEK_SET );
streamib->read_point = 0;
streamib->chars_in_buffer = 0;
} }
/* Returns -1 on error, 0 on EOF, otherwise bytes read. /* Returns -1 on error, 0 on EOF, otherwise bytes read.
@ -147,20 +147,20 @@ vips_streamib_refill( VipsStreamib *streamib )
/* We should not discard any unread bytes. /* We should not discard any unread bytes.
*/ */
g_assert( streamib->chars_unread == 0 ); g_assert( streamib->read_point == streamib->chars_in_buffer );
bytes_read = vips_streami_read( streamib->streami, bytes_read = vips_streami_read( streamib->streami,
streamib->input_buffer, VIPS_STREAMIB_BUFFER_SIZE ); streamib->input_buffer, VIPS_STREAMIB_BUFFER_SIZE );
if( bytes_read == -1 ) if( bytes_read == -1 )
return( -1 ); return( -1 );
streamib->read_point = streamib->input_buffer; streamib->read_point = 0;
streamib->chars_unread = bytes_read; streamib->chars_in_buffer = bytes_read;
/* Always add a null 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_point[bytes_read] = '\0'; streamib->input_buffer[bytes_read] = '\0';
return( bytes_read ); return( bytes_read );
} }
@ -178,18 +178,13 @@ vips_streamib_refill( VipsStreamib *streamib )
int int
vips_streamib_getc( VipsStreamib *streamib ) vips_streamib_getc( VipsStreamib *streamib )
{ {
int ch; if( streamib->read_point == streamib->chars_in_buffer &&
if( streamib->chars_unread == 0 &&
vips_streamib_refill( streamib ) <= 0 ) vips_streamib_refill( streamib ) <= 0 )
return( -1 ); return( -1 );
ch = streamib->read_point[0]; g_assert( streamib->read_point < streamib->chars_in_buffer );
streamib->read_point += 1; return( streamib->input_buffer[streamib->read_point++] );
streamib->chars_unread -= 1;
return( ch );
} }
/** /**
@ -213,10 +208,8 @@ vips_streamib_getc( VipsStreamib *streamib )
void void
vips_streamib_ungetc( VipsStreamib *streamib ) vips_streamib_ungetc( VipsStreamib *streamib )
{ {
if( streamib->read_point > streamib->input_buffer ) { if( streamib->read_point > 0 )
streamib->read_point -= 1; streamib->read_point -= 1;
streamib->chars_unread += 1;
}
} }
/** /**
@ -232,31 +225,31 @@ int
vips_streamib_require( VipsStreamib *streamib, int require ) vips_streamib_require( VipsStreamib *streamib, int require )
{ {
g_assert( require < VIPS_STREAMIB_BUFFER_SIZE ); g_assert( require < VIPS_STREAMIB_BUFFER_SIZE );
g_assert( streamib->chars_unread >= 0 ); g_assert( streamib->chars_in_buffer >= 0 );
g_assert( streamib->chars_unread <= VIPS_STREAMIB_BUFFER_SIZE ); g_assert( streamib->chars_in_buffer <= VIPS_STREAMIB_BUFFER_SIZE );
g_assert( streamib->read_point >= streamib->input_buffer ); g_assert( streamib->read_point >= 0 );
g_assert( streamib->read_point < g_assert( streamib->read_point <= streamib->chars_in_buffer );
streamib->input_buffer + VIPS_STREAMIB_BUFFER_SIZE );
if( require > streamib->chars_unread ) { if( streamib->read_point + require > streamib->chars_in_buffer ) {
/* Areas can overlap. /* Areas can overlap, so we must memmove().
*/ */
memmove( streamib->input_buffer, memmove( streamib->input_buffer,
streamib->read_point, streamib->chars_unread ); streamib->input_buffer + streamib->read_point,
streamib->read_point = streamib->input_buffer; streamib->chars_in_buffer - streamib->read_point );
streamib->chars_in_buffer -= streamib->read_point;
streamib->read_point = 0;
while( require > streamib->chars_unread ) { while( require > streamib->chars_in_buffer ) {
unsigned char *q = streamib->input_buffer + unsigned char *to = streamib->input_buffer +
streamib->chars_unread; streamib->chars_in_buffer;
int space_available = int space_available =
VIPS_STREAMIB_BUFFER_SIZE - VIPS_STREAMIB_BUFFER_SIZE -
streamib->chars_unread; streamib->chars_in_buffer;
size_t bytes_read; size_t bytes_read;
if( (bytes_read = vips_streami_read( streamib->streami, if( (bytes_read = vips_streami_read( streamib->streami,
q, space_available )) == -1 ) to, space_available )) == -1 )
return( -1 ); return( -1 );
streamib->chars_unread += bytes_read;
if( bytes_read == 0 ) { if( bytes_read == 0 ) {
vips_error( vips_error(
vips_stream_nick( VIPS_STREAM( vips_stream_nick( VIPS_STREAM(
@ -264,6 +257,9 @@ vips_streamib_require( VipsStreamib *streamib, int require )
"%s", _( "end of file" ) ); "%s", _( "end of file" ) );
return( -1 ); return( -1 );
} }
to[bytes_read] = '\0';
streamib->chars_in_buffer += bytes_read;
} }
} }
@ -323,26 +319,26 @@ vips_streamib_require( VipsStreamib *streamib, int require )
const unsigned char * const unsigned char *
vips_streamib_get_line( VipsStreamib *streamib ) vips_streamib_get_line( VipsStreamib *streamib )
{ {
unsigned char *write_point; int write_point;
int space_remaining; int space_remaining;
int ch; int ch;
write_point = streamib->line; write_point = 0;
space_remaining = VIPS_STREAMIB_BUFFER_SIZE; space_remaining = VIPS_STREAMIB_BUFFER_SIZE;
while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 && while( (ch = VIPS_STREAMIB_GETC( streamib )) != -1 &&
ch != '\n' && ch != '\n' &&
space_remaining > 0 ) { space_remaining > 0 ) {
write_point[0] = ch; streamib->line[write_point] = ch;
write_point += 1; write_point += 1;
space_remaining -= 1; space_remaining -= 1;
} }
write_point[0] = '\0'; streamib->line[write_point] = '\0';
/* If we hit EOF immediately, return EOF. /* If we hit EOF immediately, return EOF.
*/ */
if( ch == -1 && if( ch == -1 &&
write_point == streamib->line ) write_point == 0 )
return( NULL ); return( NULL );
/* If the final char in the buffer is \r, this is probably a DOS file /* If the final char in the buffer is \r, this is probably a DOS file
@ -351,9 +347,9 @@ vips_streamib_get_line( VipsStreamib *streamib )
* There's a chance this could incorrectly remove \r in very long * There's a chance this could incorrectly remove \r in very long
* lines, but ignore this. * lines, but ignore this.
*/ */
if( write_point - streamib->line > 0 && if( write_point > 0 &&
write_point[-1] == '\r' ) streamib->line[write_point - 1] == '\r' )
write_point[-1] = '\0'; streamib->line[write_point - 1] = '\0';
/* If we filled the output line without seeing \n, keep going to the /* If we filled the output line without seeing \n, keep going to the
* next \n. * next \n.
@ -400,6 +396,8 @@ vips_streamib_get_line_copy( VipsStreamib *streamib )
g_byte_array_append( buffer, &c, 1 ); g_byte_array_append( buffer, &c, 1 );
} }
/* Immediate EOF.
*/
if( ch == -1 && if( ch == -1 &&
buffer->len == 0 ) { buffer->len == 0 ) {
VIPS_FREEF( g_byte_array_unref, buffer ); VIPS_FREEF( g_byte_array_unref, buffer );