/* blorbscan.c: Blorb file analysis tool, version 1.0.2. Designed by Andrew Plotkin http://www.eblong.com/zarf/blorb/index.html This is a nifty little tool which sucks any and all information out of a Blorb file. It doesn't do it in a particularly elegant way; it pulls a lot of information directly out of the bb_map_t structure, which is normally opaque. (It can do this because it #includes "blorblow.h".) So don't take this file as sample code, ok? */ #include #include #include "blorb.h" #include "blorblow.h" void analyze_file(FILE *fl); static int opt_chunks = FALSE; static int opt_resources = FALSE; static int opt_split = FALSE; static int opt_byusage = FALSE; static int opt_palette = FALSE; static int opt_resolution = FALSE; static int opt_extras = FALSE; static int opt_release = FALSE; static int opt_zheader = FALSE; int main(int argc, char *argv[]) { int ix; char *filename = NULL; FILE *fl; int err = FALSE; int anyopts = FALSE; for (ix=1; ixnumresources; ix++) { bb_chunkdesc_t *chu; printf("Usage '%s' number %d: chunk %d", bb_id_to_string(map->resources[ix].usage), map->resources[ix].resnum, map->resources[ix].chunknum); chu = &(map->chunks[map->resources[ix].chunknum]); switch (map->resources[ix].usage) { case bb_ID_Pict: if (chu->auxdatnum >= 0) { bb_aux_pict_t *aux = &(map->auxpict[chu->auxdatnum]); printf(" (std = %g", (double)aux->ratnum / (double)aux->ratden); if (aux->minnum || aux->minden) printf(", min = %g", (double)aux->minnum / (double)aux->minden); if (aux->maxnum || aux->maxden) printf(", min = %g", (double)aux->maxnum / (double)aux->maxden); printf(")"); } break; case bb_ID_Snd: if (chu->auxdatnum >= 0) { bb_aux_sound_t *aux = &(map->auxsound[chu->auxdatnum]); printf(" (repeats = %s)", (aux->repeats ? "1" : "infinite")); } break; } printf("\n"); } printf("\n"); } if (opt_split) { printf("Writing resources to individual files...\n\n"); for (ix=0; ixnumresources; ix++) { bb_result_t res; char outfname[64]; sprintf(outfname, "chu_%c%d", (map->resources[ix].usage >> 24) & 0xff, map->resources[ix].resnum); err = bb_load_chunk_by_number(map, bb_method_FilePos, &res, map->resources[ix].chunknum); if (err) { printf("Cannot load chunk: %s\n", bb_err_to_string(err)); } else { FILE *outfl; fseek(map->file, res.data.startpos, 0); outfl = fopen(outfname, "wb"); if (outfl) { int ch, jx; for (jx=0; jxfile); if (ch == EOF) break; putc(ch, outfl); } fclose(outfl); } } } } if (opt_chunks) { printf("List of chunks:\n"); for (ix=0; ixnumchunks; ix++) { printf("Chunk %d: type '%s', starts at %d, length %d.\n", ix, bb_id_to_string(map->chunks[ix].type), map->chunks[ix].startpos, map->chunks[ix].len); } printf("\n"); } if (opt_release) { printf("Release number: %d\n\n", bb_get_release_num(map)); } if (opt_zheader) { bb_zheader_t *head = bb_get_zheader(map); if (!head) { printf("No Z-code header info.\n"); } else { int jx; printf("Release %d.\nSerial number ", head->releasenum); for (jx=0; jx<6; jx++) printf("%c", head->serialnum[jx]); printf(".\nChecksum %x.\n", head->checksum); } printf("\n"); } if (opt_resolution) { bb_resolution_t *reso = bb_get_resolution(map); if (!reso) { printf("No window size data.\n"); } else { printf("Window size: standard %d by %d; min %d by %d; max %d by %d.\n", reso->px, reso->py, reso->minx, reso->miny, reso->maxx, reso->maxy); } printf("\n"); } if (opt_palette) { bb_palette_t *pal; err = bb_get_palette(map, &pal); if (err) printf("Cannot load palette data: %s\n", bb_err_to_string(err)); else { if (!pal) printf("No palette/color depth data.\n"); else { if (pal->isdirect) { printf("Preferred color depth: %d bits per pixel.\n", pal->data.depth); } else { printf("Preferred color palette (R,G,B):"); for (ix=0; ixdata.table.numcolors; ix++) { bb_color_t *col = &(pal->data.table.colors[ix]); printf(" (%d,%d,%d)", col->red, col->green, col->blue); } printf("\n"); } } } printf("\n"); } if (opt_extras) { bb_result_t res; err = bb_load_chunk_by_type(map, bb_method_Memory, &res, bb_ID_Copyright, 0); if (!err) { printf("Copyright chunk: "); fwrite(res.data.ptr, 1, res.length, stdout); printf("\n"); } else if (err == bb_err_NotFound) printf("No copyright chunk.\n"); else printf("Cannot load copyright chunk: %s\n", bb_err_to_string(err)); err = bb_load_chunk_by_type(map, bb_method_Memory, &res, bb_ID_AUTH, 0); if (!err) { printf("Author chunk: "); fwrite(res.data.ptr, 1, res.length, stdout); printf("\n"); } else if (err == bb_err_NotFound) printf("No author chunk.\n"); else printf("Cannot load author chunk: %s\n", bb_err_to_string(err)); err = bb_load_chunk_by_type(map, bb_method_Memory, &res, bb_ID_ANNO, 0); if (!err) { printf("Annotation chunk: "); fwrite(res.data.ptr, 1, res.length, stdout); printf("\n"); } else if (err == bb_err_NotFound) printf("No annotation chunk.\n"); else printf("Cannot load annotation chunk: %s\n", bb_err_to_string(err)); printf("\n"); } err = bb_destroy_map(map); if (err) { printf("Cannot destroy map: %s\n", bb_err_to_string(err)); return; } }