Added MAME segment parsing from Omnivore

This commit is contained in:
Rob McMullen 2016-06-03 12:40:48 -07:00
parent d8b100fd95
commit f969d27e43
4 changed files with 95 additions and 2 deletions

View File

@ -14,7 +14,7 @@ from kboot import KBootImage, add_xexboot_header
from segments import SegmentData, SegmentSaver, DefaultSegment, EmptySegment, ObjSegment, RawSectorsSegment, user_bit_mask, match_bit_mask, comment_bit_mask, data_bit_mask, selected_bit_mask, diff_bit_mask, not_user_bit_mask, interleave_segments from segments import SegmentData, SegmentSaver, DefaultSegment, EmptySegment, ObjSegment, RawSectorsSegment, user_bit_mask, match_bit_mask, comment_bit_mask, data_bit_mask, selected_bit_mask, diff_bit_mask, not_user_bit_mask, interleave_segments
from spartados import SpartaDosDiskImage from spartados import SpartaDosDiskImage
from cartridge import A8CartHeader from cartridge import A8CartHeader
from parsers import SegmentParser, DefaultSegmentParser, guess_parser_for_mime, guess_parser_for_system, iter_known_segment_parsers, mime_parse_order from parsers import SegmentParser, DefaultSegmentParser, guess_parser_for_mime, guess_parser_for_system, iter_parsers, iter_known_segment_parsers, mime_parse_order
from utils import to_numpy from utils import to_numpy

65
atrcopy/mame.py Normal file
View File

@ -0,0 +1,65 @@
import zipfile
import numpy as np
from errors import *
from segments import SegmentData, EmptySegment, ObjSegment
from diskimages import DiskImageBase
from utils import to_numpy
import logging
log = logging.getLogger(__name__)
class MameZipImage(DiskImageBase):
def __init__(self, rawdata, filename=""):
self.zipdata = rawdata
fh = self.zipdata.stringio
if zipfile.is_zipfile(fh):
with zipfile.ZipFile(fh) as zf:
self.check_zip_size(zf)
self.create_rawdata(zf)
else:
raise InvalidDiskImage("Not a MAME zip file")
DiskImageBase.__init__(self, self.rawdata, filename)
def __str__(self):
return "MAME Zip file, %d ROMs, orig_size=%d, uncompressed=%d" % (len(self.zip_segment_info), len(self.zipdata), len(self.rawdata))
def setup(self):
self.check_size()
def strict_check(self):
pass
def relaxed_check(self):
pass
def check_zip_size(self, zf):
for item in zf.infolist():
_, r = divmod(item.file_size, 256)
if r > 0:
raise InvalidDiskImage("zip entry not 256 byte multiple")
def create_rawdata(self, zf):
roms = []
segment_info = []
offset = 0
for item in zf.infolist():
rom = np.fromstring(zf.open(item).read(), dtype=np.uint8)
roms.append(rom)
segment_info.append((offset, item.file_size, item.filename, item.CRC))
offset += item.file_size
data = np.concatenate(roms)
self.zip_segment_info = segment_info
self.rawdata = SegmentData(data)
def check_size(self):
pass
def parse_segments(self):
r = self.rawdata
self.segments = []
for offset, size, name, crc in self.zip_segment_info:
end = offset + size
self.segments.append(ObjSegment(r[offset:end], 0, offset, offset, end, name=name))

View File

