diff options
Diffstat (limited to 'tools/themeparser.py')
-rw-r--r-- | tools/themeparser.py | 621 |
1 files changed, 0 insertions, 621 deletions
diff --git a/tools/themeparser.py b/tools/themeparser.py deleted file mode 100644 index 993f7c79bc..0000000000 --- a/tools/themeparser.py +++ /dev/null @@ -1,621 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -""" - " ScummVM - Graphic Adventure Engine - " - " ScummVM is the legal property of its developers, whose names - " are too numerous to list here. Please refer to the COPYRIGHT - " file distributed with this source distribution. - " - " This program is free software; you can redistribute it and/or - " modify it under the terms of the GNU General Public License - " as published by the Free Software Foundation; either version 2 - " of the License, or (at your option) any later version. - " - " This program is distributed in the hope that it will be useful, - " but WITHOUT ANY WARRANTY; without even the implied warranty of - " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - " GNU General Public License for more details. - " - " You should have received a copy of the GNU General Public License - " along with this program; if not, write to the Free Software - " Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - " - " $URL$ - " $Id$ -""" - -from __future__ import with_statement -import os -import xml.dom.minidom as DOM -import struct - -FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)]) - -# adapted from Activestate Snippet Cookbook -def printBinaryDump(src, length=16): - N=0; result='' - while src: - s,src = src[:length],src[length:] - hexa = ' '.join(["%02X"%ord(x) for x in s]) - s = s.translate(FILTER) - result += "%04X %-*s %s\n" % (N, length*3, hexa, s) - N+=length - print (result) - -def pbin(data): - return str(map(lambda c: hex(ord(c)), data)) -# return " ".join(["%0.2X" % ord(c) for c in data]) - -class STXBinaryFile(object): - class InvalidRGBColor(Exception): - pass - - class InvalidResolution(Exception): - pass - - class InvalidFontIdentifier(Exception): - pass - - class InvalidBitmapName(Exception): - pass - - class InvalidDialogOverlay(Exception): - pass - - class DrawStepData(object): - def __init__(self, isDefault, packFormat, function): - self.isDefault = isDefault - self.packFormat = packFormat - self.parse = function - - BYTEORDER = '>' # big-endian format by default, platform independent - - TRUTH_VALUES = {"" : 0, "true" : 1, "false" : 0, "True" : 1, "False" : 0} - - BLOCK_HEADERS = { - "bitmaps" : 0x0100000A, - "fonts" : 0x0100000B, - "cursor" : 0x0100000C, - "drawdata" : 0x0100000D, - - "globals" : 0x0200000A, - "dialog" : 0x0200000B, - } - - DIALOG_shading = {"none" : 0x0, "dim" : 0x1, "luminance" : 0x2} - - DS_triangleOrientations = {"top" : 0x1, "bottom" : 0x2, "left" : 0x3, "right" : 0x4} - DS_fillModes = {"none" : 0x0, "foreground" : 0x1, "background" : 0x2, "gradient" : 0x3} - DS_vectorAlign = {"left" : 0x1, "right" : 0x2, "bottom" : 0x3, "top" : 0x4, "center" : 0x5} - - DS_functions = { - "void" : 0x0, "circle" : 0x1, "square" : 0x2, "roundedsq" : 0x3, "bevelsq" : 0x4, - "line" : 0x5, "triangle" : 0x6, "fill" : 0x7, "tab" : 0x8, "bitmap" : 0x9, "cross" : 0xA - } - - DS_fonts = { - "text_default" : 0x0, "text_hover" : 0x1, "text_disabled" : 0x2, - "text_inverted" : 0x3, "text_button" : 0x4, "text_button_hover" : 0x5, "text_normal" : 0x6 - } - - DS_text_alignV = {"bottom" : 0x0, "center" : 0x1, "top" : 0x2} - DS_text_alignH = {"left" : 0x0, "center" : 0x1, "right" : 0x2} - - DS_list = [ - "func", "fill", "stroke", "gradient_factor", - "width", "height", "xpos", "ypos", - "radius", "bevel", "shadow", "orientation", "file", - "fg_color", "bg_color", "gradient_start", "gradient_end", "bevel_color" - ] - - def __init__(self, themeName, autoLoad = True, verbose = False): - self._themeName = themeName - self._stxFiles = [] - self._verbose = verbose - - self.DS_data = { - # attribute name isDefault pack parse function - "func" : self.DrawStepData(False, "B", lambda f: self.DS_functions[f]), - "fill" : self.DrawStepData(True, "B", lambda f: self.DS_fillModes[f]), - "stroke" : self.DrawStepData(True, "B", int), - "gradient_factor" : self.DrawStepData(True, "B", int), - "width" : self.DrawStepData(False, "i", lambda w: -1 if w == 'height' else 0 if w == 'auto' else int(w)), - "height" : self.DrawStepData(False, "i", lambda h: -1 if h == 'width' else 0 if h == 'auto' else int(h)), - "xpos" : self.DrawStepData(False, "i", lambda pos: self.DS_vectorAlign[pos] if pos in self.DS_vectorAlign else int(pos)), - "ypos" : self.DrawStepData(False, "i", lambda pos: self.DS_vectorAlign[pos] if pos in self.DS_vectorAlign else int(pos)), - "radius" : self.DrawStepData(False, "i", lambda r: 0xFF if r == 'auto' else int(r)), - "bevel" : self.DrawStepData(True, "B", int), - "shadow" : self.DrawStepData(True, "B", int), - "orientation" : self.DrawStepData(False, "B", lambda o: self.DS_triangleOrientations[o]), - "file" : self.DrawStepData(False, "B", self.__getBitmap), - "fg_color" : self.DrawStepData(True, "4s", self.__parseColor), - "bg_color" : self.DrawStepData(True, "4s", self.__parseColor), - "gradient_start" : self.DrawStepData(True, "4s", self.__parseColor), - "gradient_end" : self.DrawStepData(True, "4s", self.__parseColor), - "bevel_color" : self.DrawStepData(True, "4s", self.__parseColor) - } - - if autoLoad: - if not os.path.isdir(themeName) or not os.path.isfile(os.path.join(themeName, "THEMERC")): - raise IOError - - for filename in os.listdir(themeName): - filename = os.path.join(themeName, filename) - if os.path.isfile(filename) and filename.endswith('.stx'): - self._stxFiles.append(filename) - - def debug(self, text): - if self._verbose: print (text) - - def debugBinary(self, data): - if self._verbose: - print ("BINARY OUTPUT (%d bytes): %s" % (len(data), " ".join(["%0.2X" % ord(c) for c in data]))) - - def addSTXFile(self, filename): - if not os.path.isfile(filename): - raise IOError - else: - self._stxFiles.append(filename) - - def parse(self): - if not self._stxFiles: - self.debug("No files have been loaded for parsing on the theme.") - raise IOError - - for f in self._stxFiles: - self.debug("Parsing %s." % f) - with open(f) as stxFile: - self.__parseFile(stxFile) - - def __parseFile(self, xmlFile): - stxDom = DOM.parse(xmlFile) - - for layout in stxDom.getElementsByTagName("layout_info"): - self.__parseLayout(layout) - - for render in stxDom.getElementsByTagName("render_info"): - self.__parseRender(render) - - stxDom.unlink() - - def __getBitmap(self, bmp): - bmp = str(bmp) - - if bmp == "": - return 0x0 - if bmp not in self._bitmaps: - raise self.InvalidBitmapName - - return self._bitmaps[bmp] - - def __parseDrawStep(self, drawstepDom, localDefaults = {}): - - dstable = {} - - if drawstepDom.tagName == "defaults": - isGlobal = drawstepDom.parentNode.tagName == "render_info" - - for ds in self.DS_list: - if self.DS_data[ds].isDefault and drawstepDom.hasAttribute(ds): - dstable[ds] = self.DS_data[ds].parse(drawstepDom.getAttribute(ds)) - - elif isGlobal: - dstable[ds] = None - - else: - for ds in self.DS_data: - if drawstepDom.hasAttribute(ds): - dstable[ds] = self.DS_data[ds].parse(drawstepDom.getAttribute(ds)) - elif self.DS_data[ds].isDefault: - dstable[ds] = localDefaults[ds] if ds in localDefaults else self._globalDefaults[ds] - else: - dstable[ds] = None - - return dstable - - - def __parseDrawStepToBin(self, stepDict): - """ - /BBBBiiiiiBBB4s4s4s4s4sB/ == - function (byte) - fill (byte) - stroke (byte) - gradient_factor (byte) - width (int32) - height (int32) - xpos (int32) - ypos (int32) - radius (int32) - bevel (byte) - shadow (byte) - orientation (byte) - file (byte) - fg_color (4 byte) - bg_color (4 byte) - gradient_start (4 byte) - gradient_end (4 byte) - bevel_color (4 byte) - """ - - packLayout = "" - packData = [] - - for ds in self.DS_list: - layout = self.DS_data[ds].packFormat - data = stepDict[ds] - - if not data: - size = struct.calcsize(layout) - packLayout += "B" * size - - for d in range(size): - packData.append(0) - else: - packLayout += layout - packData.append(data) - - - stepBin = struct.pack(self.BYTEORDER + packLayout, *tuple(packData)) - return stepBin - - - def __parseResolutionToBin(self, resString): - """ - /B bHH bHH bHH/ == 1 byte + x * 9 bytes - number of resolution sections (byte) - exclude resolution (byte) - resolution X (half) - resolution Y (half) - """ - - if resString == "": - return struct.pack(self.BYTEORDER + "BbHH", 1, 0, 0, 0) - - resolutions = resString.split(", ") - packFormat = "B" + "bHH" * len(resolutions) - packData = [len(resolutions)] - - for res in resolutions: - exclude = 0 - if res[0] == '-': - exclude = 1 - res = res[1:] - - try: - x, y = res.split('x') - x = 0 if x == 'X' else int(x) - y = 0 if y == 'Y' else int(y) - except ValueError: - raise InvalidResolution - - packData.append(exclude) - packData.append(x) - packData.append(y) - - buff = struct.pack(self.BYTEORDER + packFormat, *tuple(packData)) - return buff - - def __parseRGBToBin(self, color): - """ - /xBBB/ == 32 bits - padding (byte) - red color (byte) - green color (byte) - blue color (byte) - """ - - try: - rgb = tuple(map(int, color.split(", "))) - except ValueError: - raise self.InvalidRGBColor - - if len(rgb) != 3: - raise self.InvalidRGBColor - - for c in rgb: - if c < 0 or c > 255: - raise self.InvalidRGBColor - - rgb = struct.pack(self.BYTEORDER + "xBBB", *tuple(rgb)) - -# self.debugBinary(rgb) - return rgb - - def __parseColor(self, color): - try: - color = self.__parseRGBToBin(color) - except self.InvalidRGBColor: - if color not in self._colors: - raise self.InvalidRGBColor - color = self._colors[color] - - return color - - - def __parsePalette(self, paletteDom): - self._colors = {} - - for color in paletteDom.getElementsByTagName("color"): - color_name = color.getAttribute('name') - color_rgb = self.__parseRGBToBin(color.getAttribute('rgb')) - - self._colors[color_name] = color_rgb -# self.debug("COLOR: %s" % (color_name)) - - - def __parseBitmaps(self, bitmapsDom): - self._bitmaps = {} - idCount = 0xA0 - packLayout = "" - packData = [] - - for bitmap in bitmapsDom.getElementsByTagName("bitmap"): - bmpName = str(bitmap.getAttribute("filename")) - self._bitmaps[bmpName] = idCount - - packLayout += "B%ds" % (len(bmpName) + 1) - packData.append(idCount) - packData.append(bmpName) - idCount += 1 - - - bitmapBinary = struct.pack( - self.BYTEORDER + "IB" + packLayout, - self.BLOCK_HEADERS['bitmaps'], - len(bitmapsDom.getElementsByTagName("bitmap")), - *tuple(packData) - ) - -# self.debug("BITMAPS:\n%s\n\n" % pbin(bitmapBinary)) - return bitmapBinary - - def __parseFonts(self, fontsDom): - """ - /IB Bs4ss .../ - section header (uint32) - number of font definitions (byte) - - id for font definition (byte) - resolution for font (byte array) - color for font (4 bytes) - font filename (byte array, null terminated) - """ - - packLayout = "" - packData = [] - - for font in fontsDom.getElementsByTagName("font"): - ident = font.getAttribute("id") - - if ident not in self.DS_fonts: - raise self.InvalidFontIdentifier - - color = self.__parseColor(font.getAttribute("color")) - filename = str(font.getAttribute("file")) - - if filename == 'default': - filename = '' - - resolution = self.__parseResolutionToBin(font.getAttribute("resolution")) - - packLayout += "B%ds4s%ds" % (len(resolution), len(filename) + 1) - packData.append(self.DS_fonts[ident]) - packData.append(resolution) - packData.append(color) - packData.append(filename) - - fontsBinary = struct.pack(self.BYTEORDER + \ - "IB" + packLayout, - self.BLOCK_HEADERS['fonts'], - len(fontsDom.getElementsByTagName("font")), - *tuple(packData) - ) - - -# self.debug("FONTS DATA:\n%s\n\n" % pbin(fontsBinary)) - return fontsBinary - - def __parseTextToBin(self, textDom): - """ - /BBBx/ - font identifier (byte) - vertical alignment (byte) - horizontal alignment (byte) - padding until word (byte) - """ - - font = textDom.getAttribute("font") - if font not in self.DS_fonts: - raise self.InvalidFontIdentifier - - textBin = struct.pack(self.BYTEORDER + "BBBx", - self.DS_fonts[font], - self.DS_text_alignV[textDom.getAttribute("vertical_align")], - self.DS_text_alignH[textDom.getAttribute("horizontal_align")] - ) - - return textBin - - def __parseDrawData(self, ddDom): - """ - /IsIBBHss/ - Section Header (uint32) - Resolution (byte array, word-aligned) - DrawData id hash (uint32) - Cached (byte) - has text section? (byte) - number of DD sections (uint16) - ** text segment (4 bytes) - drawstep segments (byte array) - """ - - - localDefaults = ddDom.getElementsByTagName("defaults") - localDefaults = localDefaults[0] if localDefaults else {} - - stepList = [] - - for ds in ddDom.getElementsByTagName("drawstep"): - dstable = self.__parseDrawStep(ds, localDefaults) - dsbinary = self.__parseDrawStepToBin(dstable) - - stepList.append(dsbinary) - - stepByteArray = "".join(stepList) - - resolution = self.__parseResolutionToBin(ddDom.getAttribute("resolution")) - - text = ddDom.getElementsByTagName("text") - text = self.__parseTextToBin(text[0]) if text else "" - - id_hash = str.__hash__(str(ddDom.getAttribute("id"))) & 0xFFFFFFFF - cached = self.TRUTH_VALUES[ddDom.getAttribute("cached")] - - ddBinary = struct.pack(self.BYTEORDER + \ - "I%dsIBBH4s%ds" % (len(resolution), len(stepByteArray)), - - self.BLOCK_HEADERS['drawdata'], # Section Header (uint32) - resolution, # Resolution (byte array, word-aligned) - id_hash, # DrawData id hash (uint32) - cached, # Cached (byte) - 0x1 if text else 0x0, # has text section? (byte) - len(stepList), # number of DD sections (uint16) - text, # ** text segment (byte array) - stepByteArray # drawstep segments (byte array) - ) - -# self.debug("DRAW DATA %s (%X): \n" % (ddDom.getAttribute("id"), id_hash) + pbin(ddBinary) + "\n\n") - return ddBinary - - def __parseCursor(self, cursorDom): - """ - /IsBBhh/ - section header (uint32) - resolution string (byte array) - bitmap id (byte) - scale (byte) - hotspot X (half) - hotspot Y (half) - """ - - resolution = self.__parseResolutionToBin(cursorDom.getAttribute("resolution")) - scale = int(cursorDom.getAttribute("scale")) - hsX, hsY = cursorDom.getAttribute("hotspot").split(", ") - - cursorBin = struct.pack(self.BYTEORDER + "I%dsBBhh" % len(resolution), - self.BLOCK_HEADERS['cursor'], - resolution, - self.__getBitmap(cursorDom.getAttribute("file")), - scale, - int(hsX), - int(hsY) - ) - -# self.debug("CURSOR:\n%s\n\n" % pbin(cursorBin)) - return cursorBin - - def __parseDialog(self, dialogDom): - - dialog_id = str(dialogDom.getAttribute("name")) - resolution = self.__parseResolutionToBin(dialogDom.getAttribute("resolution")) - - overlays = str(dialogDom.getAttribute("overlays")) - overlay_type = 0x0 - overlay_parent = "" - - if overlays == "screen": - overlay_type = 0x1 - elif overlays == "screen_center": - overlay_type = 0x2 - else: - overlay_type = 0x3 - overlay_parent = str(overlays) - - dialog_enabled = 0x1 - if dialogDom.hasAttribute("enabled"): - dialog_enabled = self.TRUTH_VALUES[dialogDom.getAttribute("enabled")] - - dialog_shading = 0x0 - if dialogDom.hasAttribute("shading"): - dialog_shading = self.DIALOG_shading[dialogDom.getAttribute("shading")] - - dialog_inset = 0 - if dialogDom.hasAttribute("inset"): - dialog_inset = int(dialogDom.getAttribute("inset")) - - dialogBin = struct.pack(self.BYTEORDER + \ - "I%ds%dsBBBB%ds" % (len(resolution), len(dialog_id) + 1, len(overlay_parent) + 1), - self.BLOCK_HEADERS['dialog'], - resolution, - dialog_id, - dialog_enabled, - dialog_shading, - dialog_inset, - overlay_type, - overlay_parent, - ) - - return dialogBin - - def __parseLayout(self, layoutDom): - self.debug("GLOBAL SECTION: LAYOUT INFO.") - - dialogBIN = "" - - for dialog in layoutDom.getElementsByTagName("dialog"): - dialogBIN += self.__parseDialog(dialog) - - - printBinaryDump(dialogBIN) - - return dialogBIN - - def __parseRender(self, renderDom): - self.debug("GLOBAL SECTION: RENDER INFO.") - - bitmapBIN = "" - fontsBIN = "" - cursorBIN = "" - drawdataBIN = "" - - # parse color palettes - paletteDom = renderDom.getElementsByTagName("palette") - if paletteDom: - self.__parsePalette(paletteDom[0]) - - # parse bitmaps - bitmapsDom = renderDom.getElementsByTagName("bitmaps") - if bitmapsDom: - bitmapBIN = self.__parseBitmaps(bitmapsDom[0]) - - # parse fonts - fontsDom = renderDom.getElementsByTagName("fonts")[0] - fontsBIN = self.__parseFonts(fontsDom) - - # parse defaults - defaultsDom = renderDom.getElementsByTagName("defaults") - if defaultsDom: - self._globalDefaults = self.__parseDrawStep(defaultsDom[0]) - else: - self._globalDefaults = {} - - # parse cursors - for cur in renderDom.getElementsByTagName("cursor"): - cursorBIN += self.__parseCursor(cur) - - # parse drawdata sets - for dd in renderDom.getElementsByTagName("drawdata"): - drawdataBIN += self.__parseDrawData(dd) - - - renderInfoBIN = bitmapBIN + fontsBIN + cursorBIN + drawdataBIN - printBinaryDump(renderInfoBIN) - - return renderInfoBIN - -if __name__ == '__main__': - bin = STXBinaryFile('../gui/themes/scummclassic', True, True) - bin.parse() - |