diff options
Diffstat (limited to 'shared/common/binport.c')
-rw-r--r-- | shared/common/binport.c | 470 |
1 files changed, 329 insertions, 141 deletions
diff --git a/shared/common/binport.c b/shared/common/binport.c index 72e89c7..90eb4a1 100644 --- a/shared/common/binport.c +++ b/shared/common/binport.c @@ -10,8 +10,8 @@ #include <string.h> #include <math.h> -#define BINPORT_MAXSTRING 256 -#define BINPORT_SYMGROW 64 +#define BINPORT_MAXSTRING 1000 +#define BINPORT_SYMGROW 64 #ifndef BINPORT_STANDALONE /* load a max binary file into a Pd binbuf */ @@ -438,6 +438,16 @@ static int binpold_load(t_binpold *old) return (1); } +static int binpold_nextatom(t_binpold *old, t_atom *ap) +{ + if (old->o_ndx < old->o_natoms) + { + *ap = old->o_atombuf[old->o_ndx++]; + return (1); + } + else return (0); +} + static void binpold_free(t_binpold *old) { if (old->o_fp) @@ -484,6 +494,7 @@ static t_binpold *binpold_new(FILE *fp) typedef struct _binport { FILE *b_fp; + int b_ftype; int b_nsymbols; int b_symsize; t_symbol **b_symtable; @@ -502,6 +513,12 @@ static void binport_setfloat(t_atom *ap, float f) ap->a_w.w_float = f; } +static void binport_setsymbol(t_atom *ap, t_symbol *s) +{ + ap->a_type = A_SYMBOL; + ap->a_w.w_symbol = s; +} + static t_symbol *binport_makesymbol(t_binport *bp, int id) { char s[BINPORT_MAXSTRING]; @@ -534,17 +551,13 @@ static t_symbol *binport_makesymbol(t_binport *bp, int id) return (0); } -static t_symbol *binport_getsymbol(t_binport *bp, int id) +static int binport_setbysymtable(t_binport *bp, t_atom *ap, int id) { + t_symbol *s; if (id < bp->b_nsymbols) - return (bp->b_symtable[id]); + s = 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); + s = binport_makesymbol(bp, id); if (s) { ap->a_type = A_SYMBOL; @@ -553,30 +566,146 @@ static int binport_setsymbol(t_binport *bp, t_atom *ap, int id) return (s != 0); } -static int binport_nextatom(t_binport *bp, t_atom *ap) +/* single pass of binbuf_text(), int-preserving version */ +static int maxtext_nextatom(FILE *fp, t_atom *ap) { - unsigned char opcode; - int opval; - char buf[64]; - t_binpold *old = bp->b_old; - if (old) + char buf[BINPORT_MAXSTRING + 1], *bufp, *ebuf = buf + BINPORT_MAXSTRING; + int ready; + unsigned char ch; + ap->a_type = A_NULL; + while ((ready = binport_readbyte(fp, &ch)) && + (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')); + if (!ready) + return (0); + if (ch == ';') + ap->a_type = A_SEMI; + else if (ch == ',') + ap->a_type = A_COMMA; + else { - if (old->o_ndx < old->o_natoms) + int floatstate = 0, slash = 0, lastslash = 0, firstslash = (ch == '\\'); + bufp = buf; + do + { + *bufp = ch; + lastslash = slash; + slash = (ch == '\\'); + + if (floatstate >= 0) + { + int digit = (ch >= '0' && ch <= '9'), + dot = (ch == '.'), minus = (ch == '-'), + plusminus = (minus || (ch == '+')), + expon = (ch == 'e' || ch == 'E'); + if (floatstate == 0) /* beginning */ + { + if (minus) floatstate = 1; + else if (digit) floatstate = 2; + else if (dot) floatstate = 3; + else floatstate = -1; + } + else if (floatstate == 1) /* got minus */ + { + if (digit) floatstate = 2; + else if (dot) floatstate = 3; + else floatstate = -1; + } + else if (floatstate == 2) /* got digits */ + { + if (dot) floatstate = 4; + else if (expon) floatstate = 6; + else if (!digit) floatstate = -1; + } + else if (floatstate == 3) /* got '.' without digits */ + { + if (digit) floatstate = 5; + else floatstate = -1; + } + else if (floatstate == 4) /* got '.' after digits */ + { + if (digit) floatstate = 5; + else if (expon) floatstate = 6; + else floatstate = -1; + } + else if (floatstate == 5) /* got digits after . */ + { + if (expon) floatstate = 6; + else if (!digit) floatstate = -1; + } + else if (floatstate == 6) /* got 'e' */ + { + if (plusminus) floatstate = 7; + else if (digit) floatstate = 8; + else floatstate = -1; + } + else if (floatstate == 7) /* got plus or minus */ + { + if (digit) floatstate = 8; + else floatstate = -1; + } + else if (floatstate == 8) /* got digits */ + { + if (!digit) floatstate = -1; + } + } + if (!slash) bufp++; + } + while ((ready = binport_readbyte(fp, &ch)) && bufp != ebuf + && (slash || (ch != ' ' && ch != '\n' && ch != '\r' + && ch != '\t' && ch != ',' && ch != ';'))); + if (ready && (ch == ',' || ch == ';')) + ungetc(ch, fp); + *bufp = 0; +#if 0 + fprintf(stderr, "buf %s\n", buf); +#endif + if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash) { - *ap = old->o_atombuf[old->o_ndx++]; - return (1); + for (bufp = buf+2; *bufp; bufp++) + { + if (*bufp < '0' || *bufp > '9') + { + ap->a_type = A_DOLLSYM; + ap->a_w.w_symbol = gensym(buf+1); + break; + } + } + if (ap->a_type == A_NULL) + { + ap->a_type = A_DOLLAR; + ap->a_w.w_index = atoi(buf+1); + } } - else return (0); + else if (floatstate == 2) + binport_setint(ap, atoi(buf)); + else if (floatstate == 4 || floatstate == 5 || floatstate == 8) + binport_setfloat(ap, atof(buf)); + else + binport_setsymbol(ap, gensym(buf)); } + return (1); +} + +static int binport_nextatom(t_binport *bp, t_atom *ap) +{ + unsigned char opcode; + int opval; + char buf[64]; + + if (bp->b_ftype == BINPORT_MAXTEXT) + return (maxtext_nextatom(bp->b_fp, ap)); + else if (bp->b_ftype == BINPORT_MAXOLD && bp->b_old) + return (binpold_nextatom(bp->b_old, ap)); + if (!binport_readbyte(bp->b_fp, &opcode)) - goto bad; + goto badbin; opval = opcode & 0x0f; switch (opcode >> 4) { case BINPORT_INTTYPE: /* variable length int, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) - goto bad; + goto badbin; else { unsigned char *p = (unsigned char *)buf + opval; @@ -590,7 +719,7 @@ static int binport_nextatom(t_binport *bp, t_atom *ap) case BINPORT_FLOATTYPE: /* variable length float, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) - goto bad; + goto badbin; else { unsigned char *p = (unsigned char *)buf + opval; @@ -602,22 +731,22 @@ static int binport_nextatom(t_binport *bp, t_atom *ap) case BINPORT_SYMTYPE: /* variable length symbol id, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) - goto bad; + goto badbin; 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; + if (!binport_setbysymtable(bp, ap, i)) + goto badbin; } break; case BINPORT_DEFINTTYPE: /* half-byte int */ binport_setint(ap, opval); break; case BINPORT_DEFSYMTYPE: /* half-byte symbol id */ - if (!binport_setsymbol(bp, ap, opval)) - goto bad; + if (!binport_setbysymtable(bp, ap, opval)) + goto badbin; break; case BINPORT_SEMITYPE: /* LATER warn about nonzero opval */ @@ -637,14 +766,14 @@ static int binport_nextatom(t_binport *bp, t_atom *ap) case BINPORT_DOLLSYMTYPE: /* #symbol id, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) - goto bad; + goto badbin; 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; + if (!binport_setbysymtable(bp, ap, i)) + goto badbin; } sprintf(buf, "#%s", ap->a_w.w_symbol->s_name); #ifdef BINPORT_DEBUG @@ -654,23 +783,34 @@ static int binport_nextatom(t_binport *bp, t_atom *ap) break; default: binport_error("unknown opcode %x", (int)opcode); - goto bad; + goto badbin; } return (1); -bad: +badbin: return (0); } -static int binport_binalike(char *header) -{ - static char binport_header[4] = { 2, 0, 0, 0 }; /* CHECKME any others? */ - return (memcmp(header, binport_header, 4) == 0); -} - -static int binport_oldalike(char *header) +static int binport_alike(char *header, int *ftypep) { - static char binpold_header[4] = { 0, 0, 0, 1 }; /* CHECKME any others? */ - return (memcmp(header, binpold_header, 4) == 0); + static char bin_header[4] = { 2, 0, 0, 0 }; /* CHECKME any others? */ + static char old_header[4] = { 0, 0, 0, 1 }; /* CHECKME any others? */ + static char text_header[4] = { 'm', 'a', 'x', ' ' }; + static char pd_header[3] = { '#', 'N', ' ' }; /* canvas or struct */ + if (memcmp(header, bin_header, 4) == 0) + *ftypep = BINPORT_OK; + else if (memcmp(header, text_header, 4) == 0) + *ftypep = BINPORT_MAXTEXT; + else if (memcmp(header, old_header, 4) == 0) + *ftypep = BINPORT_MAXOLD; + else + { + if (memcmp(header, pd_header, 3) == 0) + *ftypep = BINPORT_PDFILE; + else + *ftypep = BINPORT_INVALID; + return (0); + } + return (1); } static void binport_free(t_binport *bp) @@ -688,108 +828,44 @@ static void binport_free(t_binport *bp) static t_binport *binport_new(FILE *fp, int *ftypep) { + t_binport *bp = 0; char header[4]; - *ftypep = BINPORT_INVALID; if (fread(header, 1, 4, fp) == 4) { - if (binport_binalike(header)) + int alike = binport_alike(header, ftypep); + if (alike) { - t_binport *bp = getbytes(sizeof(*bp)); + bp = getbytes(sizeof(*bp)); bp->b_fp = fp; + bp->b_ftype = *ftypep; bp->b_nsymbols = 0; - bp->b_symsize = BINPORT_SYMGROW; - bp->b_symtable = getbytes(bp->b_symsize * sizeof(*bp->b_symtable)); - bp->b_old = 0; - *ftypep = BINPORT_OK; - return (bp); - } - else if (memcmp(header, "max", 3) == 0) - *ftypep = BINPORT_MAXTEXT; - else if (binport_oldalike(header)) - { - t_binport *bp = getbytes(sizeof(*bp)); - bp->b_fp = fp; - bp->b_nsymbols = 0; - bp->b_symsize = 0; - bp->b_symtable = 0; + if (*ftypep == BINPORT_OK) + { + bp->b_symsize = BINPORT_SYMGROW; + bp->b_symtable = + getbytes(bp->b_symsize * sizeof(*bp->b_symtable)); + } + else + { + bp->b_symsize = 0; + bp->b_symtable = 0; + } bp->b_old = 0; - *ftypep = BINPORT_MAXOLD; - return (bp); - } - else - { - if (header[0] == '#') /* LATER rethink */ - *ftypep = BINPORT_PDFILE; - else binport_warning("unknown header: %x %x %x %x", - (int)header[0], (int)header[1], - (int)header[2], (int)header[3]); } + else if (*ftypep != BINPORT_PDFILE) + binport_warning("unknown header: %02x%02x%02x%02x", + (int)header[0], (int)header[1], + (int)header[2], (int)header[3]); } - else binport_warning("file too short"); - fclose(fp); - return (0); -} - -#ifndef BINPORT_STANDALONE - -static int binport_tobinbuf(t_binport *bp, t_binbuf *bb) -{ - t_atom at; - if (bp->b_old) - bp->b_old->o_ndx = 0; - while (binport_nextatom(bp, &at)) - if (at.a_type != A_NULL) - binbuf_add(bb, 1, &at); - return (1); -} - -/* 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")) + else { - int ftype; - t_binport *bp = binport_new(fp, &ftype); - if (bp) - { - int result; - if (ftype == BINPORT_OK) - result = (binport_tobinbuf(bp, bb) - ? BINPORT_OK : BINPORT_CORRUPT); - else if (ftype == BINPORT_MAXOLD) - { - t_binpold *old = binpold_new(fp); - result = BINPORT_FAILED; - if (old) - { - bp->b_old = old; - if (binpold_load(old) && binport_tobinbuf(bp, bb)) - result = BINPORT_OK; - } - else binpold_failure(filename); - } - else result = BINPORT_FAILED; - binport_free(bp); - return (result); - } - else if (ftype == BINPORT_MAXTEXT || ftype == BINPORT_PDFILE) - return (ftype); - else - binport_failure(filename); + binport_warning("file too short"); + *ftypep = BINPORT_INVALID; } - else binport_bug("cannot open file"); - return (BINPORT_INVALID); + if (!bp) fclose(fp); + return (bp); } -#else - static void binport_atomstring(t_atom *ap, char *buf, int bufsize) { char *sp, *bp, *ep; @@ -836,29 +912,141 @@ static void binport_atomstring(t_atom *ap, char *buf, int bufsize) } } -static void binport_print(t_binport *bp) +static void binport_print(t_binport *bp, FILE *fp) { char buf[BINPORT_MAXSTRING]; t_atom at; - int ac = 0; + int cnt = 0; if (bp->b_old) bp->b_old->o_ndx = 0; while (binport_nextatom(bp, &at)) { if (at.a_type == A_SEMI) { - fputs(";\n", stdout); - ac = 0; + fputs(";\n", fp); + cnt = 0; } else if (at.a_type != A_NULL) { - if (ac++) fputc(' ', stdout); + if (cnt++) fputc(' ', fp); binport_atomstring(&at, buf, BINPORT_MAXSTRING); - fputs(buf, stdout); + fputs(buf, fp); } } } +#ifndef BINPORT_STANDALONE + +static int binport_tobinbuf(t_binport *bp, t_binbuf *bb) +{ + t_atom at; + if (bp->b_old) + bp->b_old->o_ndx = 0; + while (binport_nextatom(bp, &at)) + if (at.a_type != A_NULL) + binbuf_add(bb, 1, &at); + return (1); +} + +/* LATER deal with corrupt binary files? */ +int binport_read(t_binbuf *bb, char *filename, char *dirname) +{ + int result; + 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) + { + if (ftype == BINPORT_OK) + result = (binport_tobinbuf(bp, bb) + ? BINPORT_OK : BINPORT_CORRUPT); + else if (ftype == BINPORT_MAXTEXT) + { + t_atom at; + while (binport_nextatom(bp, &at)) + if (at.a_type == A_SEMI) + break; + binbuf_addv(bb, "ss;", gensym("max"), gensym("v2")); + result = (binport_tobinbuf(bp, bb) + ? BINPORT_OK : BINPORT_CORRUPT); + } + else if (ftype == BINPORT_MAXOLD) + { + t_binpold *old = binpold_new(fp); + result = BINPORT_FAILED; + if (old) + { + bp->b_old = old; + if (binpold_load(old) && binport_tobinbuf(bp, bb)) + result = BINPORT_OK; + } + else binpold_failure(filename); + } + else result = BINPORT_FAILED; + binport_free(bp); + } + else if (ftype == BINPORT_PDFILE) + result = (binbuf_read(bb, filename, dirname, 0) + ? BINPORT_FAILED : BINPORT_PDFILE); + else + { + binport_failure(filename); + result = BINPORT_INVALID; + } + } + else + { + binport_bug("cannot open file"); + result = BINPORT_FAILED; + } + return (result); +} + +/* save as MAXTEXT */ +void binport_write(t_binbuf *bb, char *filename, char *dirname) +{ + int result; + 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, "w")) + { + char buf[BINPORT_MAXSTRING]; + t_atom *ap = binbuf_getvec(bb); + int cnt = 0, ac = binbuf_getnatom(bb); + while (ac--) + { + if (ap->a_type == A_SEMI) + { + fputs(";\n", fp); + cnt = 0; + } + else if (ap->a_type != A_NULL) + { + if (cnt++) fputc(' ', fp); + binport_atomstring(ap, buf, BINPORT_MAXSTRING); + fputs(buf, fp); + } + ap++; + } + fclose(fp); + } +} + +#else + int main(int ac, char **av) { if (ac > 1) @@ -871,7 +1059,9 @@ int main(int ac, char **av) if (bp) { if (ftype == BINPORT_OK) - binport_print(bp); + binport_print(bp, stdout); + else if (ftype == BINPORT_MAXTEXT) + binport_warning("\"%s\" looks like a Max text file", av[1]); else if (ftype == BINPORT_MAXOLD) { t_binpold *old = binpold_new(fp); @@ -879,7 +1069,7 @@ int main(int ac, char **av) { bp->b_old = old; if (binpold_load(old)) - binport_print(bp); + binport_print(bp, stdout); else ftype = BINPORT_FAILED; } @@ -888,8 +1078,6 @@ int main(int ac, char **av) } 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 |