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.