#include #include #include #include extern const char *__progname; static const char *str_hdr = 0; static const char *str_dfork = 0; static const char *str_rfork = 0; static FILE *out_hdr; static FILE *out_dfork; static FILE *out_rfork; static FILE *inf; static int fnl; static char fn[256]; static int vers; static unsigned char type[4]; static unsigned char creator[4]; static unsigned short int flags; static unsigned int dflen; static unsigned int rflen; static unsigned short int crc; static const char b64chars[64] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: extra argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-h")) { str_hdr = ""; continue; } if (!strcmp(*av,"-H")) { WANTARG(); str_hdr = av[skip]; continue; } if (!strcmp(*av,"-d")) { str_dfork = ""; continue; } if (!strcmp(*av,"-D")) { WANTARG(); str_dfork = av[skip]; continue; } if (!strcmp(*av,"-r")) { str_rfork = ""; continue; } if (!strcmp(*av,"-R")) { WANTARG(); str_rfork = av[skip]; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } static void read_leadin(void) { int bol; int c; const unsigned char *hp; bol = 1; while (1) { if (bol) hp = "(This file must be converted with BinHex 4.0)"; bol = 0; c = getchar(); switch <"outer"> (c) { case '\r': case '\n': if (hp && !*hp) { while (1) { c = getchar(); switch (c) { case ':': return; break; case EOF: case <"outer"> EOF: fprintf(stderr,"%s: leading signature not found\n",__progname); exit(1); break; } } } bol = 1; break; default: if (hp && (c == *hp)) { hp ++; } else { case '\0': hp = 0; } break; } } } typedef struct state_b64 STATE_B64; struct state_b64 { FILE *inner; unsigned char bitbuf; int nbits; } ; static int r_b64(void *svp, char *buf, int len) { STATE_B64 *s; unsigned char *bp; unsigned int bb; int nb; int c; int n; const char *cp; s = svp; bp = (void *) buf; bb = s->bitbuf; nb = s->nbits; n = 0; while <"read"> (n < len) { c = getc(s->inner); switch (c) { case EOF: break <"read">; case ':': ungetc(c,s->inner); break <"read">; } cp = memchr(&b64chars[0],c,64); if (cp == 0) continue; bb = (bb << 6) | (cp - &b64chars[0]); nb += 6; if (nb >= 8) { *bp++ = bb >> (nb - 8); n ++; nb -= 8; } } s->bitbuf = bb; s->nbits = nb; return(n); } static int c_b64(void *svp) { free(svp); return(0); } static FILE *wrap_b64(FILE *inner) { STATE_B64 *s; s = malloc(sizeof(STATE_B64)); s->inner = inner; s->bitbuf = 0; s->nbits = 0; return(funopen(s,r_b64,0,0,c_b64)); } typedef struct state_rle STATE_RLE; struct state_rle { FILE *inner; int repeats; unsigned char repchar; } ; static int r_rle(void *svp, char *buf, int len) { STATE_RLE *s; unsigned char *bp; int c; int n; s = svp; n = 0; bp = (void *) buf; while <"read"> (n < len) { if (s->repeats > 0) { *bp++ = s->repchar; n ++; s->repeats --; } else { c = getc(s->inner); switch (c) { case EOF: break <"read">; case 0x90: c = getc(s->inner); switch (c) { case EOF: break <"read">; case 0x00: *bp++ = 0x90; s->repchar = 0x90; /* XXX ??? */ n ++; break; default: s->repeats = c - 1; break; } break; default: *bp++ = c; s->repchar = c; n ++; break; } } } return(n); } static int c_rle(void *svp) { free(svp); return(0); } static FILE *wrap_rle(FILE *inner) { STATE_RLE *s; s = malloc(sizeof(STATE_RLE)); s->inner = inner; s->repeats = 0; return(funopen(s,r_rle,0,0,c_rle)); } static FILE *openout_(const char *s) { FILE *f; if (s == 0) return(0); if (*s == 0) return(stdout); f = fopen(s,"w"); if (f == 0) { fprintf(stderr,"%s: %s: %s\n",__progname,s,strerror(errno)); exit(1); } return(f); } static void openout(void) { out_hdr = openout_(str_hdr); out_dfork = openout_(str_dfork); out_rfork = openout_(str_rfork); } static int read_header(void) { __label__ ret0; static void fail(void) { goto ret0; } static unsigned char get(void) { int c; c = getc(inf); if (c == EOF) { fprintf(stderr,"%s: EOF reading header\n",__progname); fail(); } return(c); } static unsigned short int get2(void) { unsigned char c1; unsigned char c2; c1 = get(); c2 = get(); return((c1*0x0100)|c2); } static unsigned int get4(void) { unsigned char c1; unsigned char c2; unsigned char c3; unsigned char c4; c1 = get(); c2 = get(); c3 = get(); c4 = get(); return((c1*0x01000000)|(c2*0x00010000)|(c3*0x00000100)|c4); } fnl = get(); if ((fnl < 1) || (fnl > 63)) { fprintf(stderr,"%s: warning: filename length %d is out of range 1..63\n",__progname,fnl); } if (fread(&fn[0],1,fnl,inf) != fnl) { fprintf(stderr,"%s: can't read filename\n",__progname); fail(); } vers = get(); type[0] = get(); type[1] = get(); type[2] = get(); type[3] = get(); creator[0] = get(); creator[1] = get(); creator[2] = get(); creator[3] = get(); flags = get2(); dflen = get4(); rflen = get4(); crc = get2(); if (out_hdr) { fprintf(out_hdr,"Filename[%d]:\t",fnl); fwrite(&fn[0],1,fnl,out_hdr); fprintf(out_hdr,"\nVersion:\t%d\nType:\t\t",vers); fwrite(&type[0],1,4,out_hdr); fprintf(out_hdr,"\nCreator:\t"); fwrite(&creator[0],1,4,out_hdr); fprintf(out_hdr,"\nFlags:\t\t%04x\nData Len:\t%u\nResource Len:\t%u\nCRC:\t\t%04x\n",flags,dflen,rflen,crc); } return(1); ret0:; return(0); } static int read_fork(unsigned int len, FILE *outf, const char *lcname, const char *ucname) { __label__ ret0; unsigned int i; unsigned char c; unsigned short int crc; static unsigned char get(void) { int c; c = getc(inf); if (c == EOF) { fprintf(stderr,"%s: EOF reading %s fork\n",__progname,lcname); goto ret0; } return(c); } for (i=len;i>0;i--) { c = get(); if (outf) putc(c,outf); } c = get(); crc = (c * 0x0100) | get(); if (out_hdr) fprintf(out_hdr,"%s CRC:\t%04x\n",ucname,crc); return(1); ret0:; return(0); } static int read_data(void) { return(read_fork(dflen,out_dfork,"data","Data")); } static int read_resource(void) { return(read_fork(rflen,out_rfork,"resource","Resource")); } static int read_terminator(void) { int c; c = getc(inf); if (c != EOF) { fprintf(stderr,"%s: junk at end\n",__progname); return(0); } c = getc(stdin); if (c != ':') { fprintf(stderr,"%s: missing : terminator\n",__progname); return(0); } return(1); } int main(int ac, char **av) { handleargs(ac,av); read_leadin(); openout(); inf = wrap_rle(wrap_b64(stdin)); exit(!(read_header()&&read_data()&&read_resource()&&read_terminator())); }