Remove submodule, just put Dependencies in ./libs
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
from hachoir_parser.game.zsnes import ZSNESFile
|
||||
from hachoir_parser.game.spider_man_video import SpiderManVideoFile
|
||||
from hachoir_parser.game.laf import LafFile
|
||||
from hachoir_parser.game.blp import BLP1File, BLP2File
|
||||
@@ -0,0 +1,269 @@
|
||||
"""
|
||||
Blizzard BLP Image File Parser
|
||||
|
||||
Author: Robert Xiao
|
||||
Creation date: July 10 2007
|
||||
|
||||
- BLP1 File Format
|
||||
http://magos.thejefffiles.com/War3ModelEditor/MagosBlpFormat.txt
|
||||
- BLP2 File Format (Wikipedia)
|
||||
http://en.wikipedia.org/wiki/.BLP
|
||||
- S3TC (DXT1, 3, 5) Formats
|
||||
http://en.wikipedia.org/wiki/S3_Texture_Compression
|
||||
"""
|
||||
|
||||
from hachoir_core.endian import LITTLE_ENDIAN
|
||||
from hachoir_core.field import String, UInt32, UInt8, Enum, FieldSet, RawBytes, GenericVector, Bit, Bits
|
||||
from hachoir_parser.parser import Parser
|
||||
from hachoir_parser.image.common import PaletteRGBA
|
||||
from hachoir_core.tools import alignValue
|
||||
|
||||
class PaletteIndex(UInt8):
|
||||
def createDescription(self):
|
||||
return "Palette index %i (%s)" % (self.value, self["/palette/color[%i]" % self.value].description)
|
||||
|
||||
class Generic2DArray(FieldSet):
|
||||
def __init__(self, parent, name, width, height, item_class, row_name="row", item_name="item", *args, **kwargs):
|
||||
FieldSet.__init__(self, parent, name, *args, **kwargs)
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.item_class = item_class
|
||||
self.row_name = row_name
|
||||
self.item_name = item_name
|
||||
|
||||
def createFields(self):
|
||||
for i in xrange(self.height):
|
||||
yield GenericVector(self, self.row_name+"[]", self.width, self.item_class, self.item_name)
|
||||
|
||||
class BLP1File(Parser):
|
||||
MAGIC = "BLP1"
|
||||
PARSER_TAGS = {
|
||||
"id": "blp1",
|
||||
"category": "game",
|
||||
"file_ext": ("blp",),
|
||||
"mime": (u"application/x-blp",), # TODO: real mime type???
|
||||
"magic": ((MAGIC, 0),),
|
||||
"min_size": 7*32, # 7 DWORDs start, incl. magic
|
||||
"description": "Blizzard Image Format, version 1",
|
||||
}
|
||||
endian = LITTLE_ENDIAN
|
||||
|
||||
def validate(self):
|
||||
if self.stream.readBytes(0, 4) != "BLP1":
|
||||
return "Invalid magic"
|
||||
return True
|
||||
|
||||
def createFields(self):
|
||||
yield String(self, "magic", 4, "Signature (BLP1)")
|
||||
yield Enum(UInt32(self, "compression"), {
|
||||
0:"JPEG Compression",
|
||||
1:"Uncompressed"})
|
||||
yield UInt32(self, "flags")
|
||||
yield UInt32(self, "width")
|
||||
yield UInt32(self, "height")
|
||||
yield Enum(UInt32(self, "type"), {
|
||||
3:"Uncompressed Index List + Alpha List",
|
||||
4:"Uncompressed Index List + Alpha List",
|
||||
5:"Uncompressed Index List"})
|
||||
yield UInt32(self, "subtype")
|
||||
for i in xrange(16):
|
||||
yield UInt32(self, "mipmap_offset[]")
|
||||
for i in xrange(16):
|
||||
yield UInt32(self, "mipmap_size[]")
|
||||
|
||||
compression = self["compression"].value
|
||||
image_type = self["type"].value
|
||||
width = self["width"].value
|
||||
height = self["height"].value
|
||||
|
||||
if compression == 0: # JPEG Compression
|
||||
yield UInt32(self, "jpeg_header_len")
|
||||
yield RawBytes(self, "jpeg_header", self["jpeg_header_len"].value, "Shared JPEG Header")
|
||||
else:
|
||||
yield PaletteRGBA(self, "palette", 256)
|
||||
|
||||
offsets = self.array("mipmap_offset")
|
||||
sizes = self.array("mipmap_size")
|
||||
for i in xrange(16):
|
||||
if not offsets[i].value or not sizes[i].value:
|
||||
continue
|
||||
padding = self.seekByte(offsets[i].value)
|
||||
if padding:
|
||||
yield padding
|
||||
if compression == 0:
|
||||
yield RawBytes(self, "mipmap[%i]" % i, sizes[i].value, "JPEG data, append to header to recover complete image")
|
||||
elif compression == 1:
|
||||
yield Generic2DArray(self, "mipmap_indexes[%i]" % i, width, height, PaletteIndex, "row", "index", "Indexes into the palette")
|
||||
if image_type in (3, 4):
|
||||
yield Generic2DArray(self, "mipmap_alphas[%i]" % i, width, height, UInt8, "row", "alpha", "Alpha values")
|
||||
width /= 2
|
||||
height /= 2
|
||||
|
||||
def interp_avg(data_low, data_high, n):
|
||||
"""Interpolated averages. For example,
|
||||
|
||||
>>> list(interp_avg(1, 10, 3))
|
||||
[4, 7]
|
||||
"""
|
||||
if isinstance(data_low, (int, long)):
|
||||
for i in range(1, n):
|
||||
yield (data_low * (n-i) + data_high * i) / n
|
||||
else: # iterable
|
||||
pairs = zip(data_low, data_high)
|
||||
pair_iters = [interp_avg(x, y, n) for x, y in pairs]
|
||||
for i in range(1, n):
|
||||
yield [iter.next() for iter in pair_iters]
|
||||
|
||||
def color_name(data, bits):
|
||||
"""Color names in #RRGGBB format, given the number of bits for each component."""
|
||||
ret = ["#"]
|
||||
for i in range(3):
|
||||
ret.append("%02X" % (data[i] << (8-bits[i])))
|
||||
return ''.join(ret)
|
||||
|
||||
class DXT1(FieldSet):
|
||||
static_size = 64
|
||||
def __init__(self, parent, name, dxt2_mode=False, *args, **kwargs):
|
||||
"""with dxt2_mode on, this field will always use the four color model"""
|
||||
FieldSet.__init__(self, parent, name, *args, **kwargs)
|
||||
self.dxt2_mode = dxt2_mode
|
||||
def createFields(self):
|
||||
values = [[], []]
|
||||
for i in (0, 1):
|
||||
yield Bits(self, "blue[]", 5)
|
||||
yield Bits(self, "green[]", 6)
|
||||
yield Bits(self, "red[]", 5)
|
||||
values[i] = [self["red[%i]" % i].value,
|
||||
self["green[%i]" % i].value,
|
||||
self["blue[%i]" % i].value]
|
||||
if values[0] > values[1] or self.dxt2_mode:
|
||||
values += interp_avg(values[0], values[1], 3)
|
||||
else:
|
||||
values += interp_avg(values[0], values[1], 2)
|
||||
values.append(None) # transparent
|
||||
for i in xrange(16):
|
||||
pixel = Bits(self, "pixel[%i][%i]" % divmod(i, 4), 2)
|
||||
color = values[pixel.value]
|
||||
if color is None:
|
||||
pixel._description = "Transparent"
|
||||
else:
|
||||
pixel._description = "RGB color: %s" % color_name(color, [5, 6, 5])
|
||||
yield pixel
|
||||
|
||||
class DXT3Alpha(FieldSet):
|
||||
static_size = 64
|
||||
def createFields(self):
|
||||
for i in xrange(16):
|
||||
yield Bits(self, "alpha[%i][%i]" % divmod(i, 4), 4)
|
||||
|
||||
class DXT3(FieldSet):
|
||||
static_size = 128
|
||||
def createFields(self):
|
||||
yield DXT3Alpha(self, "alpha", "Alpha Channel Data")
|
||||
yield DXT1(self, "color", True, "Color Channel Data")
|
||||
|
||||
class DXT5Alpha(FieldSet):
|
||||
static_size = 64
|
||||
def createFields(self):
|
||||
values = []
|
||||
yield UInt8(self, "alpha_val[0]", "First alpha value")
|
||||
values.append(self["alpha_val[0]"].value)
|
||||
yield UInt8(self, "alpha_val[1]", "Second alpha value")
|
||||
values.append(self["alpha_val[1]"].value)
|
||||
if values[0] > values[1]:
|
||||
values += interp_avg(values[0], values[1], 7)
|
||||
else:
|
||||
values += interp_avg(values[0], values[1], 5)
|
||||
values += [0, 255]
|
||||
for i in xrange(16):
|
||||
pixel = Bits(self, "alpha[%i][%i]" % divmod(i, 4), 3)
|
||||
alpha = values[pixel.value]
|
||||
pixel._description = "Alpha value: %i" % alpha
|
||||
yield pixel
|
||||
|
||||
class DXT5(FieldSet):
|
||||
static_size = 128
|
||||
def createFields(self):
|
||||
yield DXT5Alpha(self, "alpha", "Alpha Channel Data")
|
||||
yield DXT1(self, "color", True, "Color Channel Data")
|
||||
|
||||
class BLP2File(Parser):
|
||||
MAGIC = "BLP2"
|
||||
PARSER_TAGS = {
|
||||
"id": "blp2",
|
||||
"category": "game",
|
||||
"file_ext": ("blp",),
|
||||
"mime": (u"application/x-blp",),
|
||||
"magic": ((MAGIC, 0),),
|
||||
"min_size": 5*32, # 5 DWORDs start, incl. magic
|
||||
"description": "Blizzard Image Format, version 2",
|
||||
}
|
||||
endian = LITTLE_ENDIAN
|
||||
|
||||
def validate(self):
|
||||
if self.stream.readBytes(0, 4) != "BLP2":
|
||||
return "Invalid magic"
|
||||
return True
|
||||
|
||||
def createFields(self):
|
||||
yield String(self, "magic", 4, "Signature (BLP2)")
|
||||
yield Enum(UInt32(self, "compression", "Compression type"), {
|
||||
0:"JPEG Compressed",
|
||||
1:"Uncompressed or DXT/S3TC compressed"})
|
||||
yield Enum(UInt8(self, "encoding", "Encoding type"), {
|
||||
1:"Raw",
|
||||
2:"DXT/S3TC Texture Compression (a.k.a. DirectX)"})
|
||||
yield UInt8(self, "alpha_depth", "Alpha channel depth, in bits (0 = no alpha)")
|
||||
yield Enum(UInt8(self, "alpha_encoding", "Encoding used for alpha channel"), {
|
||||
0:"DXT1 alpha (0 or 1 bit alpha)",
|
||||
1:"DXT3 alpha (4 bit alpha)",
|
||||
7:"DXT5 alpha (8 bit interpolated alpha)"})
|
||||
yield Enum(UInt8(self, "has_mips", "Are mip levels present?"), {
|
||||
0:"No mip levels",
|
||||
1:"Mip levels present; number of levels determined by image size"})
|
||||
yield UInt32(self, "width", "Base image width")
|
||||
yield UInt32(self, "height", "Base image height")
|
||||
for i in xrange(16):
|
||||
yield UInt32(self, "mipmap_offset[]")
|
||||
for i in xrange(16):
|
||||
yield UInt32(self, "mipmap_size[]")
|
||||
yield PaletteRGBA(self, "palette", 256)
|
||||
|
||||
compression = self["compression"].value
|
||||
encoding = self["encoding"].value
|
||||
alpha_depth = self["alpha_depth"].value
|
||||
alpha_encoding = self["alpha_encoding"].value
|
||||
width = self["width"].value
|
||||
height = self["height"].value
|
||||
|
||||
if compression == 0: # JPEG Compression
|
||||
yield UInt32(self, "jpeg_header_len")
|
||||
yield RawBytes(self, "jpeg_header", self["jpeg_header_len"].value, "Shared JPEG Header")
|
||||
|
||||
offsets = self.array("mipmap_offset")
|
||||
sizes = self.array("mipmap_size")
|
||||
for i in xrange(16):
|
||||
if not offsets[i].value or not sizes[i].value:
|
||||
continue
|
||||
padding = self.seekByte(offsets[i].value)
|
||||
if padding:
|
||||
yield padding
|
||||
if compression == 0:
|
||||
yield RawBytes(self, "mipmap[%i]" % i, sizes[i].value, "JPEG data, append to header to recover complete image")
|
||||
elif compression == 1 and encoding == 1:
|
||||
yield Generic2DArray(self, "mipmap_indexes[%i]" % i, height, width, PaletteIndex, "row", "index", "Indexes into the palette")
|
||||
if alpha_depth == 1:
|
||||
yield GenericVector(self, "mipmap_alphas[%i]" % i, height, width, Bit, "row", "is_opaque", "Alpha values")
|
||||
elif alpha_depth == 8:
|
||||
yield GenericVector(self, "mipmap_alphas[%i]" % i, height, width, UInt8, "row", "alpha", "Alpha values")
|
||||
elif compression == 1 and encoding == 2:
|
||||
block_height = alignValue(height, 4) // 4
|
||||
block_width = alignValue(width, 4) // 4
|
||||
if alpha_depth in [0, 1] and alpha_encoding == 0:
|
||||
yield Generic2DArray(self, "mipmap[%i]" % i, block_height, block_width, DXT1, "row", "block", "DXT1-compressed image blocks")
|
||||
elif alpha_depth == 8 and alpha_encoding == 1:
|
||||
yield Generic2DArray(self, "mipmap[%i]" % i, block_height, block_width, DXT3, "row", "block", "DXT3-compressed image blocks")
|
||||
elif alpha_depth == 8 and alpha_encoding == 7:
|
||||
yield Generic2DArray(self, "mipmap[%i]" % i, block_height, block_width, DXT5, "row", "block", "DXT5-compressed image blocks")
|
||||
width /= 2
|
||||
height /= 2
|
||||
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
LucasArts Font parser.
|
||||
|
||||
Author: Cyril Zorin
|
||||
Creation date: 1 January 2007
|
||||
"""
|
||||
|
||||
from hachoir_parser import Parser
|
||||
from hachoir_core.field import (FieldSet,
|
||||
UInt8, UInt16, UInt32, GenericVector)
|
||||
from hachoir_core.endian import LITTLE_ENDIAN
|
||||
|
||||
class CharData(FieldSet):
|
||||
def __init__(self, chars, *args):
|
||||
FieldSet.__init__(self, *args)
|
||||
self.chars = chars
|
||||
|
||||
def createFields(self):
|
||||
for char in self.chars:
|
||||
yield CharBitmap(char, self, "char_bitmap[]")
|
||||
|
||||
class CharBitmap(FieldSet):
|
||||
def __init__(self, char, *args):
|
||||
FieldSet.__init__(self, *args)
|
||||
self.char = char
|
||||
|
||||
def createFields(self):
|
||||
width = self.char["width_pixels"].value
|
||||
for line in xrange(self.char["height_pixels"].value):
|
||||
yield GenericVector(self, "line[]", width,
|
||||
UInt8, "pixel")
|
||||
|
||||
class CharInfo(FieldSet):
|
||||
static_size = 16 * 8
|
||||
|
||||
def createFields(self):
|
||||
yield UInt32(self, "data_offset")
|
||||
yield UInt8(self, "logical_width")
|
||||
yield UInt8(self, "unknown[]")
|
||||
yield UInt8(self, "unknown[]")
|
||||
yield UInt8(self, "unknown[]")
|
||||
yield UInt32(self, "width_pixels")
|
||||
yield UInt32(self, "height_pixels")
|
||||
|
||||
class LafFile(Parser):
|
||||
PARSER_TAGS = {
|
||||
"id": "lucasarts_font",
|
||||
"category": "game",
|
||||
"file_ext" : ("laf",),
|
||||
"min_size" : 32*8,
|
||||
"description" : "LucasArts Font"
|
||||
}
|
||||
|
||||
endian = LITTLE_ENDIAN
|
||||
|
||||
def validate(self):
|
||||
if self["num_chars"].value != 256:
|
||||
return "Invalid number of characters (%u)" % self["num_chars"].value
|
||||
if self["first_char_code"].value != 0:
|
||||
return "Invalid of code of first character code (%u)" % self["first_char_code"].value
|
||||
if self["last_char_code"].value != 255:
|
||||
return "Invalid of code of last character code (%u)" % self["last_char_code"].value
|
||||
if self["char_codes/char[0]"].value != 0:
|
||||
return "Invalid character code #0 (%u)" % self["char_codes/char[0]"].value
|
||||
if self["chars/char[0]/data_offset"].value != 0:
|
||||
return "Invalid character #0 offset"
|
||||
return True
|
||||
|
||||
def createFields(self):
|
||||
yield UInt32(self, "num_chars")
|
||||
yield UInt32(self, "raw_font_data_size")
|
||||
yield UInt32(self, "max_char_width")
|
||||
yield UInt32(self, "min_char_width")
|
||||
yield UInt32(self, "unknown[]", 4)
|
||||
yield UInt32(self, "unknown[]", 4)
|
||||
yield UInt32(self, "first_char_code")
|
||||
yield UInt32(self, "last_char_code")
|
||||
|
||||
yield GenericVector(self, "char_codes", self["num_chars"].value,
|
||||
UInt16, "char")
|
||||
|
||||
yield GenericVector(self, "chars", self["num_chars"].value,
|
||||
CharInfo, "char")
|
||||
|
||||
# character data. we make an effort to provide
|
||||
# something more meaningful than "RawBytes:
|
||||
# character bitmap data"
|
||||
yield CharData(self["chars"], self, "char_data")
|
||||
|
||||
# read to the end
|
||||
if self.current_size < self._size:
|
||||
yield self.seekBit(self._size, "unknown[]")
|
||||
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Parser for an obscure FMV file format: bin files from the game
|
||||
"The Amazing Spider-Man vs. The Kingpin" (Sega CD)
|
||||
|
||||
Author: Mike Melanson
|
||||
Creation date: 2006-09-30
|
||||
File samples: http://samples.mplayerhq.hu/game-formats/spiderman-segacd-bin/
|
||||
"""
|
||||
|
||||
from hachoir_parser import Parser
|
||||
from hachoir_core.field import FieldSet, UInt32, String, RawBytes
|
||||
from hachoir_core.endian import BIG_ENDIAN
|
||||
from hachoir_core.text_handler import textHandler, hexadecimal
|
||||
|
||||
class Chunk(FieldSet):
|
||||
tag_info = {
|
||||
"CONF" : ("conf[]", None, "Configuration header"),
|
||||
"AUDI" : ("audio[]", None, "Audio chunk"),
|
||||
"SYNC" : ("sync[]", None, "Start of video frame data"),
|
||||
"IVRA" : ("ivra[]", None, "Vector codebook (?)"),
|
||||
"VRAM" : ("video[]", None, "Video RAM tile pattern"),
|
||||
"CRAM" : ("color[]", None, "Color RAM (palette)"),
|
||||
"CEND" : ("video_end[]", None, "End of video data"),
|
||||
"MEND" : ("end_file", None, "End of file"),
|
||||
}
|
||||
|
||||
def __init__(self, *args):
|
||||
FieldSet.__init__(self, *args)
|
||||
self._size = self["length"].value * 8
|
||||
fourcc = self["fourcc"].value
|
||||
if fourcc in self.tag_info:
|
||||
self._name, self._parser, self._description = self.tag_info[fourcc]
|
||||
else:
|
||||
self._parser = None
|
||||
self._description = "Unknown chunk: fourcc %s" % self["fourcc"].display
|
||||
|
||||
def createFields(self):
|
||||
yield String(self, "fourcc", 4, "FourCC", charset="ASCII")
|
||||
yield textHandler(UInt32(self, "length", "length"), hexadecimal)
|
||||
size = self["length"].value - 8
|
||||
if 0 < size:
|
||||
if self._parser:
|
||||
for field in self._parser(self, size):
|
||||
yield field
|
||||
else:
|
||||
yield RawBytes(self, "data", size)
|
||||
|
||||
class SpiderManVideoFile(Parser):
|
||||
PARSER_TAGS = {
|
||||
"id": "spiderman_video",
|
||||
"category": "game",
|
||||
"file_ext": ("bin",),
|
||||
"min_size": 8*8,
|
||||
"description": "The Amazing Spider-Man vs. The Kingpin (Sega CD) FMV video"
|
||||
}
|
||||
|
||||
endian = BIG_ENDIAN
|
||||
|
||||
def validate(self):
|
||||
return (self.stream.readBytes(0, 4) == 'CONF')
|
||||
|
||||
def createFields(self):
|
||||
while not self.eof:
|
||||
yield Chunk(self, "chunk[]")
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
"""
|
||||
ZSNES Save State Parser (v143 only currently)
|
||||
|
||||
Author: Jason Gorski
|
||||
Creation date: 2006-09-15
|
||||
"""
|
||||
|
||||
from hachoir_parser import Parser
|
||||
from hachoir_core.field import (FieldSet, StaticFieldSet,
|
||||
UInt8, UInt16, UInt32,
|
||||
String, PaddingBytes, Bytes, RawBytes)
|
||||
from hachoir_core.endian import LITTLE_ENDIAN
|
||||
|
||||
class ZSTHeader(StaticFieldSet):
|
||||
format = (
|
||||
(String, "zs_mesg", 26, "File header", {"charset": "ASCII"}),
|
||||
(UInt8, "zs_mesglen", "File header string len"),
|
||||
(UInt8, "zs_version", "Version minor #"),
|
||||
(UInt8, "curcyc", "cycles left in scanline"),
|
||||
(UInt16, "curypos", "current y position"),
|
||||
(UInt8, "cacheud", "update cache every ? frames"),
|
||||
(UInt8, "ccud", "current cache increment"),
|
||||
(UInt8, "intrset", "interrupt set"),
|
||||
(UInt8, "cycpl", "cycles per scanline"),
|
||||
(UInt8, "cycphb", "cycles per hblank"),
|
||||
(UInt8, "spcon", "SPC Enable (1=enabled)"),
|
||||
(UInt16, "stackand", "value to and stack to keep it from going to the wrong area"),
|
||||
(UInt16, "stackor", "value to or stack to keep it from going to the wrong area"),
|
||||
)
|
||||
|
||||
class ZSTcpu(StaticFieldSet):
|
||||
format = (
|
||||
(UInt16, "xat"),
|
||||
(UInt8, "xdbt"),
|
||||
(UInt8, "xpbt"),
|
||||
(UInt16, "xst"),
|
||||
(UInt16, "xdt"),
|
||||
(UInt16, "xxt"),
|
||||
(UInt16, "xyt"),
|
||||
(UInt8, "xp"),
|
||||
(UInt8, "xe"),
|
||||
(UInt16, "xpc"),
|
||||
(UInt8, "xirqb", "which bank the irqs start at"),
|
||||
(UInt8, "debugger", "Start with debugger (1: yes, 0: no)"),
|
||||
(UInt32, "Curtable" "Current table address"),
|
||||
(UInt8, "curnmi", "if in NMI (1=yes)"),
|
||||
(UInt32, "cycpbl", "percentage left of CPU/SPC to run (3.58 = 175)"),
|
||||
(UInt32, "cycpblt", "percentage of CPU/SPC to run"),
|
||||
)
|
||||
|
||||
class ZSTppu(FieldSet):
|
||||
static_size = 3019*8
|
||||
def createFields(self):
|
||||
yield UInt8(self, "sndrot", "rotates to use A,X or Y for sound skip")
|
||||
yield UInt8(self, "sndrot2", "rotates a random value for sound skip")
|
||||
yield UInt8(self, "INTEnab", "enables NMI(7)/VIRQ(5)/HIRQ(4)/JOY(0)")
|
||||
yield UInt8(self, "NMIEnab", "controlled in e65816 loop. Sets to 81h")
|
||||
yield UInt16(self, "VIRQLoc", "VIRQ Y location")
|
||||
yield UInt8(self, "vidbright", "screen brightness 0..15")
|
||||
yield UInt8(self, "previdbr", "previous screen brightness")
|
||||
yield UInt8(self, "forceblnk", "force blanking on/off ($80=on)")
|
||||
yield UInt32(self, "objptr", "pointer to object data in VRAM")
|
||||
yield UInt32(self, "objptrn", "pointer2 to object data in VRAM")
|
||||
yield UInt8(self, "objsize1", "1=8dot, 4=16dot, 16=32dot, 64=64dot")
|
||||
yield UInt8(self, "objsize2", "large object size")
|
||||
yield UInt8(self, "objmovs1", "number of bytes to move/paragraph")
|
||||
yield UInt16(self, "objadds1", "number of bytes to add/paragraph")
|
||||
yield UInt8(self, "objmovs2", "number of bytes to move/paragraph")
|
||||
yield UInt16(self, "objadds2", "number of bytes to add/paragraph")
|
||||
yield UInt16(self, "oamaddrt", "oam address")
|
||||
yield UInt16(self, "oamaddrs", "oam address at beginning of vblank")
|
||||
yield UInt8(self, "objhipr", "highest priority object #")
|
||||
yield UInt8(self, "bgmode", "graphics mode 0..7")
|
||||
yield UInt8(self, "bg3highst", "is 1 if background 3 has the highest priority")
|
||||
yield UInt8(self, "bgtilesz", "0=8x8, 1=16x16 bit0=bg1, bit1=bg2, etc.")
|
||||
yield UInt8(self, "mosaicon", "mosaic on, bit 0=bg1, bit1=bg2, etc.")
|
||||
yield UInt8(self, "mosaicsz", "mosaic size in pixels")
|
||||
yield UInt16(self, "bg1ptr", "pointer to background1")
|
||||
yield UInt16(self, "bg2ptr", "pointer to background2")
|
||||
yield UInt16(self, "bg3ptr", "pointer to background3")
|
||||
yield UInt16(self, "bg4ptr", "pointer to background4")
|
||||
yield UInt16(self, "bg1ptrb", "pointer to background1")
|
||||
yield UInt16(self, "bg2ptrb", "pointer to background2")
|
||||
yield UInt16(self, "bg3ptrb", "pointer to background3")
|
||||
yield UInt16(self, "bg4ptrb", "pointer to background4")
|
||||
yield UInt16(self, "bg1ptrc", "pointer to background1")
|
||||
yield UInt16(self, "bg2ptrc", "pointer to background2")
|
||||
yield UInt16(self, "bg3ptrc", "pointer to background3")
|
||||
yield UInt16(self, "bg4ptrc", "pointer to background4")
|
||||
yield UInt16(self, "bg1ptrd", "pointer to background1")
|
||||
yield UInt16(self, "bg2ptrd", "pointer to background2")
|
||||
yield UInt16(self, "bg3ptrd", "pointer to background3")
|
||||
yield UInt16(self, "bg4ptrd", "pointer to background4")
|
||||
yield UInt8(self, "bg1scsize", "bg #1 screen size (0=1x1,1=1x2,2=2x1,3=2x2)")
|
||||
yield UInt8(self, "bg2scsize", "bg #2 screen size (0=1x1,1=1x2,2=2x1,3=2x2)")
|
||||
yield UInt8(self, "bg3scsize", "bg #3 screen size (0=1x1,1=1x2,2=2x1,3=2x2)")
|
||||
yield UInt8(self, "bg4scsize", "bg #4 screen size (0=1x1,1=1x2,2=2x1,3=2x2)")
|
||||
yield UInt16(self, "bg1objptr", "pointer to tiles in background1")
|
||||
yield UInt16(self, "bg2objptr", "pointer to tiles in background2")
|
||||
yield UInt16(self, "bg3objptr", "pointer to tiles in background3")
|
||||
yield UInt16(self, "bg4objptr", "pointer to tiles in background4")
|
||||
yield UInt16(self, "bg1scrolx", "background 1 x position")
|
||||
yield UInt16(self, "bg2scrolx", "background 2 x position")
|
||||
yield UInt16(self, "bg3scrolx", "background 3 x position")
|
||||
yield UInt16(self, "bg4scrolx", "background 4 x position")
|
||||
yield UInt16(self, "bg1sx", "Temporary Variable for Debugging purposes")
|
||||
yield UInt16(self, "bg1scroly", "background 1 y position")
|
||||
yield UInt16(self, "bg2scroly", "background 2 y position")
|
||||
yield UInt16(self, "bg3scroly", "background 3 y position")
|
||||
yield UInt16(self, "bg4scroly", "background 4 y position")
|
||||
yield UInt16(self, "addrincr", "vram increment (2,64,128,256)")
|
||||
yield UInt8(self, "vramincr", "0 = increment at 2118/2138, 1 = 2119,213A")
|
||||
yield UInt8(self, "vramread", "0 = address set, 1 = already read once")
|
||||
yield UInt32(self, "vramaddr", "vram address")
|
||||
|
||||
yield UInt16(self, "cgaddr", "cg (palette)")
|
||||
yield UInt8(self, "cgmod", "if cgram is modified or not")
|
||||
yield UInt16(self, "scrnon", "main & sub screen on")
|
||||
yield UInt8(self, "scrndist", "which background is disabled")
|
||||
yield UInt16(self, "resolutn", "screen resolution")
|
||||
yield UInt8(self, "multa", "multiplier A")
|
||||
yield UInt16(self, "diva", "divisor C")
|
||||
yield UInt16(self, "divres", "quotent of divc/divb")
|
||||
yield UInt16(self, "multres", "result of multa * multb/remainder of divc/divb")
|
||||
yield UInt16(self, "latchx", "latched x value")
|
||||
yield UInt16(self, "latchy", "latched y value")
|
||||
yield UInt8(self, "latchxr", "low or high byte read for x value")
|
||||
yield UInt8(self, "latchyr", "low or high byte read for y value")
|
||||
yield UInt8(self, "frskipper", "used to control frame skipping")
|
||||
yield UInt8(self, "winl1", "window 1 left position")
|
||||
yield UInt8(self, "winr1", "window 1 right position")
|
||||
yield UInt8(self, "winl2", "window 2 left position")
|
||||
yield UInt8(self, "winr2", "window 2 right position")
|
||||
yield UInt8(self, "winbg1en", "Win1 on (IN/OUT) or Win2 on (IN/OUT) on BG1")
|
||||
yield UInt8(self, "winbg2en", "Win1 on (IN/OUT) or Win2 on (IN/OUT) on BG2")
|
||||
yield UInt8(self, "winbg3en", "Win1 on (IN/OUT) or Win2 on (IN/OUT) on BG3")
|
||||
yield UInt8(self, "winbg4en", "Win1 on (IN/OUT) or Win2 on (IN/OUT) on BG4")
|
||||
yield UInt8(self, "winobjen", "Win1 on (IN/OUT) or Win2 on (IN/OUT) on sprites")
|
||||
yield UInt8(self, "wincolen", "Win1 on (IN/OUT) or Win2 on (IN/OUT) on backarea")
|
||||
yield UInt8(self, "winlogica", "Window logic type for BG1 to 4")
|
||||
yield UInt8(self, "winlogicb", "Window logic type for Sprites and Backarea")
|
||||
yield UInt8(self, "winenabm", "Window logic enable for main screen")
|
||||
yield UInt8(self, "winenabs", "Window logic enable for sub sceen")
|
||||
yield UInt8(self, "mode7set", "mode 7 settings")
|
||||
yield UInt16(self, "mode7A", "A value for Mode 7")
|
||||
yield UInt16(self, "mode7B", "B value for Mode 7")
|
||||
yield UInt16(self, "mode7C", "C value for Mode 7")
|
||||
yield UInt16(self, "mode7D", "D value for Mode 7")
|
||||
yield UInt16(self, "mode7X0", "Center X for Mode 7")
|
||||
yield UInt16(self, "mode7Y0", "Center Y for Mode 7")
|
||||
yield UInt8(self, "JoyAPos", "Old-Style Joystick Read Position for Joy 1 & 3")
|
||||
yield UInt8(self, "JoyBPos", "Old-Style Joystick Read Position for Joy 2 & 4")
|
||||
yield UInt32(self, "compmult", "Complement Multiplication for Mode 7")
|
||||
yield UInt8(self, "joyalt", "temporary joystick alternation")
|
||||
yield UInt32(self, "wramrwadr", "continuous read/write to wram address")
|
||||
yield RawBytes(self, "dmadata", 129, "dma data (written from ports 43xx)")
|
||||
yield UInt8(self, "irqon", "if IRQ has been called (80h) or not (0)")
|
||||
yield UInt8(self, "nexthdma", "HDMA data to execute once vblank ends")
|
||||
yield UInt8(self, "curhdma", "Currently executed hdma")
|
||||
yield RawBytes(self, "hdmadata", 152, "4 dword register addresses, # bytes to transfer/line, address increment (word)")
|
||||
yield UInt8(self, "hdmatype", "if first time executing hdma or not")
|
||||
yield UInt8(self, "coladdr", "red value of color to add")
|
||||
yield UInt8(self, "coladdg", "green value of color to add")
|
||||
yield UInt8(self, "coladdb", "blue value of color to add")
|
||||
yield UInt8(self, "colnull", "keep this 0 (when accessing colors by dword)")
|
||||
yield UInt8(self, "scaddset", "screen/fixed color addition settings")
|
||||
yield UInt8(self, "scaddtype", "which screen to add/sub")
|
||||
yield UInt8(self, "Voice0Disabl2", "Disable Voice 0")
|
||||
yield UInt8(self, "Voice1Disabl2", "Disable Voice 1")
|
||||
yield UInt8(self, "Voice2Disabl2", "Disable Voice 2")
|
||||
yield UInt8(self, "Voice3Disabl2", "Disable Voice 3")
|
||||
yield UInt8(self, "Voice4Disabl2", "Disable Voice 4")
|
||||
yield UInt8(self, "Voice5Disabl2", "Disable Voice 5")
|
||||
yield UInt8(self, "Voice6Disabl2", "Disable Voice 6")
|
||||
yield UInt8(self, "Voice7Disabl2", "Disable Voice 7")
|
||||
yield RawBytes(self, "oamram", 1024, "OAMRAM (544 bytes)")
|
||||
yield RawBytes(self, "cgram", 512, "CGRAM")
|
||||
yield RawBytes(self, "pcgram", 512, "Previous CGRAM")
|
||||
yield UInt8(self, "vraminctype")
|
||||
yield UInt8(self, "vramincby8on", "if increment by 8 is on")
|
||||
yield UInt8(self, "vramincby8left", "how many left")
|
||||
yield UInt8(self, "vramincby8totl", "how many in total (32,64,128)")
|
||||
yield UInt8(self, "vramincby8rowl", "how many left in that row (start at 8)")
|
||||
yield UInt16(self, "vramincby8ptri", "increment by how many when rowl = 0")
|
||||
yield UInt8(self, "nexthprior")
|
||||
yield UInt8(self, "doirqnext")
|
||||
yield UInt16(self, "vramincby8var")
|
||||
yield UInt8(self, "screstype")
|
||||
yield UInt8(self, "extlatch")
|
||||
yield UInt8(self, "cfield")
|
||||
yield UInt8(self, "interlval")
|
||||
yield UInt16(self, "HIRQLoc HIRQ X")
|
||||
|
||||
# NEWer ZST format
|
||||
yield UInt8(self, "KeyOnStA")
|
||||
yield UInt8(self, "KeyOnStB")
|
||||
yield UInt8(self, "SDD1BankA")
|
||||
yield UInt8(self, "SDD1BankB")
|
||||
yield UInt8(self, "SDD1BankC")
|
||||
yield UInt8(self, "SDD1BankD")
|
||||
yield UInt8(self, "vramread2")
|
||||
yield UInt8(self, "nosprincr")
|
||||
yield UInt16(self, "poamaddrs")
|
||||
yield UInt8(self, "ioportval")
|
||||
yield UInt8(self, "iohvlatch")
|
||||
yield UInt8(self, "ppustatus")
|
||||
|
||||
yield PaddingBytes(self, "tempdat", 477, "Reserved/Unused")
|
||||
|
||||
class ZSNESFile(Parser):
|
||||
PARSER_TAGS = {
|
||||
"id": "zsnes",
|
||||
"category": "game",
|
||||
"description": "ZSNES Save State File (only version 143)",
|
||||
"min_size": 3091*8,
|
||||
"file_ext": ("zst", "zs1", "zs2", "zs3", "zs4", "zs5", "zs6",
|
||||
"zs7", "zs8", "zs9")
|
||||
}
|
||||
endian = LITTLE_ENDIAN
|
||||
|
||||
def validate(self):
|
||||
temp = self.stream.readBytes(0,28)
|
||||
if temp[0:26] != "ZSNES Save State File V143":
|
||||
return "Wrong header"
|
||||
if ord(temp[27:28]) != 143: # extra...
|
||||
return "Wrong save version %d <> 143" % temp[27:1]
|
||||
return True
|
||||
|
||||
def seek(self, offset):
|
||||
padding = self.seekByte(offset, relative=False)
|
||||
if padding is not None:
|
||||
yield padding
|
||||
|
||||
def createFields(self):
|
||||
yield ZSTHeader(self, "header", "ZST header") # Offset: 0
|
||||
yield ZSTcpu(self, "cpu", "ZST cpu registers") # 41
|
||||
yield ZSTppu(self, "ppu", "ZST CPU registers") # 72
|
||||
yield RawBytes(self, "wram7E", 65536) # 3091
|
||||
yield RawBytes(self, "wram7F", 65536) # 68627
|
||||
yield RawBytes(self, "vram", 65536) # 134163
|
||||
|
||||
# TODO: Interpret extra on-cart chip data found at/beyond... 199699
|
||||
|
||||
# TODO: Interpret Thumbnail/Screenshot data found at 275291
|
||||
# 64*56*2(16bit colors) = 7168
|
||||
padding = self.seekByte(275291, relative=False)
|
||||
if padding is not None:
|
||||
yield padding
|
||||
yield Bytes(self, "thumbnail", 7168, "Thumbnail of playing game in some sort of raw 64x56x16-bit RGB mode?")
|
||||
|
||||
Reference in New Issue
Block a user