From de94a725aadad2c5d9c3fc2119eb797e4af7a43a Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 4 Nov 2019 17:52:43 +0000 Subject: [PATCH] fix up streamib a bit more radiance load is almost working --- libvips/foreign/radiance.c | 142 ++++------------------------------ libvips/include/vips/stream.h | 14 ++-- libvips/iofuncs/streamib.c | 81 ++++++++++--------- 3 files changed, 62 insertions(+), 175 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index 69ac7ab1..c9047216 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -475,9 +475,6 @@ char *buf; static const char FMTSTR[] = "FORMAT="; /* format identifier */ -static gethfunc mycheck; - - static int formatval( /* get format value (return true if format) */ char fmt[MAXFMTLEN], @@ -507,16 +504,12 @@ getheader( /* get header from file */ ) { for(;;) { - const char *line; + const unsigned char *line; - if( vips_streamib_get_line( streamib, &line ) ) + if( !(line = vips_streamib_get_line( streamib )) ) return( -1 ); - if( !line ) - /* EOF. - */ - return( -1 ); - if( strcmp( line, "" ) == 0 ) - /* Blank line. + if( strcmp( (char *) line, "" ) == 0 ) + /* Blank line. We've parsed the header successfully. */ break; @@ -528,117 +521,6 @@ getheader( /* get header from file */ return( 0 ); } -struct check { - char fs[MAXFMTLEN]; -}; - - -static int -mycheck( /* check a header line for format info. */ - char *s, - void *cp -) -{ - struct check *p = (struct check *) cp; - - if (!formatval(p->fs, s) && p->fp != NULL) { - fputs(s, p->fp); - } - return(0); -} - - -static int -globmatch( /* check for match of s against pattern p */ - const char *p, - const char *s -) -{ - int setmatch; - - do { - switch (*p) { - case '?': /* match any character */ - if (!*s++) - return(0); - break; - case '*': /* match any string */ - while (p[1] == '*') p++; - do - if ( (p[1]=='?') | (p[1]==*s) && - globmatch(p+1,s) ) - return(1); - while (*s++); - return(0); - case '[': /* character set */ - setmatch = *s == *++p; - if (!*p) - return(0); - while (*++p != ']') { - if (!*p) - return(0); - if (*p == '-') { - setmatch += (p[-1] <= *s && *s <= p[1]); - if (!*++p) - break; - } else - setmatch += (*p == *s); - } - if (!setmatch) - return(0); - s++; - break; - case '\\': /* literal next */ - p++; - /* fall through */ - default: /* normal character */ - if (*p != *s) - return(0); - s++; - break; - } - } while (*p++); - return(1); -} - - -/* - * Checkheader(fin,fmt,fout) returns a value of 1 if the input format - * matches the specification in fmt, 0 if no input format was found, - * and -1 if the input format does not match or there is an - * error reading the header. If fmt is empty, then -1 is returned - * if any input format is found (or there is an error), and 0 otherwise. - * If fmt contains any '*' or '?' characters, then checkheader - * does wildcard expansion and copies a matching result into fmt. - * Be sure that fmt is big enough to hold the match in such cases, - * and that it is not a static, read-only string! - */ - -static int -checkheader( - VipsStreamib *streamib, - char fmt[MAXFMTLEN] -) -{ - struct check cdat; - char *cp; - - cdat.fs[0] = '\0'; - if (getheader(streamib, mycheck, &cdat) < 0) - return(-1); - if (!cdat.fs[0]) - return(0); - for (cp = fmt; *cp; cp++) /* check for globbing */ - if ((*cp == '?') | (*cp == '*')) { - if (globmatch(fmt, cdat.fs)) { - strcpy(fmt, cdat.fs); - return(1); - } else - return(-1); - } - return(strcmp(fmt, cdat.fs) ? -1 : 1); /* literal match */ -} - /* Read a single scanline, encoded in the old style. */ static int @@ -726,6 +608,8 @@ scanline_read( VipsStreamib *streamib, COLR *scanline, int width ) run = code > 128; len = run ? code & 127 : code; + printf( "len = %d\n", len ); + if( j + len > width ) { vips_error( "rad2vips", "%s", _( "overrun" ) ); return( -1 ); @@ -841,15 +725,17 @@ int vips__rad_israd( VipsStreami *streami ) { VipsStreamib *streamib; - char format[256]; + const unsigned char *line; int result; - strcpy( format, PICFMT ); + /* Just test that the first line is the magic string. + */ streamib = vips_streamib_new( streami ); - result = checkheader( streamib, format ); + result = (line = vips_streamib_get_line( streamib )) && + strcmp( (char *) line, "#?RADIANCE" ) == 0; VIPS_UNREF( streamib ); - return( result == 1 ); + return( result ); } static void @@ -934,14 +820,14 @@ static int rad2vips_get_header( Read *read, VipsImage *out ) { VipsInterpretation interpretation; - const char *line; + const unsigned char *line; int width; int height; int i, j; if( getheader( read->streamib, (gethfunc *) rad2vips_process_line, read ) || - vips_streamib_get_line( read->streamib, &line ) || + !(line = vips_streamib_get_line( read->streamib )) || !str2resolu( &read->rs, line ) ) { vips_error( "rad2vips", "%s", _( "error reading radiance header" ) ); diff --git a/libvips/include/vips/stream.h b/libvips/include/vips/stream.h index 3fe0c2f8..b9179d69 100644 --- a/libvips/include/vips/stream.h +++ b/libvips/include/vips/stream.h @@ -249,14 +249,16 @@ typedef struct _VipsStreamib { 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. */ - char input_buffer[VIPS_STREAMIB_BUFFER_SIZE + 1]; - char *read_point; + unsigned char input_buffer[VIPS_STREAMIB_BUFFER_SIZE + 1]; + unsigned char *read_point; int chars_unread; /* Build lines of text here. */ - char line[VIPS_STREAMIB_BUFFER_SIZE + 1]; + unsigned char line[VIPS_STREAMIB_BUFFER_SIZE + 1]; } VipsStreamib; @@ -285,11 +287,11 @@ int vips_streamib_require( VipsStreamib *streamib, int require ); 0 : \ vips_streamib_require( (S), (R) ) \ ) -#define VIPS_STREAMIB_PEEK( S ) (( S )->read_point) +#define VIPS_STREAMIB_PEEK( S ) ((S)->read_point) #define VIPS_STREAMIB_FETCH( S ) ((S)->chars_unread--, ((S)->read_point++)[0]) -int vips_streamib_get_line( VipsStreamib *streamib, const char **line ); -int vips_streamib_get_line_copy( VipsStreamib *streamib, char **line ); +const unsigned char *vips_streamib_get_line( VipsStreamib *streamib ); +unsigned char *vips_streamib_get_line_copy( VipsStreamib *streamib ); #define VIPS_TYPE_STREAMO (vips_streamo_get_type()) #define VIPS_STREAMO( obj ) \ diff --git a/libvips/iofuncs/streamib.c b/libvips/iofuncs/streamib.c index 74977d51..86e8bc26 100644 --- a/libvips/iofuncs/streamib.c +++ b/libvips/iofuncs/streamib.c @@ -246,7 +246,7 @@ vips_streamib_require( VipsStreamib *streamib, int require ) streamib->read_point = streamib->input_buffer; while( require > streamib->chars_unread ) { - char *q = streamib->input_buffer + + unsigned char *q = streamib->input_buffer + streamib->chars_unread; int space_available = VIPS_STREAMIB_BUFFER_SIZE - @@ -304,27 +304,26 @@ vips_streamib_require( VipsStreamib *streamib, int require ) /** * vips_streamib_get_line: * @streamib: stream to operate on - * @line: return the next line of text here * - * 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 @line + * Fetch the next line of text from @streamib 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). * - * @line is set to NULL on end of file. + * Returns NULL on end of file or read error. * * 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(). * - * The return value of @line is owned by @streamib and must not be freed. It + * The return value is owned by @streamib and must not be freed. It * is valid until the next call to vips_streamib_get_line(). * - * Returns: 0 on success, -1 on error. + * Returns: the next line from the file, or NULL on EOF or read error. */ -int -vips_streamib_get_line( VipsStreamib *streamib, const char **line ) +const unsigned char * +vips_streamib_get_line( VipsStreamib *streamib ) { - char *write_point; + unsigned char *write_point; int space_remaining; int ch; @@ -342,10 +341,19 @@ vips_streamib_get_line( VipsStreamib *streamib, const char **line ) /* If we hit EOF immediately, return EOF. */ - if( write_point == streamib->line ) { - *line = NULL; - return( 0 ); - } + if( ch == -1 && + write_point == streamib->line ) + return( NULL ); + + /* If the final char in the buffer is \r, this is probably a DOS file + * and we should remove that too. + * + * There's a chance this could incorrectly remove \r in very long + * lines, but ignore this. + */ + if( write_point - streamib->line > 0 && + write_point[-1] == '\r' ) + write_point[-1] = '\0'; /* If we filled the output line without seeing \n, keep going to the * next \n. @@ -357,16 +365,7 @@ vips_streamib_get_line( VipsStreamib *streamib, const char **line ) ; } - /* 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( streamib->line ); } /** @@ -382,13 +381,13 @@ vips_streamib_get_line( VipsStreamib *streamib, const char **line ) * This is slower than vips_streamib_get_line(), but can work with lines of * any length. * - * Returns: the next line from the file, or NULL on EOF. - * + * Returns: the next line from the file, or NULL on EOF or read error. */ -int -vips_streamib_get_line_copy( VipsStreamib *streamib, char **line ) +unsigned char * +vips_streamib_get_line_copy( VipsStreamib *streamib ) { - const unsigned char null = '\0'; + static const unsigned char null = '\0'; + GByteArray *buffer; int ch; @@ -401,21 +400,21 @@ vips_streamib_get_line_copy( VipsStreamib *streamib, char **line ) g_byte_array_append( buffer, &c, 1 ); } - if( ch == -1 ) { + if( ch == -1 && + buffer->len == 0 ) { VIPS_FREEF( g_byte_array_unref, buffer ); - return( -1 ); + return( NULL ); } + /* If the character before the \n was \r, this is probably a DOS file + * and we should remove the \r. + */ + if( ch == '\n' && + buffer->len > 0 && + buffer->data[buffer->len - 1] == '\r' ) + g_byte_array_set_size( buffer, buffer->len - 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 ); + return( (unsigned char *) g_byte_array_free( buffer, FALSE ) ); }