From faada59567f8cb252f4a909116595ce309ff5828 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Fri, 23 May 2003 12:29:55 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r647, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/miXed/; revision=648 --- shared/common/binport.c | 559 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 559 insertions(+) create mode 100644 shared/common/binport.c (limited to 'shared/common/binport.c') diff --git a/shared/common/binport.c b/shared/common/binport.c new file mode 100644 index 0000000..05cc5df --- /dev/null +++ b/shared/common/binport.c @@ -0,0 +1,559 @@ +/* Copyright (c) 1997-2003 Miller Puckette, krzYszcz, and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +#include +#include +#include +#include + +#define BINPORT_MAXSTRING 256 +#define BINPORT_SYMGROW 64 + +#ifndef BINPORT_STANDALONE +/* load max binary file to a binbuf */ + +#include "m_pd.h" + +#else +/* make a max-textual listing from a max binary file */ + +/* This is a standalone version of a ``max binary to binbuf'' module. + It uses certain Pd calls and structs, which are duplicated below. + LATER should be linked to the Pd API library. */ + +#define BINPORT_VERBOSE +//#define BINPORT_DEBUG + +#endif + +#include "binport.h" + +static void binport_error(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "ERROR (binport): "); + vfprintf(stderr, fmt, ap); + putc('\n', stderr); + va_end(ap); +} + +static void binport_warning(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "warning (binport): "); + vfprintf(stderr, fmt, ap); + putc('\n', stderr); + va_end(ap); +} + +static void binport_bug(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "BUG (binport): "); + vfprintf(stderr, fmt, ap); + putc('\n', stderr); + va_end(ap); +} + +#ifdef BINPORT_STANDALONE + +typedef int t_int; +typedef float t_float; + +typedef struct _symbol +{ + char *s_name; + void *s_thing; + struct _symbol *s_next; +} t_symbol; + +typedef union word +{ + t_float w_float; + t_symbol *w_symbol; + int w_index; +} t_word; + +typedef enum +{ + A_NULL, + A_FLOAT, + A_SYMBOL, + A_POINTER, + A_SEMI, + A_COMMA, + A_DEFFLOAT, + A_DEFSYM, + A_DOLLAR, + A_DOLLSYM, + A_GIMME, + A_CANT +} t_atomtype; + +typedef struct _atom +{ + t_atomtype a_type; + union word a_w; +} t_atom; + +void *getbytes(size_t nbytes) +{ + void *ret; + if (nbytes < 1) nbytes = 1; + ret = (void *)calloc(nbytes, 1); + if (!ret) + binport_error("getbytes() failed -- out of memory"); + return (ret); +} + +void *resizebytes(void *old, size_t oldsize, size_t newsize) +{ + void *ret; + if (newsize < 1) newsize = 1; + if (oldsize < 1) oldsize = 1; + ret = (void *)realloc((char *)old, newsize); + if (newsize > oldsize && ret) + memset(((char *)ret) + oldsize, 0, newsize - oldsize); + if (!ret) + binport_error("resizebytes() failed -- out of memory"); + return (ret); +} + +void freebytes(void *fatso, size_t nbytes) +{ + free(fatso); +} + +#define HASHSIZE 1024 + +static t_symbol *symhash[HASHSIZE]; + +t_symbol *dogensym(char *s, t_symbol *oldsym) +{ + t_symbol **sym1, *sym2; + unsigned int hash1 = 0, hash2 = 0; + int length = 0; + char *s2 = s; + while (*s2) + { + hash1 += *s2; + hash2 += hash1; + length++; + s2++; + } + sym1 = symhash + (hash2 & (HASHSIZE-1)); + while (sym2 = *sym1) + { + if (!strcmp(sym2->s_name, s)) return(sym2); + sym1 = &sym2->s_next; + } + if (oldsym) sym2 = oldsym; + else + { + sym2 = (t_symbol *)getbytes(sizeof(*sym2)); + sym2->s_name = getbytes(length+1); + sym2->s_next = 0; + sym2->s_thing = 0; + strcpy(sym2->s_name, s); + } + *sym1 = sym2; + return (sym2); +} + +t_symbol *gensym(char *s) +{ + return(dogensym(s, 0)); +} + +#endif /* end of Pd API */ + +/* clumsy... LATER find a better way */ +#ifdef BINPORT_STANDALONE +#define A_INT (A_CANT + 1) +#endif + +static int binport_getint(t_atom *ap) +{ +#ifdef A_INT + return (*(int *)&ap->a_w); +#else + return (ap->a_w.w_float); +#endif +} + +static void binport_setint(t_atom *ap, int i) +{ +#ifdef A_INT + ap->a_type = A_INT; + *(int *)&ap->a_w = i; +#else + SETFLOAT(ap, (float)i); +#endif +} + +static void binport_setfloat(t_atom *ap, float f) +{ + ap->a_type = A_FLOAT; + ap->a_w.w_float = f; +} + +typedef struct _binport +{ + FILE *b_fp; + int b_nsymbols; + int b_symsize; + t_symbol **b_symtable; +} t_binport; + +static int binport_getbuf(t_binport *bp, char *buf, size_t sz) +{ + return (fread(buf, 1, sz, bp->b_fp) == sz); +} + +static int binport_getbyte(t_binport *bp, unsigned char *buf) +{ + int c; + if ((c = fgetc(bp->b_fp)) == EOF) + return (0); + *buf = (unsigned char)c; + return (1); +} + +static int binport_getstring(t_binport *bp, char *buf) +{ + int c, i = 0; + while (c = fgetc(bp->b_fp)) + { + if (c == EOF) + return (0); + if (++i < BINPORT_MAXSTRING) + *buf++ = (unsigned char)c; + } + *buf = '\0'; + if (i >= BINPORT_MAXSTRING) + binport_warning("symbol string too long, skipped"); + return (1); +} + +static t_symbol *binport_makesymbol(t_binport *bp, int id) +{ + char s[BINPORT_MAXSTRING]; + if (id < bp->b_nsymbols) + binport_bug("symbol id mismatch"); + else if (id > bp->b_nsymbols) + binport_error("unexpected symbol id"); + else if (binport_getstring(bp, s)) + { + int reqsize = ++bp->b_nsymbols; + if (reqsize > bp->b_symsize) + { + reqsize += (BINPORT_SYMGROW - 1); +#ifdef BINPORT_DEBUG + binport_warning("resizing symbol table to %d elements", reqsize); +#endif + if (bp->b_symtable = + resizebytes(bp->b_symtable, + bp->b_symsize * sizeof(*bp->b_symtable), + reqsize * sizeof(*bp->b_symtable))) + bp->b_symsize = reqsize; + else + { + bp->b_nsymbols = bp->b_symsize = 0; + return (0); + } + } + return (bp->b_symtable[id] = gensym(s)); + } + return (0); +} + +static t_symbol *binport_getsymbol(t_binport *bp, int id) +{ + if (id < bp->b_nsymbols) + return (bp->b_symtable[id]); + else + return (binport_makesymbol(bp, id)); +} + +static int binport_setsymbol(t_binport *bp, t_atom *ap, int id) +{ + t_symbol *s = binport_getsymbol(bp, id); + if (s) + { + ap->a_type = A_SYMBOL; + ap->a_w.w_symbol = s; + } + return (s != 0); +} + +static int binport_nextatom(t_binport *bp, t_atom *ap) +{ + unsigned char opcode; + int opval; + char buf[64]; + if (!binport_getbyte(bp, &opcode)) + goto bad; + opval = opcode & 0x0f; + switch (opcode >> 4) + { + case 1: /* variable length int, + opval: length (number of bytes that follow) */ + if (!binport_getbuf(bp, buf, opval)) + goto bad; + else + { + unsigned char *p = (unsigned char *)buf + opval; + int i = 0; + while (opval--) i = (i << 8) | *--p; + if (opcode == 0x12) /* FIXME */ + i = (short)i; + binport_setint(ap, i); + } + break; + case 2: /* variable length float, + opval: length (number of bytes that follow) */ + if (!binport_getbuf(bp, buf, opval)) + goto bad; + else + { + unsigned char *p = (unsigned char *)buf + opval; + int i = 0; + while (opval--) i = (i << 8) | *--p; + binport_setfloat(ap, *(t_float *)&i); + } + break; + case 3: /* variable length symbol id, + opval: length (number of bytes that follow) */ + if (!binport_getbuf(bp, buf, opval)) + goto bad; + else + { + unsigned char *p = (unsigned char *)buf + opval; + int i = 0; + while (opval--) i = (i << 8) | *--p; + if (!binport_setsymbol(bp, ap, i)) + goto bad; + } + break; + case 5: /* half-byte int */ + binport_setint(ap, opval); + break; + case 7: /* half-byte symbol id */ + if (!binport_setsymbol(bp, ap, opval)) + goto bad; + break; + case 12: /* #number */ + sprintf(buf, "#%d", opval); + ap->a_type = A_SYMBOL; + ap->a_w.w_symbol = gensym(buf); + break; + case 13: /* #symbol id, + opval: length (number of bytes that follow) */ + if (!binport_getbuf(bp, buf, opval)) + goto bad; + else + { + unsigned char *p = (unsigned char *)buf + opval; + int i = 0; + while (opval--) i = (i << 8) | *--p; + if (!binport_setsymbol(bp, ap, i)) + goto bad; + } + sprintf(buf, "#%s", ap->a_w.w_symbol->s_name); +#ifdef BINPORT_DEBUG + binport_warning(buf); +#endif + ap->a_w.w_symbol = gensym(buf); + break; + default: + switch (opcode) + { + case 0xa0: + ap->a_type = A_SEMI; + break; + default: + goto unknown; + } + } + return (1); +unknown: + binport_error("unknown opcode %x", (int)opcode); +bad: + return (0); +} + +static void binport_free(t_binport *bp) +{ + fclose(bp->b_fp); + freebytes(bp->b_symtable, bp->b_symsize * sizeof(*bp->b_symtable)); + freebytes(bp, sizeof(*bp)); +} + +static t_binport *binport_new(FILE *fp, int *ftypep) +{ + static char binport_header[4] = { 2, 0, 0, 0 }; + char header[4]; + *ftypep = BINPORT_INVALID; + if (fread(header, 1, 4, fp) == 4) + { + if (memcmp(header, binport_header, 4)) + { + if (memcmp(header, "max", 3)) + { + if (header[0] == '#') /* LATER rethink */ + *ftypep = BINPORT_PDFILE; +#ifdef BINPORT_VERBOSE + else binport_warning("unknown header: %x %x %x %x", + (int)header[0], (int)header[1], + (int)header[2], (int)header[3]); +#endif + } + else *ftypep = BINPORT_MAXTEXT; + } + else + { + t_binport *bp = getbytes(sizeof(*bp)); + bp->b_fp = fp; + bp->b_nsymbols = 0; + bp->b_symsize = BINPORT_SYMGROW; + bp->b_symtable = getbytes(bp->b_symsize * sizeof(*bp->b_symtable)); + *ftypep = BINPORT_OK; + return (bp); + } + } +#ifdef BINPORT_VERBOSE + else binport_warning("file too short"); +#endif + fclose(fp); + return (0); +} + +#ifndef BINPORT_STANDALONE + +/* LATER deal with corrupt binary files? */ +int binport_read(t_binbuf *bb, char *filename, char *dirname) +{ + FILE *fp; + char namebuf[MAXPDSTRING]; + namebuf[0] = 0; + if (*dirname) + strcat(namebuf, dirname), strcat(namebuf, "/"); + strcat(namebuf, filename); + sys_bashfilename(namebuf, namebuf); + if (fp = fopen(namebuf, "rb")) + { + int ftype; + t_binport *bp = binport_new(fp, &ftype); + if (bp) + { + t_atom at; + while (binport_nextatom(bp, &at)) + binbuf_add(bb, 1, &at); + binport_free(bp); + return (BINPORT_OK); + } + else if (ftype == BINPORT_MAXTEXT || ftype == BINPORT_PDFILE) + return (ftype); + else + binport_error("\"%s\" doesn't look like a patch file", filename); + } + else binport_bug("cannot open file"); + return (BINPORT_INVALID); +} + +#else + +static void binport_atomstring(t_atom *ap, char *buf, int bufsize) +{ + char *sp, *bp, *ep; + switch(ap->a_type) + { + case A_SEMI: + strcpy(buf, ";"); break; + case A_COMMA: + strcpy(buf, ","); break; + case A_INT: + sprintf(buf, "%d", binport_getint(ap)); break; + case A_FLOAT: + sprintf(buf, "%#f", ap->a_w.w_float); + ep = buf + strlen(buf) - 1; + while (ep > buf && *ep == '0') *ep-- = 0; + break; + case A_SYMBOL: + sp = ap->a_w.w_symbol->s_name; + bp = buf; + ep = buf + (bufsize-5); + while (bp < ep && *sp) + { + if (*sp == ';' || *sp == ',' || *sp == '\\' || + (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9')) + *bp++ = '\\'; + if ((unsigned char)*sp < 127) + *bp++ = *sp++; + else + /* FIXME this is temporary -- codepage horror */ + sprintf(bp, "\\%.3o", (unsigned char)*sp++), bp += 4; + } + if (*sp) *bp++ = '*'; + *bp = 0; + break; + case A_DOLLAR: + sprintf(buf, "$%d", ap->a_w.w_index); + break; + case A_DOLLSYM: + sprintf(buf, "$%s", ap->a_w.w_symbol->s_name); + break; + default: + binport_bug("bad atom type"); + strcpy(buf, "???"); + } +} + +int main(int ac, char **av) +{ + if (ac > 1) + { + FILE *fp = fopen(av[1], "rb"); + if (fp) + { + int ftype; + t_binport *bp = binport_new(fp, &ftype); + if (bp) + { + char buf[BINPORT_MAXSTRING]; + t_atom at; + int ac = 0; + while (binport_nextatom(bp, &at)) + { + if (at.a_type == A_SEMI) + { + fputs(";\n", stdout); + ac = 0; + } + else + { + if (ac++) fputc(' ', stdout); + binport_atomstring(&at, buf, BINPORT_MAXSTRING); + fputs(buf, stdout); + } + } + binport_free(bp); + } + else if (ftype == BINPORT_MAXTEXT) + binport_warning("\"%s\" looks like a Max text file", av[1]); + else if (ftype == BINPORT_PDFILE) + binport_warning("\"%s\" looks like a Pd patch file", av[1]); + else + binport_error("\"%s\" doesn't look like a patch file", av[1]); + } + else binport_error("cannot open file \"%s\"", av[1]); + } + else binport_error("what file?"); + return (0); +} + +#endif -- cgit v1.2.1