/* * 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. */ /* * rle_hdr.c - Functions to manipulate rle_hdr structures. * * Author: Spencer W. Thomas * EECS Dept. * University of Michigan * Date: Mon May 20 1991 * Copyright (c) 1991, University of Michigan */ #include #include "rle_config.h" #include "rle.h" /***************************************************************** * TAG( rle_names ) * * Load program and file names into header. * Inputs: * the_hdr: Header to modify. * pgmname: The program name. * fname: The file name. * img_num: Number of the image within the file. * Outputs: * the_hdr: Modified header. * Algorithm: * If values previously filled in (by testing is_init field), * free them. Make copies of file name and program name, * modifying file name for standard i/o. Set is_init field. */ void rle_names( the_hdr, pgmname, fname, img_num ) rle_hdr *the_hdr; CONST_DECL char *pgmname; CONST_DECL char *fname; int img_num; { #if 0 /* Can't do this because people do hdr1 = hdr2, which copies the pointers. */ /* If filled in, free previous values. */ if ( the_hdr->is_init == RLE_INIT_MAGIC && the_hdr->cmd != NULL && the_hdr->file_name != NULL ) { if ( pgmname != the_hdr->cmd ) free( the_hdr->cmd ); if ( fname != the_hdr->file_name ) free( the_hdr->file_name ); } #endif /* Mark as filled in. */ the_hdr->is_init = RLE_INIT_MAGIC; /* Default file name for stdin/stdout. */ if ( fname == NULL || strcmp( fname, "-" ) == 0 || *fname == '\0' ) fname = "Standard I/O"; if ( pgmname == NULL ) pgmname = rle_dflt_hdr.cmd; /* Fill in with copies of the strings. */ if ( the_hdr->cmd != pgmname ) { char *tmp = (char *)malloc( strlen( pgmname ) + 1 ); RLE_CHECK_ALLOC( pgmname, tmp, 0 ); strcpy( tmp, pgmname ); the_hdr->cmd = tmp; } if ( the_hdr->file_name != fname ) { char *tmp = (char *)malloc( strlen( fname ) + 1 ); RLE_CHECK_ALLOC( pgmname, tmp, 0 ); strcpy( tmp, fname ); the_hdr->file_name = tmp; } the_hdr->img_num = img_num; } /* Used by rle_hdr_cp and rle_hdr_init to avoid recursion loops. */ static int no_recurse = 0; /***************************************************************** * TAG( rle_hdr_cp ) * * Make a "safe" copy of a rle_hdr structure. * Inputs: * from_hdr: Header to be copied. * Outputs: * to_hdr: Copy of from_hdr, with all memory referred to * by pointers copied. Also returned as function * value. If NULL, a static header is used. * Assumptions: * It is safe to call rle_hdr_init on to_hdr. * Algorithm: * Initialize to_hdr, copy from_hdr to it, then copy the memory * referred to by all non-null pointers. */ rle_hdr * rle_hdr_cp( from_hdr, to_hdr ) rle_hdr *from_hdr, *to_hdr; { static rle_hdr dflt_hdr; CONST_DECL char *cmd, *file; int num; /* Save command, file name, and image number if already initialized. */ if ( to_hdr && to_hdr->is_init == RLE_INIT_MAGIC ) { cmd = to_hdr->cmd; file = to_hdr->file_name; num = to_hdr->img_num; } else { cmd = file = NULL; num = 0; } if ( !no_recurse ) { no_recurse++; rle_hdr_init( to_hdr ); no_recurse--; } if ( to_hdr == NULL ) to_hdr = &dflt_hdr; *to_hdr = *from_hdr; if ( to_hdr->bg_color ) { int size = to_hdr->ncolors * sizeof(int); to_hdr->bg_color = (int *)malloc( size ); RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->bg_color, "background color" ); memcpy( to_hdr->bg_color, from_hdr->bg_color, size ); } if ( to_hdr->cmap ) { int size = to_hdr->ncmap * (1 << to_hdr->cmaplen) * sizeof(rle_map); to_hdr->cmap = (rle_map *)malloc( size ); RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->cmap, "color map" ); memcpy( to_hdr->cmap, from_hdr->cmap, size ); } /* Only copy array of pointers, as the original comment memory * never gets overwritten. */ if ( to_hdr->comments ) { int size = 0; CONST_DECL char **cp; for ( cp=to_hdr->comments; *cp; cp++ ) size++; /* Count the comments. */ /* Check if there are really any comments. */ if ( size ) { size++; /* Copy the NULL pointer, too. */ size *= sizeof(char *); to_hdr->comments = (CONST_DECL char **)malloc( size ); RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->comments, "comments" ); memcpy( to_hdr->comments, from_hdr->comments, size ); } else to_hdr->comments = NULL; /* Blow off empty comment list. */ } /* Restore the names to their original values. */ to_hdr->cmd = cmd; to_hdr->file_name = file; /* Lines above mean nothing much happens if cmd and file are != NULL. */ rle_names( to_hdr, to_hdr->cmd, to_hdr->file_name, num ); return to_hdr; } /***************************************************************** * TAG( rle_hdr_clear ) * * Clear out the allocated memory pieces of a header. * * This routine is intended to be used internally by the library, to * clear a header before putting new data into it. It clears all the * fields that would be set by reading in a new image header. * Therefore, it does not clear the program and file names. * * Inputs: * the_hdr: To be cleared. * Outputs: * the_hdr: After clearing. * Assumptions: * If is_init field is RLE_INIT_MAGIC, the header has been * properly initialized. This will fail every 2^(-32) times, on * average. * Algorithm: * Free memory and set to zero all pointers, except program and * file name. */ void rle_hdr_clear( the_hdr ) rle_hdr *the_hdr; { /* Try to free memory. Assume if is_init is properly set that this * header has been previously initialized, therefore it is safe to * free memory. */ if ( the_hdr && the_hdr->is_init == RLE_INIT_MAGIC ) { if ( the_hdr->bg_color ) free( the_hdr->bg_color ); the_hdr->bg_color = 0; if ( the_hdr->cmap ) free( the_hdr->cmap ); the_hdr->cmap = 0; /* Unfortunately, we don't know how to free the comment memory. */ if ( the_hdr->comments ) free( the_hdr->comments ); the_hdr->comments = 0; } } /***************************************************************** * TAG( rle_hdr_init ) * * Initialize a rle_hdr structure. * Inputs: * the_hdr: Header to be initialized. * Outputs: * the_hdr: Initialized header. * Assumptions: * If the_hdr->is_init is RLE_INIT_MAGIC, the header has been * previously initialized. * If the_hdr is a copy of another rle_hdr structure, the copy * was made with rle_hdr_cp. * Algorithm: * Fill in fields of rle_dflt_hdr that could not be set by the loader * If the_hdr is rle_dflt_hdr, do nothing else * Else: * If the_hdr is NULL, return a copy of rle_dflt_hdr in static storage * If the_hdr->is_init is RLE_INIT_MAGIC, free all memory * pointed to by non-null pointers. * If this is a recursive call to rle_hdr_init, clear *the_hdr and * return the_hdr. * Else make a copy of rle_dflt_hdr and return its address. Make the * copy in static storage if the_hdr is NULL, and in the_hdr otherwise. */ rle_hdr * rle_hdr_init( the_hdr ) rle_hdr *the_hdr; { rle_hdr *ret_hdr; rle_dflt_hdr.rle_file = stdout; /* The rest of rle_dflt_hdr is set by the loader's data initialization */ if ( the_hdr == &rle_dflt_hdr ) return the_hdr; rle_hdr_clear( the_hdr ); /* Only call rle_hdr_cp if not called from there. */ if ( !no_recurse ) { no_recurse++; ret_hdr = rle_hdr_cp( &rle_dflt_hdr, the_hdr ); no_recurse--; } else ret_hdr = the_hdr; return ret_hdr; }