This is rle_getrow.c in view mode; [Download] [Up]
/*
* This software is copyrighted as noted below. It may be freely copied,
* modified, and redistributed, provided that the copyright notice is
* preserved on all copies.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely "as is". Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* You may not include this software in a program or other software product
* without supplying the source, or without informing the end-user that the
* source is available for no extra charge.
*
* If you modify this software, you should include a notice giving the
* name of the person performing the modification, the date of modification,
* and the reason for such modification.
*
* Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
* to have all "void" functions so declared.
*/
/*
* rle_getrow.c - Read an RLE file in.
*
* Author: Spencer W. Thomas
* Computer Science Dept.
* University of Utah
* Date: Wed Apr 10 1985
* Copyright (c) 1985 Spencer W. Thomas
*
* $Id: rle_getrow.c,v 3.0 90/08/03 15:20:45 spencer Exp $
*/
#ifndef lint
static char rcs_ident[] = "$Id: rle_getrow.c,v 3.0 90/08/03 15:20:45 spencer Exp $";
#endif
#include "stdio.h"
#include "rle.h"
#include "rle_code.h"
#ifdef USE_STDLIB_H
#include <stdlib.h>
#else
#ifdef USE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#ifndef VOID_STAR
extern char * malloc();
#else
extern void *malloc();
#endif
extern void free();
#endif /* USE_STDLIB_H */
/* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
#define VAXSHORT( var, fp )\
{ var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
/* Instruction format -- first byte is opcode, second is datum. */
#define OPCODE(inst) (inst[0] & ~LONG)
#define LONGP(inst) (inst[0] & LONG)
#define DATUM(inst) (inst[1] & 0xff) /* Make sure it's unsigned. */
static int debug_f; /* If non-zero, print debug info. */
static void bfill();
extern int vax_gshort();
/*****************************************************************
* TAG( rle_get_setup )
*
* Read the initialization information from an RLE file.
* Inputs:
* the_hdr: Contains pointer to the input file.
* Outputs:
* the_hdr: Initialized with information from the
* input file.
* Returns 0 on success, -1 if the file is not an RLE file,
* -2 if malloc of the color map failed, -3 if an immediate EOF
* is hit (empty input file), and -4 if an EOF is encountered reading
* the setup information.
* Assumptions:
* infile points to the "magic" number in an RLE file (usually
* byte 0 in the file).
* Algorithm:
* Read in the setup info and fill in the_hdr.
*/
int
rle_get_setup( the_hdr )
rle_hdr * the_hdr;
{
struct XtndRsetup setup;
short magic;
register FILE *infile = the_hdr->rle_file;
rle_pixel * bg_color;
register int i;
char * comment_buf;
VAXSHORT( magic, infile );
if ( feof( infile ) )
return RLE_EMPTY;
if ( magic != RLE_MAGIC )
return RLE_NOT_RLE;
fread( &setup, 1, SETUPSIZE, infile ); /* assume VAX packing */
if ( feof( infile ) )
return RLE_EOF;
/* Extract information from setup */
the_hdr->ncolors = setup.h_ncolors;
for ( i = 0; i < the_hdr->ncolors; i++ )
RLE_SET_BIT( *the_hdr, i );
if ( !(setup.h_flags & H_NO_BACKGROUND) )
{
the_hdr->bg_color = (int *)malloc(
(unsigned)(sizeof(int) * setup.h_ncolors) );
bg_color = (rle_pixel *)malloc(
(unsigned)(1 + (setup.h_ncolors / 2) * 2) );
fread( (char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile );
for ( i = 0; i < setup.h_ncolors; i++ )
the_hdr->bg_color[i] = bg_color[i];
free( bg_color );
}
else
{
(void)getc( infile ); /* skip filler byte */
the_hdr->bg_color = NULL;
}
if ( setup.h_flags & H_NO_BACKGROUND )
the_hdr->background = 0;
else if ( setup.h_flags & H_CLEARFIRST )
the_hdr->background = 2;
else
the_hdr->background = 1;
if ( setup.h_flags & H_ALPHA )
{
the_hdr->alpha = 1;
RLE_SET_BIT( *the_hdr, RLE_ALPHA );
}
else
the_hdr->alpha = 0;
the_hdr->xmin = vax_gshort( setup.hc_xpos );
the_hdr->ymin = vax_gshort( setup.hc_ypos );
the_hdr->xmax = the_hdr->xmin + vax_gshort( setup.hc_xlen ) - 1;
the_hdr->ymax = the_hdr->ymin + vax_gshort( setup.hc_ylen ) - 1;
the_hdr->ncmap = setup.h_ncmap;
the_hdr->cmaplen = setup.h_cmaplen;
if ( the_hdr->ncmap > 0 )
{
register int maplen =
the_hdr->ncmap * (1 << the_hdr->cmaplen);
register int i;
register char *maptemp;
the_hdr->cmap = (rle_map *)malloc(
(unsigned)(sizeof(rle_map) * maplen) );
maptemp = (char *)malloc( 2 * maplen );
if ( the_hdr->cmap == NULL || maptemp == NULL )
{
fprintf( stderr,
"Malloc failed for color map of size %d*%d in rle_get_setup\n",
the_hdr->ncmap, (1 << the_hdr->cmaplen) );
return RLE_NO_SPACE;
}
fread( maptemp, sizeof(short), maplen, infile );
for ( i = 0; i < maplen; i++ )
the_hdr->cmap[i] = vax_gshort( &maptemp[i * 2] );
free( maptemp );
}
/* Check for comments */
if ( setup.h_flags & H_COMMENT )
{
short comlen, evenlen;
register char * cp;
VAXSHORT( comlen, infile ); /* get comment length */
evenlen = (comlen + 1) & ~1; /* make it even */
if ( evenlen )
{
comment_buf = (char *)malloc( (unsigned) evenlen );
if ( comment_buf == NULL )
{
fprintf( stderr,
"Malloc failed for comment buffer of size %d in rle_get_setup\n",
comlen );
return RLE_NO_SPACE;
}
fread( comment_buf, 1, evenlen, infile );
/* Count the comments */
for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
if ( *cp == 0 )
i++;
i++; /* extra for NULL pointer at end */
/* Get space to put pointers to comments */
the_hdr->comments =
(CONST_DECL char **)malloc( (unsigned)(i * sizeof(char *)) );
if ( the_hdr->comments == NULL )
{
fprintf( stderr,
"Malloc failed for %d comment pointers in rle_get_setup\n",
i );
return RLE_NO_SPACE;
}
/* Get pointers to the comments */
*the_hdr->comments = comment_buf;
for ( i = 1, cp = comment_buf + 1;
cp < comment_buf + comlen;
cp++ )
if ( *(cp - 1) == 0 )
the_hdr->comments[i++] = cp;
the_hdr->comments[i] = NULL;
}
else
the_hdr->comments = NULL;
}
else
the_hdr->comments = NULL;
/* Initialize state for rle_getrow */
the_hdr->priv.get.scan_y = the_hdr->ymin;
the_hdr->priv.get.vert_skip = 0;
the_hdr->priv.get.is_eof = 0;
the_hdr->priv.get.is_seek = ftell( infile ) > 0;
debug_f = 0;
if ( !feof( infile ) )
return RLE_SUCCESS; /* success! */
else
{
the_hdr->priv.get.is_eof = 1;
return RLE_EOF;
}
}
/*****************************************************************
* TAG( rle_get_error )
*
* Print an error message for the return code from rle_get_setup
* Inputs:
* code: The return code from rle_get_setup.
* pgmname: Name of this program (argv[0]).
* fname: Name of the input file.
* Outputs:
* Prints an error message on standard output.
* Returns code.
*/
int
rle_get_error( code, pgmname, fname )
int code;
CONST_DECL char *pgmname;
CONST_DECL char *fname;
{
if (! fname)
fname = "Standard Input";
if ( strcmp( fname, "-" ) == 0 )
fname = "Standard Input";
switch( code )
{
case RLE_SUCCESS: /* success */
break;
case RLE_NOT_RLE: /* Not an RLE file */
fprintf( stderr, "%s: %s is not an RLE file\n",
pgmname, fname );
break;
case RLE_NO_SPACE: /* malloc failed */
fprintf( stderr,
"%s: Malloc failed reading header of file %s\n",
pgmname, fname );
break;
case RLE_EMPTY:
fprintf( stderr, "%s: %s is an empty file\n", pgmname, fname );
break;
case RLE_EOF:
fprintf( stderr,
"%s: RLE header of %s is incomplete (premature EOF)\n",
pgmname, fname );
break;
default:
fprintf( stderr, "%s: Error encountered reading header of %s\n",
pgmname, fname );
break;
}
return code;
}
/*****************************************************************
* TAG( rle_get_setup_ok )
*
* Read the initialization information from an RLE file.
* Inputs:
* the_hdr: Contains pointer to the input file.
* prog_name: Program name to be printed in the error message.
* file_name: File name to be printed in the error message.
* If NULL, the string "stdin" is generated.
* Outputs:
* the_hdr: Initialized with information from the
* input file.
* If reading the header fails, it prints an error message
* and exits with the appropriate status code.
* Algorithm:
* rle_get_setup does all the work.
*/
void
rle_get_setup_ok( the_hdr, prog_name, file_name )
rle_hdr * the_hdr;
CONST_DECL char *prog_name;
CONST_DECL char *file_name;
{
int code;
code = rle_get_error( rle_get_setup( the_hdr ), prog_name, file_name );
if (code)
exit( code );
}
/*****************************************************************
* TAG( rle_debug )
*
* Turn RLE debugging on or off.
* Inputs:
* on_off: if 0, stop debugging, else start.
* Outputs:
* Sets internal debug flag.
* Assumptions:
* [None]
* Algorithm:
* [None]
*/
void
rle_debug( on_off )
int on_off;
{
debug_f = on_off;
/* Set line buffering on stderr. Character buffering is the default, and
* it is SLOOWWW for large amounts of output.
*/
setlinebuf( stderr );
}
/*****************************************************************
* TAG( rle_getrow )
*
* Get a scanline from the input file.
* Inputs:
* the_hdr: Header structure containing information about
* the input file.
* Outputs:
* scanline: an array of pointers to the individual color
* scanlines. Scanline is assumed to have
* the_hdr->ncolors pointers to arrays of rle_pixel,
* each of which is at least the_hdr->xmax+1 long.
* Returns the current scanline number.
* Assumptions:
* rle_get_setup has already been called.
* Algorithm:
* If a vertical skip is being executed, and clear-to-background is
* specified (the_hdr->background is true), just set the
* scanlines to the background color. If clear-to-background is
* not set, just increment the scanline number and return.
*
* Otherwise, read input until a vertical skip is encountered,
* decoding the instructions into scanline data.
*
* If ymax is reached (or, somehow, passed), continue reading and
* discarding input until end of image.
*/
int
rle_getrow( the_hdr, scanline )
rle_hdr * the_hdr;
rle_pixel *scanline[];
{
register rle_pixel * scanc;
register int nc;
register FILE *infile = the_hdr->rle_file;
int scan_x = the_hdr->xmin, /* current X position */
channel = 0; /* current color channel */
short word, long_data;
char inst[2];
/* Clear to background if specified */
if ( the_hdr->background == 2 )
{
if ( the_hdr->alpha && RLE_BIT( *the_hdr, -1 ) )
bfill( (char *)scanline[-1], the_hdr->xmax + 1, 0 );
for ( nc = 0; nc < the_hdr->ncolors; nc++ )
if ( RLE_BIT( *the_hdr, nc ) )
bfill( (char *)scanline[nc], the_hdr->xmax+1,
the_hdr->bg_color[nc] );
}
/* If skipping, then just return */
if ( the_hdr->priv.get.vert_skip > 0 )
{
the_hdr->priv.get.vert_skip--;
the_hdr->priv.get.scan_y++;
if ( the_hdr->priv.get.vert_skip > 0 )
if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
{
int y = the_hdr->priv.get.scan_y;
while ( rle_getskip( the_hdr ) != 32768 )
;
return y;
}
else
return the_hdr->priv.get.scan_y;
}
/* If EOF has been encountered, return also */
if ( the_hdr->priv.get.is_eof )
return ++the_hdr->priv.get.scan_y;
/* Otherwise, read and interpret instructions until a skipLines
* instruction is encountered.
*/
if ( RLE_BIT( *the_hdr, channel ) )
scanc = scanline[channel] + scan_x;
else
scanc = NULL;
for (;;)
{
inst[0] = getc( infile );
inst[1] = getc( infile );
if ( feof(infile) )
{
the_hdr->priv.get.is_eof = 1;
break; /* <--- one of the exits */
}
switch( OPCODE(inst) )
{
case RSkipLinesOp:
if ( LONGP(inst) )
{
VAXSHORT( the_hdr->priv.get.vert_skip, infile );
}
else
the_hdr->priv.get.vert_skip = DATUM(inst);
if (debug_f)
fprintf(stderr, "Skip %d Lines (to %d)\n",
the_hdr->priv.get.vert_skip,
the_hdr->priv.get.scan_y +
the_hdr->priv.get.vert_skip );
break; /* need to break for() here, too */
case RSetColorOp:
channel = DATUM(inst); /* select color channel */
if ( channel == 255 )
channel = -1;
scan_x = the_hdr->xmin;
if ( RLE_BIT( *the_hdr, channel ) )
scanc = scanline[channel]+scan_x;
if ( debug_f )
fprintf( stderr, "Set color to %d (reset x to %d)\n",
channel, scan_x );
break;
case RSkipPixelsOp:
if ( LONGP(inst) )
{
VAXSHORT( long_data, infile );
scan_x += long_data;
scanc += long_data;
if ( debug_f )
fprintf( stderr, "Skip %d pixels (to %d)\n",
long_data, scan_x );
}
else
{
scan_x += DATUM(inst);
scanc += DATUM(inst);
if ( debug_f )
fprintf( stderr, "Skip %d pixels (to %d)\n",
DATUM(inst), scan_x );
}
break;
case RByteDataOp:
if ( LONGP(inst) )
{
VAXSHORT( nc, infile );
}
else
nc = DATUM(inst);
nc++;
if ( RLE_BIT( *the_hdr, channel ) )
{
fread( (char *)scanc, 1, nc, infile );
if ( nc & 1 )
(void)getc( infile ); /* throw away odd byte */
}
else
if ( the_hdr->priv.get.is_seek )
fseek( infile, ((nc + 1) / 2) * 2, 1 );
else
{
register int ii;
for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
(void) getc( infile ); /* discard it */
}
scanc += nc;
scan_x += nc;
if ( debug_f )
if ( RLE_BIT( *the_hdr, channel ) )
{
rle_pixel * cp = scanc - nc;
fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x );
for ( ; nc > 0; nc-- )
fprintf( stderr, "%02x", *cp++ );
putc( '\n', stderr );
}
else
fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x );
break;
case RRunDataOp:
if ( LONGP(inst) )
{
VAXSHORT( nc, infile );
}
else
nc = DATUM(inst);
scan_x += nc + 1;
VAXSHORT( word, infile );
if ( debug_f )
fprintf( stderr, "Run length %d (to %d), data %02x\n",
nc + 1, scan_x, word );
if ( RLE_BIT( *the_hdr, channel ) )
{
if ( nc >= 10 ) /* break point for 785, anyway */
{
bfill( (char *)scanc, nc + 1, word );
scanc += nc + 1;
}
else
for ( ; nc >= 0; nc--, scanc++ )
*scanc = word;
}
break;
case REOFOp:
the_hdr->priv.get.is_eof = 1;
if ( debug_f )
fprintf( stderr, "End of Image\n" );
break;
default:
fprintf( stderr,
"rle_getrow: Unrecognized opcode: %d\n", inst[0] );
exit(1);
}
if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
break; /* <--- the other loop exit */
}
/* If at end, skip the rest of a malformed image. */
if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
{
int y = the_hdr->priv.get.scan_y;
while ( rle_getskip( the_hdr ) != 32768 )
;
return y;
}
return the_hdr->priv.get.scan_y;
}
/* Fill buffer at s with n copies of character c. N must be <= 65535*/
/* ARGSUSED */
static void bfill( s, n, c )
register char *s;
register int n, c;
{
#ifdef vax
asm(" movc5 $0,*4(ap),12(ap),8(ap),*4(ap)");
#else
while ( n-- > 0 )
*s++ = c;
#endif
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.