From 283a0c5ba886df2d6505ee6b4d765d4f7c930d68 Mon Sep 17 00:00:00 2001 From: Elliot Nunn Date: Wed, 20 Sep 2017 19:54:25 +0800 Subject: [PATCH] Reimplement the Vectorize tool --- Tools/ToolSource/MPWObjFuncs.c | 696 +++++++++++++++++++++++++++++ Tools/ToolSource/Tools.make | 12 + Tools/ToolSource/Vectorize.c | 787 +++++++++++++++++++++++++++++++++ 3 files changed, 1495 insertions(+) create mode 100644 Tools/ToolSource/MPWObjFuncs.c create mode 100644 Tools/ToolSource/Tools.make create mode 100644 Tools/ToolSource/Vectorize.c diff --git a/Tools/ToolSource/MPWObjFuncs.c b/Tools/ToolSource/MPWObjFuncs.c new file mode 100644 index 0000000..c6d37d4 --- /dev/null +++ b/Tools/ToolSource/MPWObjFuncs.c @@ -0,0 +1,696 @@ +#define C_PAD 0 +#define C_FIRST 1 +#define C_LAST 2 +#define C_COMMENT 3 +#define C_DICT 4 +#define C_MODULE 5 +#define C_ENTRYPT 6 +#define C_SIZE 7 +#define C_CONTENTS 8 +#define C_REF 9 +#define C_COMPREF 10 + + +/* DATA STRUCTURES */ + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned short id; + + +/* Ugh! */ +#ifndef __GNUC__ +#define ntohs +#define ntohl +#define htons +#define htonl +#endif +#define NULL 0 + + +ushort shortfrom(char *b) +{ + return ntohs(*(ushort *)b); +} + +void setshort(char *b, ushort to) +{ + *(ushort *)b = htons(to); +} + +ulong longfrom(char *b) +{ + return ntohl(*(ulong *)b); +} + +void setlong(char *b, ulong to) +{ + *(ulong *)b = htonl(to); +} + + + +/* Wraps an MPW Object buffer */ +struct obj +{ + char *buf, *at; + id next_id; +}; + + +/* PASCAL STRING COMPARISON, CASE-INSENSITIVE */ + +int cisc(uchar *a, uchar *b) +{ + int i; + + if(*a != *b) return 0; + + for(i=1; i<=*a; i++) + { + uchar c, d; + c = a[i]; + d = b[i]; + // if(c >= 'a' && c <= 'z') c &= 223; + // if(d >= 'a' && d <= 'z') d &= 223; + if(c == d) continue; + return 0; + } + return 1; +} + +void upperpas(uchar *a) +{ + int i; + + for(i=1; i<=*a; i++) + { + if(a[i] >= 'a' && a[i] <= 'z') a[i] &= 223; + } +} + + +/* ACCESSOR FUNCTIONS */ + +/* Valid for all types */ +char obj_type(struct obj *o) +{ + return o->at[0]; +} + +/* Valid for First, Dict, Module, EntryPt, Size, Contents, Ref, CompRef */ +char obj_flags(struct obj *o) +{ + return o->at[1]; +} + +/* Valid for Module, EntryPt */ +id obj_id(struct obj *o) +{ + return ntohs(*(id *)(o->at + 2)); +} + +/* Valid for Dict */ +id obj_dictfirst(struct obj *o) +{ + return ntohs(*(id *)(o->at + 4)); +} + +/* Valid for Comment, Dict, Contents, Ref, CompRef */ +unsigned short obj_recsize(struct obj *o) +{ + return ntohs(*(unsigned short *)(o->at + 2)); +} + +/* Valid for Size */ +unsigned short obj_contsize(struct obj *o) +{ + return ntohs(*(unsigned long *)(o->at + 2)); +} + +/* Valid for all types */ +unsigned long obj_size(struct obj *o) +{ + char t; + + t = obj_type(o); + + if(t == C_COMMENT || t == C_DICT || t == C_CONTENTS || t == C_REF || t == C_COMPREF) + { + return obj_recsize(o); + } + else if(t == C_PAD) + { + return 1; + } + else if(t == C_FIRST) + { + return 4; + } + else if(t == C_MODULE) + { + return 6; + } + else if(t == C_ENTRYPT) + { + return 8; + } + else if(t == C_SIZE) + { + return 6; + } + else if(t == C_LAST) + { + return 2; + } + else + { + printf("Illegal object type at offset 0x%x: %d\n", (ulong)o->at - (ulong)o->buf, t); + return 1; + } +} + + +/* CURSOR MANIPULATOR FUNCTIONS */ + +void obj_init(struct obj *o, char *buf) +{ + o->at = o->buf = buf; +} + +void _obj_next_general(struct obj *o, int can_loop) +{ + if((long)o->at & 1) o->at ++; + + if(obj_type(o) == C_LAST) + { + //printf("Got a lastie\n"); + if(can_loop) o->at = o->buf; + } + else + { + //printf("Got a %d %d\n", obj_type(o), obj_size(o)); + o->at += obj_size(o); + } + + if((long)o->at & 1) o->at ++; +} + +/* Gets the next object without looping */ +void obj_next(struct obj *o) +{ + _obj_next_general(o, 0); +} + +/* Gets the specified module with looping */ +void obj_findmod(struct obj *o, id mod_id) +{ + char *first; + + first = o->at; + + while(obj_type(o) != C_MODULE || obj_id(o) != mod_id) + { + _obj_next_general(o, 1); + + if(o->at == first) + { + o->at = o->buf; + } + } +} + +/* Gets the next dict with looping */ +void dict_next(struct obj *o) +{ + do + { + printf("xx %d\n", obj_type(o)); + _obj_next_general(o, 1); + } + while(obj_type(o) != C_DICT); +} + +void obj_pad(struct obj *o) +{ + if((long)o->at & 1) *o->at++ = 0; +} + +int obj_nextinmod(struct obj *o) +{ + char *at = o->at; + + if(obj_type(o) == C_LAST) return 0; + + _obj_next_general(o, 0); + + if(obj_type(o) == C_LAST || obj_type(o) == C_MODULE) + { + return 0; + o->at = at; + } + + return 1; +} + +int obj_nextmod(struct obj *o) +{ + char *at = o->at; + + if(obj_type(o) == C_LAST) return 0; + + do + { + _obj_next_general(o, 0); + if(obj_type(o) == C_LAST) return 0; + } while(obj_type(o) != C_MODULE); + + return 1; +} + + + +/* DICT APPEND FUNCTION */ + +void dict_append_v(struct obj *o, uchar *s, id hint_id) +{ + ushort oldlen; + + if(obj_type(o) != C_DICT || shortfrom(o->at + 2) > 10000) + { + obj_next(o); + o->at[0] = C_DICT; + o->at[1] = 0; /* flags */ + setshort(o->at+2, 6); /* size */ + setshort(o->at+4, hint_id); /* first id */ + } + + oldlen = shortfrom(o->at + 2); + + o->at[oldlen+0] = *s + 5; + o->at[oldlen+1] = '_'; + o->at[oldlen+2] = '_'; + o->at[oldlen+3] = 'v'; + o->at[oldlen+4] = '_'; + o->at[oldlen+5] = '_'; + + memcpy(o->at + oldlen + 6, s + 1, *s); + + setshort(o->at + 2, oldlen + *s + 6); +} + + + +/* DICT SEARCH FUNCTIONS, WHICH HAVE SIDE EFFECTS */ + +id dict_id_from_str(struct obj *o, unsigned char *str) +{ + char *first_searched = NULL; + + //printf("DICT %x: %.*s = \n", o, *str, str+1); + + for(;;) + { + if(obj_type(o) == C_DICT) + { + unsigned int ctr, tlen; + unsigned char *ptr; + + tlen = ntohs(*(unsigned short *)(o->at + 2)); + ctr = ntohs(*(unsigned short *)(o->at + 4)); + ptr = (uchar *)((long)o->at + 6); + + do + { + //if(ptr[0] == str[0] && !memcmp(ptr+1, str+1, str[0])) + if(cisc(ptr, str)) + { + //printf("%d\n", ctr); + return ctr; + } + + ptr += ptr[0] + 1; + ctr++; + } while((ulong)ptr < (ulong)o->at + tlen); + } + + _obj_next_general(o, 1); + + if(o->at == first_searched) return 0; + if(!first_searched) first_searched = o->at; + } + + //printf("(not found)\n"); + + return 0; +} + +uchar *dict_str_from_id(struct obj *o, id id) +{ + char *first_searched = NULL; + + //printf("DICT %x: %d = ", o, id); + + for(;;) + { + if(obj_type(o) == C_DICT) + { + unsigned int ctr, tlen; + unsigned char *ptr; + + tlen = ntohs(*(unsigned short *)(o->at + 2)); + ctr = ntohs(*(unsigned short *)(o->at + 4)); + ptr = (uchar *)((long)o->at + 6); + + if(ctr <= id) + { + do + { + if(ctr == id) + { + //printf("%.*s\n", *ptr, ptr+1); + return ptr; + } + + ptr += ptr[0] + 1; + ctr++; + } while((ulong)ptr < (ulong)o->at + tlen); + } + } + + _obj_next_general(o, 1); + + if(o->at == first_searched) return 0; + if(!first_searched) first_searched = o->at; + } + + //printf("(not found)\n"); + + return NULL; +} + +id dict_highestid(struct obj *o) +{ + id ctr; + unsigned int tlen; + unsigned char *ptr; + + tlen = ntohs(*(unsigned short *)(o->at + 2)); + ctr = (id)ntohs(*(unsigned short *)(o->at + 4)); + ptr = (uchar *)((long)o->at + 6); + + do + { + ptr += ptr[0] + 1; + ctr++; + } while((ulong)ptr < (ulong)o->at + tlen); + + return ctr - 1; +} + + + +/* NEWDICT FUNCTIONS */ + +struct newdict +{ + struct newdict *prev, *next; /* linked list */ + + id new_id; /* increments from 256 */ + id old_id; + id patch_id; /* if this ID is just vector glue and self.next is the implementation */ + uchar name[256]; /* duh */ + + int defining_file; + int malloc_size; /* only for the main dict object */ + int fcnt; + struct newdict ***cache; + //id id_in_file[99]; /* malloc makes this array *just right* */ +}; + +void newdict_init(struct newdict *d, int file_count) +{ + d->prev = d->next = d; + d->new_id = 255; + d->fcnt = file_count; + d->malloc_size = sizeof *d; //sizeof(*d) + (file_count - 99) * sizeof(d->id_in_file[0]); +} + +void newdict_cache(struct newdict *d) +{ + int i; + struct newdict *s; + + d->cache = (struct newdict ***)calloc(d->fcnt, sizeof d->cache[0]); + + for(i=0; ifcnt; i++) + { + d->cache[i] = (struct newdict **)calloc(65536, sizeof d->cache[0][0]); + } + + for(s = d->next; s != d; s = s->next) + { + d->cache[s->defining_file][s->old_id] = s; + } +} + +id newdict_append(struct newdict *d, int file_idx, id orig_id, uchar *name) +{ + struct newdict *s; + + s = (struct newdict *)calloc(d->malloc_size, 1); + if(!s) + { + return 0; + } + + s->next = d; + s->prev = d->prev; + s->prev->next = s; + d->prev = s; + + s->new_id = s->prev->new_id + 1; + memcpy(s->name, name, name[0]+1); + + s->defining_file = file_idx; + //s->id_in_file[file_idx] = orig_id; + s->old_id = orig_id; + + return s->new_id; +} + +struct newdict *newdict_find(struct newdict *d, int file_idx, id mid) +{ + // struct newdict *s; + + // for(s = d->next; s != d; s = s->next) + // { + // if(s->id_in_file[file_idx] == mid) return s; + // } + + // return (struct newdict *)0; + + return d->cache[file_idx][mid]; +} + +// void newdict_debug_dump(struct newdict *d, char **file_names) +// { +// struct newdict *s; +// int i; + +// printf("NEWDICT_DEBUG_DUMP\n"); + +// for(s = d->next; s != d; s = s->next) +// { +// printf(" %d %.*s", s->new_id, *s->name, s->name+1); + +// if(s->defining_file != -1) +// { +// if(file_names) +// { +// printf(" (%s:%d)", file_names[s->defining_file], s->id_in_file[s->defining_file]); +// } +// else +// { +// printf(" (file_%d:%d)", s->defining_file, s->id_in_file[s->defining_file]); +// } +// } + +// if(s->patch_id) +// { +// printf(" (patch ID %d, next line is implementation:)", s->patch_id); +// } + +// printf("\n %d:%d", s->defining_file, s->id_in_file[s->defining_file]); + +// for(i=0; ifcnt; i++) +// { +// if(i == s->defining_file) continue; +// if(!s->id_in_file[i]) continue; +// printf(" %d:%d", i, s->id_in_file[i]); +// } + +// printf("\n"); +// } +// } + +unsigned long newdict_dump(struct newdict *d, char *o) +{ + unsigned long l = 0; + struct newdict *s = d->next; + + while(s != d) + { + long tl = 0; + + o[l] = C_DICT; + o[l+1] = 0; /* 0 => names needed for code/data relocation. + 1 => names needed for symbolic debugging only + (in which case they are ignored when doing a + non-symbolic link) */ + + *(ushort *)(o + l + 4) = htons(s->new_id); + + tl = 6; + + while(s != d && tl < 10000) + { + memcpy(o + l + tl, s->name, s->name[0]+1); + tl += s->name[0]+1; + s = s->next; + } + + /* doing the record! */ + *(id *)(o + l + 2) = htons(tl); + + if(tl & 1) o[l + tl++] = 0; + + l += tl; + } + + return l; +} + + + + + +// id newdict_lookup_backend(struct newdict *d, uchar *str, long major, long minor) +// { +// struct newdict *s; + +// for(s = d->prev; s != d; s = s->prev) +// { +// if(major == -1 || minor == -1 || (s->major == major && s->minor == minor)) +// { +// if(cisc(str, s->str)) +// { +// return s->n; +// } +// } +// } + +// return 0; +// } + +// id newdict_id_from_str_with_hint(struct newdict *d, uchar *str, long major, long minor) +// { +// id id; + +// id = newdict_lookup_backend(d, str, major, minor); +// if(id) return id; + +// id = newdict_lookup_backend(d, str, -1, -1); +// if(id) return id; + +// id = newdict_append(d, str, major, minor); +// return id; +// } + + + +/* COMPLETE ODDBALL */ + +// void reref(char **dest, long major, struct newdict *destdict, struct obj *src, struct obj *srcdict, id specialfrom, id specialto) +// { +// const char OFFSETS[11][3] = { +// /* 0*/ {0}, +// /* 1*/ {0}, +// /* 2*/ {0}, +// /* 3*/ {0}, +// /* 4*/ {0}, +// /* 5*/ {2,4,0}, +// /* 6*/ {2,0}, +// /* 7*/ {0}, +// /* 8*/ {0}, +// /* 9*/ {4,0}, +// /*10*/ {4,6,0}, +// }; + +// unsigned long len; +// char t; +// int i; + +// len = obj_size(src); +// t = obj_type(src); + +// memcpy(*dest, src->at, len); + +// for(i=0; OFFSETS[t][i]; i++) +// { +// id is; + +// is = ntohs(*(id *)(*dest + OFFSETS[t][i])); + +// //printf("Converting: type %d offset %d original %d special %d->%d\n", t, OFFSETS[t][i], is, specialfrom, specialto); + +// if(is == specialfrom) +// { +// is = specialto; +// } +// else +// { +// uchar *str = dict_str_from_id(srcdict, is); +// if(!str) printf("Bullshit string\n"); +// //printf("... intermediate string %x %.*s\n", str, *str, str+1); +// is = newdict_id_from_str_with_hint(destdict, str, major, is); +// } + +// //printf("... to %d\n", is); + +// *(id *)(*dest + OFFSETS[t][i]) = htons(is); +// } + +// *dest += len; + +// if((long)(*dest) & 1) *(*dest)++ = 0; +// } + + +void obj_copy(struct obj *dest, struct obj *src) +{ + char *destthing; + + obj_next(dest); + destthing = dest->at; + + memcpy(destthing, src->at, obj_size(src)); + + obj_next(dest); + obj_pad(dest); + dest->at = destthing; +} + +int obj_islastinmod(struct obj *o) +{ + struct obj j; + char t; + + memcpy(&j, o, sizeof (struct obj)); + + obj_next(&j); + t = obj_type(&j); + + return t == C_MODULE || t == C_LAST; +} \ No newline at end of file diff --git a/Tools/ToolSource/Tools.make b/Tools/ToolSource/Tools.make new file mode 100644 index 0000000..2a1dd4f --- /dev/null +++ b/Tools/ToolSource/Tools.make @@ -0,0 +1,12 @@ +LibFiles-68K = ¶ + "{Libraries}Stubs.o" ¶ + "{CLibraries}StdCLib.o" ¶ + "{Libraries}MacRuntime.o" ¶ + "{Libraries}IntEnv.o" ¶ + "{Libraries}Interface.o" ¶ + +"{ToolSrcDir}Vectorize.c.o" Ä "{ToolSrcDir}Vectorize.c" "{ToolSrcDir}MPWObjFuncs.c" + SC -o {Targ} "{ToolSrcDir}Vectorize.c" + +"{ToolDir}Vectorize" Ä "{ToolSrcDir}Vectorize.c.o" + ILink -d -t 'MPST' -c 'MPS ' -o {Targ} {LibFiles-68k} "{ToolSrcDir}Vectorize.c.o" diff --git a/Tools/ToolSource/Vectorize.c b/Tools/ToolSource/Vectorize.c new file mode 100644 index 0000000..22bf22b --- /dev/null +++ b/Tools/ToolSource/Vectorize.c @@ -0,0 +1,787 @@ +// This tool will be implemented using only standard C, the better + +#include +#include +#include +#include +#include "MPWObjFuncs.c" + +#ifndef __GNUC__ +#include +#include +#endif + +#define ERRSTR "# Vectorize Error: " +#define WARNSTR "# Vectorize Warning: " + +// Default options + +const char PASSIVE_OFFSETS[11][3] = { + /* 0*/ {0}, + /* 1*/ {0}, + /* 2*/ {0}, + /* 3*/ {0}, + /* 4*/ {0}, + /* 5*/ {2,0}, + /* 6*/ {2,0}, + /* 7*/ {0}, + /* 8*/ {0}, + /* 9*/ {4,0}, + /*10*/ {4,6,0}, +}; + +const char OFFSETS[11][3] = { + /* 0*/ {0}, + /* 1*/ {0}, + /* 2*/ {0}, + /* 3*/ {0}, + /* 4*/ {4,0}, + /* 5*/ {2,4,0}, + /* 6*/ {2,0}, + /* 7*/ {0}, + /* 8*/ {0}, + /* 9*/ {4,0}, + /*10*/ {4,6,0}, +}; + + +int warnings = 1; +char *patchObjPath = NULL; +char *symFilePath = NULL; +int do_patch = 1; +char *outputObjPath = NULL; +char **inputPaths = NULL; +int inputCount = 0; + +void to_pas(uchar *p, char *c) +{ + int sl = strlen(c); + p[0] = sl; + memcpy(p+1, c, sl); +} + +char *fname(char *x) +{ + char *y = x; + + while(*y) y++; + + while(y != x && y[-1] != ':') y--; + + return y; +} + +char *slurp(char *path) +{ + FILE *f; + long pos; + char *bytes; + + f = fopen(path, "rb"); + if(f == NULL) return NULL; + + fseek(f, 0, SEEK_END); + pos = ftell(f); + fseek(f, 0, SEEK_SET); + + bytes = (char *)malloc(pos); + if(bytes == NULL) return NULL; + + fread(bytes, pos, 1, f); + + fclose(f); + + return bytes; +} + +int blat(char *path, char *buf, ulong len) +{ + FILE *f; + + f = fopen(path, "wb"); + if(f == NULL) return 1; + + fwrite(buf, len, 1, f); + + fclose(f); + + return 0; +} + +void printUsage(char *cmdName) +{ + printf("USAGE: %s [-w] [-v PATCHES.o | -nopatch] [-log ROM.sym] -o ROM.lib INPUT1.o ...\n", cmdName); +} + +int parseOpts(int argc, char **argv) +{ + int i; + int err = 0; + + for(i=1; i *a) return -1; + + if(*b < *a) return 1; + + return 0; +} + +int tblcmp(const void *a, const void *b) +{ + return pstrcmp(((struct tblent *)a)->name, ((struct tblent *)b)->name); +} + +int ptch_order_cmp(const void *aa, const void *bb) +{ + long a = (**(struct tblent **)aa).offset_of_parent_in_module; + long b = (**(struct tblent **)bb).offset_of_parent_in_module; + + if(a > b) return -1; + if(a < b) return 1; + return 0; +} + +// int tblcmp2(const void *a, const void *b) +// { +// int res; +// printf("Comparing %.*s to %.*s", *((struct tblent *)a)->name, ((struct tblent *)a)->name+1, *((struct tblent *)b)->name, ((struct tblent *)b)->name+1); +// res = pstrcmp(((struct tblent *)a)->name, ((struct tblent *)b)->name); +// if(!res) printf(" ...match!"); +// printf("\n"); +// return res; +// } + + +// void print_tbl(struct tblent *tbl, long cnt) +// { +// long i; + +// for(i=0; i \"{PatchDump}\"\n\n", patchObjPath); + fprintf(l, " # and navigate its contents:\n"); + fprintf(l, " Find /NAVIGATE PATCHES/ \"{Active}\"\n"); + + fprintf(l, "\n"); + } + + fprintf(l, "# Dump the \"vectorized\" output file: (takes a while)\n"); + fprintf(l, " Set RomDump \"{TempFolder}VectorRomDump\"; DumpObj \"%s\" > \"{RomDump}\"\n", outputObjPath); + fprintf(l, "\n"); + fprintf(l, " # and look at it:\n"); + fprintf(l, " File \"{RomDump}\"\n"); + fprintf(l, "\n"); + fprintf(l, " # or navigate it input-file-wise:\n"); + fprintf(l, " Find /NAVIGATE OUTPUT/ \"{Active}\"\n"); + for(file_i=0; file_i nextdelta) nextdelta = hid; + } + + if(t == C_SIZE) + { + mod_sizeobj = dest.at; + } + + if(t == C_MODULE || t == C_ENTRYPT) + { + struct tblent fodder_for_bsearch, *ent; + uchar *my_name; + char *patch_mod = NULL; + int is_vectorized = 0; + + my_name = dict_str_from_id(&cur_dict, obj_id(&cur_obj)); + + if(!my_name) + { + fprintf(stderr, ERRSTR "Module with unlisted ID\n"); + return 1; + } + + fodder_for_bsearch.name = my_name; + ent = (struct tblent *)bsearch(&fodder_for_bsearch, tbl, tblcnt, sizeof (struct tblent), tblcmp); + + if(ent) /* there is a patch module, but it may be zero-size! */ + { + if(ent->data && ent->len) + { + ent->clean_id = obj_id(&dest); + patchstack[patchcnt++] = ent; + is_vectorized = 1; + + if(t == C_MODULE) + { + ent->offset_of_parent_in_module = 0; + } + else + { + ent->offset_of_parent_in_module = longfrom(dest.at+4); + } + } + } + else + { + if(warnings) + { + fprintf(stderr, WARNSTR "Missing vector patch: %.*s\n", *my_name, my_name+1); + } + } + + if(l) + { + if(t == C_MODULE) + { + fprintf(l, "File \"{RomDump}\"; Line 0; File \"{RomDump}\"; Find /Module=¶\""); + } + else + { + fprintf(l, " File \"{RomDump}\"; Line 0; File \"{RomDump}\"; Find /Entry=¶\""); + } + + if(is_vectorized) fprintf(l, "__v__"); + + fprintf(l, "%.*s¶\"/ # ID %d", *my_name, my_name+1, is_vectorized ? ent->__v__id : obj_id(&dest)); + + if(t == C_ENTRYPT) + { + fprintf(l, ", offset $%x", longfrom(dest.at+4)); + } + + fprintf(l, "\n"); + } + } + + if(mod_copy_start && obj_islastinmod(&cur_obj)) /* empty the patchstack */ + { + int pi; + + // qsort((void *)patchstack, patchcnt, sizeof (struct tblent *), ptch_order_cmp); + + for(pi=0; piname; + + original_size = longfrom(mod_sizeobj + 2); + + if(l) fprintf(l, " File \"{RomDump}\"; Line 0; File \"{RomDump}\"; Find /Entry=¶\"%.*s¶\"/ # patch ID %d, ", *my_name, my_name+1, patchstack[pi]->clean_id); + if(l) debug_print_about_patch(l, patchstack[pi]->data, patchstack[pi]->len); + if(l) fprintf(l, ", offset $%x\n", original_size); + + obj_next(&dest); /* EXTRA RECORD: CONTENTS */ + dest.at[0] = C_CONTENTS; /* type */ + dest.at[1] = 8; /* offset field present */ + setshort(dest.at + 2, 8 + patchstack[pi]->len); /* size = 8b header, plus data */ + setlong(dest.at + 4, original_size); /* offset = end of module data so far */ + memcpy(dest.at + 8, patchstack[pi]->data, patchstack[pi]->len); /* actual, you know, *contents* */ + + obj_next(&dest); /* EXTRA RECORD: ENTRY POINT (of patch) */ + dest.at[0] = C_ENTRYPT; /* type */ + dest.at[1] = 8; /* external entry point */ + setshort(dest.at + 2, patchstack[pi]->clean_id); /* ID */ + setlong(dest.at + 4, original_size); /* offset = end of module data so far */ + + /* Increment the size of this module */ + setlong(mod_sizeobj + 2, original_size + patchstack[pi]->len); + + + /* Now do the dirty work of changing self-references to use __v__... */ + + for(scratch.at=mod_copy_start; scratch.at<=mod_copy_last; obj_next(&scratch)) + { + char tt = obj_type(&scratch); + + for(i=0; PASSIVE_OFFSETS[tt][i]; i++) + { + id is = shortfrom(scratch.at + PASSIVE_OFFSETS[tt][i]); + if(is == patchstack[pi]->clean_id) + { + setshort(scratch.at + PASSIVE_OFFSETS[tt][i], patchstack[pi]->__v__id); + } + } + } + } /* patchstack loop */ + + if(l) fprintf(l, "\n"); /* newline before each module... nice touch */ + + patchcnt = 0; + } /* do patchstack or not? */ + } /* for each record */ + + free(cur_bin); + //fprintf(stderr, "Culminating in %d\n", nextdelta); + delta = nextdelta + 1; + + // delta += 5000; + // delta -= (delta % 5000); + } + + obj_next(&dest); + dest.at[0] = C_LAST; + dest.at[1] = 0; + + if(blat(outputObjPath, dest.buf, (long)(dest.at) - (long)(dest.buf) + 2)) + { + fprintf(stderr, ERRSTR "Failed to write output file\n"); + return 5; + } + + if(l) fclose(l); + + #ifndef __GNUC__ + { + FInfo fi; + Str255 pas; + int e; + + to_pas(pas, outputObjPath); + + e = GetFInfo(pas, 0, &fi); + if (e == 0) + { + fi.fdType = 0x4F424A20; /* TEXT */ + fi.fdCreator = 0x4D505320; /* MPS */ + e = SetFInfo(pas, 0, &fi); + } + + if(symFilePath) + { + to_pas(pas, symFilePath); + + e = GetFInfo(pas, 0, &fi); + if (e == 0) + { + fi.fdType = 0x54455854; /* TEXT */ + fi.fdCreator = 0x4D505320; /* MPS */ + e = SetFInfo(pas, 0, &fi); + } + } + } + #endif + + return 0; +}