/* rezrov.c
* Extracts resources from a blorb file
* Written by Felix Grützmacher and placed into the public domain */
#include <stdio.h>
#include <string.h>
/* The following might need changing on your machine */
typedef unsigned int UI32;
/* Define this if you're compiling for an Intel machine */
#define _INTEL
typedef struct {
char usage[4];
UI32 num;
UI32 start;
} RES_T;
#define MAX_RES (256)
void extract(RES_T res, FILE *blb);
#ifdef _INTEL
void endian_transform(UI32 *p);
#endif
unsigned num_ext = 0;
int main(int argc, char *argv[]) {
FILE *blb;
UI32 num_res=0;
RES_T res[MAX_RES];
UI32 i;
if(argc<2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
exit(1);
}
if(!(blb=fopen(argv[1],"rb"))) {
perror(argv[1]);
exit(2);
}
fseek(blb, 20, SEEK_SET);
if(fread(&num_res, 4, 1, blb)!=1) {
if(feof(blb))
fputs("End of file while reading resource index.\n", stderr);
else perror("Error getting number of resources");
exit(3);
}
#ifdef _INTEL
endian_transform(&num_res);
#endif
if(num_res>MAX_RES)
num_res=MAX_RES;
if(fread(res, sizeof(RES_T), num_res, blb)!=num_res) {
if(feof(blb))
fputs("End of file while reading resource index.\n", stderr);
else perror("Error reading resource index");
exit(3);
}
for(i=0; i<num_res; i++)
if(!strncmp(res[i].usage, "Snd ", 4) || !strncmp(res[i].usage, "Pict ", 4) || !strncmp(res[i].usage, "Exec", 4))
extract(res[i], blb);
/* Our work is done */
fclose(blb);
printf("Successfully captured %u resources!\n", num_ext);
return 0;
}
void extract(RES_T res, FILE *blb) {
char type[4];
UI32 len;
char fname[16]; /* max 10 digits + ".xxxx" + '\0' */
FILE *out;
UI32 i;
int c;
int tmp;
const char *ext;
#ifdef _INTEL
endian_transform(&(res.start));
endian_transform(&(res.num));
#endif
fseek(blb, res.start, SEEK_SET);
if(fread((void *)type, 1, 4, blb)!=4) {
if(feof(blb))
fputs("End of file while reading resource type.\n", stderr);
else perror("Error reading resource type");
exit(3);
}
switch(*type) {
case 'M':
ext = ".mod";
break;
case 'F':
ext = ".aiff";
break;
case 'P':
ext = ".png";
break;
case 'Z':
ext = ".z";
break;
case 'G':
ext = ".ulx";
break;
default:
return; /* skip resources of unknown type */
}
if(fread(&len, 4, 1, blb)!=1) {
if(feof(blb))
fputs("End of file while reading resource length.\n", stderr);
else perror("Error reading resource length");
exit(3);
}
tmp=len;
#ifdef _INTEL
endian_transform(&len);
#endif
sprintf(fname, "%u", res.num);
strcat(fname, ext);
if(!(out=fopen(fname, "wb"))) {
perror(fname);
exit(4);
}
/* If this is an aiff, write "FORM" and len to output */
if(*type=='F') {
if(fwrite(type, 1, 4, out)!=4) {
perror("Error writing lead-in FORM tag");
exit(4);
}
if(fwrite(&len, 4, 1, out)!=1) {
perror("Error writing lead-in form length");
exit(4);
}
}
/* Copy the data */
for(i=0; i<len; i++) {
if((c=getc(blb))==EOF) {
if(ferror(blb))
perror("Error reading resource data");
else fputs("End of file while reading resource data.\n", stderr);
exit(3);
}
if(putc(c, out)==EOF) {
perror(fname);
exit(4);
}
}
fclose(out);
num_ext++;
}
#ifdef _INTEL
void endian_transform(UI32 *p) {
UI32 r = *p;
r = (r>>24) | ((r>>8)&0x0000ff00) | ((r<<8)&0x00ff0000) | (r<<24);
*p=r;
}
#endif