@ -6,6 +6,7 @@ from kboot import KBootImage
from ataridos import AtariDosDiskImage, AtariDosFile from ataridos import AtariDosDiskImage, AtariDosFile
from spartados import SpartaDosDiskImage from spartados import SpartaDosDiskImage
from cartridge import AtariCartImage, get_known_carts from cartridge import AtariCartImage, get_known_carts
from mame import MameZipImage
from errors import * from errors import *
@ -84,6 +85,11 @@ class AtariCartSegmentParser(SegmentParser):
return self.image_type(r, self.cart_type) return self.image_type(r, self.cart_type)
class MameZipParser(SegmentParser):
menu_name = "MAME ROM Zipfile"
image_type = MameZipImage
def guess_parser_for_mime(mime, r): def guess_parser_for_mime(mime, r):
parsers = mime_parsers[mime] parsers = mime_parsers[mime]
found = None found = None
@ -103,6 +109,13 @@ def guess_parser_for_system(mime_base, r):
return mime, p return mime, p
return None, None return None, None
def iter_parsers(r):
for mime in mime_parse_order:
p = guess_parser_for_mime(mime, r)
if p is not None:
return mime, p
return None, None
mime_parsers = { mime_parsers = {
"application/vnd.atari8bit.atr": [ "application/vnd.atari8bit.atr": [
@ -114,20 +127,27 @@ mime_parsers = {
"application/vnd.atari8bit.xex": [ "application/vnd.atari8bit.xex": [
XexSegmentParser, XexSegmentParser,
], ],
"application/vnd.mame_rom": [
MameZipParser,
],
} }
mime_parse_order = [ mime_parse_order = [
"application/vnd.atari8bit.atr", "application/vnd.atari8bit.atr",
"application/vnd.atari8bit.xex", "application/vnd.atari8bit.xex",
"CARTS", # Will get filled in below
"application/vnd.mame_rom",
] ]
pretty_mime = { pretty_mime = {
"application/vnd.atari8bit.atr": "Atari 8-bit Disk Image", "application/vnd.atari8bit.atr": "Atari 8-bit Disk Image",
"application/vnd.atari8bit.xex": "Atari 8-bit Executable", "application/vnd.atari8bit.xex": "Atari 8-bit Executable",
"application/vnd.mame_rom": "MAME"
} }
grouped_carts = get_known_carts() grouped_carts = get_known_carts()
sizes = sorted(grouped_carts.keys()) sizes = sorted(grouped_carts.keys())
cart_order = []
for k in sizes: for k in sizes:
if k > 128: if k > 128:
key = "application/vnd.atari8bit.large_cart" key = "application/vnd.atari8bit.large_cart"
@ -136,13 +156,15 @@ for k in sizes:
key = "application/vnd.atari8bit.%dkb_cart" % k key = "application/vnd.atari8bit.%dkb_cart" % k
pretty = "Atari 8-bit %dKB Cartridge" % k pretty = "Atari 8-bit %dKB Cartridge" % k
if key not in mime_parsers: if key not in mime_parsers:
mime_parse_order.append(key) cart_order.append(key)
pretty_mime[key] = pretty pretty_mime[key] = pretty
mime_parsers[key] = [] mime_parsers[key] = []
for c in grouped_carts[k]: for c in grouped_carts[k]:
t = c[0] t = c[0]
kclass = type("AtariCartSegmentParser%d" % t, (AtariCartSegmentParser,), {'cart_type': t, 'cart_info': c, 'menu_name': "%s Cartridge" % c[1]}) kclass = type("AtariCartSegmentParser%d" % t, (AtariCartSegmentParser,), {'cart_type': t, 'cart_info': c, 'menu_name': "%s Cartridge" % c[1]})
mime_parsers[key].append(kclass) mime_parsers[key].append(kclass)
i = mime_parse_order.index("CARTS")
mime_parse_order[i:i+1] = cart_order
known_segment_parsers = [DefaultSegmentParser] known_segment_parsers = [DefaultSegmentParser]

View File

@ -1,4 +1,5 @@
import bisect import bisect
import cStringIO
import numpy as np import numpy as np
@ -95,6 +96,11 @@ class SegmentData(object):
def __len__(self): def __len__(self):
return len(self.data) return len(self.data)
@property
def stringio(self):
buf = cStringIO.StringIO(self.data[:])
return buf
def get_data(self): def get_data(self):
return self.data return self.data