Home | History | Annotate | Download | only in plat-mac
      1 """codefragments.py -- wrapper to modify code fragments."""
      2 
      3 # (c) 1998, Just van Rossum, Letterror
      4 
      5 __version__ = "0.8b3"
      6 __author__ = "jvr"
      7 
      8 import warnings
      9 warnings.warnpy3k("the cfmfile module is deprecated and is removed in 3,0",
     10               stacklevel=2)
     11 
     12 import Carbon.File
     13 import struct
     14 from Carbon import Res
     15 import os
     16 import sys
     17 
     18 DEBUG = 0
     19 
     20 error = "cfm.error"
     21 
     22 BUFSIZE = 0x80000
     23 
     24 def mergecfmfiles(srclist, dst, architecture = 'fat'):
     25     """Merge all files in srclist into a new file dst.
     26 
     27     If architecture is given, only code fragments of that type will be used:
     28     "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
     29     68k code, since it does not use code fragments to begin with.
     30     If architecture is None, all fragments will be used, enabling FAT binaries.
     31     """
     32 
     33     srclist = list(srclist)
     34     for i in range(len(srclist)):
     35         srclist[i] = Carbon.File.pathname(srclist[i])
     36     dst = Carbon.File.pathname(dst)
     37 
     38     dstfile = open(dst, "wb")
     39     rf = Res.FSpOpenResFile(dst, 3)
     40     try:
     41         dstcfrg = CfrgResource()
     42         for src in srclist:
     43             srccfrg = CfrgResource(src)
     44             for frag in srccfrg.fragments:
     45                 if frag.architecture == 'pwpc' and architecture == 'm68k':
     46                     continue
     47                 if frag.architecture == 'm68k' and architecture == 'pwpc':
     48                     continue
     49                 dstcfrg.append(frag)
     50 
     51                 frag.copydata(dstfile)
     52 
     53         cfrgres = Res.Resource(dstcfrg.build())
     54         Res.UseResFile(rf)
     55         cfrgres.AddResource('cfrg', 0, "")
     56     finally:
     57         dstfile.close()
     58         rf = Res.CloseResFile(rf)
     59 
     60 
     61 class CfrgResource:
     62 
     63     def __init__(self, path = None):
     64         self.version = 1
     65         self.fragments = []
     66         self.path = path
     67         if path is not None and os.path.exists(path):
     68             currentresref = Res.CurResFile()
     69             resref = Res.FSpOpenResFile(path, 1)
     70             Res.UseResFile(resref)
     71             try:
     72                 try:
     73                     data = Res.Get1Resource('cfrg', 0).data
     74                 except Res.Error:
     75                     raise Res.Error, "no 'cfrg' resource found", sys.exc_traceback
     76             finally:
     77                 Res.CloseResFile(resref)
     78                 Res.UseResFile(currentresref)
     79             self.parse(data)
     80             if self.version != 1:
     81                 raise error, "unknown 'cfrg' resource format"
     82 
     83     def parse(self, data):
     84         (res1, res2, self.version,
     85             res3, res4, res5, res6,
     86             self.memberCount) = struct.unpack("8l", data[:32])
     87         data = data[32:]
     88         while data:
     89             frag = FragmentDescriptor(self.path, data)
     90             data = data[frag.memberSize:]
     91             self.fragments.append(frag)
     92 
     93     def build(self):
     94         self.memberCount = len(self.fragments)
     95         data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
     96         for frag in self.fragments:
     97             data = data + frag.build()
     98         return data
     99 
    100     def append(self, frag):
    101         self.fragments.append(frag)
    102 
    103 
    104 class FragmentDescriptor:
    105 
    106     def __init__(self, path, data = None):
    107         self.path = path
    108         if data is not None:
    109             self.parse(data)
    110 
    111     def parse(self, data):
    112         self.architecture = data[:4]
    113         (   self.updatelevel,
    114             self.currentVersion,
    115             self.oldDefVersion,
    116             self.stacksize,
    117             self.applibdir,
    118             self.fragtype,
    119             self.where,
    120             self.offset,
    121             self.length,
    122             self.res1, self.res2,
    123             self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
    124         pname = data[42:self.memberSize]
    125         self.name = pname[1:1+ord(pname[0])]
    126 
    127     def build(self):
    128         data = self.architecture
    129         data = data + struct.pack("4lhBB4l",
    130                 self.updatelevel,
    131                 self.currentVersion,
    132                 self.oldDefVersion,
    133                 self.stacksize,
    134                 self.applibdir,
    135                 self.fragtype,
    136                 self.where,
    137                 self.offset,
    138                 self.length,
    139                 self.res1, self.res2)
    140         self.memberSize = len(data) + 2 + 1 + len(self.name)
    141         # pad to 4 byte boundaries
    142         if self.memberSize % 4:
    143             self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
    144         data = data + struct.pack("hb", self.memberSize, len(self.name))
    145         data = data + self.name
    146         data = data + '\000' * (self.memberSize - len(data))
    147         return data
    148 
    149     def getfragment(self):
    150         if self.where != 1:
    151             raise error, "can't read fragment, unsupported location"
    152         f = open(self.path, "rb")
    153         f.seek(self.offset)
    154         if self.length:
    155             frag = f.read(self.length)
    156         else:
    157             frag = f.read()
    158         f.close()
    159         return frag
    160 
    161     def copydata(self, outfile):
    162         if self.where != 1:
    163             raise error, "can't read fragment, unsupported location"
    164         infile = open(self.path, "rb")
    165         if self.length == 0:
    166             infile.seek(0, 2)
    167             self.length = infile.tell()
    168 
    169         # Position input file and record new offset from output file
    170         infile.seek(self.offset)
    171 
    172         # pad to 16 byte boundaries
    173         offset = outfile.tell()
    174         if offset % 16:
    175             offset = offset + 16 - (offset % 16)
    176         outfile.seek(offset)
    177         self.offset = offset
    178 
    179         l = self.length
    180         while l:
    181             if l > BUFSIZE:
    182                 outfile.write(infile.read(BUFSIZE))
    183                 l = l - BUFSIZE
    184             else:
    185                 outfile.write(infile.read(l))
    186                 l = 0
    187         infile.close()
    188