1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 08:34:22 +03:00
inform7/inblorb/Tests/Assistants/blorblib/blorbscan.c
2019-02-05 00:44:07 +00:00

385 lines
12 KiB
C

/* blorbscan.c: Blorb file analysis tool, version 1.0.2.
Designed by Andrew Plotkin <erkyrath@eblong.com>
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 <stdio.h>
#include <stdlib.h>
#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; ix<argc; ix++) {
if (argv[ix][0] == '-') {
char *cx = argv[ix];
for (cx++; *cx; cx++) {
switch (*cx) {
case 'c':
opt_chunks = TRUE;
anyopts = TRUE;
break;
case 'r':
opt_resources = TRUE;
anyopts = TRUE;
break;
case 'u':
opt_byusage = TRUE;
anyopts = TRUE;
break;
case 's':
opt_split = TRUE;
anyopts = TRUE;
break;
case 'p':
opt_palette = TRUE;
anyopts = TRUE;
break;
case 'x':
opt_extras = TRUE;
anyopts = TRUE;
break;
case 'n':
opt_release = TRUE;
anyopts = TRUE;
break;
case 'z':
opt_zheader = TRUE;
anyopts = TRUE;
break;
case 'w':
opt_resolution = TRUE;
anyopts = TRUE;
break;
case 'A':
opt_chunks = TRUE;
opt_resources = TRUE;
opt_byusage = TRUE;
opt_palette = TRUE;
opt_zheader = TRUE;
opt_resolution = TRUE;
opt_extras = TRUE;
opt_release = TRUE;
anyopts = TRUE;
break;
case 'h':
case '?':
err = TRUE;
break;
default:
err = TRUE;
printf("unknown option: -%c\n", *cx);
break;
}
}
}
else {
if (!filename)
filename = argv[ix];
else
err = TRUE;
}
}
if (!anyopts) {
opt_resources = TRUE;
}
if (!filename || err) {
printf("usage: %s [ -urscnzwpxA ] filename\n", argv[0]);
printf(" -u: count resources by usage\n");
printf(" -r: list resources (the default)\n");
printf(" -s: split out resources into separate files\n");
printf(" -c: list chunks\n");
printf(" -n: show release number\n");
printf(" -z: show z-code header info\n");
printf(" -w: show window resolution hints\n");
printf(" -p: show palette hints\n");
printf(" -x: show extras (author, annotation, copyright)\n");
printf(" -A: all of the above (except -s)\n");
return 0;
}
fl = fopen(filename, "rb");
if (!fl) {
printf("Unable to open file.\n");
return 0;
}
printf("Reading \"%s\"...\n\n", filename);
analyze_file(fl);
fclose(fl);
return 0;
}
void analyze_file(FILE *fl)
{
bb_map_t *map;
bb_err_t err;
int ix;
err = bb_create_map(fl, &map);
if (err) {
printf("Cannot create map: %s\n", bb_err_to_string(err));
return;
}
if (opt_byusage) {
int num, min, max;
err = bb_count_resources(map, bb_ID_Exec, &num, &min, &max);
if (!err) {
if (num == 0)
printf("No '%s' resources\n", bb_id_to_string(bb_ID_Exec));
else
printf("%d '%s' resources (numbered from %d to %d)\n",
num, bb_id_to_string(bb_ID_Exec), min, max);
}
else {
printf("Cannot count '%s' resources: %s\n",
bb_id_to_string(bb_ID_Exec), bb_err_to_string(err));
}
err = bb_count_resources(map, bb_ID_Snd, &num, &min, &max);
if (!err) {
if (num == 0)
printf("No '%s' resources\n", bb_id_to_string(bb_ID_Snd));
else
printf("%d '%s' resources (numbered from %d to %d)\n",
num, bb_id_to_string(bb_ID_Snd), min, max);
}
else {
printf("Cannot count '%s' resources: %s\n",
bb_id_to_string(bb_ID_Snd), bb_err_to_string(err));
}
err = bb_count_resources(map, bb_ID_Pict, &num, &min, &max);
if (!err) {
if (num == 0)
printf("No '%s' resources\n", bb_id_to_string(bb_ID_Pict));
else
printf("%d '%s' resources (numbered from %d to %d)\n",
num, bb_id_to_string(bb_ID_Pict), min, max);
}
else {
printf("Cannot count '%s' resources: %s\n",
bb_id_to_string(bb_ID_Pict), bb_err_to_string(err));
}
printf("\n");
}
if (opt_resources) {
printf("List of resources:\n");
for (ix=0; ix<map->numresources; 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; ix<map->numresources; 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; jx<res.length; jx++) {
ch = getc(map->file);
if (ch == EOF)
break;
putc(ch, outfl);
}
fclose(outfl);
}
}
}
}
if (opt_chunks) {
printf("List of chunks:\n");
for (ix=0; ix<map->numchunks; 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; ix<pal->data.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;
}
}