mirror of
https://github.com/elliotnunn/unlink.git
synced 2025-01-18 01:29:42 +00:00
138 lines
3.6 KiB
Python
138 lines
3.6 KiB
Python
import struct
|
|
|
|
class MPWObject:
|
|
def __init__(self):
|
|
self._list = []
|
|
self._dict = []
|
|
self._backdict = {}
|
|
self._dict_idx = 200
|
|
|
|
def __bytes__(self):
|
|
dest = bytearray()
|
|
|
|
for chunk in self._list:
|
|
dest.extend(chunk)
|
|
if len(dest) & 1: dest.append(0)
|
|
|
|
return bytes(dest)
|
|
|
|
def _ensurename(self, name):
|
|
# get the ID of this name from the dict
|
|
# If nonexistent, then add it
|
|
# i.e. idempotent
|
|
|
|
try:
|
|
return self._backdict[name]
|
|
except KeyError:
|
|
self.putdict([name])
|
|
return self._backdict[name]
|
|
|
|
def _quickappend(self, *bytelist):
|
|
self._list.append(bytes(bytelist))
|
|
|
|
def putfirst(self):
|
|
self._quickappend(1, 1, 0, 2)
|
|
|
|
def putlast(self):
|
|
self._quickappend(2, 0)
|
|
|
|
def putdict(self, items):
|
|
dest = bytearray()
|
|
|
|
dest.extend([4, 0, 99, 99])
|
|
dest.extend(struct.pack('>H', self._dict_idx))
|
|
|
|
flag = False
|
|
|
|
for item in items:
|
|
flag = True
|
|
dest.append(len(item))
|
|
dest.extend(item.encode('ascii'))
|
|
|
|
self._backdict[item] = self._dict_idx
|
|
|
|
self._dict_idx += 1 # ID of the *next* thing
|
|
|
|
if not flag: return
|
|
|
|
struct.pack_into('>H', dest, 2, len(dest))
|
|
|
|
self._list.append(dest)
|
|
|
|
def putmod(self, name='#0001', segname='Main', flags=(1<<7)+(1<<3)):
|
|
modid = self._ensurename(name)
|
|
segid = self._ensurename(segname)
|
|
self._last_mod_id = modid
|
|
|
|
self._list.append(struct.pack('>BBHH', 5, flags, modid, segid))
|
|
|
|
def putentry(self, offset, name):
|
|
entid = self._ensurename(name)
|
|
|
|
self._list.append(struct.pack('>BBHL', 6, 1<<3, entid, offset))
|
|
|
|
def putsize(self, size):
|
|
self._list.append(struct.pack('>BBL', 7, 0, size))
|
|
|
|
def putcontents(self, data): # in multiple chunks please!
|
|
done = 0
|
|
|
|
while done < len(data):
|
|
this_time = data[done:done+30000]
|
|
|
|
header = struct.pack('>BBHL', 8, 1<<3, 8 + len(this_time), done)
|
|
|
|
self._list.append(header + this_time)
|
|
|
|
done += len(this_time)
|
|
|
|
def putcomment(self, cmt):
|
|
cmt = cmt.replace('\n','\r').encode('mac_roman')
|
|
if len(cmt) & 1: cmt += b' '
|
|
|
|
dest = bytearray()
|
|
dest.extend([3, 0])
|
|
dest.extend(struct.pack('>H', len(cmt) + 4))
|
|
dest.extend(cmt)
|
|
|
|
self._list.append(dest)
|
|
|
|
def putsimpleref(self, targname, width, *offsets):
|
|
offsets = list(offsets)
|
|
|
|
if width == 2: # of the operand field, in bytes
|
|
flags = 1 << 4
|
|
elif width == 4:
|
|
flags = 0
|
|
|
|
flags |= 1<<3 # longwords in the offset list!
|
|
|
|
targid = self._ensurename(targname)
|
|
|
|
dest = struct.pack('>BBHH', 9, flags, 6 + 4 * len(offsets), targid)
|
|
dest += b''.join(struct.pack('>L', o) for o in offsets)
|
|
|
|
self._list.append(dest)
|
|
|
|
def putweirdref(self, targname, width, *offsets):
|
|
# Assumes that you've already put -offset at offset
|
|
offsets = list(offsets)
|
|
|
|
if width == 1:
|
|
flags = 2 << 4
|
|
elif width == 2: # of the operand field, in bytes
|
|
flags = 1 << 4
|
|
elif width == 4:
|
|
flags = 0 << 4
|
|
|
|
flags |= 1<<7 # difference calculation
|
|
# flags |= 1<<3 # longwords in the offset list!
|
|
|
|
targid = self._ensurename(targname)
|
|
|
|
dest = struct.pack('>BBHHH', 10, flags, 8 + 2 * len(offsets), targid, self._last_mod_id)
|
|
dest += b''.join(struct.pack('>H', o) for o in offsets)
|
|
|
|
self._list.append(dest)
|
|
|