Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rle_getrow.c
Go to the documentation of this file.
1 /*
2  * This software is copyrighted as noted below. It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is". Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  *
18  * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
19  * to have all "void" functions so declared.
20  */
21 /*
22  * rle_getrow.c - Read an RLE file in.
23  *
24  * Author: Spencer W. Thomas
25  * Computer Science Dept.
26  * University of Utah
27  * Date: Wed Apr 10 1985
28  * Copyright (c) 1985 Spencer W. Thomas
29  *
30  * $Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp spencer $
31  */
32 #ifndef lint
33 static char rcs_ident[] = "$Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp spencer $";
34 #endif
35 
36 #include "stdio.h"
37 #include "rle.h"
38 #include "rle_code.h"
39 
40 /* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
41 #define VAXSHORT( var, fp )
42  { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
43 
44 /* Instruction format -- first byte is opcode, second is datum. */
45 
46 #define OPCODE(inst) (inst[0] & ~LONG)
47 #define LONGP(inst) (inst[0] & LONG)
48 #define DATUM(inst) (inst[1] & 0xff) /* Make sure it's unsigned. */
49 
50 static int debug_f; /* If non-zero, print debug info. */
51 static void bfill();
52 extern int vax_gshort();
53 
54 /*****************************************************************
55  * TAG( rle_get_setup )
56  *
57  * Read the initialization information from an RLE file.
58  * Inputs:
59  * the_hdr: Contains pointer to the input file.
60  * Outputs:
61  * the_hdr: Initialized with information from the
62  * input file.
63  * Returns 0 on success, -1 if the file is not an RLE file,
64  * -2 if malloc of the color map failed, -3 if an immediate EOF
65  * is hit (empty input file), and -4 if an EOF is encountered reading
66  * the setup information.
67  * Assumptions:
68  * infile points to the "magic" number in an RLE file (usually
69  * byte 0 in the file).
70  * Algorithm:
71  * Read in the setup info and fill in the_hdr.
72  */
73 int
75 rle_hdr * the_hdr;
76 {
77  struct XtndRsetup setup;
78  short magic;
79  register FILE *infile = the_hdr->rle_file;
80  rle_pixel * bg_color;
81  register int i;
82  char * comment_buf;
83 
84  /* Clear old stuff out of the header. */
85  rle_hdr_clear( the_hdr );
86  if ( the_hdr->is_init != RLE_INIT_MAGIC )
87  rle_names( the_hdr, "Urt", "some file", 0 );
88  the_hdr->img_num++; /* Count images. */
89 
90  VAXSHORT( magic, infile );
91  if ( feof( infile ) )
92  return RLE_EMPTY;
93  if ( magic != RLE_MAGIC )
94  return RLE_NOT_RLE;
95  fread( &setup, 1, SETUPSIZE, infile ); /* assume VAX packing */
96  if ( feof( infile ) )
97  return RLE_EOF;
98 
99  /* Extract information from setup */
100  the_hdr->ncolors = setup.h_ncolors;
101  for ( i = 0; i < the_hdr->ncolors; i++ )
102  RLE_SET_BIT( *the_hdr, i );
103 
104  if ( !(setup.h_flags & H_NO_BACKGROUND) && setup.h_ncolors > 0 )
105  {
106  the_hdr->bg_color = (int *)malloc(
107  (unsigned)(sizeof(int) * setup.h_ncolors) );
108  bg_color = (rle_pixel *)malloc(
109  (unsigned)(1 + (setup.h_ncolors / 2) * 2) );
110  RLE_CHECK_ALLOC( the_hdr->cmd, the_hdr->bg_color && bg_color,
111  "background color" );
112  fread( (char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile );
113  for ( i = 0; i < setup.h_ncolors; i++ )
114  the_hdr->bg_color[i] = bg_color[i];
115  free( bg_color );
116  }
117  else
118  {
119  (void)getc( infile ); /* skip filler byte */
120  the_hdr->bg_color = NULL;
121  }
122 
123  if ( setup.h_flags & H_NO_BACKGROUND )
124  the_hdr->background = 0;
125  else if ( setup.h_flags & H_CLEARFIRST )
126  the_hdr->background = 2;
127  else
128  the_hdr->background = 1;
129  if ( setup.h_flags & H_ALPHA )
130  {
131  the_hdr->alpha = 1;
132  RLE_SET_BIT( *the_hdr, RLE_ALPHA );
133  }
134  else
135  the_hdr->alpha = 0;
136 
137  the_hdr->xmin = vax_gshort( setup.hc_xpos );
138  the_hdr->ymin = vax_gshort( setup.hc_ypos );
139  the_hdr->xmax = the_hdr->xmin + vax_gshort( setup.hc_xlen ) - 1;
140  the_hdr->ymax = the_hdr->ymin + vax_gshort( setup.hc_ylen ) - 1;
141 
142  the_hdr->ncmap = setup.h_ncmap;
143  the_hdr->cmaplen = setup.h_cmaplen;
144  if ( the_hdr->ncmap > 0 )
145  {
146  register int maplen =
147  the_hdr->ncmap * (1 << the_hdr->cmaplen);
148  register int i;
149  register char *maptemp;
150 
151  the_hdr->cmap = (rle_map *)malloc(
152  (unsigned)(sizeof(rle_map) * maplen) );
153  maptemp = (char *)malloc( 2 * maplen );
154  if ( the_hdr->cmap == NULL || maptemp == NULL )
155  {
156  fprintf( stderr,
157 "%s: Malloc failed for color map of size %d*%d in rle_get_setup, reading %s\n",
158  the_hdr->cmd,
159  the_hdr->ncmap, (1 << the_hdr->cmaplen),
160  the_hdr->file_name );
161  return RLE_NO_SPACE;
162  }
163  fread( maptemp, 2, maplen, infile );
164  for ( i = 0; i < maplen; i++ )
165  the_hdr->cmap[i] = vax_gshort( &maptemp[i * 2] );
166  free( maptemp );
167  }
168 
169  /* Check for comments */
170  if ( setup.h_flags & H_COMMENT )
171  {
172  short comlen, evenlen;
173  register char * cp;
174 
175  VAXSHORT( comlen, infile ); /* get comment length */
176  evenlen = (comlen + 1) & ~1; /* make it even */
177  if ( evenlen )
178  {
179  comment_buf = (char *)malloc( (unsigned) evenlen );
180 
181  if ( comment_buf == NULL )
182  {
183  fprintf( stderr,
184 "%s: Malloc failed for comment buffer of size %d in rle_get_setup, reading %s\n",
185  the_hdr->cmd, comlen, the_hdr->file_name );
186  return RLE_NO_SPACE;
187  }
188  fread( comment_buf, 1, evenlen, infile );
189  /* Count the comments */
190  for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
191  if ( *cp == 0 )
192  i++;
193  i++; /* extra for NULL pointer at end */
194  /* Get space to put pointers to comments */
195  the_hdr->comments =
196  (CONST_DECL char **)malloc( (unsigned)(i * sizeof(char *)) );
197  if ( the_hdr->comments == NULL )
198  {
199  fprintf( stderr,
200  "%s: Malloc failed for %d comment pointers in rle_get_setup, reading %s\n",
201  the_hdr->cmd, i, the_hdr->file_name );
202  return RLE_NO_SPACE;
203  }
204  /* Get pointers to the comments */
205  *the_hdr->comments = comment_buf;
206  for ( i = 1, cp = comment_buf + 1;
207  cp < comment_buf + comlen;
208  cp++ )
209  if ( *(cp - 1) == 0 )
210  the_hdr->comments[i++] = cp;
211  the_hdr->comments[i] = NULL;
212  }
213  else
214  the_hdr->comments = NULL;
215  }
216  else
217  the_hdr->comments = NULL;
218 
219  /* Initialize state for rle_getrow */
220  the_hdr->priv.get.scan_y = the_hdr->ymin;
221  the_hdr->priv.get.vert_skip = 0;
222  the_hdr->priv.get.is_eof = 0;
223  the_hdr->priv.get.is_seek = ftell( infile ) > 0;
224  debug_f = 0;
225 
226  if ( !feof( infile ) )
227  return RLE_SUCCESS; /* success! */
228  else
229  {
230  the_hdr->priv.get.is_eof = 1;
231  return RLE_EOF;
232  }
233 }
234 
235 
236 /*****************************************************************
237  * TAG( rle_get_setup_ok )
238  *
239  * Read the initialization information from an RLE file.
240  * Inputs:
241  * the_hdr: Contains pointer to the input file.
242  * prog_name: Program name to be printed in the error message.
243  * file_name: File name to be printed in the error message.
244  * If NULL, the string "stdin" is generated.
245  * Outputs:
246  * the_hdr: Initialized with information from the
247  * input file.
248  * If reading the header fails, it prints an error message
249  * and exits with the appropriate status code.
250  * Algorithm:
251  * rle_get_setup does all the work.
252  */
253 void
255 rle_hdr * the_hdr;
256 CONST_DECL char *prog_name;
257 CONST_DECL char *file_name;
258 {
259  int code;
260 
261  /* Backwards compatibility: if is_init is not properly set,
262  * initialize the header.
263  */
264  if ( the_hdr->is_init != RLE_INIT_MAGIC )
265  {
266  FILE *f = the_hdr->rle_file;
267  rle_hdr_init( the_hdr );
268  the_hdr->rle_file = f;
269  rle_names( the_hdr, prog_name, file_name, 0 );
270  }
271 
272  code = rle_get_error( rle_get_setup( the_hdr ),
273  the_hdr->cmd, the_hdr->file_name );
274  if (code)
275  exit( code );
276 }
277 
278 
279 /*****************************************************************
280  * TAG( rle_debug )
281  *
282  * Turn RLE debugging on or off.
283  * Inputs:
284  * on_off: if 0, stop debugging, else start.
285  * Outputs:
286  * Sets internal debug flag.
287  * Assumptions:
288  * [None]
289  * Algorithm:
290  * [None]
291  */
292 void
294 int on_off;
295 {
296  debug_f = on_off;
297 
298  /* Set line buffering on stderr. Character buffering is the default, and
299  * it is SLOOWWW for large amounts of output.
300  */
301  setlinebuf( stderr );
302 }
303 
304 
305 /*****************************************************************
306  * TAG( rle_getrow )
307  *
308  * Get a scanline from the input file.
309  * Inputs:
310  * the_hdr: Header structure containing information about
311  * the input file.
312  * Outputs:
313  * scanline: an array of pointers to the individual color
314  * scanlines. Scanline is assumed to have
315  * the_hdr->ncolors pointers to arrays of rle_pixel,
316  * each of which is at least the_hdr->xmax+1 long.
317  * Returns the current scanline number.
318  * Assumptions:
319  * rle_get_setup has already been called.
320  * Algorithm:
321  * If a vertical skip is being executed, and clear-to-background is
322  * specified (the_hdr->background is true), just set the
323  * scanlines to the background color. If clear-to-background is
324  * not set, just increment the scanline number and return.
325  *
326  * Otherwise, read input until a vertical skip is encountered,
327  * decoding the instructions into scanline data.
328  *
329  * If ymax is reached (or, somehow, passed), continue reading and
330  * discarding input until end of image.
331  */
332 int
334 rle_hdr * the_hdr;
335 rle_pixel *scanline[];
336 {
337  register rle_pixel * scanc;
338  register int nc;
339  register FILE *infile = the_hdr->rle_file;
340  int scan_x = the_hdr->xmin, /* current X position */
341  max_x = the_hdr->xmax, /* End of the scanline */
342  channel = 0; /* current color channel */
343  int ns; /* Number to skip */
344  short word, long_data;
345  char inst[2];
346 
347  /* Clear to background if specified */
348  if ( the_hdr->background != 1 )
349  {
350  if ( the_hdr->alpha && RLE_BIT( *the_hdr, -1 ) )
351  bzero( (char *)scanline[-1] + the_hdr->xmin,
352  the_hdr->xmax - the_hdr->xmin + 1 );
353  for ( nc = 0; nc < the_hdr->ncolors; nc++ )
354  if ( RLE_BIT( *the_hdr, nc ) ) {
355  /* Unless bg color given explicitly, use 0. */
356  if ( the_hdr->background != 2 || the_hdr->bg_color[nc] == 0 )
357  bzero( (char *)scanline[nc] + the_hdr->xmin,
358  the_hdr->xmax - the_hdr->xmin + 1 );
359  else
360  bfill( (char *)scanline[nc] + the_hdr->xmin,
361  the_hdr->xmax - the_hdr->xmin + 1,
362  the_hdr->bg_color[nc] );
363  }
364  }
365 
366  /* If skipping, then just return */
367  if ( the_hdr->priv.get.vert_skip > 0 )
368  {
369  the_hdr->priv.get.vert_skip--;
370  the_hdr->priv.get.scan_y++;
371  if ( the_hdr->priv.get.vert_skip > 0 ) {
372  if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
373  {
374  int y = the_hdr->priv.get.scan_y;
375  while ( rle_getskip( the_hdr ) != 32768 )
376  ;
377  return y;
378  }
379  else
380  return the_hdr->priv.get.scan_y;
381  }
382  }
383 
384  /* If EOF has been encountered, return also */
385  if ( the_hdr->priv.get.is_eof )
386  return ++the_hdr->priv.get.scan_y;
387 
388  /* Otherwise, read and interpret instructions until a skipLines
389  * instruction is encountered.
390  */
391  if ( RLE_BIT( *the_hdr, channel ) )
392  scanc = scanline[channel] + scan_x;
393  else
394  scanc = NULL;
395  for (;;)
396  {
397  inst[0] = getc( infile );
398  inst[1] = getc( infile );
399  if ( feof(infile) )
400  {
401  the_hdr->priv.get.is_eof = 1;
402  break; /* <--- one of the exits */
403  }
404 
405  switch( OPCODE(inst) )
406  {
407  case RSkipLinesOp:
408  if ( LONGP(inst) )
409  {
410  VAXSHORT( the_hdr->priv.get.vert_skip, infile );
411  }
412  else
413  the_hdr->priv.get.vert_skip = DATUM(inst);
414  if (debug_f)
415  fprintf(stderr, "Skip %d Lines (to %d)\n",
416  the_hdr->priv.get.vert_skip,
417  the_hdr->priv.get.scan_y +
418  the_hdr->priv.get.vert_skip );
419 
420  break; /* need to break for() here, too */
421 
422  case RSetColorOp:
423  channel = DATUM(inst); /* select color channel */
424  if ( channel == 255 )
425  channel = -1;
426  scan_x = the_hdr->xmin;
427  if ( RLE_BIT( *the_hdr, channel ) )
428  scanc = scanline[channel]+scan_x;
429  if ( debug_f )
430  fprintf( stderr, "Set color to %d (reset x to %d)\n",
431  channel, scan_x );
432  break;
433 
434  case RSkipPixelsOp:
435  if ( LONGP(inst) )
436  {
437  VAXSHORT( long_data, infile );
438  scan_x += long_data;
439  scanc += long_data;
440  if ( debug_f )
441  fprintf( stderr, "Skip %d pixels (to %d)\n",
442  long_data, scan_x );
443  }
444  else
445  {
446  scan_x += DATUM(inst);
447  scanc += DATUM(inst);
448  if ( debug_f )
449  fprintf( stderr, "Skip %d pixels (to %d)\n",
450  DATUM(inst), scan_x );
451  }
452  break;
453 
454  case RByteDataOp:
455  if ( LONGP(inst) )
456  {
457  VAXSHORT( nc, infile );
458  }
459  else
460  nc = DATUM(inst);
461  nc++;
462  if ( debug_f ) {
463  if ( RLE_BIT( *the_hdr, channel ) )
464  fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x+nc );
465  else
466  fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x+nc);
467  }
468  if ( RLE_BIT( *the_hdr, channel ) )
469  {
470  /* Don't fill past end of scanline! */
471  if ( scan_x + nc > max_x )
472  {
473  ns = scan_x + nc - max_x - 1;
474  nc -= ns;
475  }
476  else
477  ns = 0;
478  fread( (char *)scanc, 1, nc, infile );
479  while ( ns-- > 0 )
480  (void)getc( infile );
481  if ( nc & 1 )
482  (void)getc( infile ); /* throw away odd byte */
483  }
484  else
485  if ( the_hdr->priv.get.is_seek )
486  fseek( infile, ((nc + 1) / 2) * 2, 1 );
487  else
488  {
489  register int ii;
490  for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
491  (void) getc( infile ); /* discard it */
492  }
493 
494  scanc += nc;
495  scan_x += nc;
496  if ( debug_f && RLE_BIT( *the_hdr, channel ) )
497  {
498  rle_pixel * cp = scanc - nc;
499  for ( ; nc > 0; nc-- )
500  fprintf( stderr, "%02x", *cp++ );
501  putc( '\n', stderr );
502  }
503  break;
504 
505  case RRunDataOp:
506  if ( LONGP(inst) )
507  {
508  VAXSHORT( nc, infile );
509  }
510  else
511  nc = DATUM(inst);
512  nc++;
513  scan_x += nc;
514 
515  VAXSHORT( word, infile );
516  if ( debug_f )
517  fprintf( stderr, "Run length %d (to %d), data %02x\n",
518  nc, scan_x, word );
519  if ( RLE_BIT( *the_hdr, channel ) )
520  {
521  if ( scan_x > max_x )
522  {
523  ns = scan_x - max_x - 1;
524  nc -= ns;
525  }
526  else
527  ns = 0;
528  if ( nc >= 10 ) /* break point for 785, anyway */
529  {
530  bfill( (char *)scanc, nc, word );
531  scanc += nc;
532  }
533  else
534  for ( nc--; nc >= 0; nc--, scanc++ )
535  *scanc = word;
536  }
537  break;
538 
539  case REOFOp:
540  the_hdr->priv.get.is_eof = 1;
541  if ( debug_f )
542  fprintf( stderr, "End of Image\n" );
543  break;
544 
545  default:
546  fprintf( stderr,
547  "%s: rle_getrow: Unrecognized opcode: %d, reading %s\n",
548  the_hdr->cmd, inst[0], the_hdr->file_name );
549  exit(1);
550  }
551  if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
552  break; /* <--- the other loop exit */
553  }
554 
555  /* If at end, skip the rest of a malformed image. */
556  if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
557  {
558  int y = the_hdr->priv.get.scan_y;
559  while ( rle_getskip( the_hdr ) != 32768 )
560  ;
561  return y;
562  }
563 
564  return the_hdr->priv.get.scan_y;
565 }
566 
567 
568 /* Fill buffer at s with n copies of character c. N must be <= 65535*/
569 /* ARGSUSED */
570 static void bfill( s, n, c )
571 register char *s;
572 register int n, c;
573 {
574 #ifdef vax
575  asm(" movc5 $0,*4(ap),12(ap),8(ap),*4(ap)");
576 #else
577  while ( n-- > 0 )
578  *s++ = c;
579 #endif
580 }
#define RSetColorOp
Definition: rle_code.h:38
#define RLE_SET_BIT(glob, bit)
Definition: rle.h:122
#define RRunDataOp
Definition: rle_code.h:41
int xmin
Definition: rle.h:100
const char ** comments
Definition: rle.h:113
char h_ncmap
Definition: rle_code.h:55
#define H_COMMENT
Definition: rle_code.h:47
void rle_names(rle_hdr *the_hdr, const char *pgmname, const char *fname, int img_num)
Definition: rle_hdr.c:48
void rle_debug(int on_off)
Definition: rle_getrow.c:293
#define RLE_EMPTY
Definition: rle.h:73
#define RSkipLinesOp
Definition: rle_code.h:37
char h_cmaplen
Definition: rle_code.h:55
int rle_get_setup(rle_hdr *the_hdr)
Definition: rle_getrow.c:74
#define RLE_MAGIC
Definition: rle_code.h:67
#define LONGP(inst)
Definition: XtndRunget.c:85
rle_map * cmap
Definition: rle.h:112
int vax_gshort(char *msgp)
Definition: vaxshort.c:31
int rle_getrow(rle_hdr *the_hdr, scanline)
Definition: rle_getrow.c:333
int * bg_color
Definition: rle.h:100
#define RLE_SUCCESS
Definition: rle.h:70
char hc_ylen[2]
Definition: rle_code.h:51
#define H_ALPHA
Definition: rle_code.h:46
#define RLE_NOT_RLE
Definition: rle.h:71
int ymin
Definition: rle.h:100
int rle_get_error(int code, const char *pgmname, const char *fname)
Definition: rle_error.c:76
long int is_init
Definition: rle.h:131
static char rcs_ident[]
Definition: rle_getrow.c:33
char hc_xlen[2]
Definition: rle_code.h:51
char h_ncolors
Definition: rle_code.h:55
#define REOFOp
Definition: rle_code.h:42
#define H_CLEARFIRST
Definition: rle_code.h:44
const char * cmd
Definition: rle.h:133
static void bfill(char *s, int n, int c)
Definition: rle_getrow.c:570
int xmax
Definition: rle.h:100
int img_num
Definition: rle.h:135
#define RLE_INIT_MAGIC
Definition: rle.h:79
char hc_ypos[2]
Definition: rle_code.h:51
#define RSkipPixelsOp
Definition: rle_code.h:39
#define RLE_NO_SPACE
Definition: rle.h:72
#define RLE_EOF
Definition: rle.h:74
#define CONST_DECL
Definition: rle_config.h:42
unsigned int rle_getskip(rle_hdr *the_hdr)
Definition: rle_getskip.c:57
#define LONG
Definition: rle_code.h:36
void rle_get_setup_ok(rle_hdr *the_hdr, const char *prog_name, const char *file_name)
Definition: rle_getrow.c:254
#define VAXSHORT(var, fp)
Definition: rle_cp.c:33
int background
Definition: rle.h:100
#define DATUM(inst)
Definition: XtndRunget.c:86
char hc_xpos[2]
Definition: rle_code.h:51
int ncmap
Definition: rle.h:100
int ymax
Definition: rle.h:100
unsigned char rle_pixel
Definition: rle.h:56
static int debug_f
Definition: rle_getrow.c:50
int cmaplen
Definition: rle.h:100
int alpha
Definition: rle.h:100
#define RLE_ALPHA
Definition: rle.h:65
#define SETUPSIZE
Definition: rle_code.h:61
char h_flags
Definition: rle_code.h:55
unsigned short rle_map
Definition: rle.h:57
void rle_hdr_clear(rle_hdr *the_hdr)
Definition: rle_hdr.c:222
const char * file_name
Definition: rle.h:134
#define H_NO_BACKGROUND
Definition: rle_code.h:45
#define OPCODE(inst)
Definition: XtndRunget.c:84
rle_hdr * rle_hdr_init(rle_hdr *the_hdr)
Definition: rle_hdr.c:267
FILE * rle_file
Definition: rle.h:114
int ncolors
Definition: rle.h:100
#define RByteDataOp
Definition: rle_code.h:40
#define RLE_CHECK_ALLOC(pgm, ptr, name)
Definition: rle.h:86
#define RLE_BIT(glob, bit)
Definition: rle.h:126