/* Copyright (c) 1997-2004 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. */ /* LATER verify endianness transparency */ #include #include #include #include #include #define BINPORT_MAXSTRING 1000 #define BINPORT_SYMGROW 64 #ifndef BINPORT_STANDALONE /* load a max binary file into a Pd 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, ...) { #if defined (BINPORT_STANDALONE) || defined(BINPORT_VERBOSE) va_list ap; va_start(ap, fmt); fprintf(stderr, "warning (binport): "); vfprintf(stderr, fmt, ap); putc('\n', stderr); va_end(ap); #endif } 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); } static void binport_failure(char *filename) { binport_error("\"%s\" doesn't look like a patch file", filename); } static void binpold_failure(char *filename) { binport_error("tried reading \"%s\" as an old format file, but failed", filename); } #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 */ enum { BINPORT_NULLTYPE, BINPORT_INTTYPE = 1, BINPORT_FLOATTYPE, BINPORT_SYMTYPE, BINPORT_DEFINTTYPE = 5, BINPORT_DEFFLOATTYPE, BINPORT_DEFSYMTYPE, BINPORT_SEMITYPE = 10, BINPORT_COMMATYPE, BINPORT_DOLLARTYPE, BINPORT_DOLLSYMTYPE }; /* We use A_INT atom type not only for listing, but for import too -- the parser passes ints to individual token handlers, so that any required conversion has to be done during Pd message generation. */ #define A_INT A_DEFFLOAT static int binport_readbuf(FILE *fp, char *buf, size_t sz) { return (fread(buf, 1, sz, fp) == sz ? sz : 0); } static int binport_readbyte(FILE *fp, unsigned char *buf) { int c; if ((c = fgetc(fp)) == EOF) return (0); *buf = (unsigned char)c; return (1); } static int binport_readint(FILE *fp, int *iptr) { unsigned char word[4]; if (fread(word, 1, 4, fp) == 4) { *iptr = ((word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]); return (4); } else return (0); } /* LATER more testing */ /* make it binpold_readfloat() */ static int binport_readfloat(FILE *fp, float *fptr) { unsigned char word[10]; if (fread(word, 1, 10, fp) == 10) { int ex; unsigned hi, lo; ex = ((word[0] & 0x7F) << 8) | word[1]; hi = ((unsigned)word[2] << 24) | ((unsigned)word[3] << 16) | ((unsigned)word[4] << 8) | (unsigned)word[5]; lo = ((unsigned)word[6] << 24) | ((unsigned)word[7] << 16) | ((unsigned)word[8] << 8) | (unsigned)word[9]; if (ex == 0x7FFF) { binport_warning("NaN atom bashed to zero"); *fptr = 0.; } else if (ex || hi || lo) { double d; ex -= 0x401e; hi = ((hi - 0x7fffffff) - 1) + ((float)0x7fffffff + 1.); lo = ((lo - 0x7fffffff) - 1) + ((float)0x7fffffff + 1.); d = ldexp(hi, ex) + ldexp(lo, ex - 32); *fptr = ((word[0] & 0x80) ? -(float)d : (float)d); } else *fptr = 0.; #ifdef BINPORT_DEBUG fprintf(stderr, "%02x%02x", (int)word[0], (int)word[1]); fprintf(stderr, " %02x%02x%02x%02x", (int)word[2], (int)word[3], (int)word[4], (int)word[5]); fprintf(stderr, " %02x%02x%02x%02x", (int)word[6], (int)word[7], (int)word[8], (int)word[9]); fprintf(stderr, " == %g\n", *fptr); #endif return (10); } else return (0); } static int binport_readstring(FILE *fp, char *buf) { int c, i = 1; while (c = fgetc(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 (i); } typedef struct _binpold { FILE *o_fp; int o_natoms; int o_bodysize; int o_nsymbols; int o_symbolid; int o_ndx; t_atom *o_atombuf; } t_binpold; #define BINPOLD_NATOMTYPES 16 #define BINPOLD_MAXATOMS 1000000 /* LATER rethink */ static t_atomtype binpold_atomtypes[BINPOLD_NATOMTYPES] = { A_NULL, A_INT, A_FLOAT, A_SYMBOL, A_CANT, A_CANT, A_CANT, A_CANT, A_CANT, A_CANT, A_SEMI, A_COMMA, A_DOLLAR, A_CANT, A_CANT, A_CANT }; static int binpold_gettype(t_binpold *old, t_atom *ap) { int typecode; if ((typecode = fgetc(old->o_fp)) != EOF) { if (typecode > 0 && typecode < BINPOLD_NATOMTYPES) { ap->a_type = binpold_atomtypes[typecode]; if (ap->a_type != A_CANT) return (1); else binport_warning("unsupported type of atom %d: %d", old->o_ndx, typecode); } else binport_warning("bad type of atom %d: %d", old->o_ndx, typecode); } else binport_warning("failed reading type of atom %d", old->o_ndx); return (0); } static int binpold_getvalue(t_binpold *old, t_atom *ap, int *countp) { int ival; float fval; *countp = 0; switch (ap->a_type) { case A_INT: case A_SYMBOL: if (*countp = binport_readint(old->o_fp, &ival)) ap->a_w.w_index = ival; else goto valuefailed; if (ap->a_type == A_SYMBOL) { if (ival >= old->o_nsymbols) old->o_nsymbols = ival + 1; ap->a_type = A_DEFSYM; /* invalidate, until w_symbol is known */ } break; case A_FLOAT: if (*countp = binport_readfloat(old->o_fp, &fval)) ap->a_w.w_float = fval; else goto valuefailed; break; case A_SEMI: case A_COMMA: break; case A_DOLLAR: if (*countp = binport_readint(old->o_fp, &ival)) ap->a_w.w_index = ival; else goto valuefailed; break; default: goto valuefailed; } return (1); valuefailed: binport_warning("failed reading value of atom %d (type %d)", old->o_ndx, ap->a_type); return (0); } static int binpold_load(t_binpold *old) { char buf[BINPORT_MAXSTRING]; t_atom *ap; int total; #ifdef BINPORT_DEBUG fprintf(stderr, "old format: %d atoms, %d-byte chunk of atom values\n", old->o_natoms, old->o_bodysize); #endif for (old->o_ndx = 0, ap = old->o_atombuf; old->o_ndx < old->o_natoms; old->o_ndx++, ap++) if (!binpold_gettype(old, ap)) return (0); old->o_nsymbols = 0; total = 0; for (old->o_ndx = 0, ap = old->o_atombuf; old->o_ndx < old->o_natoms; old->o_ndx++, ap++) { int count; if (!binpold_getvalue(old, ap, &count)) return (0); total += count; } if (total != old->o_bodysize) { binport_warning("actual chunk size %d inconsistent with declared %d", total, old->o_bodysize); return (0); } for (old->o_symbolid = 0; old->o_symbolid < old->o_nsymbols; old->o_symbolid++) { if (binport_readstring(old->o_fp, buf)) { t_symbol *s = gensym(buf); for (old->o_ndx = 0, ap = old->o_atombuf; old->o_ndx < old->o_natoms; old->o_ndx++, ap++) { if (ap->a_type == A_DEFSYM && ap->a_w.w_index == old->o_symbolid) { ap->a_type = A_SYMBOL; ap->a_w.w_symbol = s; } } } else { binport_warning("failed reading string for symbol %d", old->o_symbolid); return (0); } } for (old->o_ndx = 0, ap = old->o_atombuf; old->o_ndx < old->o_natoms; old->o_ndx++, ap++) { if (ap->a_type == A_DEFSYM) { binport_warning("unknown string for symbol %d", ap->a_w.w_index); return (0); } else if (ap->a_type == A_DOLLAR) { sprintf(buf, "#%d", ap->a_w.w_index); ap->a_type = A_SYMBOL; ap->a_w.w_symbol = gensym(buf); } /* CHECKME A_DOLLSYM */ } 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) fclose(old->o_fp); if (old->o_atombuf) freebytes(old->o_atombuf, old->o_natoms * sizeof(*old->o_atombuf)); freebytes(old, sizeof(*old)); } static t_binpold *binpold_new(FILE *fp) { int natoms, bodysize; if (binport_readint(fp, &natoms)) { if (natoms < 0 || natoms > BINPOLD_MAXATOMS) binport_warning("bad number of atoms: %d", natoms); else if (binport_readint(fp, &bodysize)) { if (bodysize < 0) binport_warning("negative chunk size: %d", bodysize); else { t_binpold *old = getbytes(sizeof(*old)); old->o_fp = fp; old->o_natoms = natoms; old->o_bodysize = bodysize; if (!(old->o_atombuf = getbytes(old->o_natoms * sizeof(*old->o_atombuf)))) { binport_error("could not allocate %d atoms", old->o_natoms); freebytes(old, sizeof(*old)); fclose(fp); return (0); } return (old); } } } else binport_warning("file too short"); fclose(fp); return (0); } typedef struct _binport { FILE *b_fp; int b_ftype; int b_nsymbols; int b_symsize; t_symbol **b_symtable; t_binpold *b_old; } t_binport; static void binport_setint(t_atom *ap, int i) { ap->a_type = A_INT; ap->a_w.w_index = i; } static void binport_setfloat(t_atom *ap, float f) { ap->a_type = A_FLOAT; 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]; if (id < bp->b_nsymbols) binport_bug("symbol id mismatch"); else if (id > bp->b_nsymbols) binport_error("unexpected symbol id"); else if (binport_readstring(bp->b_fp, 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 int binport_setbysymtable(t_binport *bp, t_atom *ap, int id) { t_symbol *s; if (id < bp->b_nsymbols) s = bp->b_symtable[id]; else s = binport_makesymbol(bp, id); if (s) { ap->a_type = A_SYMBOL; ap->a_w.w_symbol = s; } return (s != 0); } /* single pass of binbuf_text(), int-preserving version */ static int maxtext_nextatom(FILE *fp, t_atom *ap) { 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 { 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) { 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 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 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 badbin; 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 BINPORT_FLOATTYPE: /* variable length float, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) goto badbin; 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 BINPORT_SYMTYPE: /* variable length symbol id, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) goto badbin; else { unsigned char *p = (unsigned char *)buf + opval; int i = 0; while (opval--) i = (i << 8) | *--p; 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_setbysymtable(bp, ap, opval)) goto badbin; break; case BINPORT_SEMITYPE: /* LATER warn about nonzero opval */ ap->a_type = A_SEMI; break; case BINPORT_COMMATYPE: /* CHECKME apparently never used? */ binport_warning("found the comma type in max binary..."); /* LATER warn about nonzero opval */ ap->a_type = A_COMMA; break; case BINPORT_DOLLARTYPE: /* #number */ sprintf(buf, "#%d", opval); ap->a_type = A_SYMBOL; ap->a_w.w_symbol = gensym(buf); break; case BINPORT_DOLLSYMTYPE: /* #symbol id, opval: length (number of bytes that follow) */ if (!binport_readbuf(bp->b_fp, buf, opval)) goto badbin; else { unsigned char *p = (unsigned char *)buf + opval; int i = 0; while (opval--) i = (i << 8) | *--p; if (!binport_setbysymtable(bp, ap, i)) goto badbin; } 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: binport_error("unknown opcode %x", (int)opcode); goto badbin; } return (1); badbin: return (0); } static int binport_alike(char *header, int *ftypep) { 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) { fclose(bp->b_fp); if (bp->b_symtable) freebytes(bp->b_symtable, bp->b_symsize * sizeof(*bp->b_symtable)); if (bp->b_old) { bp->b_old->o_fp = 0; binpold_free(bp->b_old); } freebytes(bp, sizeof(*bp)); } static t_binport *binport_new(FILE *fp, int *ftypep) { t_binport *bp = 0; char header[4]; if (fread(header, 1, 4, fp) == 4) { int alike = binport_alike(header, ftypep); if (alike) { bp = getbytes(sizeof(*bp)); bp->b_fp = fp; bp->b_ftype = *ftypep; bp->b_nsymbols = 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; } 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"); *ftypep = BINPORT_INVALID; } if (!bp) fclose(fp); return (bp); } 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", ap->a_w.w_index); 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, "???"); } } static void binport_print(t_binport *bp, FILE *fp) { char buf[BINPORT_MAXSTRING]; t_atom at; 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", fp); cnt = 0; } else if (at.a_type != A_NULL) { if (cnt++) fputc(' ', fp); binport_atomstring(&at, buf, BINPORT_MAXSTRING); 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) { FILE *fp = fopen(av[1], "rb"); if (fp) { int ftype; t_binport *bp = binport_new(fp, &ftype); if (bp) { if (ftype == BINPORT_OK) 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); if (old) { bp->b_old = old; if (binpold_load(old)) binport_print(bp, stdout); else ftype = BINPORT_FAILED; } else ftype = BINPORT_FAILED; if (ftype == BINPORT_FAILED) binpold_failure(av[1]); } binport_free(bp); } else if (ftype == BINPORT_PDFILE) binport_warning("\"%s\" looks like a Pd patch file", av[1]); else binport_failure(av[1]); } else binport_error("cannot open file \"%s\"", av[1]); } else binport_error("what file?"); return (0); } #endif