mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-22 08:30:05 +00:00
696 lines
12 KiB
C
696 lines
12 KiB
C
#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; i<d->fcnt; 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; i<d->fcnt; 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;
|
|
} |