Sophie

Sophie

distrib > Mandriva > 2010.2 > i586 > media > contrib-backports > by-pkgid > df29c83ca401d91ec9c00bfcf7fea4ea > files > 134

shedskin-0.8-2mdv2010.2.i586.rpm

#!/usr/bin/env python2
# I, Danny Milosavljevic, hereby place this file into the public domain.

"""
TODO: the file pointer should move to the next file after the one that was loaded.
TODO: The .t64 file demands that filenames be padded at the end with spaces.
TODO: seek to the end of the filename entry, and replace all consecutive $20 with $A0 internally.
"""

import sys
import struct
#import petascii
import entries
from entries import Entry

def find_distances(items):
    h, t = items[0], items[1:]
    if len(t) == 0:
        return []
    else:
        hh, tt = t[0], t[1:]
        return [(hh[0] - h[0], h[1])] + find_distances(t)
class Loader(entries.Loader):
    def __init__(self):
        entries.Loader.__init__(self)
        self.entries = []
        self.offsets = []
    def parse(self, stream, file_name):
        beginning_pos = int(stream.tell())
        stream.seek(0, 2)
        end_pos = int(stream.tell())
        stream.seek(0)
        header_format = "<32s2BHHH24s"
        header_size = struct.calcsize(header_format)
        data = stream.read(header_size)
        version = [0, 0]
        reserved = 0
        assert(len(data) == header_size)
        #(magic, 0, 1, 1, 0, 1, 0, 0, 0, "->ZYRON'S PD<-          ")
        magic, version[0], version[1], max_files, cur_files, reserved, user_description = struct.unpack(header_format, data)
        # assert(version[0] == 0) # whatever
        assert(version[1] == 1)
        # first string = "C64 tape image file", padded with $00.
        magic = magic.rstrip("\0")
        assert(magic == "C64 tape image file" or magic.startswith("C64S tape file") or magic.find("TAPE") > -1 or magic.find("tape") > -1)
        user_description = user_description.rstrip("\0") #.decode("petascii") # they can't decide.
        self.entries = []
        # usually 30 entries.
        self.entries = [self.parse_entry(stream) for i in range(cur_files)]
        self.offsets = sorted(map(lambda entry: (entry.tape_pos, entry), self.entries))
        self.offsets.append((end_pos, None))
        for size, entry in find_distances(self.offsets):
            entry.end_addr = entry.start_addr + size
        self.current_entry_index = -1
        self.stream = stream
        return(self)
    def parse_entry(self, stream):
        format = "<BBHHHII16s"
        size = struct.calcsize(format)
        data = stream.read(size)
        assert(len(data) == size)
        B_used, file_type, start_addr, end_addr, reserved_a, tape_pos, reserved_b, file_name = struct.unpack(format, data)
        # B_used > 1: memory snapshot
        #file_type = { # 1541 file type
        #    0x82: "PRG",
        #    0x81: "SEQ",
        #    # etc. # !=0 => PRG
        #}.get(file_type) or file_type
        # end_addr == 0xc3c6 is by a faulty tool; TODO loading all entries, sort by ascending order of offset into T64 (+2 for load addr which is part of the file). 
        B_used, file_type, start_addr, end_addr, reserved_a, tape_pos, reserved_b, file_name = struct.unpack(format, data)
        assert(B_used in [0,1])
        file_name = file_name.rstrip(b"\x20") # b"\0")
        # 0x53
        #file_name = file_name.decode("petascii")
        return(Entry(B_used = B_used > 0,
                     file_type = file_type,
                     start_addr = start_addr,
                     end_addr = 0, # unreliable
                     reserved_a = reserved_a,
                     tape_pos = tape_pos,
                     reserved_b = reserved_b,
                     file_name = file_name))
    def find_next_entry(self, file_name):
        file_name = file_name.rstrip(b"\xA0")
        while self.current_entry_index < len(self.entries):
            entry = self.entries[self.current_entry_index]
            if file_name == "" or entry.file_name == file_name:
                return(entry)
            self.current_entry_index += 1
        return(None)
    def load_header(self, file_name):
        #type_, file_name, start_addr, stop_addr, data = tape_loader.load_header(file_name)
        self.current_entry_index += 1
        print("loading header", file_name)
        entry = self.find_next_entry(file_name)
        return(entry)
        #return(entry.file_type, entry.file_name, entry.start_addr, entry.end_addr)
    def load_data(self, file_name):
        print("loading data")
        entry = self.find_next_entry(file_name)
        self.stream.seek(entry.tape_pos)
        data = self.stream.read(entry.end_addr - entry.start_addr)
        #data = tape_loader.load_data(file_name)
        return(data)

if __name__ == "__main__":
    print(Loader().parse(open(sys.argv[1], "rb"), "F").entries)