/* * ============================================================================ * Simple test program for resource manipulation routines J. Zbiciak * * Reads a resource file and writes out a directory tree corresponding to * the unpacked resource file. * * This file is mostly a quick hack for testing the routines in the RES_FILE * and DATA_FMT library of routines. * ============================================================================ */ #include "config.h" #include #include #ifdef _TMS320C6X #include #else #include #include #include #include #endif #include #include #include #include "res_file.h" #include "file_util.h" #include "macros.h" /* * ============================================================================ * Syntax: de_res [-o] [-r] file.res dir * * Reads the resource file "file.res", and unpacks the entire hierarchy * into the directory "dir". Creates directories as needed, and refuses * to overwrite files unless "-o" is specified. If "-r" is specified, * then image and font files are not decoded. * * In each subdirectory, a file named ".manifest" is created which * contains type information for each of the unpacked files. * ============================================================================ */ /* * ============================================================================ * ============================================================================ * UTILITY FUNCTIONS * ============================================================================ * ============================================================================ */ /* * ============================================================================ * WRITE_MANIFEST -- Writes a manifest in a directory, when given an * archive pointer * ============================================================================ */ int write_manifest(const char *directory, int overwrite, int raw_images, res_arch_t *archive) { char * pathname; int len; FILE * f; char work_buf[64]; res_rec_t *r; len = strlen(directory); pathname = (char*) malloc(len + 11); if (!pathname) return -1; sprintf(pathname, "%s/.manifest", directory); if (f_file_exists(pathname)) { if (overwrite) { unlink(pathname); if (f_file_exists(pathname)) goto abort; } else goto abort; } f = fopen(pathname,"w"); if (!f) goto abort; f_escape_string(archive->ident, work_buf); fprintf(f, "######################################################################\n" "# Manifest file\n" "#\n" "# Name : %-36s\n" "# State : 0x%.4x\n" "# Records : %d\n" "######################################################################\n" "# %-36s %-10s %s\n" "#---------------------------------------------------------------------\n", work_buf, archive->state, archive->count, "Resource", "Type Number", "Type Name"); r = archive->res_rec; while (r) { f_escape_string(r->ident, work_buf); if (raw_images || (r->type != RES_t_image && r->type != RES_t_font)) fprintf(f," %-36s, 0x%.8x # %s\n", r->ident, r->type, res_type_name(r->type)); else fprintf(f," %-36s, 0x%.8x # %s (PPM)\n", r->ident, r->type + 0x1000, res_type_name(r->type)); r = r->next; } fprintf(f, "######################################################################\n"); fclose(f); free(pathname); return 0; abort: free(pathname); return -1; } /* * ============================================================================ * LOCATE_PALETTE -- Finds the palette resource in an archive (if any) * ============================================================================ */ char * locate_palette(res_arch_t *arch) { res_rec_t * rec; char * pal; /* * ------------------------------------------------------------------------ * First check all resources on this level to see if we can find a * palette resource. If we find one, stop here and return it. * ------------------------------------------------------------------------ */ rec = arch->res_rec; while (rec) { if (rec->type == RES_t_palette) return rec->res.data; rec = rec->next; } /* * ------------------------------------------------------------------------ * If we didn't find a palette in this level of the hierarchy, try * recursing through all nested resource archives looking for the * palette. * ------------------------------------------------------------------------ */ rec = arch->res_rec; while (rec) { if (rec->type == RES_t_archive) if ((pal = locate_palette(rec->res.arch)) != NULL) return pal; rec = rec->next; } /* * ------------------------------------------------------------------------ * If we still didn't find anything, report failure. *sigh* * ------------------------------------------------------------------------ */ return NULL; } /* * ============================================================================ * WRITE_PPMFILE -- Takes an image resource, and writes it as a PPM file. * ============================================================================ */ int write_ppmfile(FILE *f, res_img_t *img, const unsigned char *palette) { int i, j, p, size; unsigned char *buf; size = (int)img->x_dim * (int)img->y_dim; buf = malloc(size * 3); if (!buf) { fprintf(stderr,"Error allocating temporary buffer (%d bytes)\n", size * 3); return -1; } for (i = j = 0; j < size; i+=3, j++) { p = img->img[j]; buf[i + 0] = palette[p * 3 + 0]; buf[i + 1] = palette[p * 3 + 1]; buf[i + 2] = palette[p * 3 + 2]; } fprintf(f,"P6\n%d %d\n255\n", img->x_dim, img->y_dim); if (fwrite(buf,1,i,f) < (unsigned)i) { perror("fwrite()"); free(buf); return -1; } free(buf); return 0; } /* * ============================================================================ * WRITE_ARCHIVE -- Write an archive out to disk recursively. Overwrites * files only if overwrite flag is set. Calls out to * write_manifest() to write the manifest files also. * ============================================================================ */ int write_archive(const char *directory, int overwrite, int raw_images, res_arch_t *archive, char * palette) { res_rec_t *r; char *pathname; int l; FILE *f; errno = 0; if (f_create_dir(directory, overwrite) < 0) { if (errno) perror(directory); fprintf(stderr,"Error creating directory '%s'.\n", directory); return -1; } l = strlen(directory); pathname = malloc(l + 128); strncpy(pathname, directory, l + 128); pathname[l] = '/'; l++; for (r = archive->res_rec; r; r = r->next) { f_escape_string(r->ident, pathname+l); /* If this is a archive record, recurse. */ if (r->type == RES_t_archive) { printf("Nested archive: %s:\n",pathname); fflush(stdout); if (write_archive(pathname, overwrite, raw_images, r->res.arch, palette) < 0) goto abort; continue; } printf("%36s : %20s : %10d\n", pathname+l, res_type_name(r->type), r->len); fflush(stdout); /* Otherwise, just dump out the raw file */ if (f_file_exists(pathname)) { if (overwrite) { unlink(pathname); if (f_file_exists(pathname)) { fprintf(stderr,"Error unlinking file '%s', skipping\n", pathname); continue; } } else { fprintf(stderr,"Not overwriting '%s'\n", pathname); continue; } } f = fopen(pathname, "w"); if (!f) { perror("fopen()"); fprintf(stderr,"Error opening '%s'\n",pathname); goto abort; } if (r->type == RES_t_image || r->type == RES_t_font) { if (raw_images || r->rec_state == RES_s_encoded || write_ppmfile(f, r->res.img, (const unsigned char *)palette)) { if (!res_encode(r)) fwrite((void*)r->res.data,1,r->len,f); } } else { fwrite((void*)r->res.data,1,r->len,f); } fclose(f); } free(pathname); if (write_manifest(directory, overwrite, raw_images, archive) < 0) { fprintf(stderr,"Error writing manifest file in '%s'\n", directory); return -1; } return 0; abort: free(pathname); return -1; } /* * ============================================================================ * MAIN * ============================================================================ */ int main(int argc, char *argv[]) { int overwrite = 0, raw_images = 0, i, ok; res_rec_t *rec; res_arch_t *archive; size_t len; FILE *f; char *palette_resource, my_palette[768]; void *raw_img; size_t file_len; while (argc > 3) { if (argv[1][0] != '-') break; switch (argv[1][1]) { case 'o' : overwrite = 1; ok = 1; break; case 'r' : raw_images = 1; ok = 1; break; default : fprintf(stderr,"Invalid flag '%s'\n", argv[1]); ok = 0; } if (!ok) break; argc -= ok; argv += ok; } if (argc != 3) { fprintf(stderr,"Usage: %s [-o] [-r] file.res directory\n", argv[0]?argv[0]:"de_res"); exit(1); } f = fopen(argv[1], "r"); if (!f) { perror("fopen()"); fprintf(stderr,"Error opening resource archive '%s'\n",argv[1]); exit(1); } fseek(f, 0, SEEK_END); file_len = len = ftell(f); raw_img = malloc(file_len); if (!raw_img) { perror("malloc()"); fprintf(stderr,"Error allocating %d bytes for memory image\n", file_len); exit(1); } fseek(f, 0, SEEK_SET); fread(raw_img, 1, file_len, f); fclose(f); /* XXX: TODO: This really should be in the res_file library. */ rec = malloc(sizeof(res_rec_t)); res_init_rec(rec, NULL, NULL, NULL); rec->rec_state = RES_s_encoded; rec->type = RES_t_archive; rec->res.data = raw_img; rec->len = len = file_len; if (res_decode(rec, (RES_RECURSE | RES_ALL) & (raw_images ? ~(MASK_BIT(RES_t_image)| MASK_BIT(RES_t_font)) : ~0), NULL, NULL )) { fprintf(stderr,"Decode aborted!\n"); for (i = 0; ilib_state->num_err; i++) { fprintf(stderr,"Decode error: %s\n",rec->lib_state->err_msg[i]); } exit(1); } archive = rec->res.arch; if (!archive) { fprintf(stderr,"Error loading archive file. Extract aborted.\n"); exit(1); } printf("Read %d bytes from archive. Writing to disk...\n", (int)len); palette_resource = locate_palette(archive); if (!palette_resource) { fprintf(stderr,"Warning: Could not locate palette resource.\n"); fprintf(stderr,"Output colors will be gibberish in PPM files.\n"); } else { for (i=0; i<768; i++) { my_palette[i] = palette_resource[i] * 4; } } if (write_archive(argv[2], overwrite, raw_images, archive, my_palette) < 0) fprintf(stderr,"Error writing archive contents to disk. Aborted.\n"); return 0; } /* * ============================================================================ * Copyright (c) 1998, Joseph Zbiciak. * ============================================================================ */