From: <edh...@us...> - 2008-03-05 23:37:32
|
Revision: 5110 http://gemrb.svn.sourceforge.net/gemrb/?rev=5110&view=rev Author: edheldil Date: 2008-03-05 15:37:38 -0800 (Wed, 05 Mar 2008) Log Message: ----------- * Started work on refactoring ie_shell package to a reusable module * First stab on implementing write operations * Pass stream as a parameter instead of keeping it with the *_Format objects Modified Paths: -------------- ie_shell/branches/iesh-infinity/Makefile ie_shell/branches/iesh-infinity/README ie_shell/branches/iesh-infinity/ie_shell/builtins.py ie_shell/branches/iesh-infinity/ie_shell/core.py ie_shell/branches/iesh-infinity/ie_shell/formats/chui.py ie_shell/branches/iesh-infinity/ie_shell/formats/dtypes.py ie_shell/branches/iesh-infinity/ie_shell/formats/format.py ie_shell/branches/iesh-infinity/ie_shell/formats/key.py ie_shell/branches/iesh-infinity/ie_shell/formats/stream.py ie_shell/branches/iesh-infinity/ie_shell/formats/tlk.py ie_shell/branches/iesh-infinity/ie_shell/formats/wmap.py ie_shell/branches/iesh-infinity/iesh Modified: ie_shell/branches/iesh-infinity/Makefile =================================================================== --- ie_shell/branches/iesh-infinity/Makefile 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/Makefile 2008-03-05 23:37:38 UTC (rev 5110) @@ -15,5 +15,5 @@ if test -d $(FULLNAME) ; then rm -rf $(FULLNAME); fi clean: - rm -f *.pyc */*.pyc *~ */*~ $(FULLNAME).tar.gz - + rm -f *.pyc */*.pyc *~ */*~ $(FULLNAME).tar.gz MANIFEST + rm -rf build dist Modified: ie_shell/branches/iesh-infinity/README =================================================================== --- ie_shell/branches/iesh-infinity/README 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/README 2008-03-05 23:37:38 UTC (rev 5110) @@ -1,16 +1,22 @@ -ie_shell - Simple Python shell for exploring Infinity Engine-based game files -============================================================================== +iesh - Simple Python shell for exploring Infinity Engine-based game files +========================================================================= Installation: ------------- -None at present, just untar the tarball somewhere convenient. +If you are installing from the source package, type +# python ./setup.py install + +If you are installing from the binary package, untar the tarball +to a usual directory, e.g. /usr/local + Package contents: - ./ie_shell.py - ./data/ - directory for storing exported data, provided for convenience + iesh - the shell + ie_shell/ - python module(s) dealing with the reading of IE files + examples/ - some example code snippets - ./formats/format.py + ie_shell/formats/format.py ./formats/stream.py ./formats/bam.py ... @@ -19,6 +25,7 @@ ./plugins/core.py ./plugins/builtins.py ./plugins/... + ./data/ - directory for storing exported data, provided for convenience Configuration: @@ -41,7 +48,7 @@ Running: -------- -Just type ./ie_shell.py or python ./ie_shell.py and you should see +Just type ./iesh or python ./iesh and you should see dots marking progress as the program loads CHITIN.KEY and DIALOG.TLK. !!! This might take *extremely* long time on a slow computer and @@ -73,7 +80,7 @@ License, disclaimer and similar stuff: -------------------------------------- -Copyright (C) 2004-2006 by Jaroslav Benkovsky, <edh...@us...> +Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -88,3 +95,5 @@ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Modified: ie_shell/branches/iesh-infinity/ie_shell/builtins.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/builtins.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/builtins.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -45,8 +45,14 @@ else: return ResourceStream(name, type).load_object () - ################################################### +def print_file (filename, type = None): + fs = FileStream ().open (filename) + obj = fs.load_object (type) + obj.printme () + return obj + +################################################### def find_str (text): """Finds all strings in loaded DIALOG.TLK file matching regular expression and prints their STRREFs""" Modified: ie_shell/branches/iesh-infinity/ie_shell/core.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/core.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/core.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -29,9 +29,11 @@ global slash_trans slash_trans = string.maketrans ('\\', '/') -t_cp1250 = '\xE1\xE8\xEF\xE9\xEC\xED\xF2\xF3\xF8\x9A\x9D\xFA\xF9\xFD\x9E\xC1\xC8\xCF\xC9\xCC\xCD\xD2\xD3؊\x8D\xDA\xD9ݎ' -t_iso8859_2 = '\xE1\xE8\xEF\xE9\xEC\xED\xF2\xF3\xF8\xB9\xBB\xFA\xF9\xFD\xBE\xC1\xC8\xCF\xC9\xCC\xCD\xD2\xD3ة\xAB\xDA\xD9ݮ' +t_cp1250 = '\xe1\xe8\xef\xe9\xec\xed\xf2\xf3\xf8\x9a\x9d\xfa\xf9\xfd\x9e\xc1\xc8\xcf\xc9\xcc\xcd\xd2\xd3\xd8\x8a\x8d\xda\xd9\xdd\x8e' +t_iso8859_2 = '\xe1\xe8\xef\xe9\xec\xed\xf2\xf3\xf8\xb9\xbb\xfa\xf9\xfd\xbe\xc1\xc8\xcf\xc9\xcc\xcd\xd2\xd3\xd8\xa9\xab\xda\xd9\xdd\xae' + + global lang_trans lang_trans = string.maketrans (t_cp1250, t_iso8859_2) Modified: ie_shell/branches/iesh-infinity/ie_shell/formats/chui.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/formats/chui.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/formats/chui.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -21,424 +21,425 @@ from ie_shell.formats.format import Format, register_format class CHUI_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'CHUI' + header_desc = ( + { 'key': 'signature', + 'type': 'STR4', + 'off': 0x0000, + 'label': 'Signature' }, - self.window_list = [] + { 'key': 'version', + 'type': 'STR4', + 'off':0x0004, + 'label': 'Version'}, + { 'key': 'num_of_windows', + 'type': 'DWORD', + 'off': 0x0008, + 'label': '# of windows'}, - self.header_desc = ( - { 'key': 'signature', - 'type': 'STR4', - 'off': 0x0000, - 'label': 'Signature' }, - - { 'key': 'version', - 'type': 'STR4', - 'off':0x0004, - 'label': 'Version'}, - - { 'key': 'num_of_windows', - 'type': 'DWORD', - 'off': 0x0008, - 'label': '# of windows'}, - - { 'key': 'control_table_offset', - 'type': 'DWORD', - 'off': 0x000C, - 'label': 'Control table offset'}, + { 'key': 'control_table_offset', + 'type': 'DWORD', + 'off': 0x000C, + 'label': 'Control table offset'}, - { 'key': 'window_offset', - 'type': 'DWORD', - 'off': 0x0010, - 'label': 'First window offset'}, - ) - + { 'key': 'window_offset', + 'type': 'DWORD', + 'off': 0x0010, + 'label': 'First window offset'}, + ) - self.window_record_desc = ( - { 'key': 'id', - 'type': 'WORD', - 'off': 0x0000, - 'label': 'Window id' }, - - { 'key': 'unknown1', - 'type': 'WORD', - 'off': 0x0002, - 'label': 'Unknown 1' }, - - { 'key': 'xpos', - 'type': 'WORD', - 'off': 0x0004, - 'label': 'X position' }, - - { 'key': 'ypos', - 'type': 'WORD', - 'off': 0x0006, - 'label': 'Y position' }, - - { 'key': 'width', - 'type': 'WORD', - 'off': 0x0008, - 'label': 'Width' }, - - { 'key': 'height', - 'type': 'WORD', - 'off': 0x000A, - 'label': 'Height' }, - - { 'key': 'bg_flag', - 'type': 'WORD', - 'off': 0x000C, - 'label': 'Background flag' }, - - { 'key': 'num_of_controls', - 'type': 'WORD', - 'off': 0x000E, - 'label': '# of controls' }, - - { 'key': 'bg_name', - 'type': 'RESREF', - 'off': 0x0010, - 'label': 'Background filename' }, - { 'key': 'control_ndx', - 'type': 'WORD', - 'off': 0x0018, - 'label': 'Index of first control' }, + window_record_desc = ( + { 'key': 'id', + 'type': 'WORD', + 'off': 0x0000, + 'label': 'Window id' }, - { 'key': 'unknown2', - 'type': 'WORD', - 'off': 0x001A, - 'label': 'Unknown 2' }, - - ) + { 'key': 'unknown1', + 'type': 'WORD', + 'off': 0x0002, + 'label': 'Unknown 1' }, - self.control_table_record_desc = ( - { 'key': 'control_offset', - 'type': 'DWORD', - 'off': 0x0000, - 'label': 'Offset of control'}, + { 'key': 'xpos', + 'type': 'WORD', + 'off': 0x0004, + 'label': 'X position' }, - { 'key': 'control_len', - 'type': 'DWORD', - 'off': 0x0004, - 'label': 'Length of control structure'}, - ) + { 'key': 'ypos', + 'type': 'WORD', + 'off': 0x0006, + 'label': 'Y position' }, - self.control_common_record_desc = ( - { 'key': 'id', - 'type': 'CTLID', - 'off': 0x0000, - 'label': 'Control ID' }, - - { 'key': 'xpos', - 'type': 'WORD', - 'off': 0x0004, - 'label': 'X position in window' }, - - { 'key': 'ypos', - 'type': 'WORD', - 'off': 0x0006, - 'label': 'Y position in window' }, - - { 'key': 'width', - 'type': 'WORD', - 'off': 0x0008, - 'label': 'Width' }, - - { 'key': 'height', - 'type': 'WORD', - 'off': 0x000A, - 'label': 'Height' }, - - { 'key': 'type', - 'type': 'CTLTYPE', - 'off': 0x000C, - 'label': 'Control type' }, + { 'key': 'width', + 'type': 'WORD', + 'off': 0x0008, + 'label': 'Width' }, - { 'key': 'unknown', - 'type': 'BYTE', - 'off': 0x000D, - 'label': 'Unknown' }, + { 'key': 'height', + 'type': 'WORD', + 'off': 0x000A, + 'label': 'Height' }, - ) + { 'key': 'bg_flag', + 'type': 'WORD', + 'off': 0x000C, + 'label': 'Background flag' }, + { 'key': 'num_of_controls', + 'type': 'WORD', + 'off': 0x000E, + 'label': '# of controls' }, - self.control_button_record_desc = ( - { 'key': 'bam_file', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of BAM file w/ pixmap' }, - - { 'key': 'bam_cycle', - 'type': 'BYTE', - 'off': 0x0016, - 'label': 'Cycle in BAM file' }, - - { 'key': 'justification', - 'type': 'BYTE', - 'off': 0x0017, - 'label': 'Button text justification' }, - - { 'key': 'frame_unpressed', - 'type': 'WORD', - 'off': 0x0018, - 'label': 'BAM frame: button unpressed' }, - - { 'key': 'frame_pressed', - 'type': 'WORD', - 'off': 0x001A, - 'label': 'BAM frame: button pressed' }, - - { 'key': 'frame_selected', - 'type': 'WORD', - 'off': 0x001C, - 'label': 'BAM frame: button selected' }, - - { 'key': 'frame_disabled', - 'type': 'WORD', - 'off': 0x001E, - 'label': 'BAM frame: button disabled' }, - - ) + { 'key': 'bg_name', + 'type': 'RESREF', + 'off': 0x0010, + 'label': 'Background filename' }, - self.control_slider_record_desc = ( - { 'key': 'mos_file', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of MOS file w/ background' }, - - { 'key': 'bam_file', - 'type': 'RESREF', - 'off': 0x0016, - 'label': 'Name of BAM file w/ pixmap' }, - - { 'key': 'bam_cycle', - 'type': 'BYTE', - 'off': 0x001E, - 'label': 'Cycle in BAM file' }, - - { 'key': 'frame_ungrabbed', - 'type': 'WORD', - 'off': 0x0020, - 'label': 'BAM frame: slider ungrabbed' }, - - { 'key': 'frame_grabbed', - 'type': 'WORD', - 'off': 0x0022, - 'label': 'BAM frame: slider grabbed' }, - - { 'key': 'knob_x', - 'type': 'WORD', - 'off': 0x0024, - 'label': 'Knob X offset' }, - - { 'key': 'knob_y', - 'type': 'WORD', - 'off': 0x0026, - 'label': 'Knob Y offset' }, - - { 'key': 'knob_jump_width', - 'type': 'WORD', - 'off': 0x0028, - 'label': 'Knob jump width' }, - - { 'key': 'knob_jump_count', - 'type': 'WORD', - 'off': 0x002A, - 'label': 'Knob jump count' }, - - { 'key': 'unknown2', - 'type': 'WORD', - 'off': 0x002C, - 'label': 'Unknown 2' }, - - { 'key': 'unknown3', - 'type': 'WORD', - 'off': 0x002E, - 'label': 'Unknown 3' }, - - { 'key': 'unknown4', - 'type': 'WORD', - 'off': 0x0030, - 'label': 'Unknown 4' }, - - { 'key': 'unknown5', - 'type': 'WORD', - 'off': 0x0032, - 'label': 'Unknown 5' }, - - ) + { 'key': 'control_ndx', + 'type': 'WORD', + 'off': 0x0018, + 'label': 'Index of first control' }, - self.control_textedit_record_desc = ( - { 'key': 'mos_file_1', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'MOS file 1' }, - - { 'key': 'mos_file_2', - 'type': 'RESREF', - 'off': 0x0016, - 'label': 'MOS file 2' }, - - { 'key': 'mos_file_3', - 'type': 'RESREF', - 'off': 0x001E, - 'label': 'MOS file 3' }, - - { 'key': 'cursor_file', - 'type': 'RESREF', - 'off': 0x0026, - 'label': 'Name of BAM file w/ cursor' }, - - { 'key': 'unknown2', - 'type': 'BYTES', - 'off': 0x002E, - 'size': 12, - 'label': 'Unknown 2' }, - - { 'key': 'font_file', - 'type': 'RESREF', - 'off': 0x003A, - 'label': 'Name of BAM file w/ font' }, - - { 'key': 'unknown3', - 'type': 'BYTES', - 'off': 0x0042, - 'size': 34, - 'label': 'Unknown 3' }, + { 'key': 'unknown2', + 'type': 'WORD', + 'off': 0x001A, + 'label': 'Unknown 2' }, - { 'key': 'input_len', - 'type': 'WORD', - 'off': 0x0064, - 'label': 'Max. input length' }, - - { 'key': 'unknown4', - 'type': 'DWORD', - 'off': 0x0066, - 'label': 'Unknown 4' }, - - ) + ) - self.control_textarea_record_desc = ( - { 'key': 'font_file_1', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of BAM file w/ font 1' }, - - { 'key': 'font_file_2', - 'type': 'RESREF', - 'off': 0x0016, - 'label': 'Name of BAM file w/ font 2' }, - - { 'key': 'color_1', - 'type': 'RGBA', - 'off': 0x001E, - 'label': 'Color 1' }, - - { 'key': 'color_2', - 'type': 'RGBA', - 'off': 0x0022, - 'label': 'Color 2' }, - - { 'key': 'color_3', - 'type': 'RGBA', - 'off': 0x0026, - 'label': 'Color 3' }, - - { 'key': 'scrollbar', - 'type': 'DWORD', - 'off': 0x002A, - 'label': 'Scrollbar ID' }, - - ) + control_table_record_desc = ( + { 'key': 'control_offset', + 'type': 'DWORD', + 'off': 0x0000, + 'label': 'Offset of control'}, - self.control_label_record_desc = ( - { 'key': 'text', - 'type': 'STRREF', - 'off': 0x000E, - 'label': 'Initial text' }, + { 'key': 'control_len', + 'type': 'DWORD', + 'off': 0x0004, + 'label': 'Length of control structure'}, + ) - { 'key': 'font_file', - 'type': 'RESREF', - 'off': 0x0012, - 'label': 'Name of BAM file w/ font' }, - - { 'key': 'color_1', - 'type': 'RGBA', - 'off': 0x001A, - 'label': 'Color 1' }, - - { 'key': 'color_2', - 'type': 'RGBA', - 'off': 0x001E, - 'label': 'Color 2' }, - - { 'key': 'justification', - 'type': 'WORD', - 'off': 0x0022, - 'label': 'Justification' }, - - ) + control_common_record_desc = ( + { 'key': 'id', + 'type': 'CTLID', + 'off': 0x0000, + 'label': 'Control ID' }, + { 'key': 'xpos', + 'type': 'WORD', + 'off': 0x0004, + 'label': 'X position in window' }, - self.control_scrollbar_record_desc = ( - { 'key': 'bam_file', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of BAM file w/ pixmap' }, + { 'key': 'ypos', + 'type': 'WORD', + 'off': 0x0006, + 'label': 'Y position in window' }, - { 'key': 'bam_cycle', - 'type': 'WORD', - 'off': 0x0016, - 'label': 'Cycle in BAM file' }, - - { 'key': 'frame_up_unpressed', - 'type': 'WORD', - 'off': 0x0018, - 'label': 'BAM frame: up-arrow unpressed' }, - - { 'key': 'frame_up_pressed', - 'type': 'WORD', - 'off': 0x001A, - 'label': 'BAM frame: up-arrow pressed' }, - - { 'key': 'frame_down_unpressed', - 'type': 'WORD', - 'off': 0x001C, - 'label': 'BAM frame: down-arrow unpressed' }, - - { 'key': 'frame_down_pressed', - 'type': 'WORD', - 'off': 0x001E, - 'label': 'BAM frame: down-arrow pressed' }, - - { 'key': 'frame_trough', - 'type': 'WORD', - 'off': 0x0020, - 'label': 'BAM frame: trough' }, - - { 'key': 'frame_slider', - 'type': 'WORD', - 'off': 0x0022, - 'label': 'BAM frame: slider' }, - - { 'key': 'textarea', - 'type': 'DWORD', - 'off': 0x0024, - 'label': 'Textarea ID' }, - - ) + { 'key': 'width', + 'type': 'WORD', + 'off': 0x0008, + 'label': 'Width' }, + { 'key': 'height', + 'type': 'WORD', + 'off': 0x000A, + 'label': 'Height' }, - def decode_file (self): - self.decode_header () + { 'key': 'type', + 'type': 'CTLTYPE', + 'off': 0x000C, + 'label': 'Control type' }, + { 'key': 'unknown', + 'type': 'BYTE', + 'off': 0x000D, + 'label': 'Unknown' }, + + ) + + + control_button_record_desc = ( + { 'key': 'bam_file', + 'type': 'RESREF', + 'off': 0x000E, + 'label': 'Name of BAM file w/ pixmap' }, + + { 'key': 'bam_cycle', + 'type': 'BYTE', + 'off': 0x0016, + 'label': 'Cycle in BAM file' }, + + { 'key': 'justification', + 'type': 'BYTE', + 'off': 0x0017, + 'label': 'Button text justification' }, + + { 'key': 'frame_unpressed', + 'type': 'WORD', + 'off': 0x0018, + 'label': 'BAM frame: button unpressed' }, + + { 'key': 'frame_pressed', + 'type': 'WORD', + 'off': 0x001A, + 'label': 'BAM frame: button pressed' }, + + { 'key': 'frame_selected', + 'type': 'WORD', + 'off': 0x001C, + 'label': 'BAM frame: button selected' }, + + { 'key': 'frame_disabled', + 'type': 'WORD', + 'off': 0x001E, + 'label': 'BAM frame: button disabled' }, + + ) + + control_slider_record_desc = ( + { 'key': 'mos_file', + 'type': 'RESREF', + 'off': 0x000E, + 'label': 'Name of MOS file w/ background' }, + + { 'key': 'bam_file', + 'type': 'RESREF', + 'off': 0x0016, + 'label': 'Name of BAM file w/ pixmap' }, + + { 'key': 'bam_cycle', + 'type': 'BYTE', + 'off': 0x001E, + 'label': 'Cycle in BAM file' }, + + { 'key': 'frame_ungrabbed', + 'type': 'WORD', + 'off': 0x0020, + 'label': 'BAM frame: slider ungrabbed' }, + + { 'key': 'frame_grabbed', + 'type': 'WORD', + 'off': 0x0022, + 'label': 'BAM frame: slider grabbed' }, + + { 'key': 'knob_x', + 'type': 'WORD', + 'off': 0x0024, + 'label': 'Knob X offset' }, + + { 'key': 'knob_y', + 'type': 'WORD', + 'off': 0x0026, + 'label': 'Knob Y offset' }, + + { 'key': 'knob_jump_width', + 'type': 'WORD', + 'off': 0x0028, + 'label': 'Knob jump width' }, + + { 'key': 'knob_jump_count', + 'type': 'WORD', + 'off': 0x002A, + 'label': 'Knob jump count' }, + + { 'key': 'unknown2', + 'type': 'WORD', + 'off': 0x002C, + 'label': 'Unknown 2' }, + + { 'key': 'unknown3', + 'type': 'WORD', + 'off': 0x002E, + 'label': 'Unknown 3' }, + + { 'key': 'unknown4', + 'type': 'WORD', + 'off': 0x0030, + 'label': 'Unknown 4' }, + + { 'key': 'unknown5', + 'type': 'WORD', + 'off': 0x0032, + 'label': 'Unknown 5' }, + + ) + + control_textedit_record_desc = ( + { 'key': 'mos_file_1', + 'type': 'RESREF', + 'off': 0x000E, + 'label': 'MOS file 1' }, + + { 'key': 'mos_file_2', + 'type': 'RESREF', + 'off': 0x0016, + 'label': 'MOS file 2' }, + + { 'key': 'mos_file_3', + 'type': 'RESREF', + 'off': 0x001E, + 'label': 'MOS file 3' }, + + { 'key': 'cursor_file', + 'type': 'RESREF', + 'off': 0x0026, + 'label': 'Name of BAM file w/ cursor' }, + + { 'key': 'unknown2', + 'type': 'BYTES', + 'off': 0x002E, + 'size': 12, + 'label': 'Unknown 2' }, + + { 'key': 'font_file', + 'type': 'RESREF', + 'off': 0x003A, + 'label': 'Name of BAM file w/ font' }, + + { 'key': 'unknown3', + 'type': 'BYTES', + 'off': 0x0042, + 'size': 34, + 'label': 'Unknown 3' }, + + { 'key': 'input_len', + 'type': 'WORD', + 'off': 0x0064, + 'label': 'Max. input length' }, + + { 'key': 'unknown4', + 'type': 'DWORD', + 'off': 0x0066, + 'label': 'Unknown 4' }, + + ) + + control_textarea_record_desc = ( + { 'key': 'font_file_1', + 'type': 'RESREF', + 'off': 0x000E, + 'label': 'Name of BAM file w/ font 1' }, + + { 'key': 'font_file_2', + 'type': 'RESREF', + 'off': 0x0016, + 'label': 'Name of BAM file w/ font 2' }, + + { 'key': 'color_1', + 'type': 'RGBA', + 'off': 0x001E, + 'label': 'Color 1' }, + + { 'key': 'color_2', + 'type': 'RGBA', + 'off': 0x0022, + 'label': 'Color 2' }, + + { 'key': 'color_3', + 'type': 'RGBA', + 'off': 0x0026, + 'label': 'Color 3' }, + + { 'key': 'scrollbar', + 'type': 'DWORD', + 'off': 0x002A, + 'label': 'Scrollbar ID' }, + + ) + + control_label_record_desc = ( + { 'key': 'text', + 'type': 'STRREF', + 'off': 0x000E, + 'label': 'Initial text' }, + + { 'key': 'font_file', + 'type': 'RESREF', + 'off': 0x0012, + 'label': 'Name of BAM file w/ font' }, + + { 'key': 'color_1', + 'type': 'RGBA', + 'off': 0x001A, + 'label': 'Color 1' }, + + { 'key': 'color_2', + 'type': 'RGBA', + 'off': 0x001E, + 'label': 'Color 2' }, + + { 'key': 'justification', + 'type': 'WORD', + 'off': 0x0022, + 'label': 'Justification' }, + + ) + + + control_scrollbar_record_desc = ( + { 'key': 'bam_file', + 'type': 'RESREF', + 'off': 0x000E, + 'label': 'Name of BAM file w/ pixmap' }, + + { 'key': 'bam_cycle', + 'type': 'WORD', + 'off': 0x0016, + 'label': 'Cycle in BAM file' }, + + { 'key': 'frame_up_unpressed', + 'type': 'WORD', + 'off': 0x0018, + 'label': 'BAM frame: up-arrow unpressed' }, + + { 'key': 'frame_up_pressed', + 'type': 'WORD', + 'off': 0x001A, + 'label': 'BAM frame: up-arrow pressed' }, + + { 'key': 'frame_down_unpressed', + 'type': 'WORD', + 'off': 0x001C, + 'label': 'BAM frame: down-arrow unpressed' }, + + { 'key': 'frame_down_pressed', + 'type': 'WORD', + 'off': 0x001E, + 'label': 'BAM frame: down-arrow pressed' }, + + { 'key': 'frame_trough', + 'type': 'WORD', + 'off': 0x0020, + 'label': 'BAM frame: trough' }, + + { 'key': 'frame_slider', + 'type': 'WORD', + 'off': 0x0022, + 'label': 'BAM frame: slider' }, + + { 'key': 'textarea', + 'type': 'DWORD', + 'off': 0x0024, + 'label': 'Textarea ID' }, + + ) + + + def __init__ (self): + Format.__init__ (self) + + self.expect_signature = 'CHUI' + self.window_list = [] + + + + def read (self, stream): + self.read_header (stream) + off = self.header['window_offset'] for i in range (self.header['num_of_windows']): obj = {} - self.decode_window_record (off, obj) + self.read_window_record (stream, off, obj) self.window_list.append (obj) off = off + 28 @@ -447,12 +448,12 @@ for j in range (obj['num_of_controls']): obj2 = {} - self.decode_control_record (off2, obj2) + self.read_control_record (stream, off2, obj2) obj['control_list'].append (obj2) off2 = off2 + 8 - def print_file (self): + def printme (self): self.print_header () i = 0 @@ -462,19 +463,54 @@ i = i + 1 - def decode_header (self): + + def write (self, stream): + self.header['window_offset'] = self.get_struc_size (self.header_desc, self.header) + self.header['num_of_windows'] = len (self.window_list) + + offset = self.header['window_offset'] + num_controls = 0 + for obj in self.window_list: + offset += self.get_struc_size (self.window_record_desc, obj) + obj['control_ndx'] = num_controls + obj['num_of_controls'] = len (obj['control_list']) + num_controls += obj['num_of_controls'] + + + self.header['control_table_offset'] = offset + + + self.write_struc (stream, 0x0000, CHUI_Format.header_desc, self.header) + + window_offset = self.header['window_offset'] + table_offset = self.header['control_table_offset'] + control_offset = self.header['control_table_offset'] + num_controls * 8 + + for obj in self.window_list: + self.write_struc (stream, window_offset, self.window_record_desc, obj) + window_offset += self.get_struc_size (self.window_record_desc, obj) + for obj2 in obj['control_list']: + size = self.write_control (stream, control_offset, obj2) + obj3 = { 'control_offset': control_offset, 'control_len': size } + self.write_struc (stream, table_offset, self.control_table_record_desc, obj2) + control_offset += size + table_offset += 8 # FIXME + #xyx() + + + def read_header (self, stream): self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) + self.read_struc (stream, 0x0000, self.header_desc, self.header) def print_header (self): - self.print_by_desc (self.header, self.header_desc) + self.print_struc (self.header, self.header_desc) - def decode_window_record (self, offset, obj): - self.decode_by_desc (offset, self.window_record_desc, obj) + def read_window_record (self, stream, offset, obj): + self.read_struc (stream, offset, self.window_record_desc, obj) def print_window_record (self, obj): - self.print_by_desc (obj, self.window_record_desc) + self.print_struc (obj, self.window_record_desc) j = 0 for ctl in obj['control_list']: @@ -491,20 +527,35 @@ elif type == 6: return self.control_label_record_desc elif type == 7: return self.control_scrollbar_record_desc - def decode_control_record (self, offset, obj): - self.decode_by_desc (offset, self.control_table_record_desc, obj) + def read_control_record (self, stream, offset, obj): + self.read_struc (stream, offset, self.control_table_record_desc, obj) off2 = obj['control_offset'] - self.decode_by_desc (off2, self.control_common_record_desc, obj) + self.read_struc (stream, off2, self.control_common_record_desc, obj) desc = self.control_type_to_desc (obj['type']) - self.decode_by_desc (off2, desc, obj) + self.read_struc (stream, off2, desc, obj) + + def write_control (self, stream, offset, obj): + #print obj + #size = 0 + #print offset, + self.write_struc (stream, offset, self.control_common_record_desc, obj) + + #size += self.get_struc_size (self.control_common_record_desc, obj) + desc = self.control_type_to_desc (obj['type']) + self.write_struc (stream, offset, desc, obj) + size = self.get_struc_size (desc, obj) + + return size + + def print_control_record (self, obj): - self.print_by_desc (obj, self.control_table_record_desc) - self.print_by_desc (obj, self.control_common_record_desc) + self.print_struc (obj, self.control_table_record_desc) + self.print_struc (obj, self.control_common_record_desc) desc = self.control_type_to_desc (obj['type']) - self.print_by_desc (obj, desc) + self.print_struc (obj, desc) Modified: ie_shell/branches/iesh-infinity/ie_shell/formats/dtypes.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/formats/dtypes.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/formats/dtypes.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -2,18 +2,35 @@ dtypes = {} - -class DescItem: +class IE_Type: def __init__ (self): pass - def printme (self, desc): - pass + def repr (self, value, *args): + return str (value) - def load (self, desc, stream): - pass + def read (self, stream, offset): + return None - def save (self, desc, stream): + def write (self, stream, offset, value): pass + def size (self, value): + return 0 + +class IE_WORD (IEType): + def read (self, stream, offset): + stream.read () +class IE_STRING (IE_Type): + pass + +class IE_RESREF (IE_STRING): + pass + +# FIXME: read/write/ etc should be class methods, perhaps? + +dtypes = { + 'STRING': IE_STRING (), + 'RESREF': IE_RESREF, + } Modified: ie_shell/branches/iesh-infinity/ie_shell/formats/format.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/formats/format.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/formats/format.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -43,17 +43,23 @@ default_options = {} - def __init__ (self, source): + def __init__ (self): self.header_size = 0 self.bitmask_cache = {} self.options = {} - if not isinstance (source, Stream): - source = FileStream (source) +## def load (self, source): +## if source != None: +## if not isinstance (source, Stream): +## source = FileStream (source) - self.stream = source - self.stream.open () +## self.stream = source +## if not source.is_open: +## source.open (mode) +## self.stream = source + + def get_masked_bits (self, value, mask, bl): return (value & mask) >> bl @@ -77,17 +83,34 @@ return mask, bl -# { 'key': '', 'type': '', 'off': 0x00, 'label': '' }, + # { 'key': '', 'type': '', 'off': 0x00, 'label': '' }, - def decode_by_desc (self, offset, desc, obj): + def reset_struc (self, desc, obj): for d in desc: key = d['key'] type = d['type'] + try: + value = d['default'] + except: + if type in ('BYTE', 'WORD', 'DWORD', 'CTLTYPE', 'CTLID', 'RGBA', 'STRREF', 'RESTYPE'): + value = 0 + elif type in ('STR2', 'STR4', 'STR8', 'STR32', 'RESREF', 'STRSIZED'): + value = '' + else: + raise Error ("Unknown type") + + # FIXME: bit masks + obj[key] = value + + return obj + + def read_struc (self, stream, offset, desc, obj): + for d in desc: + key = d['key'] + type = d['type'] local_offset = d['off'] - stream = self.stream - - if self.get_option ('debug_decode'): + if self.get_option ('debug_read'): print d if type == 'BYTE': @@ -132,7 +155,7 @@ elif type == '_BYTE': value = '?' else: - raise "Unknown data type `%s'" %type + raise ValueError ("Unknown data type: " + type) #value = '' if d.has_key ('bits'): @@ -141,15 +164,121 @@ obj[key] = value - if self.get_option ('debug_decode'): + if self.get_option ('debug_read'): self.print_date_by_desc (obj, d) - def print_by_desc (self, obj, desc): + def print_struc (self, obj, desc): for d in desc: self.print_date_by_desc (obj, d) print + def write_struc (self, stream, offset, desc, obj): + for d in desc: + key = d['key'] + type = d['type'] + local_offset = d['off'] + + value = obj[key] + + if self.get_option ('debug_write'): + print '%05d' %(offset + local_offset), d, value + + if type == 'BYTE': + stream.put_char (chr (value), offset + local_offset) + elif type == 'CTLTYPE': + stream.put_char (chr (value), offset + local_offset) + elif type == 'WORD': + stream.write_word (value, offset + local_offset) + elif type == 'DWORD': + stream.write_dword (value, offset + local_offset) + elif type == 'CTLID': + stream.write_dword (value, offset + local_offset) + elif type == 'RGBA': + stream.write_dword (value, offset + local_offset) + elif type == 'STR2': + stream.write_sized_string (value, offset + local_offset, 2) + elif type == 'STR4': + stream.write_sized_string (value, offset + local_offset, 4) + elif type == 'STR8': + stream.write_sized_string (value, offset + local_offset, 8) + elif type == 'STR32': + stream.write_sized_string (value, offset + local_offset, 32) + elif type == 'RESREF': + # FIXME: value = string.translate (value, core.slash_trans, '\x00') + stream.write_resref (value, offset + local_offset) + elif type == 'STRREF': + stream.write_dword (value, offset + local_offset) + elif type == 'RESTYPE': + stream.write_word (value, offset + local_offset) + elif type == 'STROFF': + raise RuntimeError (type + " not implemented") + elif type == 'STRSIZED': + # FIXME: encoding + stream.write_dword (len (value), offset + local_offset) + stream.write_sized_string (value, offset + local_offset, len (value)) + elif type == 'BYTES': + value = stream.write_blob (value, offset + local_offset) + elif type.startswith ('_'): + pass + else: + raise ValueError ("Unknown data type: " + type) + + def get_struc_size (self, desc, obj = None): + total_size = 0 + + for d in desc: + key = d['key'] + type = d['type'] + local_offset = d['off'] + + + if type == 'BYTE': + size = 1 + elif type == 'CTLTYPE': + size = 1 + elif type == 'WORD': + size = 2 + elif type == 'DWORD': + size = 4 + elif type == 'CTLID': + size = 2 + elif type == 'RGBA': + size = 4 + elif type == 'STR2': + size = 2 + elif type == 'STR4': + size = 4 + elif type == 'STR8': + size = 8 + elif type == 'STR32': + size = 32 + elif type == 'RESREF': + size = 8 + elif type == 'STRREF': + size = 4 + elif type == 'RESTYPE': + size = 2 + elif type == 'STROFF': + raise RuntimeError (type + " not implemented") + elif type == 'STRSIZED': + # FIXME: encoding + value = obj[key] + size = 4 + len (value) + elif type == 'BYTES': + value = obj[key] + size = len (value) + elif type.startswith ('_'): + # Ignore the fields starting with '_' + size = 0 + else: + raise ValueError ("Unknown data type: " + type) + + total_size = max (total_size, local_offset + size) + + return total_size + + def print_date_by_desc (self, obj, d): key = d['key'] rec_type = d['type'] @@ -219,7 +348,8 @@ return Format.default_options[key] -Format.default_options['debug_decode'] = 0 +Format.default_options['debug_read'] = 0 +Format.default_options['debug_write'] = 0 Modified: ie_shell/branches/iesh-infinity/ie_shell/formats/key.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/formats/key.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/formats/key.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,21 +24,7 @@ from ie_shell.formats.format import Format, register_format, TICK_SIZE, TACK_SIZE class KEY_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'KEY' - - self.bif_list = [] - self.bif_hash = {} - - self.resref_list = [] - self.resref_hash = {} - - # when set to some number, read that number of resources at most - #self.options['max_read_bifs'] = None - self.options['max_read_resrefs'] = None - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -71,7 +57,7 @@ ) - self.bif_record_desc = ( + bif_record_desc = ( { 'key': 'file_len', 'type': 'DWORD', 'off': 0x0000, @@ -98,7 +84,7 @@ 'label': 'BIF location' }, ) - self.resref_record_desc = ( + resref_record_desc = ( { 'key': 'resref_name', 'type': 'RESREF', 'off': 0x0000, @@ -133,32 +119,49 @@ 'label': 'resref locator (non-tileset index)' }, ) - def decode_file (self): - self.decode_header () + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'KEY' + self.bif_list = [] + self.bif_hash = {} + + self.resref_list = [] + self.resref_hash = {} + + # when set to some number, read that number of resources at most + #self.options['max_read_bifs'] = None + self.options['max_read_resrefs'] = None + + + def read (self, stream): + self.read_header (stream) + off = self.header['bif_offset'] + bif_record_size = self.get_struc_size (self.bif_record_desc) for i in range (self.header['num_of_bifs']): obj = {} - self.decode_bif_record (off, obj) + self.read_bif_record (stream, off, obj) self.bif_list.append (obj) self.bif_hash[obj['file_name']] = obj - off = off + 12 + off = off + bif_record_size off = self.header['resref_offset'] max_read_resrefs = self.header['num_of_resrefs'] if self.options['max_read_resrefs']: max_read_resrefs = min (max_read_resrefs, self.options['max_read_resrefs']) - + + resref_record_size = self.get_struc_size (self.resref_record_desc) for i in range (max_read_resrefs): #if i == 1000: # break obj = {} - self.decode_resref_record (off, obj) + self.read_resref_record (stream, off, obj) self.resref_list.append (obj) obj['file_name'] = self.bif_list[obj['locator_src_ndx']] self.resref_hash[obj['resref_name']] = obj - off = off + 14 + off = off + resref_record_size if not (i % TICK_SIZE): sys.stdout.write('.') @@ -167,7 +170,31 @@ sys.stdout.flush () print - def print_file (self): + def write (self, stream): + # FIXME: STROFF is missing + header_size = self.get_struc_size (self.header_desc) + bif_record_size = self.get_struc_size (self.bif_record_desc) + resref_record_size = self.get_struc_size (self.resref_record_desc) + + self.header['num_of_bifs'] = len (self.bif_list) + self.header['num_of_resrefs'] = len (self.resref_list) + self.header['bif_offset'] = header_size + self.header['resref_offset'] = header_size + len (self.bif_list) * bif_record_size + + self.write_struc (stream, 0x0000, self.header_desc, self.header) + + off2 = self.header['bif_offset'] + for obj in self.bif_list: + self.write_struc (stream, off2, self.bif_record_desc, obj) + off2 += bif_record_size + + off2 = self.header['resref_offset'] + for obj in self.resref_list: + self.write_struc (stream, off2, self.resref_record_desc, obj) + off2 += resref_record_size + + + def printme (self): self.print_header () i = 0 @@ -183,26 +210,26 @@ i = i + 1 - def decode_header (self): + def read_header (self, stream): self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) + self.read_struc (stream, 0x0000, self.header_desc, self.header) def print_header (self): - self.print_by_desc (self.header, self.header_desc) + self.print_struc (self.header, self.header_desc) - def decode_bif_record (self, offset, obj): - self.decode_by_desc (offset, self.bif_record_desc, obj) + def decode_bif_record (self, stream, offset, obj): + self.read_struc (stream, offset, self.bif_record_desc, obj) def print_bif_record (self, obj): - self.print_by_desc (obj, self.bif_record_desc) + self.print_struc (obj, self.bif_record_desc) - def decode_resref_record (self, offset, obj): - self.decode_by_desc (offset, self.resref_record_desc, obj) + def read_resref_record (self, stream, offset, obj): + self.read_struc (stream, offset, self.resref_record_desc, obj) def print_resref_record (self, obj): - self.print_by_desc (obj, self.resref_record_desc) + self.print_struc (obj, self.resref_record_desc) Modified: ie_shell/branches/iesh-infinity/ie_shell/formats/stream.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/formats/stream.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/formats/stream.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -26,12 +26,15 @@ from ie_shell import core + class Stream: def __init__ (self): self.is_open = False - def open (self): - pass + def open (self, mode = 'r'): + # do the real open here + self.is_open = True + return self def close (self): pass @@ -42,11 +45,16 @@ def read (self, count = None): pass + def write (self, data, count = None): + pass + def readline (self): pass + def writeline (self, line): + pass - def get_char (self, offset): + def get_char (self, offset = None): # offset == None means "current offset" here if offset != None: self.seek (offset) @@ -55,10 +63,21 @@ #v = self.read (1) #return struct.unpack ('c', v)[0] + def put_char (self, char, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + + self.write (char, 1) + def get_line (self): #return self.readline () return self.decode_line_string () + def put_line (self): + #FIXME + pass + def decode_word (self, offset): # offset == None means "current offset" here if offset != None: @@ -66,6 +85,13 @@ v = self.read (2) return struct.unpack ('H', v)[0] + def write_word (self, value, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + bytes = struct.pack ('H', value) + self.write (bytes) + def decode_dword (self, offset): # offset == None means "current offset" here if offset != None: @@ -73,6 +99,13 @@ v = self.read (4) return struct.unpack ('I', v)[0] + def write_dword (self, value, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + bytes = struct.pack ('I', value) + self.write (bytes) + def decode_sized_string (self, offset, size): # offset == None means "current offset" here if offset != None: @@ -81,6 +114,14 @@ return struct.unpack ('%ds' %size, v)[0] + def write_sized_string (self, value, offset, size): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + + bytes = struct.pack ('%ds' %size, value) + self.write (bytes) + def decode_asciiz_string (self, off): s = '' @@ -110,6 +151,9 @@ def decode_resref (self, off): return self.decode_sized_string (off, 8) + def write_resref (self, value, off): + self.write_sized_string (value, off, 8) + def decode_blob (self, offset, size = None): # offset == None means "current offset" here # size == None means "till the end of stream" @@ -118,7 +162,15 @@ return self.read (size) + def write_blob (self, value, offset, size = None): + # offset == None means "current offset" here + # size == None means "till the end of stream" + if offset != None: + self.seek (offset) + return self.write (value) + + def get_signature (self): was_open = self.is_open if not self.is_open: @@ -153,19 +205,22 @@ def load_object (self, type = 0): fmt = self.get_format () - return fmt (self) + obj = fmt () + obj.read (self) + return obj class FileStream (Stream): - def __init__ (self, filename): + def __init__ (self): Stream.__init__ (self) + def open (self, filename, mode = 'r'): + # FIXME: reset offset? self.filename = filename - - def open (self): - self.fh = open (self.filename, "r") + self.fh = open (self.filename, mode) self.is_open = True + return self def close (self): self.fh.close () @@ -179,21 +234,26 @@ return self.fh.read (size) else: return self.fh.read () - + def write (self, bytes, size = None): + #if size != None: + # self.fh.write (bytes, size) + #else: + self.fh.write (bytes) + def __repr__ (self): return "<FileStream: %s>" %self.filename class MemoryStream (Stream): - def __init__ (self, membuffer): + def __init__ (self): Stream.__init__ (self) + def open (self, membuffer): self.buffer = membuffer - - def open (self): self.offset = 0 self.is_open = True + return self def decrypt (self): for i in range (len (self.buffer)): @@ -217,12 +277,13 @@ class ResourceStream (MemoryStream): - def __init__ (self, name, type = None): + def __init__ (self): MemoryStream.__init__ (self, '') + + def open (self, name, type = None): self.resref = name self.type = type - def open (self): if core.keys == None: raise RuntimeError, "Core game files are not loaded. See load_game ()." @@ -242,8 +303,8 @@ b.get_file_data (obj) self.buffer = obj['data'] - MemoryStream.open (self) - + return MemoryStream.open (self) + def load_object (self): return Stream.load_object (self, self.type) @@ -253,5 +314,6 @@ class CompressedStream (MemoryStream): - def __init__ (self, membuffer): - MemoryStream.__init__ (self, gzip.zlib.decompress (membuffer)) + def open (self, membuffer): + return MemoryStream.open (self, gzip.zlib.decompress (membuffer)) + Modified: ie_shell/branches/iesh-infinity/ie_shell/formats/tlk.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/formats/tlk.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/ie_shell/formats/tlk.py 2008-03-05 23:37:38 UTC (rev 5110) @@ -27,83 +27,83 @@ class TLK_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - - self.expect_signature = 'TLK' - - self.strref_list = [] - - self.header_desc = ( - { 'key': 'signature', - 'type': 'STR4', - 'off': 0x0000, - 'label': 'Signature' }, + header_desc = ( + { 'key': 'signature', + 'type': 'STR4', + 'off': 0x0000, + 'label': 'Signature' }, - { 'key': 'version', - 'type': 'STR4', - 'off':0x0004, - 'label': 'Version'}, + { 'key': 'version', + 'type': 'STR4', + 'off':0x0004, + 'label': 'Version'}, - { 'key': 'unknown', - 'type': 'WORD', - 'off': 0x0008, - 'label': '???' }, + { 'key': 'unknown', + 'type': 'WORD', + 'off': 0x0008, + 'label': '???' }, - { 'key': 'num_of_strrefs', - 'type': 'DWORD', - 'off': 0x000A, - 'label': '# of strref entries'}, + { 'key': 'num_of_strrefs', + 'type': 'DWORD', + 'off': 0x000A, + 'label': '# of strref entries'}, - { 'key': 'string_offset', - 'type': 'DWORD', - 'off': 0x000E, - 'label': 'First string data offset'}, - ) + { 'key': 'string_offset', + 'type': 'DWORD', + 'off': 0x000E, + 'label': 'First string data offset'}, + ) - self.strref_record_desc = ( - { 'key': 'content_type', - 'type': 'WORD', - 'off': 0x0000, - 'label': 'Content of this entry' }, + strref_record_desc = ( + { 'key': 'content_type', + 'type': 'WORD', + 'off': 0x0000, + 'label': 'Content of this entry' }, + + { 'key': 'sound_resref', + 'type': 'RESREF', + 'off': 0x0002, + 'label': 'Sound resref' }, + + { 'key': 'volume_variance', + 'type': 'DWORD', + 'off': 0x000A, + 'label': 'Volume variance' }, + + { 'key': 'pitch_variance', + 'type': 'DWORD', + 'off': 0x000E, + 'label': 'Pitch variance' }, - { 'key': 'sound_resref', - 'type': 'RESREF', - 'off': 0x0002, - 'label': 'Sound resref' }, - - { 'key': 'volume_variance', - 'type': 'DWORD', - 'off': 0x000A, - 'label': 'Volume variance' }, - - { 'key': 'pitch_variance', - 'type': 'DWORD', - 'off': 0x000E, - 'label': 'Pitch variance' }, - - { 'key': 'string_offset', - 'type': 'DWORD', - 'off': 0x0012, - 'label': 'String data rel offset' }, + { 'key': 'string_offset', + 'type': 'DWORD', + 'off': 0x0012, + 'label': 'String data rel offset' }, - { 'key': 'string_len', - 'type': 'DWORD', - 'off': 0x0016, - 'label': 'String data size' }, + { 'key': 'string_len', + 'type': 'DWORD', + 'off': 0x0016, + 'label': 'String data size' }, - { 'key': 'string', - 'type': '_STRING', - 'off': 0x0000, - 'label': 'String' }, + { 'key': 'string', + 'type': '_STRING', + 'off': 0x0000, + 'label': 'String' }, - ) + ) + def __init__ (self): + Format.__init__ (self) + + self.expect_signature = 'TLK' - def decode_file (self): - self.decode_header () + self.strref_list = [] + + def read (self, stream): + self.read_header (stream) + off = 0x0012 if not self.get_option ('tlk_decode_strrefs'): @@ -112,7 +112,7 @@ for i in range (self.header['num_of_strrefs']): obj = {} - self.decode_strref_record (off, obj) + self.read_strref_record (stream, off, obj) self.strref_list.append (obj) off = off + 26 @@ -123,8 +123,28 @@ sys.stdout.flush () print + def write (self, stream): + self.header['num_strings'] = len (self.strref_list) + self.header['string_offset'] = self.get_struc_size (self.header_desc, self.header) + len (self.strref_list) * self.get_struc_size (self.strref_record_desc, None) + self.write_struc (stream, 0x0000, self.header_desc, self.header) + + strref_offset = self.get_struc_size (self.header_desc, self.header) + string_offset = 0 + strref_size = self.get_struc_size (self.strref_record_desc, None) + for strref in self.strref_list: + # FIXME: possibly test strref type instead + if len (strref['string']) != 0: + strref['string_offset'] = string_offset + stream.write_sized_string (strref['string'], self.header['string_offset'] + string_offset, len (strref['string'])) + else: + strref['string_offset'] = 0 + self.write_struc (stream, strref_offset, sel... [truncated message content] |
From: <edh...@us...> - 2008-03-05 23:56:06
|
Revision: 5111 http://gemrb.svn.sourceforge.net/gemrb/?rev=5111&view=rev Author: edheldil Date: 2008-03-05 15:56:08 -0800 (Wed, 05 Mar 2008) Log Message: ----------- Renamed python package ie_shell to infinity Added Paths: ----------- ie_shell/branches/iesh-infinity/infinity/ ie_shell/branches/iesh-infinity/infinity/__init__.py ie_shell/branches/iesh-infinity/infinity/builtins.py ie_shell/branches/iesh-infinity/infinity/core.py ie_shell/branches/iesh-infinity/infinity/formats/ Removed Paths: ------------- ie_shell/branches/iesh-infinity/ie_shell/ ie_shell/branches/iesh-infinity/infinity/__init__.py ie_shell/branches/iesh-infinity/infinity/builtins.py ie_shell/branches/iesh-infinity/infinity/core.py ie_shell/branches/iesh-infinity/infinity/formats/ Copied: ie_shell/branches/iesh-infinity/infinity (from rev 5109, ie_shell/branches/iesh-infinity/ie_shell) Deleted: ie_shell/branches/iesh-infinity/infinity/__init__.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/__init__.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/infinity/__init__.py 2008-03-05 23:56:08 UTC (rev 5111) @@ -1 +0,0 @@ - Copied: ie_shell/branches/iesh-infinity/infinity/__init__.py (from rev 5110, ie_shell/branches/iesh-infinity/ie_shell/__init__.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/__init__.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/__init__.py 2008-03-05 23:56:08 UTC (rev 5111) @@ -0,0 +1 @@ + Deleted: ie_shell/branches/iesh-infinity/infinity/builtins.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/builtins.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-03-05 23:56:08 UTC (rev 5111) @@ -1,148 +0,0 @@ -#-*-python-*- - -import os.path - -from ie_shell import core -from ie_shell.formats.stream import ResourceStream, FileStream - -################################################### -def load_game (game_dir, chitin_file = core.chitin_file, dialog_file = core.dialog_file): - """Loads key and dialog files from the specified directory. - The directory parameter is mandatory, the others are optional. - Most of the other commands assume that these two files are - already loaded. The loaded objects are stored in core.keys and - core.strrefs.""" - - core.game_dir = game_dir - core.chitin_file = chitin_file - core.dialog_file = dialog_file - - # Load RESREF index file (CHITIN.KEY) - core.keys = core.get_format ('KEY') (os.path.join (game_dir, chitin_file)) - core.keys.decode_header () - print "Loading %d file refs and %d RESREFs. This may take ages" %(core.keys.header['num_of_bifs'], core.keys.header['num_of_resrefs']) - core.keys.decode_file () - - - # LOAD STRREF index file (DIALOG.TLK) - core.strrefs = core.get_format ('TLK') (os.path.join (game_dir, dialog_file)) - core.strrefs.decode_header () - print "Loading %d STRREFs. This may take eternity" %(core.strrefs.header['num_of_strrefs']) - core.strrefs.decode_file () - - -################################################### -def load_object (name, type = None): - - try: - fh = open (name) - except: - fh = None - - if fh: - fh.close () - return FileStream(name).load_object () - else: - return ResourceStream(name, type).load_object () - - -################################################### -def find_str (text): - """Finds all strings in loaded DIALOG.TLK file matching regular expression - and prints their STRREFs""" - - for o in core.strrefs.get_strref_by_str_re(text): - print core.strrefs.strref_list.index(o), o['string'] - -################################################### -def export_obj (name, filename, type = None, index = 0): - """Exports resource `name' into file `filename'. If the `name' is not - unique, specify resource type with `type' and eventually `index' if - there's still more than one""" - - oo = core.keys.get_resref_by_name_re(name) - if type != None: - oo = filter (lambda o: o['type'] == type, oo) - - if len (oo) > 1 and type == None: - print "More than one result" - return - - o = oo[index] - - src_file = core.keys.bif_list[o['locator_src_ndx']] - b = core.formats['BIFF'] (os.path.join (core.game_dir, src_file['file_name'])) - b.decode_file () - b.save_file_data (filename, b.file_list[o['locator_ntset_ndx']]) - - -################################################### -def iterate_objects_by_type (type, fn): - - # FIXME: this function opens and decodes a bif file EACH time some - # object from it is accessed, so it's slow as hell. It should use - # some caching - - #def resref_to_obj (res): - # print res['resref_name'] - # return ResourceStream (res['resref_name'], type).load_object () - - for res in filter (lambda res: res['type'] == type, core.keys.resref_list): - print res['resref_name'] - obj = ResourceStream (res['resref_name'], type).load_object () - fn (obj) - - -################################################### -def sprintf (format_str, params): - return format_str %(params) - -def printf (format_str, params): - print sprintf (format_str, params) - -def loaded_object (obj): - obj.decode_file () - return obj - -################################################### -def pok(): - def p (obj): - obj.decode_file () - obj.print_file () - - iterate_objects_by_type (0x03ed, p) - -################################################### -def load_ids (): - def p (obj): - obj.decode_file () - print obj.stream.resref - #obj.print_file () - - iterate_objects_by_type (0x03f0, p) - -################################################### -def get_restype_stats (): - stats = {} - for o in core.keys.resref_list: - if not stats.has_key (o['type']): - stats[o['type']] = 1 - else: - stats[o['type']] = stats[o['type']] + 1 - - return stats - - -################################################### -def print_restype_stats (): - stats = get_restype_stats () - for s in stats.keys (): - if core.restype_hash.has_key (s): - type = core.restype_hash[s] - else: - type = '??' - print "0x%04x (%s):\t%5d" %(s, type, stats[s]) - - -################################################### -# End of file builtins.py Copied: ie_shell/branches/iesh-infinity/infinity/builtins.py (from rev 5110, ie_shell/branches/iesh-infinity/ie_shell/builtins.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/builtins.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-03-05 23:56:08 UTC (rev 5111) @@ -0,0 +1,154 @@ +#-*-python-*- + +import os.path + +from ie_shell import core +from ie_shell.formats.stream import ResourceStream, FileStream + +################################################### +def load_game (game_dir, chitin_file = core.chitin_file, dialog_file = core.dialog_file): + """Loads key and dialog files from the specified directory. + The directory parameter is mandatory, the others are optional. + Most of the other commands assume that these two files are + already loaded. The loaded objects are stored in core.keys and + core.strrefs.""" + + core.game_dir = game_dir + core.chitin_file = chitin_file + core.dialog_file = dialog_file + + # Load RESREF index file (CHITIN.KEY) + core.keys = core.get_format ('KEY') (os.path.join (game_dir, chitin_file)) + core.keys.decode_header () + print "Loading %d file refs and %d RESREFs. This may take ages" %(core.keys.header['num_of_bifs'], core.keys.header['num_of_resrefs']) + core.keys.decode_file () + + + # LOAD STRREF index file (DIALOG.TLK) + core.strrefs = core.get_format ('TLK') (os.path.join (game_dir, dialog_file)) + core.strrefs.decode_header () + print "Loading %d STRREFs. This may take eternity" %(core.strrefs.header['num_of_strrefs']) + core.strrefs.decode_file () + + +################################################### +def load_object (name, type = None): + + try: + fh = open (name) + except: + fh = None + + if fh: + fh.close () + return FileStream(name).load_object () + else: + return ResourceStream(name, type).load_object () + +################################################### +def print_file (filename, type = None): + fs = FileStream ().open (filename) + obj = fs.load_object (type) + obj.printme () + return obj + +################################################### +def find_str (text): + """Finds all strings in loaded DIALOG.TLK file matching regular expression + and prints their STRREFs""" + + for o in core.strrefs.get_strref_by_str_re(text): + print core.strrefs.strref_list.index(o), o['string'] + +################################################### +def export_obj (name, filename, type = None, index = 0): + """Exports resource `name' into file `filename'. If the `name' is not + unique, specify resource type with `type' and eventually `index' if + there's still more than one""" + + oo = core.keys.get_resref_by_name_re(name) + if type != None: + oo = filter (lambda o: o['type'] == type, oo) + + if len (oo) > 1 and type == None: + print "More than one result" + return + + o = oo[index] + + src_file = core.keys.bif_list[o['locator_src_ndx']] + b = core.formats['BIFF'] (os.path.join (core.game_dir, src_file['file_name'])) + b.decode_file () + b.save_file_data (filename, b.file_list[o['locator_ntset_ndx']]) + + +################################################### +def iterate_objects_by_type (type, fn): + + # FIXME: this function opens and decodes a bif file EACH time some + # object from it is accessed, so it's slow as hell. It should use + # some caching + + #def resref_to_obj (res): + # print res['resref_name'] + # return ResourceStream (res['resref_name'], type).load_object () + + for res in filter (lambda res: res['type'] == type, core.keys.resref_list): + print res['resref_name'] + obj = ResourceStream (res['resref_name'], type).load_object () + fn (obj) + + +################################################### +def sprintf (format_str, params): + return format_str %(params) + +def printf (format_str, params): + print sprintf (format_str, params) + +def loaded_object (obj): + obj.decode_file () + return obj + +################################################### +def pok(): + def p (obj): + obj.decode_file () + obj.print_file () + + iterate_objects_by_type (0x03ed, p) + +################################################### +def load_ids (): + def p (obj): + obj.decode_file () + print obj.stream.resref + #obj.print_file () + + iterate_objects_by_type (0x03f0, p) + +################################################### +def get_restype_stats (): + stats = {} + for o in core.keys.resref_list: + if not stats.has_key (o['type']): + stats[o['type']] = 1 + else: + stats[o['type']] = stats[o['type']] + 1 + + return stats + + +################################################### +def print_restype_stats (): + stats = get_restype_stats () + for s in stats.keys (): + if core.restype_hash.has_key (s): + type = core.restype_hash[s] + else: + type = '??' + print "0x%04x (%s):\t%5d" %(s, type, stats[s]) + + +################################################### +# End of file builtins.py Deleted: ie_shell/branches/iesh-infinity/infinity/core.py =================================================================== --- ie_shell/branches/iesh-infinity/ie_shell/core.py 2008-03-05 22:53:57 UTC (rev 5109) +++ ie_shell/branches/iesh-infinity/infinity/core.py 2008-03-05 23:56:08 UTC (rev 5111) @@ -1,177 +0,0 @@ -# -*-python-*- - -import string - - -global formats -formats = {} - -global strrefs -strrefs = None - -global keys -keys = None - -global options -options = {} - -# Loaded IDS files -global ids -ids = {} - -game_dir = None -chitin_file = 'CHITIN.KEY' -dialog_file = 'dialog.tlk' - -xor_key = "\x88\xa8\x8f\xba\x8a\xd3\xb9\xf5\xed\xb1\xcf\xea\xaa\xe4\xb5\xfb\xeb\x82\xf9\x90\xca\xc9\xb5\xe7\xdc\x8e\xb7\xac\xee\xf7\xe0\xca\x8e\xea\xca\x80\xce\xc5\xad\xb7\xc4\xd0\x84\x93\xd5\xf0\xeb\xc8\xb4\x9d\xcc\xaf\xa5\x95\xba\x99\x87\xd2\x9d\xe3\x91\xba\x90\xca" - - -global slash_trans -slash_trans = string.maketrans ('\\', '/') - -t_cp1250 = '\xE1\xE8\xEF\xE9\xEC\xED\xF2\xF3\xF8\x9A\x9D\xFA\xF9\xFD\x9E\xC1\xC8\xCF\xC9\xCC\xCD\xD2\xD3؊\x8D\xDA\xD9ݎ' -t_iso8859_2 = '\xE1\xE8\xEF\xE9\xEC\xED\xF2\xF3\xF8\xB9\xBB\xFA\xF9\xFD\xBE\xC1\xC8\xCF\xC9\xCC\xCD\xD2\xD3ة\xAB\xDA\xD9ݮ' - -global lang_trans -lang_trans = string.maketrans (t_cp1250, t_iso8859_2) - -def translate_to_iso (s): - return string.translate (s, lang_trans) - -def cond (c, a, b): - if c: return a - else: return b - -def translate_to_ord (s): - return map (lambda c: (cond (ord (c) < 128, c, "\\x%02X" %(ord (c))), s)) - -restype_list = [ - [0x0001, 'BMP', ''], - [0x0002, 'MVE', ''], - [0x0004, 'WAV', ''], - [0x0004, 'WAVC', ''], - [0x0005, 'WFX', ''], - [0x0006, 'PLT', ''], - [0x03e8, 'BAM', ''], - [0x03e8, 'BAMC', ''], - [0x03e9, 'WED', ''], - [0x03ea, 'CHUI', ''], - [0x03eb, 'TIS', ''], - [0x03ec, 'MOS', ''], - [0x03ec, 'MOSC', ''], - [0x03ed, 'ITM', ''], - [0x03ee, 'SPL', ''], - [0x03ef, 'BCS', ''], - [0x03f0, 'IDS', ''], - [0x03f1, 'CRE', ''], - [0x03f2, 'ARE', ''], - [0x03f3, 'DLG', ''], - [0x03f4, '2DA', ''], - [0x03f5, 'GAME', ''], - [0x03f6, 'STOR', ''], - [0x03f7, 'WMAP', ''], - [0x03f8, 'CHR', ''], - [0x03f8, 'EFF', ''], - [0x03f9, 'BS', ''], - [0x03fa, 'CHR', ''], - [0x03fb, 'VVC', ''], - [0x03fc, 'VEF', ''], - [0x03fd, 'PRO', ''], - [0x03fe, 'BIO', ''], - [0x044c, 'BAH', ''], - [0x0802, 'INI', ''], - [0x0803, 'SRC', ''], - ] - -restype_hash = { - 0x0001 : 'BMP', - 0x0002 : 'MVE', - 0x0004 : 'WAV', # also WAVC - 0x0005 : 'WFX', - 0x0006 : 'PLT', - 0x03e8 : 'BAM', # also BAMC - 0x03e9 : 'WED', - 0x03ea : 'CHUI', - 0x03eb : 'TIS', - 0x03ec : 'MOS', # also MOSC - 0x03ed : 'ITM', - 0x03ee : 'SPL', - 0x03ef : 'BCS', - 0x03f0 : 'IDS', - 0x03f1 : 'CRE', - 0x03f2 : 'ARE', - 0x03f3 : 'DLG', - 0x03f4 : '2DA', - 0x03f5 : 'GAME', - 0x03f6 : 'STOR', - 0x03f7 : 'WMAP', - 0x03f8 : 'CHR', # also EFF - 0x03f9 : 'BS', - 0x03fa : 'CHR', - 0x03fb : 'VVC', - 0x03fc : 'VEF', - 0x03fd : 'PRO', - 0x03fe : 'BIO', - 0x044c : 'BAH', - 0x0802 : 'INI', - 0x0803 : 'SRC', - } - -restype_rev_hash = { - '2DA' : 0x03f4, - 'ARE' : 0x03f2, - 'BAH' : 0x044c, - 'BAM' : 0x03e8, - 'BAMC' : 0x03e8, - 'BCS' : 0x03ef, - 'BIO' : 0x03fe, - 'BMP' : 0x0001, - 'BS' : 0x03f9, - 'CHR' : 0x03fa, - #'CHR' : 0x03f8, - 'CHUI' : 0x03ea, - 'CRE' : 0x03f1, - 'DLG' : 0x03f3, - 'EFF' : 0x03f8, - 'GAME' : 0x03f5, - 'IDS' : 0x03f0, - 'INI' : 0x0802, - 'ITM' : 0x03ed, - 'MOS' : 0x03ec, - 'MOSC' : 0x03ec, - 'MVE' : 0x0002, - 'PLT' : 0x0006, - 'PRO' : 0x03fd, - 'SPL' : 0x03ee, - 'SRC' : 0x0803, - 'STOR' : 0x03f6, - 'TIS' : 0x03eb, - 'VEF' : 0x03fc, - 'VVC' : 0x03fb, - 'WAV' : 0x0004, - 'WAVC' : 0x0004, - 'WED' : 0x03e9, - 'WFX' : 0x0005, - 'WMAP' : 0x03f7, - } - - -def register_format (signature, version, klass): - #core.formats[(signature, version)] = klass - formats[signature] = klass - - -def get_format (signature, version = None): - try: - return formats[signature] - except: - return None - - -def get_format_by_type (type): - try: - signature = restype_hash[type] - return get_format (signature) - except: - return None - Copied: ie_shell/branches/iesh-infinity/infinity/core.py (from rev 5110, ie_shell/branches/iesh-infinity/ie_shell/core.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/core.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/core.py 2008-03-05 23:56:08 UTC (rev 5111) @@ -0,0 +1,179 @@ +# -*-python-*- + +import string + + +global formats +formats = {} + +global strrefs +strrefs = None + +global keys +keys = None + +global options +options = {} + +# Loaded IDS files +global ids +ids = {} + +game_dir = None +chitin_file = 'CHITIN.KEY' +dialog_file = 'dialog.tlk' + +xor_key = "\x88\xa8\x8f\xba\x8a\xd3\xb9\xf5\xed\xb1\xcf\xea\xaa\xe4\xb5\xfb\xeb\x82\xf9\x90\xca\xc9\xb5\xe7\xdc\x8e\xb7\xac\xee\xf7\xe0\xca\x8e\xea\xca\x80\xce\xc5\xad\xb7\xc4\xd0\x84\x93\xd5\xf0\xeb\xc8\xb4\x9d\xcc\xaf\xa5\x95\xba\x99\x87\xd2\x9d\xe3\x91\xba\x90\xca" + + +global slash_trans +slash_trans = string.maketrans ('\\', '/') + +t_cp1250 = '\xe1\xe8\xef\xe9\xec\xed\xf2\xf3\xf8\x9a\x9d\xfa\xf9\xfd\x9e\xc1\xc8\xcf\xc9\xcc\xcd\xd2\xd3\xd8\x8a\x8d\xda\xd9\xdd\x8e' +t_iso8859_2 = '\xe1\xe8\xef\xe9\xec\xed\xf2\xf3\xf8\xb9\xbb\xfa\xf9\xfd\xbe\xc1\xc8\xcf\xc9\xcc\xcd\xd2\xd3\xd8\xa9\xab\xda\xd9\xdd\xae' + + + +global lang_trans +lang_trans = string.maketrans (t_cp1250, t_iso8859_2) + +def translate_to_iso (s): + return string.translate (s, lang_trans) + +def cond (c, a, b): + if c: return a + else: return b + +def translate_to_ord (s): + return map (lambda c: (cond (ord (c) < 128, c, "\\x%02X" %(ord (c))), s)) + +restype_list = [ + [0x0001, 'BMP', ''], + [0x0002, 'MVE', ''], + [0x0004, 'WAV', ''], + [0x0004, 'WAVC', ''], + [0x0005, 'WFX', ''], + [0x0006, 'PLT', ''], + [0x03e8, 'BAM', ''], + [0x03e8, 'BAMC', ''], + [0x03e9, 'WED', ''], + [0x03ea, 'CHUI', ''], + [0x03eb, 'TIS', ''], + [0x03ec, 'MOS', ''], + [0x03ec, 'MOSC', ''], + [0x03ed, 'ITM', ''], + [0x03ee, 'SPL', ''], + [0x03ef, 'BCS', ''], + [0x03f0, 'IDS', ''], + [0x03f1, 'CRE', ''], + [0x03f2, 'ARE', ''], + [0x03f3, 'DLG', ''], + [0x03f4, '2DA', ''], + [0x03f5, 'GAME', ''], + [0x03f6, 'STOR', ''], + [0x03f7, 'WMAP', ''], + [0x03f8, 'CHR', ''], + [0x03f8, 'EFF', ''], + [0x03f9, 'BS', ''], + [0x03fa, 'CHR', ''], + [0x03fb, 'VVC', ''], + [0x03fc, 'VEF', ''], + [0x03fd, 'PRO', ''], + [0x03fe, 'BIO', ''], + [0x044c, 'BAH', ''], + [0x0802, 'INI', ''], + [0x0803, 'SRC', ''], + ] + +restype_hash = { + 0x0001 : 'BMP', + 0x0002 : 'MVE', + 0x0004 : 'WAV', # also WAVC + 0x0005 : 'WFX', + 0x0006 : 'PLT', + 0x03e8 : 'BAM', # also BAMC + 0x03e9 : 'WED', + 0x03ea : 'CHUI', + 0x03eb : 'TIS', + 0x03ec : 'MOS', # also MOSC + 0x03ed : 'ITM', + 0x03ee : 'SPL', + 0x03ef : 'BCS', + 0x03f0 : 'IDS', + 0x03f1 : 'CRE', + 0x03f2 : 'ARE', + 0x03f3 : 'DLG', + 0x03f4 : '2DA', + 0x03f5 : 'GAME', + 0x03f6 : 'STOR', + 0x03f7 : 'WMAP', + 0x03f8 : 'CHR', # also EFF + 0x03f9 : 'BS', + 0x03fa : 'CHR', + 0x03fb : 'VVC', + 0x03fc : 'VEF', + 0x03fd : 'PRO', + 0x03fe : 'BIO', + 0x044c : 'BAH', + 0x0802 : 'INI', + 0x0803 : 'SRC', + } + +restype_rev_hash = { + '2DA' : 0x03f4, + 'ARE' : 0x03f2, + 'BAH' : 0x044c, + 'BAM' : 0x03e8, + 'BAMC' : 0x03e8, + 'BCS' : 0x03ef, + 'BIO' : 0x03fe, + 'BMP' : 0x0001, + 'BS' : 0x03f9, + 'CHR' : 0x03fa, + #'CHR' : 0x03f8, + 'CHUI' : 0x03ea, + 'CRE' : 0x03f1, + 'DLG' : 0x03f3, + 'EFF' : 0x03f8, + 'GAME' : 0x03f5, + 'IDS' : 0x03f0, + 'INI' : 0x0802, + 'ITM' : 0x03ed, + 'MOS' : 0x03ec, + 'MOSC' : 0x03ec, + 'MVE' : 0x0002, + 'PLT' : 0x0006, + 'PRO' : 0x03fd, + 'SPL' : 0x03ee, + 'SRC' : 0x0803, + 'STOR' : 0x03f6, + 'TIS' : 0x03eb, + 'VEF' : 0x03fc, + 'VVC' : 0x03fb, + 'WAV' : 0x0004, + 'WAVC' : 0x0004, + 'WED' : 0x03e9, + 'WFX' : 0x0005, + 'WMAP' : 0x03f7, + } + + +def register_format (signature, version, klass): + #core.formats[(signature, version)] = klass + formats[signature] = klass + + +def get_format (signature, version = None): + try: + return formats[signature] + except: + return None + + +def get_format_by_type (type): + try: + signature = restype_hash[type] + return get_format (signature) + except: + return None + Copied: ie_shell/branches/iesh-infinity/infinity/formats (from rev 5110, ie_shell/branches/iesh-infinity/ie_shell/formats) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <edh...@us...> - 2008-03-06 00:29:52
|
Revision: 5113 http://gemrb.svn.sourceforge.net/gemrb/?rev=5113&view=rev Author: edheldil Date: 2008-03-05 16:29:55 -0800 (Wed, 05 Mar 2008) Log Message: ----------- * Leave only actual format classes in the formats package * Move others to infinity package * Correct the imports and distutils file Modified Paths: -------------- ie_shell/branches/iesh-infinity/iesh ie_shell/branches/iesh-infinity/infinity/formats/__init__.py ie_shell/branches/iesh-infinity/infinity/formats/are.py ie_shell/branches/iesh-infinity/infinity/formats/bam.py ie_shell/branches/iesh-infinity/infinity/formats/biff.py ie_shell/branches/iesh-infinity/infinity/formats/chui.py ie_shell/branches/iesh-infinity/infinity/formats/cre.py ie_shell/branches/iesh-infinity/infinity/formats/dlg.py ie_shell/branches/iesh-infinity/infinity/formats/ids.py ie_shell/branches/iesh-infinity/infinity/formats/itm.py ie_shell/branches/iesh-infinity/infinity/formats/key.py ie_shell/branches/iesh-infinity/infinity/formats/pro.py ie_shell/branches/iesh-infinity/infinity/formats/spl.py ie_shell/branches/iesh-infinity/infinity/formats/tis.py ie_shell/branches/iesh-infinity/infinity/formats/tlk.py ie_shell/branches/iesh-infinity/infinity/formats/vvc.py ie_shell/branches/iesh-infinity/infinity/formats/wed.py ie_shell/branches/iesh-infinity/infinity/formats/wfx.py ie_shell/branches/iesh-infinity/infinity/formats/wmap.py ie_shell/branches/iesh-infinity/setup.py Added Paths: ----------- ie_shell/branches/iesh-infinity/infinity/dtypes.py ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/stream.py Removed Paths: ------------- ie_shell/branches/iesh-infinity/infinity/formats/dtypes.py ie_shell/branches/iesh-infinity/infinity/formats/format.py ie_shell/branches/iesh-infinity/infinity/formats/stream.py Modified: ie_shell/branches/iesh-infinity/iesh =================================================================== --- ie_shell/branches/iesh-infinity/iesh 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/iesh 2008-03-06 00:29:55 UTC (rev 5113) @@ -26,11 +26,11 @@ import sys import traceback -from ie_shell import core -from ie_shell.builtins import * +from infinity import core +from infinity.builtins import * +from infinity.stream import * -from ie_shell.formats import * -from ie_shell.formats.stream import * +from infinity.formats import * ################################################### IESH_NORMAL_PROMPT = 'Cmd: ' Copied: ie_shell/branches/iesh-infinity/infinity/dtypes.py (from rev 5111, ie_shell/branches/iesh-infinity/infinity/formats/dtypes.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/dtypes.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/dtypes.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -0,0 +1,36 @@ +# -*-python-*- + +dtypes = {} + +class IE_Type: + def __init__ (self): + pass + + def repr (self, value, *args): + return str (value) + + def read (self, stream, offset): + return None + + def write (self, stream, offset, value): + pass + + def size (self, value): + return 0 + +class IE_WORD (IEType): + def read (self, stream, offset): + stream.read () + +class IE_STRING (IE_Type): + pass + +class IE_RESREF (IE_STRING): + pass + +# FIXME: read/write/ etc should be class methods, perhaps? + +dtypes = { + 'STRING': IE_STRING (), + 'RESREF': IE_RESREF, + } Copied: ie_shell/branches/iesh-infinity/infinity/format.py (from rev 5111, ie_shell/branches/iesh-infinity/infinity/formats/format.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -0,0 +1,368 @@ +# -*-python-*- +# ie_shell.py - Simple shell for Infinity Engine-based game files +# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# RCS: $Id: format.py,v 1.5 2006/07/08 14:29:26 edheldil Exp $ + +import os.path +import re +import string +import struct +import types + +from infinity import core +from infinity.stream import Stream, FileStream, ResourceStream + +PAGE_SIZE = 4096 + +TICK_SIZE = 100 +TACK_SIZE = 5000 + +def ResolveFilePath (filename): + if os.path.isfile (filename): + return filename + + + + +class Format: + + default_options = {} + + def __init__ (self): + self.header_size = 0 + self.bitmask_cache = {} + self.options = {} + +## def load (self, source): +## if source != None: +## if not isinstance (source, Stream): +## source = FileStream (source) + +## self.stream = source +## if not source.is_open: +## source.open (mode) + +## self.stream = source + + + def get_masked_bits (self, value, mask, bl): + return (value & mask) >> bl + + # FIXME: cache it globally ... + def bits_to_mask (self, bits): + try: + return self.bitmask_cache[bits] + except: + bh, bl = map (int, string.split (bits, '-')) + if bl > bh: + print "warning: bh < bl:", bits + bh, bl = bl, bh + + mask = 0L + for i in range (bl, bh + 1): + mask = mask | (1L << i) + + #print "MASK: 0x%08x\n" %mask + + self.bitmask_cache[bits] = (mask, bl) + return mask, bl + + + # { 'key': '', 'type': '', 'off': 0x00, 'label': '' }, + + def reset_struc (self, desc, obj): + for d in desc: + key = d['key'] + type = d['type'] + try: + value = d['default'] + except: + if type in ('BYTE', 'WORD', 'DWORD', 'CTLTYPE', 'CTLID', 'RGBA', 'STRREF', 'RESTYPE'): + value = 0 + elif type in ('STR2', 'STR4', 'STR8', 'STR32', 'RESREF', 'STRSIZED'): + value = '' + else: + raise Error ("Unknown type") + + # FIXME: bit masks + obj[key] = value + + return obj + + def read_struc (self, stream, offset, desc, obj): + for d in desc: + key = d['key'] + type = d['type'] + local_offset = d['off'] + + if self.get_option ('debug_read'): + print d + + if type == 'BYTE': + value = ord (stream.get_char (offset + local_offset)) + elif type == 'CTLTYPE': + value = ord (stream.get_char (offset + local_offset)) + elif type == 'WORD': + value = stream.decode_word (offset + local_offset) + elif type == 'DWORD': + value = stream.decode_dword (offset + local_offset) + elif type == 'CTLID': + value = stream.decode_dword (offset + local_offset) + elif type == 'RGBA': + value = stream.decode_dword (offset + local_offset) + elif type == 'STR2': + value = stream.decode_sized_string (offset + local_offset, 2) + elif type == 'STR4': + value = stream.decode_sized_string (offset + local_offset, 4) + elif type == 'STR8': + value = stream.decode_sized_string (offset + local_offset, 8) + elif type == 'STR32': + value = stream.decode_sized_string (offset + local_offset, 32) + elif type == 'RESREF': + value = stream.decode_resref (offset + local_offset) + value = string.translate (value, core.slash_trans, '\x00') + elif type == 'STRREF': + value = stream.decode_dword (offset + local_offset) + elif type == 'RESTYPE': + value = stream.decode_word (offset + local_offset) + elif type == 'STROFF': + stroff = stream.decode_dword (offset + local_offset) + value = stream.decode_asciiz_string (stroff) + value = string.translate (value, core.slash_trans, '\x00') + elif type == 'STRSIZED': + length = stream.decode_dword (offset + local_offset) + # FIXME: asciiz or sized??? + value = stream.decode_asciiz_string (offset + local_offset + 4) + elif type == 'BYTES': + value = stream.decode_blob (offset + local_offset, d['size']) + elif type == '_STRING': + value = '' + elif type == '_BYTE': + value = '?' + else: + raise ValueError ("Unknown data type: " + type) + #value = '' + + if d.has_key ('bits'): + mask, bl = self.bits_to_mask (d['bits']) + value = self.get_masked_bits (value, mask, bl) + + obj[key] = value + + if self.get_option ('debug_read'): + self.print_date_by_desc (obj, d) + + + def print_struc (self, obj, desc): + for d in desc: + self.print_date_by_desc (obj, d) + print + + def write_struc (self, stream, offset, desc, obj): + for d in desc: + key = d['key'] + type = d['type'] + local_offset = d['off'] + + value = obj[key] + + if self.get_option ('debug_write'): + print '%05d' %(offset + local_offset), d, value + + if type == 'BYTE': + stream.put_char (chr (value), offset + local_offset) + elif type == 'CTLTYPE': + stream.put_char (chr (value), offset + local_offset) + elif type == 'WORD': + stream.write_word (value, offset + local_offset) + elif type == 'DWORD': + stream.write_dword (value, offset + local_offset) + elif type == 'CTLID': + stream.write_dword (value, offset + local_offset) + elif type == 'RGBA': + stream.write_dword (value, offset + local_offset) + elif type == 'STR2': + stream.write_sized_string (value, offset + local_offset, 2) + elif type == 'STR4': + stream.write_sized_string (value, offset + local_offset, 4) + elif type == 'STR8': + stream.write_sized_string (value, offset + local_offset, 8) + elif type == 'STR32': + stream.write_sized_string (value, offset + local_offset, 32) + elif type == 'RESREF': + # FIXME: value = string.translate (value, core.slash_trans, '\x00') + stream.write_resref (value, offset + local_offset) + elif type == 'STRREF': + stream.write_dword (value, offset + local_offset) + elif type == 'RESTYPE': + stream.write_word (value, offset + local_offset) + elif type == 'STROFF': + raise RuntimeError (type + " not implemented") + elif type == 'STRSIZED': + # FIXME: encoding + stream.write_dword (len (value), offset + local_offset) + stream.write_sized_string (value, offset + local_offset, len (value)) + elif type == 'BYTES': + value = stream.write_blob (value, offset + local_offset) + elif type.startswith ('_'): + pass + else: + raise ValueError ("Unknown data type: " + type) + + def get_struc_size (self, desc, obj = None): + total_size = 0 + + for d in desc: + key = d['key'] + type = d['type'] + local_offset = d['off'] + + + if type == 'BYTE': + size = 1 + elif type == 'CTLTYPE': + size = 1 + elif type == 'WORD': + size = 2 + elif type == 'DWORD': + size = 4 + elif type == 'CTLID': + size = 2 + elif type == 'RGBA': + size = 4 + elif type == 'STR2': + size = 2 + elif type == 'STR4': + size = 4 + elif type == 'STR8': + size = 8 + elif type == 'STR32': + size = 32 + elif type == 'RESREF': + size = 8 + elif type == 'STRREF': + size = 4 + elif type == 'RESTYPE': + size = 2 + elif type == 'STROFF': + raise RuntimeError (type + " not implemented") + elif type == 'STRSIZED': + # FIXME: encoding + value = obj[key] + size = 4 + len (value) + elif type == 'BYTES': + value = obj[key] + size = len (value) + elif type.startswith ('_'): + # Ignore the fields starting with '_' + size = 0 + else: + raise ValueError ("Unknown data type: " + type) + + total_size = max (total_size, local_offset + size) + + return total_size + + + def print_date_by_desc (self, obj, d): + key = d['key'] + rec_type = d['type'] + label = d['label'] + + try: enum = d['enum'] + except: enum = None + + try: mask = d['mask'] + except: mask = None + + value = obj[key] + value2 = '' + + if rec_type == 'RESTYPE': + try: value2 = '(' + core.restype_hash[value] + ')' + except: pass + elif rec_type == 'CTLTYPE': + try: value2 = '(' + ctltype_hash[value] + ')' + except: pass + elif rec_type == 'CTLID': + try: value2 = '(' + '0x%08x' %value + ')' + except: pass + elif rec_type == 'STRREF' and core.strrefs: + try: value2 = '(' + core.strrefs.strref_list[value]['string'] + ')' + except: pass + elif rec_type == 'RGBA': + try: value2 = '(' + '%08x' %value + ')' + except: pass + elif enum != None: + if type (enum) == types.DictType: + try: value2 = '(' + enum[value] + ')' + except: pass + + elif type (enum) == types.StringType: + if not core.ids.has_key (enum): + try: + # FIXME: ugly & should use 'IDS' instead of 0x3F0 + ids = ResourceStream (enum, 0x03F0).load_object () + ids.decode_file () + core.ids[enum] = ids + except: + pass + + try: value2 = '(' + core.ids[enum].ids[value] + ')' + except: pass + + + elif mask != None: + value2 = '(' + string.join (map (lambda m, mask=mask: mask[m], filter (lambda m, v=value: (m & v) == m, mask.keys ())), '|') + ')' + + print label + ':', value, value2 + + + def set_option_default (key, value): + Format.default_options[key] = value + + def set_option (self, key, value): + self.options[key] = value + + def get_option (self, key): + if self.options.has_key (key): + return self.options[key] + elif core.options.has_key (key): + return core.options[key] + else: + return Format.default_options[key] + + +Format.default_options['debug_read'] = 0 +Format.default_options['debug_write'] = 0 + + + +ctltype_hash = { + 0 : 'button/pixmap', + 2 : 'slider', + 3 : 'textedit', + 5 : 'textarea', + 6 : 'label?', + 7 : 'scrollbar', + } + + + +def register_format (signature, version, klass): + core.register_format (signature, version, klass) Modified: ie_shell/branches/iesh-infinity/infinity/formats/__init__.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -1,7 +1,5 @@ # -*-python-*- -import format - import are import bam import biff Modified: ie_shell/branches/iesh-infinity/infinity/formats/are.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: pro.py,v 1.1 2006/07/08 14:29:26 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class ARE_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/bam.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/bam.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/bam.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -21,8 +21,8 @@ import struct import sys -from ie_shell.formats.format import Format, register_format -from ie_shell.formats.stream import CompressedStream +from infinity.format import Format, register_format +from infinity.stream import CompressedStream class BAM_Format (Format): Modified: ie_shell/branches/iesh-infinity/infinity/formats/biff.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -19,7 +19,7 @@ # RCS: $Id: biff.py,v 1.3 2006/07/08 14:29:26 edheldil Exp $ import gzip -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format class BIFF_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/chui.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/chui.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/chui.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,7 @@ # RCS: $Id: chui.py,v 1.1 2005/03/02 20:44:22 edheldil Exp $ -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format class CHUI_Format (Format): header_desc = ( Modified: ie_shell/branches/iesh-infinity/infinity/formats/cre.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,7 @@ # RCS: $Id: cre.py,v 1.3 2006/07/03 18:15:35 edheldil Exp $ -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format # FIXME: incomplete! Modified: ie_shell/branches/iesh-infinity/infinity/formats/dlg.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/dlg.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/dlg.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: dlg.py,v 1.1 2006/07/03 18:15:35 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class DLG_Format (Format): def __init__ (self, filename): Deleted: ie_shell/branches/iesh-infinity/infinity/formats/dtypes.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/dtypes.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/dtypes.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -1,36 +0,0 @@ -# -*-python-*- - -dtypes = {} - -class IE_Type: - def __init__ (self): - pass - - def repr (self, value, *args): - return str (value) - - def read (self, stream, offset): - return None - - def write (self, stream, offset, value): - pass - - def size (self, value): - return 0 - -class IE_WORD (IEType): - def read (self, stream, offset): - stream.read () - -class IE_STRING (IE_Type): - pass - -class IE_RESREF (IE_STRING): - pass - -# FIXME: read/write/ etc should be class methods, perhaps? - -dtypes = { - 'STRING': IE_STRING (), - 'RESREF': IE_RESREF, - } Deleted: ie_shell/branches/iesh-infinity/infinity/formats/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/format.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/format.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -1,368 +0,0 @@ -# -*-python-*- -# ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> -# -# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# RCS: $Id: format.py,v 1.5 2006/07/08 14:29:26 edheldil Exp $ - -import os.path -import re -import string -import struct -import types - -from ie_shell import core -from ie_shell.formats.stream import Stream, FileStream, ResourceStream - -PAGE_SIZE = 4096 - -TICK_SIZE = 100 -TACK_SIZE = 5000 - -def ResolveFilePath (filename): - if os.path.isfile (filename): - return filename - - - - -class Format: - - default_options = {} - - def __init__ (self): - self.header_size = 0 - self.bitmask_cache = {} - self.options = {} - -## def load (self, source): -## if source != None: -## if not isinstance (source, Stream): -## source = FileStream (source) - -## self.stream = source -## if not source.is_open: -## source.open (mode) - -## self.stream = source - - - def get_masked_bits (self, value, mask, bl): - return (value & mask) >> bl - - # FIXME: cache it globally ... - def bits_to_mask (self, bits): - try: - return self.bitmask_cache[bits] - except: - bh, bl = map (int, string.split (bits, '-')) - if bl > bh: - print "warning: bh < bl:", bits - bh, bl = bl, bh - - mask = 0L - for i in range (bl, bh + 1): - mask = mask | (1L << i) - - #print "MASK: 0x%08x\n" %mask - - self.bitmask_cache[bits] = (mask, bl) - return mask, bl - - - # { 'key': '', 'type': '', 'off': 0x00, 'label': '' }, - - def reset_struc (self, desc, obj): - for d in desc: - key = d['key'] - type = d['type'] - try: - value = d['default'] - except: - if type in ('BYTE', 'WORD', 'DWORD', 'CTLTYPE', 'CTLID', 'RGBA', 'STRREF', 'RESTYPE'): - value = 0 - elif type in ('STR2', 'STR4', 'STR8', 'STR32', 'RESREF', 'STRSIZED'): - value = '' - else: - raise Error ("Unknown type") - - # FIXME: bit masks - obj[key] = value - - return obj - - def read_struc (self, stream, offset, desc, obj): - for d in desc: - key = d['key'] - type = d['type'] - local_offset = d['off'] - - if self.get_option ('debug_read'): - print d - - if type == 'BYTE': - value = ord (stream.get_char (offset + local_offset)) - elif type == 'CTLTYPE': - value = ord (stream.get_char (offset + local_offset)) - elif type == 'WORD': - value = stream.decode_word (offset + local_offset) - elif type == 'DWORD': - value = stream.decode_dword (offset + local_offset) - elif type == 'CTLID': - value = stream.decode_dword (offset + local_offset) - elif type == 'RGBA': - value = stream.decode_dword (offset + local_offset) - elif type == 'STR2': - value = stream.decode_sized_string (offset + local_offset, 2) - elif type == 'STR4': - value = stream.decode_sized_string (offset + local_offset, 4) - elif type == 'STR8': - value = stream.decode_sized_string (offset + local_offset, 8) - elif type == 'STR32': - value = stream.decode_sized_string (offset + local_offset, 32) - elif type == 'RESREF': - value = stream.decode_resref (offset + local_offset) - value = string.translate (value, core.slash_trans, '\x00') - elif type == 'STRREF': - value = stream.decode_dword (offset + local_offset) - elif type == 'RESTYPE': - value = stream.decode_word (offset + local_offset) - elif type == 'STROFF': - stroff = stream.decode_dword (offset + local_offset) - value = stream.decode_asciiz_string (stroff) - value = string.translate (value, core.slash_trans, '\x00') - elif type == 'STRSIZED': - length = stream.decode_dword (offset + local_offset) - # FIXME: asciiz or sized??? - value = stream.decode_asciiz_string (offset + local_offset + 4) - elif type == 'BYTES': - value = stream.decode_blob (offset + local_offset, d['size']) - elif type == '_STRING': - value = '' - elif type == '_BYTE': - value = '?' - else: - raise ValueError ("Unknown data type: " + type) - #value = '' - - if d.has_key ('bits'): - mask, bl = self.bits_to_mask (d['bits']) - value = self.get_masked_bits (value, mask, bl) - - obj[key] = value - - if self.get_option ('debug_read'): - self.print_date_by_desc (obj, d) - - - def print_struc (self, obj, desc): - for d in desc: - self.print_date_by_desc (obj, d) - print - - def write_struc (self, stream, offset, desc, obj): - for d in desc: - key = d['key'] - type = d['type'] - local_offset = d['off'] - - value = obj[key] - - if self.get_option ('debug_write'): - print '%05d' %(offset + local_offset), d, value - - if type == 'BYTE': - stream.put_char (chr (value), offset + local_offset) - elif type == 'CTLTYPE': - stream.put_char (chr (value), offset + local_offset) - elif type == 'WORD': - stream.write_word (value, offset + local_offset) - elif type == 'DWORD': - stream.write_dword (value, offset + local_offset) - elif type == 'CTLID': - stream.write_dword (value, offset + local_offset) - elif type == 'RGBA': - stream.write_dword (value, offset + local_offset) - elif type == 'STR2': - stream.write_sized_string (value, offset + local_offset, 2) - elif type == 'STR4': - stream.write_sized_string (value, offset + local_offset, 4) - elif type == 'STR8': - stream.write_sized_string (value, offset + local_offset, 8) - elif type == 'STR32': - stream.write_sized_string (value, offset + local_offset, 32) - elif type == 'RESREF': - # FIXME: value = string.translate (value, core.slash_trans, '\x00') - stream.write_resref (value, offset + local_offset) - elif type == 'STRREF': - stream.write_dword (value, offset + local_offset) - elif type == 'RESTYPE': - stream.write_word (value, offset + local_offset) - elif type == 'STROFF': - raise RuntimeError (type + " not implemented") - elif type == 'STRSIZED': - # FIXME: encoding - stream.write_dword (len (value), offset + local_offset) - stream.write_sized_string (value, offset + local_offset, len (value)) - elif type == 'BYTES': - value = stream.write_blob (value, offset + local_offset) - elif type.startswith ('_'): - pass - else: - raise ValueError ("Unknown data type: " + type) - - def get_struc_size (self, desc, obj = None): - total_size = 0 - - for d in desc: - key = d['key'] - type = d['type'] - local_offset = d['off'] - - - if type == 'BYTE': - size = 1 - elif type == 'CTLTYPE': - size = 1 - elif type == 'WORD': - size = 2 - elif type == 'DWORD': - size = 4 - elif type == 'CTLID': - size = 2 - elif type == 'RGBA': - size = 4 - elif type == 'STR2': - size = 2 - elif type == 'STR4': - size = 4 - elif type == 'STR8': - size = 8 - elif type == 'STR32': - size = 32 - elif type == 'RESREF': - size = 8 - elif type == 'STRREF': - size = 4 - elif type == 'RESTYPE': - size = 2 - elif type == 'STROFF': - raise RuntimeError (type + " not implemented") - elif type == 'STRSIZED': - # FIXME: encoding - value = obj[key] - size = 4 + len (value) - elif type == 'BYTES': - value = obj[key] - size = len (value) - elif type.startswith ('_'): - # Ignore the fields starting with '_' - size = 0 - else: - raise ValueError ("Unknown data type: " + type) - - total_size = max (total_size, local_offset + size) - - return total_size - - - def print_date_by_desc (self, obj, d): - key = d['key'] - rec_type = d['type'] - label = d['label'] - - try: enum = d['enum'] - except: enum = None - - try: mask = d['mask'] - except: mask = None - - value = obj[key] - value2 = '' - - if rec_type == 'RESTYPE': - try: value2 = '(' + core.restype_hash[value] + ')' - except: pass - elif rec_type == 'CTLTYPE': - try: value2 = '(' + ctltype_hash[value] + ')' - except: pass - elif rec_type == 'CTLID': - try: value2 = '(' + '0x%08x' %value + ')' - except: pass - elif rec_type == 'STRREF' and core.strrefs: - try: value2 = '(' + core.strrefs.strref_list[value]['string'] + ')' - except: pass - elif rec_type == 'RGBA': - try: value2 = '(' + '%08x' %value + ')' - except: pass - elif enum != None: - if type (enum) == types.DictType: - try: value2 = '(' + enum[value] + ')' - except: pass - - elif type (enum) == types.StringType: - if not core.ids.has_key (enum): - try: - # FIXME: ugly & should use 'IDS' instead of 0x3F0 - ids = ResourceStream (enum, 0x03F0).load_object () - ids.decode_file () - core.ids[enum] = ids - except: - pass - - try: value2 = '(' + core.ids[enum].ids[value] + ')' - except: pass - - - elif mask != None: - value2 = '(' + string.join (map (lambda m, mask=mask: mask[m], filter (lambda m, v=value: (m & v) == m, mask.keys ())), '|') + ')' - - print label + ':', value, value2 - - - def set_option_default (key, value): - Format.default_options[key] = value - - def set_option (self, key, value): - self.options[key] = value - - def get_option (self, key): - if self.options.has_key (key): - return self.options[key] - elif core.options.has_key (key): - return core.options[key] - else: - return Format.default_options[key] - - -Format.default_options['debug_read'] = 0 -Format.default_options['debug_write'] = 0 - - - -ctltype_hash = { - 0 : 'button/pixmap', - 2 : 'slider', - 3 : 'textedit', - 5 : 'textarea', - 6 : 'label?', - 7 : 'scrollbar', - } - - - -def register_format (signature, version, klass): - core.register_format (signature, version, klass) Modified: ie_shell/branches/iesh-infinity/infinity/formats/ids.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -20,7 +20,7 @@ import re import sys -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format class IDS_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/itm.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,7 @@ # RCS: $Id: itm.py,v 1.1 2005/03/02 20:44:23 edheldil Exp $ -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format class ITM_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/key.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/key.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/key.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -21,7 +21,7 @@ import re import sys -from ie_shell.formats.format import Format, register_format, TICK_SIZE, TACK_SIZE +from infinity.format import Format, register_format, TICK_SIZE, TACK_SIZE class KEY_Format (Format): header_desc = ( Modified: ie_shell/branches/iesh-infinity/infinity/formats/pro.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/pro.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/pro.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: pro.py,v 1.1 2006/07/08 14:29:26 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class PRO_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/spl.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/spl.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/spl.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,7 @@ # RCS: $Id: spl.py,v 1.1 2005/03/02 20:44:23 edheldil Exp $ -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format class SPL_Format (Format): def __init__ (self, filename): Deleted: ie_shell/branches/iesh-infinity/infinity/formats/stream.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/stream.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/stream.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -1,319 +0,0 @@ -# -*-python-*- -# ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> -# -# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# RCS: $Id: stream.py,v 1.3 2006/07/08 14:29:27 edheldil Exp $ - -import gzip -import os.path -import re -import string -import struct - -from ie_shell import core - - -class Stream: - def __init__ (self): - self.is_open = False - - def open (self, mode = 'r'): - # do the real open here - self.is_open = True - return self - - def close (self): - pass - - def seek (self, offset): - pass - - def read (self, count = None): - pass - - def write (self, data, count = None): - pass - - def readline (self): - pass - - def writeline (self, line): - pass - - def get_char (self, offset = None): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - - return self.read (1) - #v = self.read (1) - #return struct.unpack ('c', v)[0] - - def put_char (self, char, offset = None): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - - self.write (char, 1) - - def get_line (self): - #return self.readline () - return self.decode_line_string () - - def put_line (self): - #FIXME - pass - - def decode_word (self, offset): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - v = self.read (2) - return struct.unpack ('H', v)[0] - - def write_word (self, value, offset = None): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - bytes = struct.pack ('H', value) - self.write (bytes) - - def decode_dword (self, offset): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - v = self.read (4) - return struct.unpack ('I', v)[0] - - def write_dword (self, value, offset = None): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - bytes = struct.pack ('I', value) - self.write (bytes) - - def decode_sized_string (self, offset, size): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - v = self.read (size) - - return struct.unpack ('%ds' %size, v)[0] - - def write_sized_string (self, value, offset, size): - # offset == None means "current offset" here - if offset != None: - self.seek (offset) - - bytes = struct.pack ('%ds' %size, value) - self.write (bytes) - - def decode_asciiz_string (self, off): - s = '' - - while 1: - c = self.get_char (off) - if c == '\0': break - s = s + c - off = off + 1 - - return s - - def decode_line_string (self): - s = '' - - while 1: - c = self.get_char (None) - if c == '\n': break - if c == '': - if s == '': - s = None - break - - s = s + c - - return s - - def decode_resref (self, off): - return self.decode_sized_string (off, 8) - - def write_resref (self, value, off): - self.write_sized_string (value, off, 8) - - def decode_blob (self, offset, size = None): - # offset == None means "current offset" here - # size == None means "till the end of stream" - if offset != None: - self.seek (offset) - - return self.read (size) - - def write_blob (self, value, offset, size = None): - # offset == None means "current offset" here - # size == None means "till the end of stream" - if offset != None: - self.seek (offset) - - return self.write (value) - - - def get_signature (self): - was_open = self.is_open - if not self.is_open: - self.open () - - s = self.decode_sized_string (0, 8) - - if not was_open: - self.close () - else: - self.seek (0) - - - if re.match ("[0-9]{1,4}[\r\n ]", s) or re.match ("0[xX][0-9A-Fa-f]{1,4} ", s) or re.match ("-1[\r\n]", s): - signature = "IDS" - version = "" - else: - signature = s[0:4].strip () - version = s[4:8].strip () - - return (signature, version) - - def get_format (self, type = 0): - signature, version = self.get_signature () - fmt = core.get_format (signature, version) - - if fmt == None and type != 0: - fmt = core.get_format_by_type (type) - - return fmt - - - def load_object (self, type = 0): - fmt = self.get_format () - obj = fmt () - obj.read (self) - return obj - - - -class FileStream (Stream): - def __init__ (self): - Stream.__init__ (self) - - def open (self, filename, mode = 'r'): - # FIXME: reset offset? - self.filename = filename - self.fh = open (self.filename, mode) - self.is_open = True - return self - - def close (self): - self.fh.close () - self.is_open = False - - def seek (self, offset): - self.fh.seek (offset) - - def read (self, size = None): - if size != None: - return self.fh.read (size) - else: - return self.fh.read () - - def write (self, bytes, size = None): - #if size != None: - # self.fh.write (bytes, size) - #else: - self.fh.write (bytes) - - def __repr__ (self): - return "<FileStream: %s>" %self.filename - - -class MemoryStream (Stream): - def __init__ (self): - Stream.__init__ (self) - - def open (self, membuffer): - self.buffer = membuffer - self.offset = 0 - self.is_open = True - return self - - def decrypt (self): - for i in range (len (self.buffer)): - print chr (ord (self.buffer[i]) ^ ord (core.xor_key[i])) - - def close (self): - self.is_open = False - - def seek (self, offset): - self.offset = offset - - def read (self, count = None): - if count != None: - data = self.buffer[self.offset:self.offset+count] - else: - data = self.buffer[self.offset:] - - self.offset = self.offset + len (data) - return data - - - -class ResourceStream (MemoryStream): - def __init__ (self): - MemoryStream.__init__ (self, '') - - def open (self, name, type = None): - self.resref = name - self.type = type - - if core.keys == None: - raise RuntimeError, "Core game files are not loaded. See load_game ()." - - oo = core.keys.get_resref_by_name_re (self.resref) - if self.type != None: - oo = filter (lambda o: o['type'] == self.type, oo) - - if len (oo) > 1 and self.type == None: - raise RuntimeError, "More than one result" - - o = oo[0] - - src_file = core.keys.bif_list[o['locator_src_ndx']] - b = core.formats['BIFF'] (os.path.join (core.game_dir, src_file['file_name'])) - b.decode_file () - obj = b.file_list[o['locator_ntset_ndx']] - b.get_file_data (obj) - - self.buffer = obj['data'] - return MemoryStream.open (self) - - def load_object (self): - return Stream.load_object (self, self.type) - - - def __repr__ (self): - return "<ResStream: %s>" %self.resref - - -class CompressedStream (MemoryStream): - def open (self, membuffer): - return MemoryStream.open (self, gzip.zlib.decompress (membuffer)) - Modified: ie_shell/branches/iesh-infinity/infinity/formats/tis.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/tis.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/tis.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: tis.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class TIS_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/tlk.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/tlk.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/tlk.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -22,8 +22,8 @@ import string import sys -from ie_shell import core -from ie_shell.formats.format import Format, register_format, TICK_SIZE, TACK_SIZE +from infinity import core +from infinity.format import Format, register_format, TICK_SIZE, TACK_SIZE class TLK_Format (Format): Modified: ie_shell/branches/iesh-infinity/infinity/formats/vvc.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/vvc.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/vvc.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: vvc.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class VVC_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/wed.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: wed.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class WED_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/wfx.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wfx.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/wfx.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -18,7 +18,8 @@ # RCS: $Id: wfx.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ -from ie_shell.formats.format import Format, register_format, core +from infinity import core +from infinity.format import Format, register_format class WFX_Format (Format): def __init__ (self, filename): Modified: ie_shell/branches/iesh-infinity/infinity/formats/wmap.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wmap.py 2008-03-05 23:59:07 UTC (rev 5112) +++ ie_shell/branches/iesh-infinity/infinity/formats/wmap.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -19,11 +19,11 @@ # RCS: $Id: wmap.py,v 1.1 2005/03/02 20:44:23 edheldil Exp $ -from ie_shell.formats.format import Format, register_format +from infinity.format import Format, register_format class WMAP_Format (Format): - header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -46,7 +46,7 @@ ) - wmap_record_desc = ( + wmap_record_desc = ( { 'key': 'map_resref', 'type': 'RESREF', 'off': 0x0000, @@ -109,7 +109,7 @@ ) - area_record_desc = ( + area_record_desc = ( { 'key': 'area_name', 'type': 'RESREF', 'off': 0x0000, @@ -206,7 +206,7 @@ ) - arealink_record_desc = ( + arealink_record_desc = ( { 'key': 'dest_map_ndx', 'type': 'DWORD', 'off': 0x0000, Copied: ie_shell/branches/iesh-infinity/infinity/stream.py (from rev 5111, ie_shell/branches/iesh-infinity/infinity/formats/stream.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/stream.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/stream.py 2008-03-06 00:29:55 UTC (rev 5113) @@ -0,0 +1,319 @@ +# -*-python-*- +# ie_shell.py - Simple shell for Infinity Engine-based game files +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# RCS: $Id: stream.py,v 1.3 2006/07/08 14:29:27 edheldil Exp $ + +import gzip +import os.path +import re +import string +import struct + +from infinity import core + + +class Stream: + def __init__ (self): + self.is_open = False + + def open (self, mode = 'r'): + # do the real open here + self.is_open = True + return self + + def close (self): + pass + + def seek (self, offset): + pass + + def read (self, count = None): + pass + + def write (self, data, count = None): + pass + + def readline (self): + pass + + def writeline (self, line): + pass + + def get_char (self, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + + return self.read (1) + #v = self.read (1) + #return struct.unpack ('c', v)[0] + + def put_char (self, char, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + + self.write (char, 1) + + def get_line (self): + #return self.readline () + return self.decode_line_string () + + def put_line (self): + #FIXME + pass + + def decode_word (self, offset): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + v = self.read (2) + return struct.unpack ('H', v)[0] + + def write_word (self, value, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + bytes = struct.pack ('H', value) + self.write (bytes) + + def decode_dword (self, offset): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + v = self.read (4) + return struct.unpack ('I', v)[0] + + def write_dword (self, value, offset = None): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + bytes = struct.pack ('I', value) + self.write (bytes) + + def decode_sized_string (self, offset, size): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + v = self.read (size) + + return struct.unpack ('%ds' %size, v)[0] + + def write_sized_string (self, value, offset, size): + # offset == None means "current offset" here + if offset != None: + self.seek (offset) + + bytes = struct.pack ('%ds' %size, value) + self.write (bytes) + + def decode_asciiz_string (self, off): + s = '' + + while 1: + c = self.get_char (off) + if c == '\0': break + s = s + c + off = off + 1 + + return s + + def decode_line_string (self): + s = '' + + while 1: + c = self.get_char (None) + if c == '\n': break + if c == '': + if s == '': + s = None + break + + s = s + c + + return s + + def decode_resref (self, off): + return self.decode_sized_string (off, 8) + + def write_resref (self, value, off): + self.write_sized_string (value, off, 8) + + def decode_blob (self, offset, size = None): + # offset == None means "current offset" here + # size == None means "till the end of stream" + if offset != None: + self.seek (offset) + + return self.read (size) + + def write_blob (self, value, offset, size = None): + # offset == None means "current offset" here + # size == None means "till the end of stream" + if offset != None: + self.seek (offset) + + return self.write (value) + + + def get_signature (self): + was_open = self.is_open + if not self.is_open: + self.open () + + s = self.decode_sized_string (0, 8) + + if not was_open: + self.close () + else: + self.seek (0) + + + if re.match ("[0-9]{1,4}[\r\n ]", s) or re.match ("0[xX][0-9A-Fa-f]{1,4} ", s) or re.match ("-1[\r\n]", s): + signature = "IDS" + version = "" + else: + signature = s[0:4].strip () + version = s[4:8].strip () + + return (signature, version) + + def get_format (self, type = 0): + signature, version = self.get_signature () + fmt = core.get_format (signature, version) + + if fmt == None and type != 0: + fmt = core.get_format_by_type (type) + + return fmt + + + def load_object (self, type = 0): + fmt = self.get_format () + obj = fmt () + obj.read (self) + return obj + + + +class FileStream (Stream): + def __init__ (self): + Stream.__init__ (self) + + def open (self, filename, mode = 'r'): + # FIXME: reset offset? + self.filename = filename + self.fh = open (self.filename, mode) + self.is_open = True + return self + + def close (self): + self.fh.close () + self.is_open = False + + def seek (self, offset): + self.fh.seek (offset) + + def read (self, size = None): + if size != None: + return self.fh.read (size) + else: + return self.fh.read () + + def write (self, bytes, size = None): + #if size != None: + # self.fh.write (bytes, size) + #else: + self.fh.write (bytes) + + def __repr__ (self): + return "<FileStream: %s>" %self.filename + + +class MemoryStream (Stream): + def __init__ (self): + Stream.__init__ (self) + + def open (self, membuffer): + self.buffer = membuffer + self.offset = 0 + self.is_open = True + return self + + def decrypt (self): + for i in range (len (self.buffer)): + print chr (ord (self.buffer[i]) ^ ord (core.xor_key[i])) + + def close (self): + self.is_open = False + + def seek (self, offset): + self.offset = offset + + def read (self, count = None): + if count != None: + data = self.buffer[self.offset:self.offset+count] + else: + data = self.buffer[self.offset:] + + self.offset = self.offset + len (data) + return data + + + +class ResourceStream (MemoryStream): + def __init__ (self): + MemoryStream.__init__ (self, '') + + def open (self, name, type = None): + self.resref = name + self.type = type + + if core.keys == None: + raise RuntimeError, "Core game files are not loaded. See load_game ()." + + oo = core.keys.get_resref_by_name_re (self.resref) + if self.type != None: + oo = filter (lambda o: o['type'] == self.type, oo) + + if len (oo) > 1 and self.type == None: + raise RuntimeError, "More than one result" + + o = oo[0] + + src_file = core.keys.bif_list[o['locator_src_ndx']] + b = core.formats['BIFF'] (os.path.join (core.game_dir, src_file['file_name'])) + b.decode_file () + obj = b.file_list[o['locator_ntset_ndx']] + b.get_file_data (obj) + + self.buffer = obj['data'] + return MemoryStream.open (self) + + def load_object (self): + return Stream.load_object (self, self.type) + + + def __repr__ (self): + return "<ResStream: %s>" %self.resref + + +class CompressedStream (MemoryStream): + def open (self, membuffer): + return MemoryStream.open (self, gzip.zlib.decompress (membuffer)) + Modified: ie_shell/branch... [truncated message content] |
From: <edh...@us...> - 2008-03-15 01:48:30
|
Revision: 5117 http://gemrb.svn.sourceforge.net/gemrb/?rev=5117&view=rev Author: edheldil Date: 2008-03-14 18:48:36 -0700 (Fri, 14 Mar 2008) Log Message: ----------- Updated the formats for new API Modified Paths: -------------- ie_shell/branches/iesh-infinity/examples/button_frames.py ie_shell/branches/iesh-infinity/infinity/builtins.py ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/formats/__init__.py ie_shell/branches/iesh-infinity/infinity/formats/are.py ie_shell/branches/iesh-infinity/infinity/formats/bam.py ie_shell/branches/iesh-infinity/infinity/formats/biff.py ie_shell/branches/iesh-infinity/infinity/formats/chui.py ie_shell/branches/iesh-infinity/infinity/formats/cre.py ie_shell/branches/iesh-infinity/infinity/formats/dlg.py ie_shell/branches/iesh-infinity/infinity/formats/ids.py ie_shell/branches/iesh-infinity/infinity/formats/itm.py ie_shell/branches/iesh-infinity/infinity/formats/key.py ie_shell/branches/iesh-infinity/infinity/formats/pro.py ie_shell/branches/iesh-infinity/infinity/formats/spl.py ie_shell/branches/iesh-infinity/infinity/formats/tis.py ie_shell/branches/iesh-infinity/infinity/formats/tlk.py ie_shell/branches/iesh-infinity/infinity/formats/vvc.py ie_shell/branches/iesh-infinity/infinity/formats/wed.py ie_shell/branches/iesh-infinity/infinity/formats/wfx.py ie_shell/branches/iesh-infinity/infinity/formats/wmap.py ie_shell/branches/iesh-infinity/infinity/stream.py Added Paths: ----------- ie_shell/branches/iesh-infinity/iesh.e3p Modified: ie_shell/branches/iesh-infinity/examples/button_frames.py =================================================================== --- ie_shell/branches/iesh-infinity/examples/button_frames.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/examples/button_frames.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -5,7 +5,7 @@ # print buttons which have frame indices other than 0, 1, 0, 0 def print_button_frames (filename): c = chui.CHUI_Format (filename) - c.decode_file() + c.read() for w in c.window_list: Added: ie_shell/branches/iesh-infinity/iesh.e3p =================================================================== --- ie_shell/branches/iesh-infinity/iesh.e3p (rev 0) +++ ie_shell/branches/iesh-infinity/iesh.e3p 2008-03-15 01:48:36 UTC (rev 5117) @@ -0,0 +1,238 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE Project SYSTEM "Project-3.9.dtd"> +<!-- Project file for project iesh --> +<!-- Saved: 2008-03-07, 21:35:43 --> +<!-- Copyright (C) 2008 , --> +<Project version="3.9"> + <ProgLanguage mixed="0">Python</ProgLanguage> + <UIType>Console</UIType> + <Description></Description> + <Version>0.1</Version> + <Author></Author> + <Email></Email> + <Sources> + <Source> + <Dir>examples</Dir> + <Name>button_frames.py</Name> + </Source> + <Source> + <Dir>examples</Dir> + <Name>__init__.py</Name> + </Source> + <Source> + <Dir>examples</Dir> + <Name>raw_strings.py</Name> + </Source> + <Source> + <Name>test_tlk.py</Name> + </Source> + <Source> + <Name>examples.py</Name> + </Source> + <Source> + <Name>setup.py</Name> + </Source> + <Source> + <Name>pok.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Name>__init__.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Name>builtins.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Name>core.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>__init__.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>are.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>bam.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>biff.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>chui.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>cre.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>dlg.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>ids.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>itm.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>key.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>pro.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>spl.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>tis.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>tlk.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>vvc.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>wed.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>wfx.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>wmap.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Name>stream.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Name>dtypes.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Name>format.py</Name> + </Source> + <Source> + <Name>test_chui.py</Name> + </Source> + <Source> + <Name>test_key.py</Name> + </Source> + <Source> + <Name>iesh</Name> + </Source> + <Source> + <Name>test_wmap.py</Name> + </Source> + <Source> + <Name>test_dlg.py</Name> + </Source> + <Source> + <Name>test_fmt.py</Name> + </Source> + </Sources> + <Forms> + </Forms> + <Translations> + </Translations> + <Interfaces> + </Interfaces> + <Others> + <Other> + <Name>iesh</Name> + </Other> + </Others> + <MainScript> + <Name>iesh</Name> + </MainScript> + <Vcs> + <VcsType>Subversion</VcsType> + <VcsOptions>(dp0 +S'status' +p1 +(lp2 +sS'log' +p3 +(lp4 +sS'global' +p5 +(lp6 +sS'update' +p7 +(lp8 +sS'remove' +p9 +(lp10 +sS'add' +p11 +(lp12 +sS'tag' +p13 +(lp14 +sS'export' +p15 +(lp16 +sS'commit' +p17 +(lp18 +sS'diff' +p19 +(lp20 +sS'checkout' +p21 +(lp22 +sS'history' +p23 +(lp24 +s.</VcsOptions> + <VcsOtherData>(dp0 +S'standardLayout' +p1 +I1 +s.</VcsOtherData> + </Vcs> + <FiletypeAssociations> + <FiletypeAssociation pattern="*.ui.h" type="FORMS" /> + <FiletypeAssociation pattern="*.ui" type="FORMS" /> + <FiletypeAssociation pattern="*.idl" type="INTERFACES" /> + <FiletypeAssociation pattern="*.py" type="SOURCES" /> + <FiletypeAssociation pattern="*.ptl" type="SOURCES" /> + </FiletypeAssociations> +</Project> Modified: ie_shell/branches/iesh-infinity/infinity/builtins.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -2,8 +2,8 @@ import os.path -from ie_shell import core -from ie_shell.formats.stream import ResourceStream, FileStream +from infinity import core +from infinity.stream import ResourceStream, FileStream ################################################### def load_game (game_dir, chitin_file = core.chitin_file, dialog_file = core.dialog_file): @@ -18,17 +18,19 @@ core.dialog_file = dialog_file # Load RESREF index file (CHITIN.KEY) - core.keys = core.get_format ('KEY') (os.path.join (game_dir, chitin_file)) - core.keys.decode_header () + stream = FileStream ().open (os.path.join (game_dir, chitin_file)) + core.keys = core.get_format ('KEY') () + core.keys.read_header (stream) print "Loading %d file refs and %d RESREFs. This may take ages" %(core.keys.header['num_of_bifs'], core.keys.header['num_of_resrefs']) - core.keys.decode_file () + core.keys.read (stream) # LOAD STRREF index file (DIALOG.TLK) - core.strrefs = core.get_format ('TLK') (os.path.join (game_dir, dialog_file)) - core.strrefs.decode_header () + stream = FileStream ().open (os.path.join (game_dir, dialog_file)) + core.strrefs = core.get_format ('TLK') () + core.strrefs.read_header (stream) print "Loading %d STRREFs. This may take eternity" %(core.strrefs.header['num_of_strrefs']) - core.strrefs.decode_file () + core.strrefs.read (stream) ################################################### @@ -78,7 +80,7 @@ src_file = core.keys.bif_list[o['locator_src_ndx']] b = core.formats['BIFF'] (os.path.join (core.game_dir, src_file['file_name'])) - b.decode_file () + b.read () b.save_file_data (filename, b.file_list[o['locator_ntset_ndx']]) @@ -95,7 +97,7 @@ for res in filter (lambda res: res['type'] == type, core.keys.resref_list): print res['resref_name'] - obj = ResourceStream (res['resref_name'], type).load_object () + obj = ResourceStream ().open (res['resref_name'], type).load_object () fn (obj) @@ -107,21 +109,21 @@ print sprintf (format_str, params) def loaded_object (obj): - obj.decode_file () + obj.read () return obj ################################################### def pok(): def p (obj): - obj.decode_file () - obj.print_file () + obj.read () + obj.printme () iterate_objects_by_type (0x03ed, p) ################################################### def load_ids (): def p (obj): - obj.decode_file () + obj.read () print obj.stream.resref #obj.print_file () Modified: ie_shell/branches/iesh-infinity/infinity/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -59,7 +59,17 @@ ## self.stream = source + def read_header (self, stream): + self.header = {} + self.read_struc (stream, 0x0000, self.header_desc, self.header) + def write_header (self, stream): + self.write_struc (stream, 0x0000, self.header_desc, self.header) + + def print_header (self): + self.print_struc (self.header, self.header_desc) + + def get_masked_bits (self, value, mask, bl): return (value & mask) >> bl @@ -141,9 +151,13 @@ elif type == 'RESTYPE': value = stream.read_word (offset + local_offset) elif type == 'STROFF': - stroff = stream.read_dword (offset + local_offset) - value = stream.read_asciiz_string (stroff) - value = string.translate (value, core.slash_trans, '\x00') + str_offset = stream.read_dword (offset + local_offset) + str_value = stream.read_asciiz_string (str_offset) + str_value = string.translate (str_value, core.slash_trans, '\x00') + obj[key + ':offset'] = str_offset + # FIXME: ugly + #value = (str_offset, str_value) + value = str_value elif type == 'STRSIZED': length = stream.read_dword (offset + local_offset) # FIXME: asciiz or sized??? @@ -212,7 +226,11 @@ elif type == 'RESTYPE': stream.write_word (value, offset + local_offset) elif type == 'STROFF': - raise RuntimeError (type + " not implemented") + stream.write_dword (obj[key + ':offset'], offset + local_offset) + # FIXME: won't work for files starting at non-zero offsets + # FIXME: asciiz or fixed len? + stream.write_asciiz_string (value, obj[key + ':offset']) + #raise RuntimeError (type + " not implemented") elif type == 'STRSIZED': # FIXME: encoding stream.write_dword (len (value), offset + local_offset) @@ -260,7 +278,9 @@ elif type == 'RESTYPE': size = 2 elif type == 'STROFF': - raise RuntimeError (type + " not implemented") + #raise RuntimeError (type + " not implemented") + # NOTE: that is only a size of the pointer, not the string itself + size = 4 elif type == 'STRSIZED': # FIXME: encoding value = obj[key] @@ -319,7 +339,7 @@ try: # FIXME: ugly & should use 'IDS' instead of 0x3F0 ids = ResourceStream (enum, 0x03F0).load_object () - ids.decode_file () + ids.read () core.ids[enum] = ids except: pass Modified: ie_shell/branches/iesh-infinity/infinity/formats/__init__.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -9,6 +9,7 @@ import ids import itm import key +import mos import pro import spl import tis Modified: ie_shell/branches/iesh-infinity/infinity/formats/are.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -240,21 +240,5 @@ # if self.header['projectile_type'] == 3: # self.print_area_header () - - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) - def print_header (self): - self.print_struc (self.header, self.header_desc) - - -# def decode_area_header (self): -# self.area_header = {} -# self.decode_by_desc (0x0000, self.area_header_desc, self.area_header) - -# def print_area_header (self): -# self.print_by_desc (self.area_header, self.area_header_desc) - - register_format ('AREA', 'V1.0', ARE_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/bam.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/bam.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/bam.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -26,17 +26,7 @@ class BAM_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'BAM' - - self.frame_list = [] - self.cycle_list = [] - self.palette_entry_list = [] - self.frame_lut_entry_list = [] - - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -84,7 +74,7 @@ ) - self.frame_desc = ( + frame_desc = ( { 'key': 'width', 'type': 'WORD', 'off': 0x0000, @@ -118,7 +108,7 @@ 'label': 'Frame data offset'}, ) - self.cycle_desc = ( + cycle_desc = ( { 'key': 'frame_cnt', 'type': 'WORD', 'off': 0x0000, @@ -135,7 +125,7 @@ 'label': 'Frame indices'}, ) - self.palette_entry_desc = ( + palette_entry_desc = ( { 'key': 'r', 'type': 'BYTE', 'off': 0x0000, @@ -157,33 +147,44 @@ 'label': 'A'}, ) - self.frame_lut_entry_desc = ( + frame_lut_entry_desc = ( { 'key': 'frame', 'type': 'WORD', 'off': 0x0000, 'label': 'Frame'}, ) - def decode_file (self): - self.decode_header () + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'BAM' + + self.frame_list = [] + self.cycle_list = [] + self.palette_entry_list = [] + self.frame_lut_entry_list = [] + + + def read (self, stream): + self.read_header (stream) + off = self.header['frame_off'] for i in range (self.header['frame_cnt']): obj = {} - self.decode_frame (off, obj) + self.read_frame (stream, off, obj) self.frame_list.append (obj) off = off + 12 for i in range (self.header['cycle_cnt']): obj = {} - self.decode_cycle (off, obj) + self.read_cycle (stream, off, obj) self.cycle_list.append (obj) off = off + 4 - self.decode_palette (self.header['palette_off']) + self.read_palette (stream, self.header['palette_off']) - def print_file (self): + def printme (self): self.print_header () i = 0 @@ -202,51 +203,43 @@ self.print_palette () - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - + def read_frame (self, stream, offset, obj): + self.read_struc (stream, offset, self.frame_desc, obj) - def decode_frame (self, offset, obj): - self.decode_by_desc (offset, self.frame_desc, obj) - if self.get_option ('bam_decode_frame_data'): if self.get_option ('bam_force_rle') or obj['rle_encoded']: - self.decode_rle_frame_data (obj) + self.read_rle_frame_data (stream, obj) else: - self.decode_frame_data (obj) + self.read_frame_data (stream, obj) def print_frame (self, obj): - self.print_by_desc (obj, self.frame_desc) + self.print_struc (obj, self.frame_desc) if self.get_option ('bam_print_frame_bitmap'): self.print_frame_bitmap (obj) - def decode_cycle (self, offset, obj): - self.decode_by_desc (offset, self.cycle_desc, obj) + def read_cycle (self, stream, offset, obj): + self.read_struc (stream, offset, self.cycle_desc, obj) obj['frame_list'] = [] off2 = self.header['frame_lut_off'] + 2 * obj['frame_lut_ndx'] obj2 = {} for i in range (obj['frame_cnt']): - self.decode_by_desc (off2, self.frame_lut_entry_desc, obj2) + self.read_struc (stream, off2, self.frame_lut_entry_desc, obj2) obj['frame_list'].append (obj2['frame']) obj['frames'] = obj['frames'] + str(obj2['frame']) + ' ' off2 = off2 + 2 def print_cycle (self, obj): - self.print_by_desc (obj, self.cycle_desc) + self.print_struc (obj, self.cycle_desc) - def decode_palette (self, offset): + def read_palette (self, stream, offset): transp_color = None for i in range (256): obj = {} - self.decode_by_desc (offset, self.palette_entry_desc, obj) + self.read_struc (stream, offset, self.palette_entry_desc, obj) self.palette_entry_list.append (obj) if transp_color == None and obj['r'] == 0 and obj['g'] == 255 and obj['b'] == 0: @@ -266,22 +259,22 @@ i = i + 1 - def decode_frame_data (self, obj): + def read_frame_data (self, stream, obj): size = obj['width'] * obj['height'] - bin_data = self.stream.decode_blob (obj['frame_data_off'], size) + bin_data = stream.read_blob (obj['frame_data_off'], size) obj['frame_data'] = struct.unpack ('%dB' %size, bin_data) - def decode_rle_frame_data (self, obj): + def read_rle_frame_data (self, stream, obj): off = obj['frame_data_off'] size = obj['width'] * obj['height'] compressed_color = self.header['comp_color_ndx'] data = [] while len (data) < size: - pix = struct.unpack ('B', self.stream.get_char (off))[0] + pix = struct.unpack ('B', stream.get_char (off))[0] if pix == compressed_color: off = off + 1 - cnt = struct.unpack ('B', self.stream.get_char (off))[0] + cnt = struct.unpack ('B', stream.get_char (off))[0] for j in range (cnt + 1): data.append (compressed_color) else: @@ -325,12 +318,7 @@ class BAMC_Format (BAM_Format): - def __init__ (self, filename): - BAM_Format.__init__ (self, filename) - self.expect_signature = 'BAMC' - - - self.envelope_desc = ( + envelope_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -348,25 +336,30 @@ ) - def decode_file (self): - self.decode_envelope () - data = self.stream.decode_blob (0x0C) + def __init__ (self): + BAM_Format.__init__ (self) + self.expect_signature = 'BAMC' - self.stream.close () - self.stream = CompressedStream (data) - BAM_Format.decode_file (self) + def read (self, stream): + self.read_envelope (stream) + data = stream.read_blob (0x0C) - def print_file (self): + #self.stream.close () + stream = CompressedStream ().open (data) + + return BAM_Format.read (self, stream) + + def printme (self): self.print_envelope () - BAM_Format.print_file (self) + BAM_Format.printme (self) - def decode_envelope (self): + def read_envelope (self, stream): self.envelope = {} - self.decode_by_desc (0x0000, self.envelope_desc, self.envelope) + self.read_struc (stream, 0x0000, self.envelope_desc, self.envelope) def print_envelope (self): - self.print_by_desc (self.envelope, self.envelope_desc) + self.print_struc (self.envelope, self.envelope_desc) Modified: ie_shell/branches/iesh-infinity/infinity/formats/biff.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -22,14 +22,7 @@ from infinity.format import Format, register_format class BIFF_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'BIFF' - - self.file_list = [] - self.tileset_list = [] - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -57,7 +50,7 @@ ) - self.file_record_desc = ( + file_record_desc = ( { 'key': 'locator', 'type': 'DWORD', 'off': 0x0000, @@ -78,13 +71,13 @@ 'off': 0x000C, 'label': 'File res type' }, - { 'key': 'unknown', + { 'key': 'unknown_0E', 'type': 'WORD', 'off': 0x000E, - 'label': '???' }, + 'label': 'Unknown 0E' }, ) - self.tileset_record_desc = ( + tileset_record_desc = ( { 'key': 'locator', 'type': 'DWORD', 'off': 0x0000, @@ -117,24 +110,34 @@ ) - def decode_file (self): - self.decode_header () + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'BIFF' + self.file_list = [] + self.tileset_list = [] + + + def read (self, stream): + self.read_header (stream) + off = self.header['files_offset'] for i in range (self.header['num_of_files']): obj = {} - self.decode_file_record (off, obj) + self.read_file_record (stream, off, obj) self.file_list.append (obj) off = off + 16 for i in range (self.header['num_of_tilesets']): obj = {} - self.decode_tileset_record (off, obj) + self.read_tileset_record (stream, off, obj) self.tileset_list.append (obj) off = off + 20 + if self.get_option ('biff_read_data'): + self.read_all_data (stream) - def print_file (self): + def printme (self): self.print_header () i = 0 @@ -150,57 +153,53 @@ i = i + 1 - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) + def read_file_record (self, stream, offset, obj): + self.read_struc (stream, offset, self.file_record_desc, obj) - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - - - def decode_file_record (self, offset, obj): - self.decode_by_desc (offset, self.file_record_desc, obj) - def print_file_record (self, obj): - self.print_by_desc (obj, self.file_record_desc) + self.print_struc (obj, self.file_record_desc) - def decode_tileset_record (self, offset, obj): - self.decode_by_desc (offset, self.tileset_record_desc, obj) + def read_tileset_record (self, stream, offset, obj): + self.read_struc (stream, offset, self.tileset_record_desc, obj) def print_tileset_record (self, obj): - self.print_by_desc (obj, self.tileset_record_desc) + self.print_struc (obj, self.tileset_record_desc) + def read_all_data (self, stream): + for obj in self.file_list: + self.read_ntset_data (stream, obj) + + for obj in self.tileset_list: + self.read_tileset_data (stream, obj) - def get_ntset_data (self, obj): - obj['data'] = self.stream.decode_blob (obj['data_offset'], obj['data_size']) + def read_ntset_data (self, stream, obj): + obj['data'] = stream.read_blob (obj['data_offset'], obj['data_size']) - def get_tileset_data (self, obj): + def read_tileset_data (self, stream, obj): # FIXME: also add bytes for the TIS header - obj['data'] = self.stream.decode_blob (obj['data_offset'], obj['tile_size'] * obj['tile_cnt']) + obj['data'] = stream.read_blob (obj['data_offset'], obj['tile_size'] * obj['tile_cnt']) + # FIXME: the following API is ugly - def get_file_data (self, obj): + def get_file_data (self, stream, obj): if obj.has_key ('tile_cnt'): - return self.get_tileset_data (obj) + return self.read_tileset_data (stream, obj) else: - return self.get_ntset_data (obj) + return self.read_ntset_data (stream, obj) + # FIXME: this is ugly - def save_file_data (self, filename, obj): - self.get_file_data (obj) + def save_file_data (self, stream, filename, obj): + self.get_file_data (stream, obj) fh = open (filename, 'w') fh.write (obj['data']) fh.close () class BIFC_V1_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'BIF ' - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -233,30 +232,35 @@ ) - def decode_file (self): - self.decode_header () + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'BIF ' - self.decode_by_desc (0x000c + self.header['filename_len'], (self.header_desc[4], ), self.header) - self.decode_by_desc (0x0010 + self.header['filename_len'], ( self.header_desc[5], ), self.header) + def read (self, stream): + self.read_header (stream) + self.read_struc (stream, 0x000c + self.header['filename_len'], (self.header_desc[4], ), self.header) + self.read_struc (stream, 0x0010 + self.header['filename_len'], ( self.header_desc[5], ), self.header) + #self.stream.seek (..) - data = self.stream.decode_blob (0x0014 + self.header['filename_len'], self.header['compressed_size']) + data = stream.decode_blob (0x0014 + self.header['filename_len'], self.header['compressed_size']) self.data = gzip.zlib.decompress (data) - def print_file (self): + def printme (self): self.print_header () - def decode_header (self): + def read_header (self, stream): self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) + self.read_struc (stream, 0x0000, self.header_desc, self.header) def print_header (self): - self.print_by_desc (self.header, self.header_desc) + self.print_struc (self.header, self.header_desc) +BIFF_Format.default_options['biff_read_data'] = False register_format ('BIFF', 'V1', BIFF_Format) register_format ('BIF ', 'V1.0', BIFC_V1_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/chui.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/chui.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/chui.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -480,7 +480,7 @@ self.header['control_table_offset'] = offset - self.write_struc (stream, 0x0000, CHUI_Format.header_desc, self.header) + self.write_struc (stream, 0x0000, self.header_desc, self.header) window_offset = self.header['window_offset'] table_offset = self.header['control_table_offset'] @@ -498,14 +498,6 @@ #xyx() - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_struc (self.header, self.header_desc) - - def read_window_record (self, stream, offset, obj): self.read_struc (stream, offset, self.window_record_desc, obj) Modified: ie_shell/branches/iesh-infinity/infinity/formats/cre.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -23,14 +23,8 @@ # FIXME: incomplete! class CRE_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'CRE' - self.window_list = [] - - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -95,7 +89,7 @@ ) - self.window_record_desc = ( + window_record_desc = ( { 'key': 'id', 'type': 'WORD', 'off': 0x0000, @@ -153,7 +147,7 @@ ) - self.control_table_record_desc = ( + control_table_record_desc = ( { 'key': 'control_offset', 'type': 'DWORD', 'off': 0x0000, @@ -165,7 +159,7 @@ 'label': 'Length of control structure'}, ) - self.control_common_record_desc = ( + control_common_record_desc = ( { 'key': 'id', 'type': 'CTLID', 'off': 0x0000, @@ -204,7 +198,7 @@ ) - self.control_button_record_desc = ( + control_button_record_desc = ( { 'key': 'bam_file', 'type': 'RESREF', 'off': 0x000E, @@ -242,7 +236,7 @@ ) - self.control_slider_record_desc = ( + control_slider_record_desc = ( { 'key': 'mos_file', 'type': 'RESREF', 'off': 0x000E, @@ -310,7 +304,7 @@ ) - self.control_textedit_record_desc = ( + control_textedit_record_desc = ( { 'key': 'mos_file_1', 'type': 'RESREF', 'off': 0x000E, @@ -360,7 +354,7 @@ ) - self.control_textarea_record_desc = ( + control_textarea_record_desc = ( { 'key': 'font_file_1', 'type': 'RESREF', 'off': 0x000E, @@ -393,7 +387,7 @@ ) - self.control_label_record_desc = ( + control_label_record_desc = ( { 'key': 'text', 'type': 'STRREF', 'off': 0x000E, @@ -422,7 +416,7 @@ ) - self.control_scrollbar_record_desc = ( + control_scrollbar_record_desc = ( { 'key': 'bam_file', 'type': 'RESREF', 'off': 0x000E, @@ -470,9 +464,15 @@ ) + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'CRE' - def decode_file (self): - self.decode_header () + self.window_list = [] + + + def read (self, stream): + self.read_header (stream) return self # off = self.header['window_offset'] @@ -493,7 +493,7 @@ - def print_file (self): + def printme (self): self.print_header () # i = 0 @@ -503,14 +503,6 @@ # i = i + 1 - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - - def decode_window_record (self, offset, obj): self.decode_by_desc (offset, self.window_record_desc, obj) Modified: ie_shell/branches/iesh-infinity/infinity/formats/dlg.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/dlg.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/dlg.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -22,18 +22,7 @@ from infinity.format import Format, register_format class DLG_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'DLG' - - self.state_list = [] - self.transition_list = [] - self.state_trigger_list = [] - self.transition_trigger_list = [] - self.action_list = [] - - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -99,7 +88,7 @@ ) - self.state_desc = ( + state_desc = ( { 'key': 'npc_text', 'type': 'STRREF', 'off': 0x0000, @@ -123,7 +112,7 @@ ) - self.transition_desc = ( + transition_desc = ( { 'key': 'flags', 'type': 'DWORD', 'mask': {0x01:'has text', 0x02:'has trigger', 0x04:'has action', 0x08:'terminates dlg', 0x10:'journal entry', 0x20:'unknown', 0x40:'add quest journal', 0x80:'del quest journal', 0x100:'add done quest journal'}, @@ -162,7 +151,7 @@ ) - self.script_desc = ( + script_desc = ( { 'key': 'script_off', 'type': 'DWORD', 'off': 0x0000, @@ -180,22 +169,32 @@ ) + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'DLG' + self.state_list = [] + self.transition_list = [] + self.state_trigger_list = [] + self.transition_trigger_list = [] + self.action_list = [] - def decode_file (self): - self.decode_header () + + def read (self, stream): + self.read_header (stream) + off = self.header['state_off'] for i in range (self.header['state_cnt']): obj = {} - self.decode_state (off, obj) + self.read_state (stream, off, obj) self.state_list.append (obj) off = off + 16 off = self.header['transition_off'] for i in range (self.header['transition_cnt']): obj = {} - self.decode_transition (off, obj) + self.read_transition (stream, off, obj) self.transition_list.append (obj) off = off + 32 @@ -203,21 +202,21 @@ off = self.header['state_trigger_off'] for i in range (self.header['state_trigger_cnt']): obj = {} - self.decode_script (off, obj) + self.read_script (stream, off, obj) self.state_trigger_list.append (obj) off = off + 8 off = self.header['transition_trigger_off'] for i in range (self.header['transition_trigger_cnt']): obj = {} - self.decode_script (off, obj) + self.read_script (stream, off, obj) self.transition_trigger_list.append (obj) off = off + 8 off = self.header['action_off'] for i in range (self.header['action_cnt']): obj = {} - self.decode_script (off, obj) + self.read_script (stream, off, obj) self.action_list.append (obj) off = off + 8 @@ -230,7 +229,7 @@ # off = off + 48 - def print_file (self): + def printme (self): self.print_header () i = 0 @@ -264,26 +263,16 @@ i = i + 1 + def read_state (self, stream, offset, obj): + self.read_struc (stream, offset, self.state_desc, obj) + def read_transition (self, stream, offset, obj): + self.read_struc (stream, offset, self.transition_desc, obj) - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - + def read_script (self, stream, offset, obj): + self.read_struc (stream, offset, self.script_desc, obj) - def decode_state (self, offset, obj): - self.decode_by_desc (offset, self.state_desc, obj) - - def decode_transition (self, offset, obj): - self.decode_by_desc (offset, self.transition_desc, obj) - - def decode_script (self, offset, obj): - self.decode_by_desc (offset, self.script_desc, obj) - - obj['code'] = self.stream.decode_sized_string (obj['script_off'], obj['script_len']) + obj['code'] = stream.read_sized_string (obj['script_off'], obj['script_len']) obj['code_raw'] = obj['code'] #if core.lang_trans: # obj['code'] = string.translate (obj['code'], core.lang_trans) @@ -298,13 +287,13 @@ # off2 = off2 + 48 def print_state (self, obj): - self.print_by_desc (obj, self.state_desc) + self.print_struc (obj, self.state_desc) def print_transition (self, obj): - self.print_by_desc (obj, self.transition_desc) + self.print_struc (obj, self.transition_desc) def print_script (self, obj): - self.print_by_desc (obj, self.script_desc) + self.print_struc (obj, self.script_desc) def print_flow (self): Modified: ie_shell/branches/iesh-infinity/infinity/formats/ids.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -23,20 +23,20 @@ from infinity.format import Format, register_format class IDS_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - #self.expect_signature = 'KEY' + def __init__ (self): + Format.__init__ (self) + #self.expect_signature = 'IDS' self.ids = {} self.ids_re = {} self.ids_list = [] - def decode_file (self): + def read (self, stream): s = "" line_no = 0 while s != None: - s = self.stream.get_line () + s = stream.get_line () if s == None: break @@ -74,26 +74,11 @@ - def print_file (self): + def printme (self): for key, value in self.ids_list: print "%s\t%s" %(key, value) -# def get_bif_by_name_re (self, name): -# rx = re.compile (name) -# return filter (lambda s, rx=rx: rx.search (s['file_name']), self.bif_list) - - -# def get_resref_by_file_index (self, index): -# return filter (lambda s, i=index: s['locator_src_ndx'] == i, self.resref_list) - -# def get_resref_by_name_re (self, name): -# rx = re.compile (name) -# return filter (lambda s, rx=rx: rx.search (s['resref_name']), self.resref_list) - -# def get_resref_by_name (self, name): -# return filter (lambda s, name=name: s['resref_name'] == name, self.resref_list) - register_format ('IDS', '', IDS_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/itm.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -454,8 +454,8 @@ ) - def decode_file (self): - self.decode_header () + def read (self): + self.read_header () off = self.header['extended_header_off'] for i in range (self.header['extended_header_cnt']): @@ -472,7 +472,7 @@ off = off + 48 - def print_file (self): + def printme (self): self.print_header () i = 0 @@ -488,7 +488,7 @@ i = i + 1 - def decode_header (self): + def read_header (self): self.header = {} self.decode_by_desc (0x0000, self.header_desc, self.header) Modified: ie_shell/branches/iesh-infinity/infinity/formats/key.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/key.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/key.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -210,15 +210,7 @@ i = i + 1 - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_struc (self.header, self.header_desc) - - - def decode_bif_record (self, stream, offset, obj): + def read_bif_record (self, stream, offset, obj): self.read_struc (stream, offset, self.bif_record_desc, obj) def print_bif_record (self, obj): Modified: ie_shell/branches/iesh-infinity/infinity/formats/pro.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/pro.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/pro.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -320,8 +320,6 @@ self.expect_signature = 'PRO' - - def read (self, stream): self.read_header (stream) if self.header['projectile_type'] == 3: @@ -332,15 +330,7 @@ self.print_header () if self.header['projectile_type'] == 3: self.print_area_header () - - - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) - def print_header (self): - self.print_struc (self.header, self.header_desc) - def read_area_header (self, stream): self.area_header = {} Modified: ie_shell/branches/iesh-infinity/infinity/formats/spl.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/spl.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/spl.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -21,15 +21,7 @@ from infinity.format import Format, register_format class SPL_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'SPL' - - self.extended_header_list = [] - self.casting_feature_block_list = [] - - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -199,7 +191,7 @@ ) - self.extended_header_desc = ( + extended_header_desc = ( { 'key': 'spell_form', 'type': 'BYTE', 'off': 0x0000, @@ -288,7 +280,7 @@ ) - self.feature_block_desc = ( + feature_block_desc = ( { 'key': 'opcode_number', 'type': 'WORD', 'off': 0x0000, @@ -375,26 +367,33 @@ ) + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'SPL' - def decode_file (self): - self.decode_header () + self.extended_header_list = [] + self.casting_feature_block_list = [] + + def read (self, stream): + self.read_header (stream) + off = self.header['extended_header_off'] for i in range (self.header['extended_header_cnt']): obj = {} - self.decode_extended_header (off, obj) + self.read_extended_header (stream, off, obj) self.extended_header_list.append (obj) off = off + 40 off = self.header['feature_block_off'] + self.header['casting_feature_block_off'] * 48 for i in range (self.header['casting_feature_block_cnt']): obj = {} - self.decode_feature_block (off, obj) + self.read_feature_block (stream, off, obj) self.casting_feature_block_list.append (obj) off = off + 48 - def print_file (self): + def printme (self): self.print_header () i = 0 @@ -410,27 +409,19 @@ i = i + 1 - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - + def read_extended_header (self, stream, offset, obj): + self.read_struc (stream, offset, self.extended_header_desc, obj) - def decode_extended_header (self, offset, obj): - self.decode_by_desc (offset, self.extended_header_desc, obj) - obj['feature_list'] = [] off2 = self.header['feature_block_off'] + obj['feature_off'] * 48 for j in range (obj['feature_cnt']): obj2 = {} - self.decode_feature_block (off2, obj2) + self.read_feature_block (stream, off2, obj2) obj['feature_list'].append (obj2) off2 = off2 + 48 def print_extended_header (self, obj): - self.print_by_desc (obj, self.extended_header_desc) + self.print_struc (obj, self.extended_header_desc) j = 0 for feature in obj['feature_list']: @@ -438,11 +429,11 @@ self.print_feature_block (feature) j = j + 1 - def decode_feature_block (self, offset, obj): - self.decode_by_desc (offset, self.feature_block_desc, obj) + def read_feature_block (self, stream, offset, obj): + self.read_struc (stream,offset, self.feature_block_desc, obj) def print_feature_block (self, obj): - self.print_by_desc (obj, self.feature_block_desc) + self.print_struc (obj, self.feature_block_desc) register_format ('SPL', 'V1', SPL_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/tis.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/tis.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/tis.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -68,13 +68,5 @@ def printme (self): self.print_header () - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) - def print_header (self): - self.print_struc (self.header, self.header_desc) - - - register_format ('TIS', 'V1 ', TIS_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/tlk.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/tlk.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/tlk.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -154,17 +154,9 @@ i = i + 1 - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_struc (self.header, self.header_desc) - - def read_strref_record (self, stream, offset, obj): self.read_struc (stream, offset, self.strref_record_desc, obj) - obj['string'] = stream.decode_sized_string (self.header['string_offset'] + obj['string_offset'], obj['string_len']) + obj['string'] = stream.read_sized_string (self.header['string_offset'] + obj['string_offset'], obj['string_len']) obj['string_raw'] = obj['string'] if core.lang_trans: obj['string'] = string.translate (obj['string'], core.lang_trans) Modified: ie_shell/branches/iesh-infinity/infinity/formats/vvc.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/vvc.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/vvc.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -22,12 +22,8 @@ from infinity.format import Format, register_format class VVC_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'VVC' - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -252,21 +248,16 @@ ) + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'VVC' + def read (self, stream): + self.read_header (stream) - def decode_file (self): - self.decode_header () - - def print_file (self): + def printme (self): self.print_header () - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) - - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - register_format ('VVC', 'V1.0', VVC_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/wed.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-03-15 01:46:42 UTC (rev 5116) +++ ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-03-15 01:48:36 UTC (rev 5117) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -22,15 +22,7 @@ from infinity.format import Format, register_format class WED_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'WED' - - self.secondary_header = {} - self.overlay_list = [] - self.door_list = [] - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -73,7 +65,7 @@ ) - self.overlay_desc = ( + overlay_desc = ( { 'key': 'width', 'type': 'WORD', 'off': 0x0000, @@ -106,7 +98,7 @@ ) - self.secondary_header_desc = ( + secondary_header_desc = ( { 'key': 'polygon_cnt', 'type': 'DWORD', 'off': 0x0000, @@ -134,7 +126,7 @@ ) - self.door_desc = ( + door_desc = ( { 'key': 'door_name', 'type': 'STR8', 'off': 0x0000, @@ -177,7 +169,7 @@ ) - self.tilemap_desc = ( + tilemap_desc = ( { 'key': 'tile_index_lut_ndx', 'type': 'WORD', 'off': 0x0000, @@ -210,7 +202,7 @@ # Tile index lookup table desc - self.wallgroup_desc = ( + wallgroup_desc = ( { 'key': 'polygon_ndx', 'type': 'WORD', 'off': 0x0000, @@ -223,7 +215,7 @@ ) - self.polygon_desc = ( + polygon_desc = ( { 'key': 'vertex_ndx', 'type': 'DWORD', 'off': 0x0000, @@ -278,7 +270,7 @@ # Polygon index LUT desc - self.vertex_desc = ( + vertex_desc = ( { 'key': 'x', 'type': 'WORD', 'off': 0x0000, @@ -291,27 +283,36 @@ ) - def decode_file (self): - self.decode_header () - self.decode_secondary_header (self.header['secondary_header_off'], self.secondary_header) + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'WED' + self.secondary_header = {} + self.overlay_list = [] + self.door_list = [] + + + def read (self, stream): + self.read_header (stream) + self.read_secondary_header (stream, self.header['secondary_header_off'], self.secondary_header) + off = self.header['overlay_off'] for i in range (self.header['overlay_cnt']): obj = {} - self.decode_overlay (off, obj) + self.read_overlay (stream, off, obj) self.overlay_list.append (obj) off = off + 24 off = self.header['door_off'] for i in range (self.header['door_cnt']): obj = {} - self.decode_door (off, obj) + self.read_door (stream, off, obj) self.door_list.append (obj) off = off + 26 - def print_file (self): + def printme (self): self.print_header () self.print_secondary_header () @@ -328,36 +329,28 @@ i = i + 1 - def decode_header (self): - self.header = {} - self.decode_by_desc (0x0000, self.header_desc, self.header) + def read_secondary_header (self, stream, offset, obj): + self.read_struc (stream, offset, self.secondary_header_desc, obj) - def print_header (self): - self.print_by_desc (self.header, self.header_desc) - - - def decode_secondary_header (self, offset, obj): - self.decode_by_desc (offset, self.secondary_header_desc, obj) - def print_secondary_header (self): - self.print_by_desc (self.secondary_header, self.secondary_header_desc) + self.print_struc (self.secondary_header, self.secondary_header_desc) - def decode_overlay (self, offset, obj): - self.decode_by_desc (offset, self.overlay_desc, obj) + def read_overlay (self, stream, offset, obj): + self.read_struc (stream, offset, self.overlay_desc, obj) def print_overlay (self, obj): - self.print_by_desc (obj, self.overlay_desc) + self.print_struc (obj, self.overlay_desc) - def decode_door (self, offset, obj): - self.decode_by_desc (offset, self.door_desc, obj) + def read_door (self, stream, offset, obj): + self.read_struc (stream, offset, self.door_desc, obj) obj['open_door_poly_list'] = [] off = obj['open_door_poly_off'] for i in range (obj['open_door_poly_cnt']): obj2 = {} - self.decode_polygon (off, obj2) + self.read_polygon (stream, off, obj2) obj['open_door_poly_list'].append (obj2) off = off + 34 @@ -365,13 +358,13 @@ off = obj['closed_door_poly_off'] for i in range (obj['closed_door_poly_cnt']): obj2 = {} - self.decode_polygon (off, obj2) + self.read_polygon (stream, off, obj2) obj['closed_door_... [truncated message content] |
From: <edh...@us...> - 2008-03-21 23:40:49
|
Revision: 5126 http://gemrb.svn.sourceforge.net/gemrb/?rev=5126&view=rev Author: edheldil Date: 2008-03-21 16:39:50 -0700 (Fri, 21 Mar 2008) Log Message: ----------- * Added TODO * Almost completed ARE file * Improved BIFF, SPL and ITM files * Easier handling of lists Modified Paths: -------------- ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/formats/are.py ie_shell/branches/iesh-infinity/infinity/formats/biff.py ie_shell/branches/iesh-infinity/infinity/formats/itm.py ie_shell/branches/iesh-infinity/infinity/formats/spl.py ie_shell/branches/iesh-infinity/infinity/stream.py Added Paths: ----------- ie_shell/branches/iesh-infinity/TODO Added: ie_shell/branches/iesh-infinity/TODO =================================================================== --- ie_shell/branches/iesh-infinity/TODO (rev 0) +++ ie_shell/branches/iesh-infinity/TODO 2008-03-21 23:39:50 UTC (rev 5126) @@ -0,0 +1,7 @@ +1. use search path for files +2. Format.read_struc(): allow for offset based on size of other field (STRSIZED, as in BIFC_Format) +3. make the MemoryStream data buffer autostrech (shrink/grow) +4. canonize field names and labels + - e.g.: + door_cnt or doors_cnt ? + # of doors or Doors count? Modified: ie_shell/branches/iesh-infinity/infinity/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py 2008-03-18 08:55:56 UTC (rev 5125) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-03-21 23:39:50 UTC (rev 5126) @@ -69,7 +69,34 @@ def print_header (self): self.print_struc (self.header, self.header_desc) + def read_list (self, stream, name, desc = None, list = None): + if desc == None: + desc = self.__class__.__dict__ [name + '_desc'] + if list == None: + list = self.__dict__ [name + '_list'] + off = self.header[name + '_off'] + size = self.get_struc_size (desc) + + for i in range (self.header[name + '_cnt']): + obj = {} + self.read_struc (stream, off, desc, obj) + list.append (obj) + off += size + + def print_list (self, name, desc = None, list = None): + if desc == None: + desc = self.__class__.__dict__ [name + '_desc'] + if list == None: + list = self.__dict__ [name + '_list'] + + i = 0 + for obj in list: + print name.capitalize () + " #%d:" %i + self.print_struc (obj, desc) + i += 1 + + def get_masked_bits (self, value, mask, bl): return (value & mask) >> bl @@ -106,6 +133,10 @@ value = 0 elif type in ('STR2', 'STR4', 'STR8', 'STR32', 'RESREF', 'STRSIZED'): value = '' + elif type == 'POINT': + value = (0, 0) + elif type == 'RECT': + value = (0, 0, 0, 0) else: raise Error ("Unknown type") @@ -131,6 +162,16 @@ value = stream.read_word (offset + local_offset) elif type == 'DWORD': value = stream.read_dword (offset + local_offset) + elif type == 'POINT': + value0 = stream.read_word (offset + local_offset) + value1 = stream.read_word (offset + local_offset + 2) + value = (value0, value1) + elif type == 'RECT': + value0 = stream.read_word (offset + local_offset) + value1 = stream.read_word (offset + local_offset + 2) + value2 = stream.read_word (offset + local_offset + 4) + value3 = stream.read_word (offset + local_offset + 6) + value = (value0, value1, value2, value3) elif type == 'CTLID': value = stream.read_dword (offset + local_offset) elif type == 'RGBA': @@ -206,6 +247,14 @@ stream.write_word (value, offset + local_offset) elif type == 'DWORD': stream.write_dword (value, offset + local_offset) + elif type == 'POINT': + stream.write_word (value[0], offset + local_offset) + stream.write_word (value[1], offset + local_offset + 2) + elif type == 'RECT': + stream.write_word (value[0], offset + local_offset) + stream.write_word (value[1], offset + local_offset + 2) + stream.write_word (value[2], offset + local_offset + 4) + stream.write_word (value[3], offset + local_offset + 6) elif type == 'CTLID': stream.write_dword (value, offset + local_offset) elif type == 'RGBA': @@ -259,6 +308,10 @@ size = 2 elif type == 'DWORD': size = 4 + elif type == 'POINT': + size = 4 + elif type == 'RECT': + size = 8 elif type == 'CTLID': size = 2 elif type == 'RGBA': Modified: ie_shell/branches/iesh-infinity/infinity/formats/are.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-18 08:55:56 UTC (rev 5125) +++ ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-21 23:39:50 UTC (rev 5126) @@ -218,27 +218,1482 @@ 'off': 0x0084, 'label': 'Ambients offset'}, + { 'key': 'variable_off', + 'type': 'DWORD', + 'off': 0x0088, + 'label': 'Variables offset'}, + + { 'key': 'variable_cnt', + 'type': 'DWORD', + 'off': 0x008C, + 'label': '# of variables'}, + + { 'key': 'unknown_90', + 'type': 'DWORD', + 'off': 0x0090, + 'label': 'Unknown 90'}, + + { 'key': 'area_script', + 'type': 'RESREF', + 'off': 0x0094, + 'label': 'Area Script Resref'}, + + { 'key': 'explored_bitmask_size', + 'type': 'DWORD', + 'off': 0x009C, + 'label': 'Explored bitmask size'}, + + { 'key': 'explored_bitmask_off', + 'type': 'DWORD', + 'off': 0x00A0, + 'label': 'Explored bitmask offset'}, + + { 'key': 'door_cnt', + 'type': 'DWORD', + 'off': 0x00A4, + 'label': '# of doors'}, + + { 'key': 'door_off', + 'type': 'DWORD', + 'off': 0x00A8, + 'label': 'Doors offset'}, + + { 'key': 'animation_cnt', + 'type': 'DWORD', + 'off': 0x00AC, + 'label': '# of animations'}, + + { 'key': 'animation_off', + 'type': 'DWORD', + 'off': 0x00B0, + 'label': 'Animations offset'}, + + { 'key': 'tiled_object_cnt', + 'type': 'DWORD', + 'off': 0x00B4, + 'label': '# of tiled of objects'}, + + { 'key': 'tiled_object_off', + 'type': 'DWORD', + 'off': 0x00B8, + 'label': 'Tiled objects offset'}, + + { 'key': 'song_off', + 'type': 'DWORD', + 'off': 0x00BC, + 'label': 'Song entries offset'}, + + { 'key': 'rest_interrupt_off', + 'type': 'DWORD', + 'off': 0x00C0, + 'label': 'Interruption of rest party option offset'}, + + { 'key': 'automap_note_off', + 'type': 'DWORD', + 'off': 0x00C4, + 'label': 'Automap notes offset (non PST)'}, # PST has 0xFFFFFFFF here + + { 'key': 'automap_note_cnt', + 'type': 'DWORD', + 'off': 0x00C8, + 'label': '# of automap notes (non PST)'}, # PST has automap_note_off here + + { 'key': 'projectile_trap_off', + 'type': 'DWORD', + 'off': 0x00CC, + 'label': 'Projectile traps offset (non PST)'}, # PST has automap_note_cnt here + + { 'key': 'projectile_trap_cnt', + 'type': 'DWORD', + 'off': 0x00D0, + 'label': '# of projectile traps'}, + + { 'key': 'unknown_D4', + 'type': 'BYTES', + 'off': 0x00D4, + 'size': 4 * 18, + 'label': 'Unknown D4'}, + ) + actor_desc = ( + { 'key': 'actor_name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Actor name (for editors)' }, + + { 'key': 'position', + 'type': 'POINT', + 'off': 0x0020, + 'label': 'Current actor position' }, + + { 'key': 'destination', + 'type': 'POINT', + 'off': 0x0024, + 'label': 'Current actor destination' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0028, + 'mask': { 0x01: 'CRE not attached', 0x02: 'Unknown 0x02', 0x04: 'Unknown 0x04', 0x08: 'Actor name as death var' }, + 'label': 'Flags' }, + + { 'key': 'spawned_flag', + 'type': 'DWORD', + 'off': 0x002C, + 'label': 'Spawned flag (in memory)' }, + + { 'key': 'animation', + 'type': 'DWORD', + 'off': 0x0030, + 'label': 'Animation' }, + + { 'key': 'orientation', + 'type': 'DWORD', + 'off': 0x0034, + 'enum': { 0: 'S', 1: 'SSW', 2: 'SW', 3: 'WSW', 4: 'W', 5: 'WNW', 6: 'NW', 7: 'NNW', 8: 'N', 9: 'NNE', 10: 'NE', 11: 'ENE', 12: 'E', 13: 'ESE', 14: 'SE', 15: 'SSE' }, + 'label': 'Orientation' }, + + { 'key': 'unknown_38', + 'type': 'DWORD', + 'off': 0x0038, + 'label': 'Unknown 38' }, + + { 'key': 'unknown_3C', + 'type': 'DWORD', + 'off': 0x003C, + 'label': 'Unknown 3C' }, + + { 'key': 'appearance_time', + 'type': 'DWORD', + 'off': 0x0040, + 'mask': { 2^0: '00:30-01:29', 2^1: '01:30-02:29', 2^2: '02:30-03:29', 2^3: '03:30-04:29', 2^4: '04:30-05:29', 2^5: '05:30-06:29', 2^6: '06:30-07:29', 2^7: '07:30-08:29', 2^8: '08:30-09:29', 2^9: '09:30-10:29', 2^10: '10:30-11:29', 2^11: '11:30-12:29', 2^12: '12:30-13:29', 2^13: '13:30-14:29', 2^14: '14:30-15:29', 2^15: '15:30-16:29', 2^16: '16:30-17:29', 2^17: '17:30-18:29', 2^18: '18:30-19:29', 2^19: '19:30-20:29', 2^20: '20:30-21:29 (dusk)', 2^21: '21:30-22:29 (night)', 2^22: '22:30-23:29', 2^23: '23:30-00:29' }, + 'label': 'Actor appearance time' }, + + { 'key': 'times_spoken_to', + 'type': 'DWORD', + 'off': 0x0044, + 'label': 'Number of times spoken to (in SAV)' }, + + { 'key': 'dialog', + 'type': 'RESREF', + 'off': 0x0048, + 'label': 'Dialog (overrides CRE dialog)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x0050, + 'label': 'Script (override)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x0058, + 'label': 'Script (class)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x0060, + 'label': 'Script (race)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x0068, + 'label': 'Script (general)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x0070, + 'label': 'Script (default)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x0078, + 'label': 'Script (specific)' }, + + { 'key': 'cre_file', + 'type': 'RESREF', + 'off': 0x0080, + 'label': 'CRE file' }, + + { 'key': 'cre_off', + 'type': 'DWORD', + 'off': 0x0088, + 'label': 'CRE structure offset' }, + + { 'key': 'cre_size', + 'type': 'DWORD', + 'off': 0x008C, + 'label': 'CRE structure size' }, + + { 'key': 'unknown_90', + 'type': 'BYTES', + 'off': 0x0090, + 'size': 128, + 'label': 'Unknown 90' }, + ) + # These are called info points in IESDP, but include info points, triggers and exits + infopoint_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Hotspot/Infopoint name (for editors)' }, + + { 'key': 'type', + 'type': 'WORD', + 'off': 0x0020, + 'enum': { 0: 'Proximity', 1: 'Info', 2: 'Travel' }, + 'label': 'Hotspot/Infopoint type' }, + + { 'key': 'bounding_box', + 'type': 'RECT', + 'off': 0x0022, + 'label': 'Minimal bounding box' }, + + { 'key': 'vertex_cnt', + 'type': 'WORD', + 'off': 0x002A, + 'label': 'Count of border vertices' }, + + { 'key': 'vertex_ndx', + 'type': 'DWORD', + 'off': 0x002C, + 'label': 'First vertex index' }, + + { 'key': 'unknown_30', + 'type': 'DWORD', + 'off': 0x0030, + 'label': 'Unknown 30' }, + + { 'key': 'cursor_ndx', + 'type': 'DWORD', + 'off': 0x0034, + 'enum': { 22: 'info point', 28: 'inside exit', 30: 'outside exit' }, + 'pst:enum': { 20: 'info', 34: 'exit' }, + 'label': 'Frame index to cursors.bam' }, + + { 'key': 'destination_area', + 'type': 'RESREF', + 'off': 0x0038, + 'label': 'Resref of destination area for exits' }, + + { 'key': 'destination_entrance', + 'type': 'STR32', + 'off': 0x0040, + 'label': 'Entrance in destination area for exits' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0060, + 'mask': { 0x01: 'Invisible trap', 0x02: 'Reset trap (proximity)', 0x04: 'Party required (travel)', 0x08: 'Detectable', 0x10: 'Unknown bit4', 0x20: 'Unknown bit5', 0x40: 'NPC can trigger', 0x80: 'Unknown bit7', 0x100: 'Deactivated (proximity)', 0x200: 'NPC can\'t pass (travel)', 0x400: 'Alternative point', 0x800: 'Used by door?', 0x1000: 'Unknown bit12', 0x2000: 'Unknown bit13', 0x4000: 'Unknown bit14', 0x8000: 'Unknown bit15' }, + 'label': 'Flags' }, + + { 'key': 'info_text', + 'type': 'STRREF', + 'off': 0x0064, + 'label': 'Info point text' }, + + { 'key': 'trap_detection_difficulty', + 'type': 'WORD', + 'off': 0x0068, + 'label': 'Trap detection difficulty (%)' }, + + { 'key': 'trap_removal_difficulty', + 'type': 'WORD', + 'off': 0x006A, + 'label': 'Trap removal difficulty (%)' }, + + { 'key': 'trapped_flag', + 'type': 'WORD', + 'off': 0x006C, + 'label': 'Trapped flag' }, + + { 'key': 'trap_detected', + 'type': 'WORD', + 'off': 0x006E, + 'label': 'Trap detected flag' }, + + { 'key': 'trap_launch_location', + 'type': 'POINT', + 'off': 0x0070, + 'label': 'Trap launch location' }, + + { 'key': 'key_type', + 'type': 'BYTES', + 'off': 0x0074, + 'size': 8, + 'label': 'Key type (usage unknown)' }, + + { 'key': 'script', + 'type': 'RESREF', + 'off': 0x007C, + 'label': 'Script (if trigger point)' }, + + { 'key': 'alternative_use_point', + 'type': 'POINT', + 'off': 0x0084, + 'label': 'Alternative use point' }, + + { 'key': 'unknown_88', + 'type': 'DWORD', + 'off': 0x0088, + 'label': 'Unknown 88' }, + + { 'key': 'unknown_8C', + 'type': 'BYTES', + 'off': 0x008C, + 'size': 44, + 'label': 'Unknown 8C' }, + + { 'key': 'unknown_B4', + 'type': 'POINT', + 'off': 0x00B4, + 'label': 'Unknown B4' }, + + { 'key': 'unknown_B8', + 'type': 'DWORD', + 'off': 0x00B8, + 'label': 'Unknown B8' }, + + { 'key': 'dialog_pst', + 'type': 'RESREF', + 'off': 0x00BC, + 'label': 'Dialog Resref (PST only?)' }, + ) + + spawnpoint_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Spawnpoint name' }, + + { 'key': 'location', + 'type': 'POINT', + 'off': 0x0020, + 'label': 'Spawnpoint location' }, + + { 'key': 'cre_resref_0', + 'type': 'RESREF', + 'off': 0x0024, + 'label': 'CRE Resref 0' }, + + { 'key': 'cre_resref_1', + 'type': 'RESREF', + 'off': 0x002C, + 'label': 'CRE Resref 1' }, + + { 'key': 'cre_resref_2', + 'type': 'RESREF', + 'off': 0x0034, + 'label': 'CRE Resref 2' }, + + { 'key': 'cre_resref_3', + 'type': 'RESREF', + 'off': 0x003C, + 'label': 'CRE Resref 3' }, + + { 'key': 'cre_resref_4', + 'type': 'RESREF', + 'off': 0x0044, + 'label': 'CRE Resref 4' }, + + { 'key': 'cre_resref_5', + 'type': 'RESREF', + 'off': 0x004C, + 'label': 'CRE Resref 5' }, + + { 'key': 'cre_resref_6', + 'type': 'RESREF', + 'off': 0x0054, + 'label': 'CRE Resref 6' }, + + { 'key': 'cre_resref_7', + 'type': 'RESREF', + 'off': 0x005C, + 'label': 'CRE Resref 7' }, + + { 'key': 'cre_resref_8', + 'type': 'RESREF', + 'off': 0x0064, + 'label': 'CRE Resref 8' }, + + { 'key': 'cre_resref_9', + 'type': 'RESREF', + 'off': 0x006C, + 'label': 'CRE Resref 9' }, + + { 'key': 'cre_resref_cnt', + 'type': 'WORD', + 'off': 0x0074, + 'label': 'CRE Resref count' }, + + { 'key': 'base_spawn_cnt', + 'type': 'WORD', + 'off': 0x0076, + 'label': 'Base creature number to spawn' }, + + { 'key': 'spawn_interval', + 'type': 'WORD', + 'off': 0x0078, + 'label': 'Time interval [s] between spawns' }, + + { 'key': 'spawn_method', + 'type': 'WORD', + 'off': 0x007A, + 'enum': { 1: 'Rest', 2: 'Revealed' }, + 'label': 'Spawn method' }, + + { 'key': 'unknown_7C', + 'type': 'WORD', + 'off': 0x007C, + 'enum': { 0: 'Disable spawnpoint' }, + 'label': 'Unknown 7C' }, + + { 'key': 'unknown_80', + 'type': 'WORD', + 'off': 0x0080, + 'label': 'Unknown 80' }, + + { 'key': 'unknown_82', + 'type': 'WORD', + 'off': 0x0082, + 'label': 'Unknown 82' }, + + { 'key': 'max_spawn_cnt', + 'type': 'WORD', + 'off': 0x0084, + 'label': 'Max spawned number' }, + + { 'key': 'active_flag', + 'type': 'WORD', + 'off': 0x0086, + 'label': 'Active flag' }, + + { 'key': 'appearance_time', + 'type': 'DWORD', + 'off': 0x0088, + 'mask': { 2^0: '00:30-01:29', 2^1: '01:30-02:29', 2^2: '02:30-03:29', 2^3: '03:30-04:29', 2^4: '04:30-05:29', 2^5: '05:30-06:29', 2^6: '06:30-07:29', 2^7: '07:30-08:29', 2^8: '08:30-09:29', 2^9: '09:30-10:29', 2^10: '10:30-11:29', 2^11: '11:30-12:29', 2^12: '12:30-13:29', 2^13: '13:30-14:29', 2^14: '14:30-15:29', 2^15: '15:30-16:29', 2^16: '16:30-17:29', 2^17: '17:30-18:29', 2^18: '18:30-19:29', 2^19: '19:30-20:29', 2^20: '20:30-21:29 (dusk)', 2^21: '21:30-22:29 (night)', 2^22: '22:30-23:29', 2^23: '23:30-00:29' }, + 'label': 'Spawnpoint appearance time' }, + + { 'key': 'day_chance', + 'type': 'WORD', + 'off': 0x008C, + 'label': 'Day chance?' }, + + { 'key': 'night_chance', + 'type': 'WORD', + 'off': 0x008E, + 'label': 'Night chance?' }, + + { 'key': 'unknown_90', + 'type': 'BYTES', + 'off': 0x0090, + 'size': 56, + 'label': 'Unknown 90' }, + ) + + entrance_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Entrance name' }, + + { 'key': 'location', + 'type': 'POINT', + 'off': 0x0020, + 'label': 'Entrance location point' }, + + { 'key': 'direction', + 'type': 'WORD', + 'off': 0x0024, + 'label': 'Entrance direction' }, + + { 'key': 'unknown_26', + 'type': 'BYTES', + 'off': 0x0026, + 'size': 66, # FIXME: IESDP has 62 here.... + 'label': 'Unknown 26' }, + ) + + container_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Container name (for editors)' }, + + { 'key': 'location', + 'type': 'POINT', + 'off': 0x0020, + 'label': 'Container location' }, + + { 'key': 'type', + 'type': 'WORD', + 'off': 0x0024, + 'enum': { 0x00: 'N/A', 0x01: 'Bag', 0x02: 'Chest', 0x03: 'Drawer', 0x04: 'Pile', 0x05: 'Table', 0x06: 'Shelf', 0x07: 'Altar', 0x08: 'Nonvisible', 0x09: 'Spellbook', 0x0A: 'Body', 0x0B: 'Barrel', 0x0C: 'Crate' }, + 'label': 'Container type' }, + + { 'key': 'lock_difficulty', + 'type': 'WORD', + 'off': 0x0026, + 'label': 'Lock difficulty' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0028, + 'mask': { 0x01: 'Locked', 0x02: 'Unknown bit1', 0x04: 'Unknown bit2', 0x08: 'Reset trap', 0x10: 'Unknown bit4', 0x20: 'Disabled' }, + 'label': 'Flags' }, + + { 'key': 'trap_detection_difficulty', + 'type': 'WORD', + 'off': 0x002C, + 'label': 'Trap detection difficulty' }, + + { 'key': 'trap_removal_difficulty', + 'type': 'WORD', + 'off': 0x002E, + 'label': 'Trap removal difficulty' }, + + { 'key': 'is_trapped', + 'type': 'WORD', + 'off': 0x0030, + 'label': 'Container is trapped' }, + + { 'key': 'is_detected', + 'type': 'WORD', + 'off': 0x0032, + 'label': 'Trap has been detected' }, + + { 'key': 'trap_launch_target', + 'type': 'POINT', + 'off': 0x0034, + 'label': 'Trap launch target' }, + + { 'key': 'bounding_box', + 'type': 'RECT', + 'off': 0x0038, + 'label': 'Minimal bounding box' }, + + { 'key': 'item_ndx', + 'type': 'DWORD', + 'off': 0x0040, + 'label': 'First item index' }, + + { 'key': 'item_cnt', + 'type': 'DWORD', + 'off': 0x0044, + 'label': 'Item count' }, + + { 'key': 'trap_script', + 'type': 'RESREF', + 'off': 0x0048, + 'label': 'Resref of trap script' }, + + { 'key': 'vertex_ndx', + 'type': 'DWORD', + 'off': 0x0050, + 'label': 'First vertex index' }, + + { 'key': 'vertex_cnt', + 'type': 'WORD', + 'off': 0x0054, + 'label': 'Count of border vertices' }, + + { 'key': 'unknown_58', + 'type': 'STR32', + 'off': 0x0058, + 'label': 'Unknown 58 (some trap trigger?)' }, + + { 'key': 'key_resref', + 'type': 'RESREF', + 'off': 0x0078, + 'label': 'Resref of key item' }, + + { 'key': 'unknown_80', + 'type': 'DWORD', + 'off': 0x0080, + 'label': 'Unknown 80' }, + + { 'key': 'unlockable_tlk_ref', + 'type': 'DWORD', + 'off': 0x0084, + 'label': 'TLK ref when lockpicking unlockable container' }, + + { 'key': 'unknown_88', + 'type': 'BYTES', + 'off': 0x0088, + 'size': 56, + 'label': 'Unknown 88' }, + ) + + + item_desc = ( + { 'key': 'item_resref', + 'type': 'RESREF', + 'off': 0x0000, + 'label': 'ITM resource Resref' }, + + { 'key': 'expiration_time', + 'type': 'WORD', + 'off': 0x0008, + 'label': 'Item expiration time (replace with drained item)' }, + + { 'key': 'usage1', + 'type': 'WORD', + 'off': 0x000A, + 'label': 'Usage 1 (usually # of items or charges)' }, + + { 'key': 'usage2', + 'type': 'WORD', + 'off': 0x000C, + 'label': 'Usage 2 (usually # of sec. charges)' }, + + { 'key': 'usage3', + 'type': 'WORD', + 'off': 0x000E, + 'label': 'Usage 3 (usually # of terc. charges)' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0010, + 'mask': { 0x1: 'Identified', 0x2: 'Unstealable', 0x4: 'Stolen', 0x8: 'Undroppable' }, + 'label': 'Flags' }, + + ) + + # Vertices + + ambient_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Ambient name' }, + + { 'key': 'origin_point', + 'type': 'POINT', + 'off': 0x0020, + 'label': 'Origin point' }, + + { 'key': 'radius', + 'type': 'WORD', + 'off': 0x0024, + 'label': 'Sound radius' }, + + { 'key': 'height', + 'type': 'BYTES', + 'off': 0x0026, + 'size': 2, + 'label': 'Sound height' }, + + { 'key': 'unknown_28', + 'type': 'BYTES', + 'off': 0x0028, + 'size': 6, + 'label': 'Unknown 28' }, + + { 'key': 'volume', + 'type': 'WORD', + 'off': 0x002E, + 'label': 'Sound volume' }, + + { 'key': 'sound_resref_0', + 'type': 'RESREF', + 'off': 0x0030, + 'label': 'Sound Resref 0' }, + + { 'key': 'sound_resref_1', + 'type': 'RESREF', + 'off': 0x0038, + 'label': 'Sound Resref 1' }, + + { 'key': 'sound_resref_2', + 'type': 'RESREF', + 'off': 0x0040, + 'label': 'Sound Resref 2' }, + + { 'key': 'sound_resref_3', + 'type': 'RESREF', + 'off': 0x0048, + 'label': 'Sound Resref 3' }, + + { 'key': 'sound_resref_4', + 'type': 'RESREF', + 'off': 0x0050, + 'label': 'Sound Resref 4' }, + + { 'key': 'sound_resref_5', + 'type': 'RESREF', + 'off': 0x0058, + 'label': 'Sound Resref 5' }, + + { 'key': 'sound_resref_6', + 'type': 'RESREF', + 'off': 0x0060, + 'label': 'Sound Resref 6' }, + + { 'key': 'sound_resref_7', + 'type': 'RESREF', + 'off': 0x0068, + 'label': 'Sound Resref 7' }, + + { 'key': 'sound_resref_8', + 'type': 'RESREF', + 'off': 0x0070, + 'label': 'Sound Resref 8' }, + + { 'key': 'sound_resref_9', + 'type': 'RESREF', + 'off': 0x0078, + 'label': 'Sound Resref 9' }, + + { 'key': 'sound_resref_cnt', + 'type': 'WORD', + 'off': 0x0080, + 'label': 'Count of sound Resrefs' }, + + { 'key': 'sound_resref_cnt2', + 'type': 'WORD', + 'off': 0x0082, + 'label': 'Count of sound Resrefs or 0' }, + + { 'key': 'base_time_interval', + 'type': 'DWORD', + 'off': 0x0084, + 'label': 'Base time interval [s] between sounds' }, + + { 'key': 'base_time_deviation', + 'type': 'DWORD', + 'off': 0x0088, + 'label': 'Base time deviation' }, + + { 'key': 'appearance_time', + 'type': 'DWORD', + 'off': 0x008C, + 'mask': { 2^0: '00:30-01:29', 2^1: '01:30-02:29', 2^2: '02:30-03:29', 2^3: '03:30-04:29', 2^4: '04:30-05:29', 2^5: '05:30-06:29', 2^6: '06:30-07:29', 2^7: '07:30-08:29', 2^8: '08:30-09:29', 2^9: '09:30-10:29', 2^10: '10:30-11:29', 2^11: '11:30-12:29', 2^12: '12:30-13:29', 2^13: '13:30-14:29', 2^14: '14:30-15:29', 2^15: '15:30-16:29', 2^16: '16:30-17:29', 2^17: '17:30-18:29', 2^18: '18:30-19:29', 2^19: '19:30-20:29', 2^20: '20:30-21:29 (dusk)', 2^21: '21:30-22:29 (night)', 2^22: '22:30-23:29', 2^23: '23:30-00:29' }, + 'label': 'Ambient appearance time' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0090, + 'mask': { 0x01: 'Ambient enabled', 0x02: 'Reverb', 0x04: 'Global', 0x08: 'Random ambient selection', 0x10: 'Unknown bit4', 0x20: 'Unknown bit5', 0x40: 'Unknown bit6', 0x80: 'Unknown bit7' }, + 'label': 'Flags' }, + + { 'key': 'unknown_94', + 'type': 'BYTES', + 'off': 0x0094, + 'size': 64, + 'label': 'Unknown 94' }, + ) + + + variable_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Variable name' }, + + { 'key': 'unknown_20', + 'type': 'BYTES', + 'off': 0x0020, + 'size': 8, + 'label': 'Unknown 20' }, + + { 'key': 'value', + 'type': 'DWORD', + 'off': 0x0028, + 'label': 'Variable value' }, + + { 'key': 'unknown_2C', + 'type': 'BYTES', + 'off': 0x002C, + 'size': 40, + 'label': 'Unknown 2C' }, + + ) + + # Explored bitmask + + door_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Long name' }, + + { 'key': 'short_name', + 'type': 'STR8', + 'off': 0x0020, + 'label': 'Short name' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0028, + 'mask': { 0x0001: 'Door open', 0x0002: 'Locked', 0x0004: 'Reset trap', 0x0008: 'Trap detectable', 0x0010: 'Broken', 0x0020: 'Can\'t close', 0x0040: 'Linked', 0x0080: 'Door hidden', 0x0100: 'Door found', 0x0200: 'Don\'t block LOS', 0x0400: 'Remove key', 0x0800: 'Slide' }, + 'label': 'Flags' }, + + { 'key': 'open_vertex_ndx', + 'type': 'DWORD', + 'off': 0x002C, + 'label': 'First vertex index of open door outline' }, + + { 'key': 'open_vertex_cnt', + 'type': 'WORD', + 'off': 0x0030, + 'label': 'Count of vertices in open door outline' }, + + { 'key': 'closed_vertex_cnt', + 'type': 'WORD', + 'off': 0x0032, + 'label': 'Count of vertices in closed door outline' }, + + { 'key': 'closed_vertex_ndx', + 'type': 'DWORD', + 'off': 0x0034, + 'label': 'First vertex index of closed door outline' }, + + { 'key': 'open_bounding_box', + 'type': 'RECT', + 'off': 0x0038, + 'label': 'Open door bounding box' }, + + { 'key': 'closed_bounding_box', + 'type': 'RECT', + 'off': 0x0040, + 'label': 'Closed door bounding box' }, + + { 'key': 'impeded_open_vertex_ndx', + 'type': 'DWORD', + 'off': 0x0048, + 'label': 'First vertex index of open door impeded cell block' }, + + { 'key': 'impeded_open_vertex_cnt', + 'type': 'WORD', + 'off': 0x004C, + 'label': 'Count of vertices in open door impeded cell block' }, + + { 'key': 'impeded_closed_vertex_cnt', + 'type': 'WORD', + 'off': 0x004E, + 'label': 'Count of vertices in closed door impeded cell block' }, + + { 'key': 'impeded_closed_vertex_ndx', + 'type': 'DWORD', + 'off': 0x0050, + 'label': 'First vertex index of closed door impeded cell block' }, + + { 'key': 'unknown_54', + 'type': 'WORD', + 'off': 0x0054, + 'label': 'Unknown 54' }, + + { 'key': 'unknown_56', + 'type': 'WORD', + 'off': 0x0056, + 'label': 'Unknown 56' }, + + { 'key': 'open_door_sound', + 'type': 'RESREF', + 'off': 0x0058, + 'label': 'Open door sound' }, + + { 'key': 'close_door_sound', + 'type': 'RESREF', + 'off': 0x0060, + 'label': 'Close door sound' }, + + { 'key': 'cursor_ndx', + 'type': 'DWORD', + 'off': 0x0068, + 'label': 'Frame index to cursors.bam' }, + + { 'key': 'trap_detection_difficulty', + 'type': 'WORD', + 'off': 0x006C, + 'label': 'Trap detection difficulty' }, + + { 'key': 'trap_removal_difficulty', + 'type': 'WORD', + 'off': 0x006E, + 'label': 'Trap removal difficulty' }, + + { 'key': 'trapped_flag', + 'type': 'WORD', + 'off': 0x0070, + 'label': 'Trapped flag' }, + + { 'key': 'trap_detected_flag', + 'type': 'WORD', + 'off': 0x0072, + 'label': 'Trap detected flag' }, + + { 'key': 'trap_launch_target', + 'type': 'POINT', + 'off': 0x0074, + 'label': 'Trap launch target' }, + + { 'key': 'key_resref', + 'type': 'RESREF', + 'off': 0x0078, + 'label': 'Key item Resref' }, + + { 'key': 'key_script', + 'type': 'RESREF', + 'off': 0x0080, + 'label': 'Key item script Resref' }, + + { 'key': 'detection_difficulty', + 'type': 'DWORD', + 'off': 0x0088, + 'label': 'Detection difficulty (secret doors)' }, + + { 'key': 'lock_difficulty', + 'type': 'DWORD', + 'off': 0x008C, + 'label': 'Lock difficulty [%]' }, + + { 'key': 'approach_location_0', + 'type': 'POINT', + 'off': 0x0090, + 'label': 'First location to approach the door' }, + + { 'key': 'approach_location_1', + 'type': 'POINT', + 'off': 0x0094, + 'label': 'Second location to approach the door' }, + + { 'key': 'unpickable_strref', + 'type': 'STRREF', + 'off': 0x0098, + 'label': 'Picklock attempt on unpickable door strref' }, + + { 'key': 'region_link', + 'type': 'STR32', + 'off': 0x009C, + 'label': 'Region link' }, + + { 'key': 'dialog_name', + 'type': 'STRREF', + 'off': 0x00BC, + 'label': 'Name used in dialogs' }, + + { 'key': 'dialog_resref', + 'type': 'RESREF', + 'off': 0x00C0, + 'label': 'Door\'s dialog Resref' }, + ) + + # Animations + animation_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Animation name' }, + + { 'key': 'centre', + 'type': 'POINT', + 'off': 0x0020, + 'label': 'Centre point' }, + + { 'key': 'appearance_time', + 'type': 'DWORD', + 'off': 0x0024, + 'mask': { 2^0: '00:30-01:29', 2^1: '01:30-02:29', 2^2: '02:30-03:29', 2^3: '03:30-04:29', 2^4: '04:30-05:29', 2^5: '05:30-06:29', 2^6: '06:30-07:29', 2^7: '07:30-08:29', 2^8: '08:30-09:29', 2^9: '09:30-10:29', 2^10: '10:30-11:29', 2^11: '11:30-12:29', 2^12: '12:30-13:29', 2^13: '13:30-14:29', 2^14: '14:30-15:29', 2^15: '15:30-16:29', 2^16: '16:30-17:29', 2^17: '17:30-18:29', 2^18: '18:30-19:29', 2^19: '19:30-20:29', 2^20: '20:30-21:29 (dusk)', 2^21: '21:30-22:29 (night)', 2^22: '22:30-23:29', 2^23: '23:30-00:29' }, + 'label': 'Appearance time' }, + + { 'key': 'bam_resref', + 'type': 'RESREF', + 'off': 0x0028, + 'label': 'Animation BAM resref' }, + + { 'key': 'bam_sequence', + 'type': 'WORD', + 'off': 0x0030, + 'label': 'BAM sequence number' }, + + { 'key': 'bam_frame', + 'type': 'WORD', + 'off': 0x0032, + 'label': 'Number of frame within BAM sequence' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0034, + 'mask': { 0x0001: 'Anim enabled', 0x0002: 'Black is transparent', 0x0004: 'Non-self illumination', 0x0008: 'Partial animation', 0x0010: 'Synchronized draw', 0x0020: 'Unknown bit5', 0x0040: 'Wall doesn\'t hide anim', 0x0080: 'Invisible in dark', 0x0100: 'Not cover', 0x0200: 'Play all frames', 0x0400: 'Use palette bitmap', 0x0800: 'Mirrored', 0x1000: 'Show in combat', 0x2000: 'Unknown bit13', 0x4000: 'Unknown bit14', 0x8000: 'Unknown bit15' }, + 'label': 'Flags' }, + + { 'key': 'height', + 'type': 'WORD', + 'off': 0x0038, + 'label': 'Height' }, + + { 'key': 'transparency', + 'type': 'WORD', + 'off': 0x003A, + 'label': 'Transparency (255 is invisible)' }, + + { 'key': 'starting_frame', + 'type': 'WORD', + 'off': 0x003C, + 'label': 'Starting frame (0 is random)' }, + + { 'key': 'looping_chance', + 'type': 'BYTE', + 'off': 0x003E, + 'label': 'Looping chance (0 is 100)' }, + + { 'key': 'skip_cycles', + 'type': 'BYTE', + 'off': 0x003F, + 'label': 'Skip cycles' }, + + { 'key': 'palette', + 'type': 'RESREF', + 'off': 0x0040, + 'label': 'Palette' }, + + { 'key': 'unknown_48', + 'type': 'DWORD', + 'off': 0x0048, + 'label': 'Unknown 48' }, + ) + + + automap_note_pst_desc = ( + { 'key': 'x', + 'type': 'DWORD', + 'off': 0x0000, + 'label': 'X coordinate' }, + + { 'key': 'y', + 'type': 'DWORD', + 'off': 0x0004, + 'label': 'Y coordinate' }, + + { 'key': 'text', + 'type': 'BYTES', + 'off': 0x0008, + 'size': 500, + 'label': 'Note text' }, + + { 'key': 'color', + 'type': 'DWORD', + 'off': 0x01FC, + 'enum': {0 : 'Blue (user)', 1: 'Red (game)' }, + 'label': 'Note pin color / type' }, + + { 'key': 'unknown_200', + 'type': 'BYTES', + 'off': 0x0200, + 'size': 5 * 4, + 'label': 'Unknown 200' }, + + ) + + automap_note_desc = automap_note_pst_desc + + + tiled_object_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Tiled object name' }, + + { 'key': 'unknown_20', + 'type': 'RESREF', + 'off': 0x0020, + 'label': 'Unknown 20' }, + + { 'key': 'unknown_28', + 'type': 'DWORD', + 'off': 0x0028, + 'label': 'Unknown 28' }, + + { 'key': 'primary_search_squares_start', + 'type': 'DWORD', + 'off': 0x002C, + 'label': 'Primary search squares start' }, + + { 'key': 'primary_search_squares_cnt', + 'type': 'DWORD', + 'off': 0x0030, + 'label': 'Primary search squares count' }, + + { 'key': 'secondary_search_squares_start', + 'type': 'DWORD', + 'off': 0x0034, + 'label': 'Secondary search squares start' }, + + { 'key': 'secondary_search_squares_cnt', + 'type': 'DWORD', + 'off': 0x0038, + 'label': 'Secondary search squares count' }, + + { 'key': 'unknown_3C', + 'type': 'BYTES', + 'off': 0x003C, + 'size': 48, + 'label': 'Unknown 3C' }, + + ) + + + projectile_trap_desc = ( + { 'key': 'projectile_resref', + 'type': 'RESREF', + 'off': 0x0000, + 'label': 'Projectile resref' }, + + { 'key': 'effect_block_off', + 'type': 'DWORD', + 'off': 0x0008, + 'label': 'Effect block offset' }, + + { 'key': 'effect_block_size', + 'type': 'DWORD', + 'off': 0x000C, + 'label': 'Effect block size' }, + + { 'key': 'unknown_10', + 'type': 'DWORD', + 'off': 0x0010, + 'label': 'Unknown 10' }, + + { 'key': 'position', + 'type': 'POINT', + 'off': 0x0014, + 'label': 'Position' }, + + { 'key': 'unknown_18', + 'type': 'WORD', + 'off': 0x0018, + 'label': 'Unknown 18' }, + ) + + + song_desc = ( + { 'key': 'day_song_ref_no', + 'type': 'DWORD', + 'off': 0x0000, + 'label': 'Day song reference number' }, + + { 'key': 'night_song_ref_no', + 'type': 'DWORD', + 'off': 0x0004, + 'label': 'Night song reference number' }, + + { 'key': 'win_song_ref_no', + 'type': 'DWORD', + 'off': 0x0008, + 'label': 'Win song reference number' }, + + { 'key': 'battle_song_ref_no', + 'type': 'DWORD', + 'off': 0x000C, + 'label': 'Battle song reference number' }, + + { 'key': 'lose_song_ref_no', + 'type': 'DWORD', + 'off': 0x0010, + 'label': 'Lose song reference number' }, + + { 'key': 'unknown_14', + 'type': 'DWORD', + 'off': 0x0014, + 'label': 'Unknown 14' }, + + { 'key': 'unknown_18', + 'type': 'DWORD', + 'off': 0x0018, + 'label': 'Unknown 18' }, + + { 'key': 'unknown_1C', + 'type': 'DWORD', + 'off': 0x001C, + 'label': 'Unknown 1C' }, + + { 'key': 'unknown_20', + 'type': 'DWORD', + 'off': 0x0020, + 'label': 'Unknown 20' }, + + { 'key': 'unknown_24', + 'type': 'DWORD', + 'off': 0x0024, + 'label': 'Unknown 24' }, + + { 'key': 'main_day_ambient_1', + 'type': 'RESREF', + 'off': 0x0028, + 'label': 'Main day ambient 1 (WAV)' }, + + { 'key': 'main_day_ambient_2', + 'type': 'RESREF', + 'off': 0x0030, + 'label': 'Main day ambient 2 (WAV)' }, + + { 'key': 'main_day_ambient_volume', + 'type': 'DWORD', + 'off': 0x0038, + 'label': 'Main day ambient volume [%]' }, + + { 'key': 'main_night_ambient_1', + 'type': 'RESREF', + 'off': 0x003C, + 'label': 'Main night ambient 1 (WAV)' }, + + { 'key': 'main_night_ambient_2', + 'type': 'RESREF', + 'off': 0x0044, + 'label': 'Main night ambient 2 (WAV)' }, + + { 'key': 'main_night_ambient_volume', + 'type': 'DWORD', + 'off': 0x004C, + 'label': 'Main night ambient volume [%]' }, + + { 'key': 'pst_songflag_ids', + 'type': 'DWORD', + 'off': 0x0050, + 'enum': 'songflag', + 'label': 'PST SongFlag.IDS link' }, + + { 'key': 'unknown_54', + 'type': 'BYTES', + 'off': 0x0054, + 'size': 60, + 'label': 'Unknown 54' }, + ) + + + rest_interrupt_desc = ( + { 'key': 'name', + 'type': 'STR32', + 'off': 0x0000, + 'label': 'Name' }, + + { 'key': 'strref_0', + 'type': 'STRREF', + 'off': 0x0020, + 'label': 'Strref 0' }, + + { 'key': 'strref_1', + 'type': 'STRREF', + 'off': 0x0024, + 'label': 'Strref 1' }, + + { 'key': 'strref_2', + 'type': 'STRREF', + 'off': 0x0028, + 'label': 'Strref 2' }, + + { 'key': 'strref_3', + 'type': 'STRREF', + 'off': 0x002C, + 'label': 'Strref 3' }, + + { 'key': 'strref_4', + 'type': 'STRREF', + 'off': 0x0030, + 'label': 'Strref 4' }, + + { 'key': 'strref_5', + 'type': 'STRREF', + 'off': 0x0034, + 'label': 'Strref 5' }, + + { 'key': 'strref_6', + 'type': 'STRREF', + 'off': 0x0038, + 'label': 'Strref 6' }, + + { 'key': 'strref_7', + 'type': 'STRREF', + 'off': 0x003C, + 'label': 'Strref 7' }, + + { 'key': 'strref_8', + 'type': 'STRREF', + 'off': 0x0040, + 'label': 'Strref 8' }, + + { 'key': 'strref_9', + 'type': 'STRREF', + 'off': 0x0044, + 'label': 'Strref 9' }, + + { 'key': 'cre_resref_0', + 'type': 'RESREF', + 'off': 0x0048, + 'label': 'CRE resref 0' }, + + { 'key': 'cre_resref_1', + 'type': 'RESREF', + 'off': 0x0050, + 'label': 'CRE resref 1' }, + + { 'key': 'cre_resref_2', + 'type': 'RESREF', + 'off': 0x0058, + 'label': 'CRE resref 2' }, + + { 'key': 'cre_resref_3', + 'type': 'RESREF', + 'off': 0x0060, + 'label': 'CRE resref 3' }, + + { 'key': 'cre_resref_4', + 'type': 'RESREF', + 'off': 0x0068, + 'label': 'CRE resref 4' }, + + { 'key': 'cre_resref_5', + 'type': 'RESREF', + 'off': 0x0070, + 'label': 'CRE resref 5' }, + + { 'key': 'cre_resref_6', + 'type': 'RESREF', + 'off': 0x0078, + 'label': 'CRE resref 6' }, + + { 'key': 'cre_resref_7', + 'type': 'RESREF', + 'off': 0x0080, + 'label': 'CRE resref 7' }, + + { 'key': 'cre_resref_8', + 'type': 'RESREF', + 'off': 0x0088, + 'label': 'CRE resref 8' }, + + { 'key': 'cre_resref_9', + 'type': 'RESREF', + 'off': 0x0090, + 'label': 'CRE resref 9' }, + + { 'key': 'cre_cnt', + 'type': 'WORD', + 'off': 0x0098, + 'label': 'Count of CRE entries' }, + + { 'key': 'unknown_9A', + 'type': 'WORD', + 'off': 0x009A, + 'label': 'Unknown 9A (freq? diff?)' }, + + { 'key': 'unknown_9C', + 'type': 'DWORD', + 'off': 0x009C, + 'label': 'Unknown 9C' }, + + { 'key': 'unknown_A0', + 'type': 'WORD', + 'off': 0x00A0, + 'label': 'Unknown A0' }, + + { 'key': 'unknown_A2', + 'type': 'WORD', + 'off': 0x00A2, + 'label': 'Unknown A2' }, + + { 'key': 'spawned_cnt_max', + 'type': 'WORD', + 'off': 0x00A4, + 'label': 'Max number of spawned creatures' }, + + { 'key': 'unknown_A6', + 'type': 'WORD', + 'off': 0x00A6, + 'label': 'Unknown A6' }, + + { 'key': 'day_chance', + 'type': 'WORD', + 'off': 0x00A8, + 'label': 'Day chance?' }, + + { 'key': 'night_chance', + 'type': 'WORD', + 'off': 0x00AA, + 'label': 'Night chance?' }, + + { 'key': 'unknown_AC', + 'type': 'BYTES', + 'off': 0x00AC, + 'size': 56, + 'label': 'Unknown AC' }, + ) + + + def __init__ (self): Format.__init__ (self) self.expect_signature = 'AREA' + self.actor_list = [] + self.infopoint_list = [] + self.spawnpoint_list = [] + self.entrance_list = [] + self.container_list = [] + self.item_list = [] + # vertex_list + self.ambient_list = [] + self.variable_list = [] + # "Explored" bitmask + self.door_list = [] + self.animation_list = [] + self.automap_note_list = [] + self.tiled_object_list = [] + self.projectile_trap_list = [] + self.song = None + self.rest_interrupt = None - - def read (self, stream): self.read_header (stream) -# if self.header['projectile_type'] == 3: -# self.decode_area_header () + ##self.read_list (stream, 'actor') + ##self.read_list (stream, 'infopoint') + self.read_list (stream, 'spawnpoint') + ##self.read_list (stream, 'entrance') + self.read_list (stream, 'container') + self.read_list (stream, 'item') + # vertex_list + ##self.read_list (stream, 'ambient') + self.read_list (stream, 'variable') + # "Explored" bitmask + self.read_list (stream, 'door') + self.read_list (stream, 'animation') + self.read_list (stream, 'automap_note') + self.read_list (stream, 'tiled_object') + self.read_list (stream, 'projectile_trap') + obj = {} + self.read_struc (stream, self.header['song_off'], self.song_desc, obj) + self.song = obj + + obj = {} + self.read_struc (stream, self.header['rest_interrupt_off'], self.rest_interrupt_desc, obj) + self.rest_interrupt = obj + + def printme (self): self.print_header () -# if self.header['projectile_type'] == 3: -# self.print_area_header () - + self.print_list ('actor') + self.print_list ('infopoint') + self.print_list ('spawnpoint') + self.print_list ('entrance') + self.print_list ('container') + self.print_list ('item') + # vertex_list + self.print_list ('ambient') + self.print_list ('variable') + # "Explored" bitmask + self.print_list ('door') + self.print_list ('animation') + self.print_list ('automap_note') + self.print_list ('tiled_object') + self.print_list ('projectile_trap') + self.print_struc (self.song, self.song_desc) + self.print_struc (self.rest_interrupt, self.rest_interrupt_desc) + + register_format ('AREA', 'V1.0', ARE_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/biff.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-03-18 08:55:56 UTC (rev 5125) +++ ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-03-21 23:39:50 UTC (rev 5126) @@ -20,7 +20,9 @@ import gzip from infinity.format import Format, register_format +from infinity.stream import CompressedStream + class BIFF_Format (Format): header_desc = ( { 'key': 'signature', @@ -184,6 +186,11 @@ # FIXME: the following API is ugly def get_file_data (self, stream, obj): + # avoid rereading already read data and also do not replace data read from uncompressed stream + # in the case of a CBF file + if obj.has_key ('data'): + return obj['data'] + if obj.has_key ('tile_cnt'): return self.read_tileset_data (stream, obj) else: @@ -192,14 +199,15 @@ # FIXME: this is ugly def save_file_data (self, stream, filename, obj): + # FIXME: does not work with CBF files and the outer stream self.get_file_data (stream, obj) fh = open (filename, 'w') fh.write (obj['data']) fh.close () -class BIFC_V1_Format (Format): - header_desc = ( +class BIFC_V1_Format (BIFF_Format): + envelope_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -233,30 +241,34 @@ ) def __init__ (self): - Format.__init__ (self) + BIFF_Format.__init__ (self) self.expect_signature = 'BIF ' def read (self, stream): - self.read_header (stream) + self.read_envelope (stream) - self.read_struc (stream, 0x000c + self.header['filename_len'], (self.header_desc[4], ), self.header) - self.read_struc (stream, 0x0010 + self.header['filename_len'], ( self.header_desc[5], ), self.header) + self.read_struc (stream, 0x000C + self.envelope['filename_len'], (self.envelope_desc[4], ), self.envelope) + self.read_struc (stream, 0x0010 + self.envelope['filename_len'], ( self.envelope_desc[5], ), self.envelope) - #self.stream.seek (..) - data = stream.decode_blob (0x0014 + self.header['filename_len'], self.header['compressed_size']) - self.data = gzip.zlib.decompress (data) + data = stream.read_blob (0x0014 + self.envelope['filename_len'], self.envelope['compressed_size']) + stream2 = CompressedStream ().open (data) + res = BIFF_Format.read (self, stream2) + # read the data with uncompressed stream while we have it + self.read_all_data (stream2) + return res + - def printme (self): - self.print_header () + self.print_envelope () + print + BIFF_Format.printme (self) - - def read_header (self, stream): - self.header = {} - self.read_struc (stream, 0x0000, self.header_desc, self.header) + def read_envelope (self, stream): + self.envelope = {} + self.read_struc (stream, 0x0000, self.envelope_desc, self.envelope) - def print_header (self): - self.print_struc (self.header, self.header_desc) + def print_envelope (self): + self.print_struc (self.envelope, self.envelope_desc) Modified: ie_shell/branches/iesh-infinity/infinity/formats/itm.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-03-18 08:55:56 UTC (rev 5125) +++ ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-03-21 23:39:50 UTC (rev 5126) @@ -1,6 +1,6 @@ # -*-python-*- # ie_shell.py - Simple shell for Infinity Engine-based game files -# Copyright (C) 2004 by Jaroslav Benkovsky, <edh...@us...> +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -21,15 +21,7 @@ from infinity.format import Format, register_format class ITM_Format (Format): - def __init__ (self, filename): - Format.__init__ (self, filename) - self.expect_signature = 'ITM' - - self.extended_header_list = [] - self.equipping_feature_block_list = [] - - - self.header_desc = ( + header_desc = ( { 'key': 'signature', 'type': 'STR4', 'off': 0x0000, @@ -183,15 +175,15 @@ 'off': 0x006A, 'label': 'Feature block offset'}, - { 'key': 'equipping_feature_block_off', + { 'key': 'equipping_feature_ndx', 'type': 'WORD', 'off': 0x006E, - 'label': 'Equipping feature block offset'}, + 'label': 'First equipping feature index'}, - { 'key': 'equipping_feature_... [truncated message content] |
From: <edh...@us...> - 2008-03-24 21:34:55
|
Revision: 5127 http://gemrb.svn.sourceforge.net/gemrb/?rev=5127&view=rev Author: edheldil Date: 2008-03-24 14:34:58 -0700 (Mon, 24 Mar 2008) Log Message: ----------- * added STOR format * small bugfix in IDS * moved some lines in TODO Modified Paths: -------------- ie_shell/branches/iesh-infinity/TODO ie_shell/branches/iesh-infinity/infinity/formats/__init__.py ie_shell/branches/iesh-infinity/infinity/formats/ids.py Added Paths: ----------- ie_shell/branches/iesh-infinity/infinity/formats/stor.py Modified: ie_shell/branches/iesh-infinity/TODO =================================================================== --- ie_shell/branches/iesh-infinity/TODO 2008-03-21 23:39:50 UTC (rev 5126) +++ ie_shell/branches/iesh-infinity/TODO 2008-03-24 21:34:58 UTC (rev 5127) @@ -5,3 +5,9 @@ - e.g.: door_cnt or doors_cnt ? # of doors or Doors count? + +Data types: + +1. OFFSET/COUNT data type? +2. make data types with mask automatically report unknown bits +3. Add file type to RESREF data type (i.e. RESREF/ITM) Modified: ie_shell/branches/iesh-infinity/infinity/formats/__init__.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-03-21 23:39:50 UTC (rev 5126) +++ ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-03-24 21:34:58 UTC (rev 5127) @@ -12,6 +12,7 @@ import mos import pro import spl +import stor import tis import tlk import vvc Modified: ie_shell/branches/iesh-infinity/infinity/formats/ids.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-03-21 23:39:50 UTC (rev 5126) +++ ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-03-24 21:34:58 UTC (rev 5127) @@ -63,12 +63,12 @@ # FIXME: if keys are duplicate, which one wins? # The first one or the last one? if self.ids.has_key (ikey): - print "Warning: %s: Duplicate key %s" %(self.stream, key) + print "Warning: %s: Duplicate key %s" %(stream, key) else: self.ids[ikey] = value if self.ids_re.has_key (value): - print "Warning: %s: Duplicate value %s" %(self.stream, value) + print "Warning: %s: Duplicate value %s" %(stream, value) else: self.ids_re[value] = ikey Copied: ie_shell/branches/iesh-infinity/infinity/formats/stor.py (from rev 5117, ie_shell/branches/iesh-infinity/infinity/formats/cre.py) =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/stor.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/formats/stor.py 2008-03-24 21:34:58 UTC (rev 5127) @@ -0,0 +1,308 @@ +# -*-python-*- +# ie_shell.py - Simple shell for Infinity Engine-based game files +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# RCS: $Id: cre.py,v 1.3 2006/07/03 18:15:35 edheldil Exp $ + +from infinity.format import Format, register_format + + +class STOR_Format (Format): + + header_desc = ( + { 'key': 'signature', + 'type': 'STR4', + 'off': 0x0000, + 'label': 'Signature' }, + + { 'key': 'version', + 'type': 'STR4', + 'off':0x0004, + 'label': 'Version'}, + + { 'key': 'type', + 'type': 'DWORD', + 'off': 0x0008, + 'enum': { 0: 'Store', 1: 'Tavern', 2: 'Inn', 3: 'Temple' }, + 'label': 'Type' }, + + { 'key': 'name', + 'type': 'STRREF', + 'off': 0x000C, + 'label': 'Name strref' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0010, + 'mask': { 0x0001: 'Sells items', 0x0002: 'Buys items', 0x0004: 'Identify', 0x0008: 'Steal', 0x0010: 'Donate', 0x0020: 'Cures', 0x00040: 'Drinks', 0x0080: 'Unknown bit7', 0x0100: 'Unknown bit8', 0x0200: 'Unknown bit9', 0x0400: 'Unknown/Recharge?', 0x0800: 'Unknown bit11', 0x1000: 'Buy fenced goods' }, + 'label': 'Flags' }, + + { 'key': 'sell_price_markup', + 'type': 'DWORD', + 'off': 0x0014, + 'label': 'Sell price markup (% of base price when store sells)' }, + + { 'key': 'buy_price_markup', + 'type': 'DWORD', + 'off': 0x0018, + 'label': 'Buy price markup (% of base price when store buys)' }, + + + { 'key': 'depreciation_rate', + 'type': 'DWORD', + 'off': 0x001C, + 'label': 'Depreciation rate' }, + + { 'key': 'steal_failure_chance', + 'type': 'WORD', #FIXME: IESDP has DWORD here + 'off': 0x0020, + 'label': 'Steal failure chance' }, + + { 'key': 'capacity', + 'type': 'WORD', #FIXME: IESDP has DWORD here + 'off': 0x0022, + 'label': 'Capacity' }, + + { 'key': 'unknown_24', + 'type': 'BYTES', + 'off': 0x0024, + 'size': 8, + 'label': 'Unknown 24' }, + + { 'key': 'bought_item_off', + 'type': 'DWORD', + 'off': 0x002C, + 'label': 'Offset of items bought here' }, + + { 'key': 'bought_item_cnt', + 'type': 'DWORD', + 'off': 0x0030, + 'label': 'Count of items bought here' }, + + { 'key': 'sold_item_off', + 'type': 'DWORD', + 'off': 0x0034, + 'label': 'Offset of items for sale' }, + + { 'key': 'sold_item_cnt', + 'type': 'DWORD', + 'off': 0x0038, + 'label': 'Count of items for sale' }, + + { 'key': 'lore', + 'type': 'DWORD', + 'off': 0x003C, + 'label': 'Lore' }, + + { 'key': 'id_price', + 'type': 'DWORD', + 'off': 0x0040, + 'label': 'ID price' }, + + { 'key': 'rumours_tavern', + 'type': 'RESREF', + 'off': 0x0044, + 'label': 'Rumours (tavern)' }, + + { 'key': 'drink_off', + 'type': 'DWORD', + 'off': 0x004C, + 'label': 'Offset to drinks' }, + + { 'key': 'drink_cnt', + 'type': 'DWORD', + 'off': 0x0050, + 'label': 'Count of drinks' }, + + { 'key': 'rumours_temple', + 'type': 'RESREF', + 'off': 0x0054, + 'label': 'Rumours (temple)' }, + + { 'key': 'room_flags', + 'type': 'DWORD', + 'off': 0x005C, + 'mask': { 0x01: 'Peasant', 0x02: 'Merchant', 0x04: 'Noble', 0x08: 'Royal' }, + 'label': 'Room type flags' }, + + { 'key': 'price_peasant_room', + 'type': 'DWORD', + 'off': 0x0060, + 'label': 'Price of a peasant room' }, + + { 'key': 'price_merchant_room', + 'type': 'DWORD', + 'off': 0x0064, + 'label': 'Price of a merchant room' }, + + { 'key': 'price_noble_room', + 'type': 'DWORD', + 'off': 0x0068, + 'label': 'Price of a noble room' }, + + { 'key': 'price_royal_room', + 'type': 'DWORD', + 'off': 0x006C, + 'label': 'Price of a royal room' }, + + { 'key': 'cure_off', + 'type': 'DWORD', + 'off': 0x0070, + 'label': 'Offset to cures' }, + + { 'key': 'cure_cnt', + 'type': 'DWORD', + 'off': 0x0074, + 'label': 'Count of cures' }, + + { 'key': 'unknown_78', + 'type': 'BYTES', + 'off': 0x0078, + 'size': 36, + 'label': 'Unknown 78' }, + ) + + bought_item_desc = ( + { 'key': 'type', + 'type': 'DWORD', + 'off': 0x0000, + 'enum': 'itemtypes', + 'label': 'Type' }, + ) + + + sold_item_desc = ( + { 'key': 'itm_resref', + 'type': 'RESREF', + 'off': 0x0000, + 'label': 'ITM resref' }, + + { 'key': 'unknown_08', + 'type': 'WORD', + 'off': 0x0008, + 'label': 'Unknown 08' }, + + { 'key': 'usage_1', + 'type': 'WORD', + 'off': 0x000A, + 'label': 'Usage 1/Stock amount' }, + + { 'key': 'usage_2', + 'type': 'WORD', + 'off': 0x000C, + 'label': 'Usage 2' }, + + { 'key': 'usage_3', + 'type': 'WORD', + 'off': 0x000E, + 'label': 'Usage 3' }, + + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0010, + 'mask': { 0x01: 'Identified', 0x02: 'Unstealable', 0x04: 'Stolen', 0x08: 'Undroppable' }, + 'label': 'Flags' }, + + { 'key': 'amount_in_stock', + 'type': 'DWORD', + 'off': 0x0014, + 'label': 'Amount in stock' }, + + { 'key': 'infinite_supply_flag', + 'type': 'DWORD', + 'off': 0x0018, + 'label': 'Infinite supply flag (1=infinite stock)' }, + + { 'key': 'trigger_strref', + 'type': 'STRREF', + 'off': 0x001C, + 'label': 'Trigger strref' }, + + { 'key': 'unknown_20', + 'type': 'BYTES', + 'off': 0x0020, + 'size': 56, + 'label': 'Unknown 20' }, + ) + + + drink_desc = ( + { 'key': 'rumour_resref', + 'type': 'RESREF', + 'off': 0x0000, + 'label': 'Rumour resref' }, + + { 'key': 'name', + 'type': 'STRREF', + 'off': 0x0008, + 'label': 'Drink name' }, + + { 'key': 'price', + 'type': 'DWORD', + 'off': 0x000C, + 'label': 'Drink price' }, + + { 'key': 'strength', + 'type': 'DWORD', + 'off': 0x0010, + 'label': 'Alcoholic strength' }, + ) + + + cure_desc = ( + { 'key': 'spl_resref', + 'type': 'RESREF', + 'off': 0x0000, + 'label': 'SPL resref' }, + + { 'key': 'price', + 'type': 'DWORD', + 'off': 0x0008, + 'label': 'Price of this cure' }, + ) + + + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'STOR' + + self.bought_item_list = [] + self.sold_item_list = [] + self.drink_list = [] + self.cure_list = [] + + + def read (self, stream): + self.read_header (stream) + + self.read_list (stream, 'bought_item') + self.read_list (stream, 'sold_item') + self.read_list (stream, 'drink') + self.read_list (stream, 'cure') + + + def printme (self): + self.print_header () + + self.print_list ('bought_item') + self.print_list ('sold_item') + self.print_list ('drink') + self.print_list ('cure') + + + +register_format ('STOR', 'V1.1', STOR_Format) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <edh...@us...> - 2008-04-01 07:56:41
|
Revision: 5131 http://gemrb.svn.sourceforge.net/gemrb/?rev=5131&view=rev Author: edheldil Date: 2008-04-01 00:56:44 -0700 (Tue, 01 Apr 2008) Log Message: ----------- * CRE header is more or less complete * tweaks, data model enhancements Modified Paths: -------------- ie_shell/branches/iesh-infinity/TODO ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/formats/are.py ie_shell/branches/iesh-infinity/infinity/formats/cre.py ie_shell/branches/iesh-infinity/infinity/formats/stor.py ie_shell/branches/iesh-infinity/infinity/formats/wmap.py Modified: ie_shell/branches/iesh-infinity/TODO =================================================================== --- ie_shell/branches/iesh-infinity/TODO 2008-03-29 09:11:00 UTC (rev 5130) +++ ie_shell/branches/iesh-infinity/TODO 2008-04-01 07:56:44 UTC (rev 5131) @@ -10,4 +10,7 @@ 1. OFFSET/COUNT data type? 2. make data types with mask automatically report unknown bits -3. Add file type to RESREF data type (i.e. RESREF/ITM) +3. Add file type to RESREF data type (e.g. RESREF/ITM) +4. Strip trailing garbage from strings +5. Signed data types (SWORD, SDWORD,...). Ugly, Adding unsigned ones would be better +6. allow for name enums desc items with count > 1 (e.g. 100 strrefs in CRE) Modified: ie_shell/branches/iesh-infinity/infinity/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py 2008-03-29 09:11:00 UTC (rev 5130) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-04-01 07:56:44 UTC (rev 5131) @@ -69,6 +69,7 @@ def print_header (self): self.print_struc (self.header, self.header_desc) + def read_list (self, stream, name, desc = None, list = None): if desc == None: desc = self.__class__.__dict__ [name + '_desc'] @@ -84,6 +85,23 @@ list.append (obj) off += size + def write_list (self, stream, offset, name, desc = None, list = None): + if desc == None: + desc = self.__class__.__dict__ [name + '_desc'] + if list == None: + list = self.__dict__ [name + '_list'] + + self.header[name + '_off'] = offset + self.header[name + '_cnt'] = len (list) + size = self.get_struc_size (desc) + + for obj in list: + self.write_struc (stream, offset, desc, obj) + offset += size + + return offset + + def print_list (self, name, desc = None, list = None): if desc == None: desc = self.__class__.__dict__ [name + '_desc'] @@ -150,75 +168,87 @@ key = d['key'] type = d['type'] local_offset = d['off'] + try: count = d['count'] + except: count = 1 + d['count'] = 1 + size = self.get_struc_size ([ d ]) - local_offset + d['count'] = count if self.get_option ('debug_read'): print d - if type == 'BYTE': - value = ord (stream.get_char (offset + local_offset)) - elif type == 'CTLTYPE': - value = ord (stream.get_char (offset + local_offset)) - elif type == 'WORD': - value = stream.read_word (offset + local_offset) - elif type == 'DWORD': - value = stream.read_dword (offset + local_offset) - elif type == 'POINT': - value0 = stream.read_word (offset + local_offset) - value1 = stream.read_word (offset + local_offset + 2) - value = (value0, value1) - elif type == 'RECT': - value0 = stream.read_word (offset + local_offset) - value1 = stream.read_word (offset + local_offset + 2) - value2 = stream.read_word (offset + local_offset + 4) - value3 = stream.read_word (offset + local_offset + 6) - value = (value0, value1, value2, value3) - elif type == 'CTLID': - value = stream.read_dword (offset + local_offset) - elif type == 'RGBA': - value = stream.read_dword (offset + local_offset) - elif type == 'STR2': - value = stream.read_sized_string (offset + local_offset, 2) - elif type == 'STR4': - value = stream.read_sized_string (offset + local_offset, 4) - elif type == 'STR8': - value = stream.read_sized_string (offset + local_offset, 8) - elif type == 'STR32': - value = stream.read_sized_string (offset + local_offset, 32) - elif type == 'RESREF': - value = stream.read_resref (offset + local_offset) - value = string.translate (value, core.slash_trans, '\x00') - elif type == 'STRREF': - value = stream.read_dword (offset + local_offset) - elif type == 'RESTYPE': - value = stream.read_word (offset + local_offset) - elif type == 'STROFF': - str_offset = stream.read_dword (offset + local_offset) - str_value = stream.read_asciiz_string (str_offset) - str_value = string.translate (str_value, core.slash_trans, '\x00') - obj[key + ':offset'] = str_offset - # FIXME: ugly - #value = (str_offset, str_value) - value = str_value - elif type == 'STRSIZED': - length = stream.read_dword (offset + local_offset) - # FIXME: asciiz or sized??? - value = stream.read_asciiz_string (offset + local_offset + 4) - elif type == 'BYTES': - value = stream.read_blob (offset + local_offset, d['size']) - elif type == '_STRING': - value = '' - elif type == '_BYTE': - value = '?' - else: - raise ValueError ("Unknown data type: " + type) - #value = '' + for index in range (count): + #print d, local_offset, key, type, count, index, size + if type == 'BYTE': + value = ord (stream.get_char (offset + local_offset)) + elif type == 'CTLTYPE': + value = ord (stream.get_char (offset + local_offset)) + elif type == 'WORD': + value = stream.read_word (offset + local_offset) + elif type == 'DWORD': + value = stream.read_dword (offset + local_offset) + elif type == 'POINT': + value0 = stream.read_word (offset + local_offset) + value1 = stream.read_word (offset + local_offset + 2) + value = (value0, value1) + elif type == 'RECT': + value0 = stream.read_word (offset + local_offset) + value1 = stream.read_word (offset + local_offset + 2) + value2 = stream.read_word (offset + local_offset + 4) + value3 = stream.read_word (offset + local_offset + 6) + value = (value0, value1, value2, value3) + elif type == 'CTLID': + value = stream.read_dword (offset + local_offset) + elif type == 'RGBA': + value = stream.read_dword (offset + local_offset) + elif type == 'STR2': + value = stream.read_sized_string (offset + local_offset, 2) + elif type == 'STR4': + value = stream.read_sized_string (offset + local_offset, 4) + elif type == 'STR8': + value = stream.read_sized_string (offset + local_offset, 8) + elif type == 'STR32': + value = stream.read_sized_string (offset + local_offset, 32) + elif type == 'RESREF': + value = stream.read_resref (offset + local_offset) + value = string.translate (value, core.slash_trans, '\x00') + elif type == 'STRREF': + value = stream.read_dword (offset + local_offset) + elif type == 'RESTYPE': + value = stream.read_word (offset + local_offset) + elif type == 'STROFF': + str_offset = stream.read_dword (offset + local_offset) + str_value = stream.read_asciiz_string (str_offset) + str_value = string.translate (str_value, core.slash_trans, '\x00') + obj[key + ':offset'] = str_offset + # FIXME: ugly + #value = (str_offset, str_value) + value = str_value + elif type == 'STRSIZED': + length = stream.read_dword (offset + local_offset) + # FIXME: asciiz or sized??? + value = stream.read_asciiz_string (offset + local_offset + 4) + elif type == 'BYTES': + value = stream.read_blob (offset + local_offset, d['size']) + elif type == '_STRING': + value = '' + elif type == '_BYTE': + value = '?' + else: + raise ValueError ("Unknown data type: " + type) + #value = '' + + if d.has_key ('bits'): + mask, bl = self.bits_to_mask (d['bits']) + value = self.get_masked_bits (value, mask, bl) + + if count > 1: + try: obj[key].append (value) + except KeyError: obj[key] = [ value ] + local_offset += size + else: + obj[key] = value - if d.has_key ('bits'): - mask, bl = self.bits_to_mask (d['bits']) - value = self.get_masked_bits (value, mask, bl) - - obj[key] = value - if self.get_option ('debug_read'): self.print_date_by_desc (obj, d) @@ -291,6 +321,7 @@ else: raise ValueError ("Unknown data type: " + type) + def get_struc_size (self, desc, obj = None): total_size = 0 @@ -364,49 +395,60 @@ try: mask = d['mask'] except: mask = None - value = obj[key] - value2 = '' + try: count = d['count'] + except: count = 1 - if rec_type == 'RESTYPE': - try: value2 = '(' + core.restype_hash[value] + ')' - except: pass - elif rec_type == 'CTLTYPE': - try: value2 = '(' + ctltype_hash[value] + ')' - except: pass - elif rec_type == 'CTLID': - try: value2 = '(' + '0x%08x' %value + ')' - except: pass - elif rec_type == 'STRREF' and core.strrefs: - try: value2 = '(' + core.strrefs.strref_list[value]['string'] + ')' - except: pass - elif rec_type == 'RGBA': - try: value2 = '(' + '%08x' %value + ')' - except: pass - elif enum != None: - if type (enum) == types.DictType: - try: value2 = '(' + enum[value] + ')' + for index in range (count): + if count > 1: + value = obj[key][index] + else: + value = obj[key] + + value2 = '' + + if rec_type == 'RESTYPE': + try: value2 = '(' + core.restype_hash[value] + ')' except: pass - - elif type (enum) == types.StringType: - if not core.ids.has_key (enum): - try: - # FIXME: ugly & should use 'IDS' instead of 0x3F0 - ids = ResourceStream (enum, 0x03F0).load_object () - ids.read () - core.ids[enum] = ids - except: - pass - - try: value2 = '(' + core.ids[enum].ids[value] + ')' + elif rec_type == 'CTLTYPE': + try: value2 = '(' + ctltype_hash[value] + ')' except: pass + elif rec_type == 'CTLID': + try: value2 = '(' + '0x%08x' %value + ')' + except: pass + elif rec_type == 'STRREF' and core.strrefs: + try: value2 = '(' + core.strrefs.strref_list[value]['string'] + ')' + except: pass + elif rec_type == 'RGBA': + try: value2 = '(' + '%08x' %value + ')' + except: pass + elif enum != None: + if type (enum) == types.DictType: + try: value2 = '(' + enum[value] + ')' + except: pass + + elif type (enum) == types.StringType: + if not core.ids.has_key (enum): + try: + # FIXME: ugly & should use 'IDS' instead of 0x3F0 + ids = ResourceStream (enum, 0x03F0).load_object () + ids.read () + core.ids[enum] = ids + except: + pass + + try: value2 = '(' + core.ids[enum].ids[value] + ')' + except: pass + - - elif mask != None: - value2 = '(' + string.join (map (lambda m, mask=mask: mask[m], filter (lambda m, v=value: (m & v) == m, mask.keys ())), '|') + ')' + elif mask != None: + value2 = '(' + string.join (map (lambda m, mask=mask: mask[m], filter (lambda m, v=value: (m & v) == m, mask.keys ())), '|') + ')' + + if count > 1: + print label + '[%d]:' %index, value, value2 + else: + print label + ':', value, value2 - print label + ':', value, value2 - def set_option_default (key, value): Format.default_options[key] = value Modified: ie_shell/branches/iesh-infinity/infinity/formats/are.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-03-29 09:11:00 UTC (rev 5130) +++ ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-04-01 07:56:44 UTC (rev 5131) @@ -860,8 +860,14 @@ ) - # Vertices + vertex_desc = ( + { 'key': 'vertex', + 'type': 'POINT', + 'off': 0x0000, + 'label': 'Vertex' }, + ) + ambient_desc = ( { 'key': 'name', 'type': 'STR32', @@ -1010,8 +1016,6 @@ ) - # Explored bitmask - door_desc = ( { 'key': 'name', 'type': 'STR32', @@ -1180,7 +1184,6 @@ 'label': 'Door\'s dialog Resref' }, ) - # Animations animation_desc = ( { 'key': 'name', 'type': 'STR32', @@ -1633,10 +1636,10 @@ self.entrance_list = [] self.container_list = [] self.item_list = [] - # vertex_list + self.vertex_list = [] self.ambient_list = [] self.variable_list = [] - # "Explored" bitmask + self.explored_bitmask = None self.door_list = [] self.animation_list = [] self.automap_note_list = [] @@ -1649,16 +1652,16 @@ def read (self, stream): self.read_header (stream) - ##self.read_list (stream, 'actor') - ##self.read_list (stream, 'infopoint') + self.read_list (stream, 'actor') + self.read_list (stream, 'infopoint') self.read_list (stream, 'spawnpoint') - ##self.read_list (stream, 'entrance') + self.read_list (stream, 'entrance') self.read_list (stream, 'container') self.read_list (stream, 'item') - # vertex_list - ##self.read_list (stream, 'ambient') + self.read_list (stream, 'vertex') + self.read_list (stream, 'ambient') self.read_list (stream, 'variable') - # "Explored" bitmask + self.explored_bitmask = stream.read_blob (self.header['explored_bitmask_off'], self.header['explored_bitmask_size']) self.read_list (stream, 'door') self.read_list (stream, 'animation') self.read_list (stream, 'automap_note') @@ -1674,6 +1677,38 @@ self.rest_interrupt = obj + def write (self, stream): + off = self.get_struc_size (self.header_desc) + + off = self.write_list (stream, off, 'actor') + off = self.write_list (stream, off, 'infopoint') + off = self.write_list (stream, off, 'spawnpoint') + off = self.write_list (stream, off, 'entrance') + off = self.write_list (stream, off, 'container') + off = self.write_list (stream, off, 'item') + off = self.write_list (stream, off, 'vertex') + off = self.write_list (stream, off, 'ambient') + off = self.write_list (stream, off, 'variable') + + stream.write_blob (self.explored_bitmask, off) + off += len (self.explored_bitmask) + + off = self.write_list (stream, off, 'door') + off = self.write_list (stream, off, 'animation') + off = self.write_list (stream, off, 'automap_note') + off = self.write_list (stream, off, 'tiled_object') + off = self.write_list (stream, off, 'projectile_trap') + + self.header['song_off'] = off + self.write_struc (stream, off, self.song_desc, self.song) + off += self.get_struc_size (self.song_desc) + + self.header['rest_interrupt_off'] = off + self.write_struc (stream, off, self.rest_interrupt_desc, self.rest_interrupt) + off += self.get_struc_size (self.rest_interrupt_desc) + + self.write_header (stream) + def printme (self): self.print_header () @@ -1683,10 +1718,10 @@ self.print_list ('entrance') self.print_list ('container') self.print_list ('item') - # vertex_list + self.print_list ('vertex') self.print_list ('ambient') self.print_list ('variable') - # "Explored" bitmask + # "Explored" bitmask. We need map width and height to print the mask, though and they're not in the ARE structure self.print_list ('door') self.print_list ('animation') self.print_list ('automap_note') Modified: ie_shell/branches/iesh-infinity/infinity/formats/cre.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-03-29 09:11:00 UTC (rev 5130) +++ ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-04-01 07:56:44 UTC (rev 5131) @@ -29,17 +29,17 @@ 'type': 'STR4', 'off': 0x0000, 'label': 'Signature' }, - + { 'key': 'version', 'type': 'STR4', 'off':0x0004, 'label': 'Version'}, - + { 'key': 'long_name', 'type': 'STRREF', 'off': 0x0008, 'label': 'Long creature name'}, - + { 'key': 'short_name', 'type': 'STRREF', 'off': 0x000C, @@ -48,6 +48,7 @@ { 'key': 'flags', 'type': 'DWORD', 'off': 0x0010, + 'mask': { 0x0001: 'Dmg doesn\'t stop casting', 0x0002: 'No corpse', 0x0004: 'Keep corpse', 0x0008: 'Orig class Fighter', 0x0010: 'Orig class Mage', 0x0020: 'Orig class Cleric', 0x0040: 'Orig class Thief', 0x0080: 'Orig class Druid', 0x0100: 'Orig class Ranger', 0x0200: 'Fallen Paladin', 0x0400: 'Fallen Ranger', 0x0800: 'Exportable', 0x1000: 'Unknown bit12', 0x2000: 'Unknown bit13', 0x4000: 'Can activate non-NPC triggers?', 0x8000: 'Been in party'}, 'label': 'Creature flags'}, { 'key': 'xp', @@ -68,6 +69,7 @@ { 'key': 'permanent_status_flags', 'type': 'DWORD', 'off': 0x0020, + 'enum': 'STATE', 'label': 'Permanent status flags'}, # as per STATE.IDS { 'key': 'current_hp', @@ -86,391 +88,648 @@ 'enum': 'ANIMATE', 'label': 'Animation ID'}, # as per ANIMATE.IDS - ) - + { 'key': 'unknown_2A', + 'type': 'WORD', + 'off': 0x002A, + 'label': 'Unknown 2A' }, - window_record_desc = ( - { 'key': 'id', - 'type': 'WORD', - 'off': 0x0000, - 'label': 'Window id' }, - - { 'key': 'unknown1', - 'type': 'WORD', - 'off': 0x0002, - 'label': 'Unknown 1' }, - - { 'key': 'xpos', - 'type': 'WORD', - 'off': 0x0004, - 'label': 'X position' }, - - { 'key': 'ypos', - 'type': 'WORD', - 'off': 0x0006, - 'label': 'Y position' }, - - { 'key': 'width', - 'type': 'WORD', - 'off': 0x0008, - 'label': 'Width' }, - - { 'key': 'height', - 'type': 'WORD', - 'off': 0x000A, - 'label': 'Height' }, - - { 'key': 'bg_flag', - 'type': 'WORD', - 'off': 0x000C, - 'label': 'Background flag' }, - - { 'key': 'num_of_controls', - 'type': 'WORD', - 'off': 0x000E, - 'label': '# of controls' }, - - { 'key': 'bg_name', - 'type': 'RESREF', - 'off': 0x0010, - 'label': 'Background filename' }, + { 'key': 'metal_color_index', + 'type': 'BYTE', + 'off': 0x002C, + 'label': 'Metal color index (BG1 anim)' }, - { 'key': 'control_ndx', - 'type': 'WORD', - 'off': 0x0018, - 'label': 'Index of first control' }, + { 'key': 'minor_color_index', + 'type': 'BYTE', + 'off': 0x002D, + 'label': 'Minor color index (BG1 anim)' }, - { 'key': 'unknown2', - 'type': 'WORD', - 'off': 0x001A, - 'label': 'Unknown 2' }, - - ) + { 'key': 'major_color_index', + 'type': 'BYTE', + 'off': 0x002E, + 'label': 'Major color index (BG1 anim)' }, - control_table_record_desc = ( - { 'key': 'control_offset', - 'type': 'DWORD', - 'off': 0x0000, - 'label': 'Offset of control'}, + { 'key': 'skin_color_index', + 'type': 'BYTE', + 'off': 0x002F, + 'label': 'Skin color index (BG1 anim)' }, - { 'key': 'control_len', - 'type': 'DWORD', - 'off': 0x0004, - 'label': 'Length of control structure'}, - ) + { 'key': 'leather_color_index', + 'type': 'BYTE', + 'off': 0x0030, + 'label': 'Leather color index (BG1 anim)' }, - control_common_record_desc = ( - { 'key': 'id', - 'type': 'CTLID', - 'off': 0x0000, - 'label': 'Control ID' }, - - { 'key': 'xpos', - 'type': 'WORD', - 'off': 0x0004, - 'label': 'X position in window' }, - - { 'key': 'ypos', - 'type': 'WORD', - 'off': 0x0006, - 'label': 'Y position in window' }, - - { 'key': 'width', - 'type': 'WORD', - 'off': 0x0008, - 'label': 'Width' }, - - { 'key': 'height', - 'type': 'WORD', - 'off': 0x000A, - 'label': 'Height' }, - - { 'key': 'type', - 'type': 'CTLTYPE', - 'off': 0x000C, - 'label': 'Control type' }, + { 'key': 'armor_color_index', + 'type': 'BYTE', + 'off': 0x0031, + 'label': 'Armor color index (BG1 anim)' }, - { 'key': 'unknown', - 'type': 'BYTE', - 'off': 0x000D, - 'label': 'Unknown' }, + { 'key': 'hair_color_index', + 'type': 'BYTE', + 'off': 0x0032, + 'label': 'Hair color index (BG1 anim)' }, - ) + { 'key': 'eff_structure_version', + 'type': 'BYTE', + 'off': 0x0033, + 'enum': { 0: 'Version 1', 1: 'Version 2' }, + 'label': 'EFF structure version' }, + { 'key': 'small_portrait_resref', + 'type': 'RESREF', + 'off': 0x0034, + 'label': 'Small portrait resref' }, - control_button_record_desc = ( - { 'key': 'bam_file', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of BAM file w/ pixmap' }, - - { 'key': 'bam_cycle', - 'type': 'BYTE', - 'off': 0x0016, - 'label': 'Cycle in BAM file' }, - - { 'key': 'justification', - 'type': 'BYTE', - 'off': 0x0017, - 'label': 'Button text justification' }, - - { 'key': 'frame_unpressed', - 'type': 'WORD', - 'off': 0x0018, - 'label': 'BAM frame: button unpressed' }, - - { 'key': 'frame_pressed', - 'type': 'WORD', - 'off': 0x001A, - 'label': 'BAM frame: button pressed' }, - - { 'key': 'frame_selected', - 'type': 'WORD', - 'off': 0x001C, - 'label': 'BAM frame: button selected' }, - - { 'key': 'frame_disabled', - 'type': 'WORD', - 'off': 0x001E, - 'label': 'BAM frame: button disabled' }, - - ) + { 'key': 'large_portrait_resref', + 'type': 'RESREF', + 'off': 0x003C, + 'label': 'Large portrait resref' }, - control_slider_record_desc = ( - { 'key': 'mos_file', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of MOS file w/ background' }, - - { 'key': 'bam_file', - 'type': 'RESREF', - 'off': 0x0016, - 'label': 'Name of BAM file w/ pixmap' }, - - { 'key': 'bam_cycle', - 'type': 'BYTE', - 'off': 0x001E, - 'label': 'Cycle in BAM file' }, - - { 'key': 'frame_ungrabbed', - 'type': 'WORD', - 'off': 0x0020, - 'label': 'BAM frame: slider ungrabbed' }, - - { 'key': 'frame_grabbed', - 'type': 'WORD', - 'off': 0x0022, - 'label': 'BAM frame: slider grabbed' }, - - { 'key': 'knob_x', - 'type': 'WORD', - 'off': 0x0024, - 'label': 'Knob X offset' }, - - { 'key': 'knob_y', - 'type': 'WORD', - 'off': 0x0026, - 'label': 'Knob Y offset' }, - - { 'key': 'knob_jump_width', - 'type': 'WORD', - 'off': 0x0028, - 'label': 'Knob jump width' }, - - { 'key': 'knob_jump_count', - 'type': 'WORD', - 'off': 0x002A, - 'label': 'Knob jump count' }, - - { 'key': 'unknown2', - 'type': 'WORD', - 'off': 0x002C, - 'label': 'Unknown 2' }, - - { 'key': 'unknown3', - 'type': 'WORD', - 'off': 0x002E, - 'label': 'Unknown 3' }, - - { 'key': 'unknown4', - 'type': 'WORD', - 'off': 0x0030, - 'label': 'Unknown 4' }, - - { 'key': 'unknown5', - 'type': 'WORD', - 'off': 0x0032, - 'label': 'Unknown 5' }, - - ) + { 'key': 'reputation', + 'type': 'BYTE', # FIXME: actually it's a signed byte + 'off': 0x0044, + 'label': 'Reputation' }, - control_textedit_record_desc = ( - { 'key': 'mos_file_1', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'MOS file 1' }, - - { 'key': 'mos_file_2', - 'type': 'RESREF', - 'off': 0x0016, - 'label': 'MOS file 2' }, - - { 'key': 'mos_file_3', - 'type': 'RESREF', - 'off': 0x001E, - 'label': 'MOS file 3' }, - - { 'key': 'cursor_file', - 'type': 'RESREF', - 'off': 0x0026, - 'label': 'Name of BAM file w/ cursor' }, - - { 'key': 'unknown2', - 'type': 'BYTES', - 'off': 0x002E, - 'size': 12, - 'label': 'Unknown 2' }, - - { 'key': 'font_file', - 'type': 'RESREF', - 'off': 0x003A, - 'label': 'Name of BAM file w/ font' }, - - { 'key': 'unknown3', - 'type': 'BYTES', - 'off': 0x0042, - 'size': 34, - 'label': 'Unknown 3' }, + { 'key': 'hide_in_shadows', + 'type': 'BYTE', + 'off': 0x0045, + 'label': 'Hide in shadows (base)' }, - { 'key': 'input_len', - 'type': 'WORD', - 'off': 0x0064, - 'label': 'Max. input length' }, - - { 'key': 'unknown4', - 'type': 'DWORD', - 'off': 0x0066, - 'label': 'Unknown 4' }, - - ) + { 'key': 'armor_class_natural', + 'type': 'WORD', # FIXME: actually signed word + 'off': 0x0046, + 'label': 'Armor class (natural)' }, - control_textarea_record_desc = ( - { 'key': 'font_file_1', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of BAM file w/ font 1' }, - - { 'key': 'font_file_2', - 'type': 'RESREF', - 'off': 0x0016, - 'label': 'Name of BAM file w/ font 2' }, - - { 'key': 'color_1', - 'type': 'RGBA', - 'off': 0x001E, - 'label': 'Color 1' }, - - { 'key': 'color_2', - 'type': 'RGBA', - 'off': 0x0022, - 'label': 'Color 2' }, - - { 'key': 'color_3', - 'type': 'RGBA', - 'off': 0x0026, - 'label': 'Color 3' }, - - { 'key': 'scrollbar', - 'type': 'DWORD', - 'off': 0x002A, - 'label': 'Scrollbar ID' }, - - ) + { 'key': 'armor_class_effective', + 'type': 'WORD', # FIXME: actually signed word + 'off': 0x0048, + 'label': 'Armor class (effective)' }, - control_label_record_desc = ( - { 'key': 'text', - 'type': 'STRREF', - 'off': 0x000E, - 'label': 'Initial text' }, + { 'key': 'armor_class_crushing_mod', + 'type': 'WORD', # FIXME: actually signed word + 'off': 0x004A, + 'label': 'Armor class (crushing att mod)' }, - { 'key': 'font_file', - 'type': 'RESREF', - 'off': 0x0012, - 'label': 'Name of BAM file w/ font' }, - - { 'key': 'color_1', - 'type': 'RGBA', - 'off': 0x001A, - 'label': 'Color 1' }, - - { 'key': 'color_2', - 'type': 'RGBA', - 'off': 0x001E, - 'label': 'Color 2' }, - - { 'key': 'justification', - 'type': 'WORD', - 'off': 0x0022, - 'label': 'Justification' }, - - ) + { 'key': 'armor_class_missile_mod', + 'type': 'WORD', # FIXME: actually signed word + 'off': 0x004C, + 'label': 'Armor class (missile att mod)' }, + { 'key': 'armor_class_piercing_mod', + 'type': 'WORD', # FIXME: actually signed word + 'off': 0x004E, + 'label': 'Armor class (piercing att mod)' }, - control_scrollbar_record_desc = ( - { 'key': 'bam_file', - 'type': 'RESREF', - 'off': 0x000E, - 'label': 'Name of BAM file w/ pixmap' }, + { 'key': 'armor_class_slashing_mod', + 'type': 'WORD', # FIXME: actually signed word + 'off': 0x0050, + 'label': 'Armor class (slashing att mod)' }, - { 'key': 'bam_cycle', - 'type': 'WORD', - 'off': 0x0016, - 'label': 'Cycle in BAM file' }, - - { 'key': 'frame_up_unpressed', - 'type': 'WORD', - 'off': 0x0018, - 'label': 'BAM frame: up-arrow unpressed' }, - - { 'key': 'frame_up_pressed', - 'type': 'WORD', - 'off': 0x001A, - 'label': 'BAM frame: up-arrow pressed' }, - - { 'key': 'frame_down_unpressed', - 'type': 'WORD', - 'off': 0x001C, - 'label': 'BAM frame: down-arrow unpressed' }, - - { 'key': 'frame_down_pressed', - 'type': 'WORD', - 'off': 0x001E, - 'label': 'BAM frame: down-arrow pressed' }, - - { 'key': 'frame_trough', - 'type': 'WORD', - 'off': 0x0020, - 'label': 'BAM frame: trough' }, - - { 'key': 'frame_slider', - 'type': 'WORD', - 'off': 0x0022, - 'label': 'BAM frame: slider' }, - - { 'key': 'textarea', - 'type': 'DWORD', - 'off': 0x0024, - 'label': 'Textarea ID' }, - + { 'key': 'thac0', + 'type': 'BYTE', + 'off': 0x0052, + 'label': 'THAC0 (1-25)' }, + + { 'key': 'num_attacks', + 'type': 'BYTE', + 'off': 0x0053, + 'label': 'Number of attacks (0-10)' }, + + { 'key': 'save_vs_death', + 'type': 'BYTE', + 'off': 0x0054, + 'label': 'Save versus death (0-20)' }, + + { 'key': 'save_vs_wands', + 'type': 'BYTE', + 'off': 0x0055, + 'label': 'Save versus wands (0-20)' }, + + { 'key': 'save_vs_polymorph', + 'type': 'BYTE', + 'off': 0x0056, + 'label': 'Save versus polymorph (0-20)' }, + + { 'key': 'save_vs_breath', + 'type': 'BYTE', + 'off': 0x0057, + 'label': 'Save versus breath attacks (0-20)' }, + + { 'key': 'save_vs_spells', + 'type': 'BYTE', + 'off': 0x0058, + 'label': 'Save versus spells (0-20)' }, + + { 'key': 'resist_fire', + 'type': 'BYTE', + 'off': 0x0059, + 'label': 'Resist fire (0-100)' }, + + { 'key': 'resist_cold', + 'type': 'BYTE', + 'off': 0x005A, + 'label': 'Resist cold (0-100)' }, + + { 'key': 'resist_electricity', + 'type': 'BYTE', + 'off': 0x005B, + 'label': 'Resist electricity (0-100)' }, + + { 'key': 'resist_acid', + 'type': 'BYTE', + 'off': 0x005C, + 'label': 'Resist acid (0-100)' }, + + { 'key': 'resist_magic', + 'type': 'BYTE', + 'off': 0x005D, + 'label': 'Resist magic (0-100)' }, + + { 'key': 'resist_magic_fire', + 'type': 'BYTE', + 'off': 0x005E, + 'label': 'Resist magic fire (0-100)' }, + + { 'key': 'resist_magic_cold', + 'type': 'BYTE', + 'off': 0x005F, + 'label': 'Resist magic cold (0-100)' }, + + { 'key': 'resist_slashing', + 'type': 'BYTE', + 'off': 0x0060, + 'label': 'Resist slashing (0-100)' }, + + { 'key': 'resist_crushing', + 'type': 'BYTE', + 'off': 0x0061, + 'label': 'Resist crushing (0-100)' }, + + { 'key': 'resist_piercing', + 'type': 'BYTE', + 'off': 0x0062, + 'label': 'Resist piercing (0-100)' }, + + { 'key': 'resist_missile', + 'type': 'BYTE', + 'off': 0x0063, + 'label': 'Resist missile (0-100)' }, + + { 'key': 'detect_illusion', + 'type': 'BYTE', + 'off': 0x0064, + 'label': 'Detect illusion' }, + + { 'key': 'set_traps', + 'type': 'BYTE', + 'off': 0x0065, + 'label': 'Set traps' }, + + { 'key': 'lore', + 'type': 'BYTE', + 'off': 0x0066, + 'label': 'Lore' }, + + { 'key': 'lockpicking', + 'type': 'BYTE', + 'off': 0x0067, + 'label': 'Lockpicking' }, + + { 'key': 'stealth', + 'type': 'BYTE', + 'off': 0x0068, + 'label': 'Stealth' }, + + { 'key': 'find_disarm_traps', + 'type': 'BYTE', + 'off': 0x0069, + 'label': 'Find and disarm traps' }, + + { 'key': 'pick_pockets', + 'type': 'BYTE', + 'off': 0x006A, + 'label': 'Pick pockets' }, + + { 'key': 'fatigue', + 'type': 'BYTE', + 'off': 0x006B, + 'label': 'Fatigue' }, + + { 'key': 'intoxication', + 'type': 'BYTE', + 'off': 0x006C, + 'label': 'Intoxication' }, + + { 'key': 'luck', + 'type': 'BYTE', + 'off': 0x006D, + 'label': 'Luck' }, + + { 'key': 'fist_proficiency', + 'type': 'BYTE', + 'off': 0x006E, + 'label': 'Fist proficiency' }, + + { 'key': 'edged_proficiency', + 'type': 'BYTE', + 'off': 0x006F, + 'label': 'Edged proficiency' }, + + { 'key': 'hammer_proficiency', + 'type': 'BYTE', + 'off': 0x0070, + 'label': 'Hammer proficiency' }, + + { 'key': 'axe_proficiency', + 'type': 'BYTE', + 'off': 0x0071, + 'label': 'Axe proficiency' }, + + { 'key': 'club_proficiency', + 'type': 'BYTE', + 'off': 0x0072, + 'label': 'Club proficiency' }, + + { 'key': 'bow_proficiency', + 'type': 'BYTE', + 'off': 0x0073, + 'label': 'Bow proficiency' }, + + { 'key': 'unused_proficiency', + 'type': 'BYTE', + 'off': 0x0074, + 'count': 15, + 'label': 'Unused proficiency slot' }, + + { 'key': 'tracking_skill', + 'type': 'BYTE', + 'off': 0x0083, + 'label': 'Tracking skill' }, + + { 'key': 'unknown_84', + 'type': 'BYTES', + 'off': 0x0084, + 'size': 32, + 'label': 'Unknown 84' }, + + + { 'key': 'strref', # see SOUNDOFF.IDS (for BG1) and SNDSLOT.IDS for (BG2) + 'type': 'STRREF', + 'off': 0x00A4, + 'count': 100, + 'label': 'Strref' }, + + { 'key': 'primary_highest_level', + 'type': 'BYTE', + 'off': 0x0234, + 'label': 'Highest level in primary class' }, + + { 'key': 'secondary_highest_level', + 'type': 'BYTE', + 'off': 0x0235, + 'label': 'Highest level in secondary class' }, + + { 'key': 'tertiary_highest_level', + 'type': 'BYTE', + 'off': 0x0236, + 'label': 'Highest level in tertiary class' }, + + { 'key': 'sex', + 'type': 'BYTE', + 'off': 0x0237, + 'enum': 'gender', + 'label': 'Sex (not modified)' }, + + { 'key': 'strength', + 'type': 'BYTE', + 'off': 0x0238, + 'label': 'Strength' }, + + { 'key': 'strength_bonus', + 'type': 'BYTE', + 'off': 0x0239, + 'label': 'Strength % bonus' }, + + { 'key': 'intelligence', + 'type': 'BYTE', + 'off': 0x023A, + 'label': 'Intelligence' }, + + { 'key': 'wisdom', + 'type': 'BYTE', + 'off': 0x023B, + 'label': 'Wisdom' }, + + { 'key': 'dexterity', + 'type': 'BYTE', + 'off': 0x023C, + 'label': 'Dexterity' }, + + { 'key': 'constitution', + 'type': 'BYTE', + 'off': 0x023D, + 'label': 'Constitution' }, + + { 'key': 'charisma', + 'type': 'BYTE', + 'off': 0x023E, + 'label': 'Charisma' }, + + { 'key': 'morale', + 'type': 'BYTE', + 'off': 0x023F, + 'label': 'Morale' }, + + { 'key': 'morale_break', + 'type': 'BYTE', + 'off': 0x0240, + 'label': 'Morale break' }, + + { 'key': 'racial_enemy', + 'type': 'BYTE', + 'off': 0x0241, + 'enum': 'race', + 'label': 'Racial enemy' }, + + { 'key': 'morale_recovery_time', + 'type': 'BYTE', + 'off': 0x0242, + 'label': 'Morale recovery time' }, + + { 'key': 'unknown_243', + 'type': 'BYTE', + 'off': 0x0243, + 'label': 'Unknown 243' }, + + { 'key': 'kit_info', + 'type': 'DWORD', + 'off': 0x0244, + 'mask': { 0x00000000: 'None', 0x00400000: 'Abjurer', 0x00800000: 'Conjurer', 0x01000000: 'Diviner', 0x02000000: 'Enchanter', 0x04000000: 'Illusionist', 0x08000000: 'Invoker', 0x10000000: 'Necromancer', 0x20000000: 'Transmuter' }, + 'label': 'Kit information' }, + + { 'key': 'override_script', + 'type': 'RESREF', + 'off': 0x0248, + 'label': 'Creature script - override' }, + + { 'key': 'class_script', + 'type': 'RESREF', + 'off': 0x0250, + 'label': 'Creature script - class' }, + + { 'key': 'race_script', + 'type': 'RESREF', + 'off': 0x0258, + 'label': 'Creature script - race' }, + + { 'key': 'general_script', + 'type': 'RESREF', + 'off': 0x0260, + 'label': 'Creature script - general' }, + + { 'key': 'default_script', + 'type': 'RESREF', + 'off': 0x0268, + 'label': 'Creature script - default' }, + + { 'key': 'unknown_270', + 'type': 'BYTES', + 'off': 0x0270, + 'size': 52, + 'label': 'Unknown 270' }, + + { 'key': 'overlay_off', + 'type': 'DWORD', + 'off': 0x0294, + 'label': 'Offset to overlay section' }, + + { 'key': 'overlay_size', + 'type': 'DWORD', + 'off': 0x0298, + 'label': 'Size of overlay section' }, + + { 'key': 'xp_secondary', + 'type': 'DWORD', + 'off': 0x029C, + 'label': 'XP (secondary class)' }, + + { 'key': 'xp_tertiary', + 'type': 'DWORD', + 'off': 0x02A0, + 'label': 'XP (tertiary class)' }, + + { 'key': 'internal', + 'type': 'WORD', + 'off': 0x02A4, + 'count': 12, # FIXME: IESDP has 10 here + 'label': 'Internal' }, + + { 'key': 'monstrous_compendium_entry', + 'type': 'STR32', + 'off': 0x02BC, # FIXME: IESDP has 2B8 here + 'label': 'Monstrous compendium entry' }, + + { 'key': 'dialog_activation_range', + 'type': 'BYTE', + 'off': 0x02DC, + 'label': 'Dialog activation range' }, + + { 'key': 'selection_cirle_size', + 'type': 'BYTE', + 'off': 0x02DD, + 'label': 'Selection circle size' }, + + { 'key': 'unknown_2DE', + 'type': 'BYTE', + 'off': 0x002DE, + 'label': 'Unknown 2DE' }, + + { 'key': 'num_colors', + 'type': 'BYTE', + 'off': 0x02DF, + 'label': 'Number of colors' }, + + { 'key': 'attr_flags', + 'type': 'DWORD', + 'off': 0x02E0, + 'mask': { 0x0002: 'Transparent', 0x100: 'Invulnerable' }, + 'label': 'Attribute flags' }, + + { 'key': 'color', + 'type': 'WORD', + 'off': 0x02E4, + 'enum': 'Clownclr', + 'count': 7, + 'label': 'Color' }, + + { 'key': 'unknown_2F2', + 'type': 'BYTES', + 'off': 0x002F2, + 'size': 3, + 'label': 'Unknown 2F2' }, + + { 'key': 'color_placement', + 'type': 'BYTE', + 'off': 0x02F5, + 'count': 7, + 'label': 'Color placement' }, + + { 'key': 'unknown_2FC', + 'type': 'BYTES', + 'off': 0x002FC, + 'size': 21, + 'label': 'Unknown 2FC' }, + + { 'key': 'species', + 'type': 'BYTE', + 'off': 0x0311, + 'enum': 'RACE', + 'label': 'Species' }, + + { 'key': 'team', + 'type': 'BYTE', + 'off': 0x0312, + 'enum': 'TEAM', + 'label': 'Team' }, + + { 'key': 'faction', + 'type': 'BYTE', + 'off': 0x0313, + 'enum': 'FACTION', + 'label': 'Faction' }, + + { 'key': 'enemy_ally', + 'type': 'BYTE', + 'off': 0x0314, + 'enum': 'EA', + 'label': 'Enemy-ally' }, + + { 'key': 'general', + 'type': 'BYTE', + 'off': 0x0315, + 'enum': 'GENERAL', + 'label': 'General' }, + + { 'key': 'race', + 'type': 'BYTE', + 'off': 0x0316, + 'enum': 'RACE', + 'label': 'Race' }, + + { 'key': 'class', + 'type': 'BYTE', + 'off': 0x0317, + 'enum': 'CLASS', + 'label': 'Class' }, + + { 'key': 'specific', + 'type': 'BYTE', + 'off': 0x0318, + 'enum': 'SPECIFIC', + 'label': 'Specific' }, + + { 'key': 'gender', + 'type': 'BYTE', + 'off': 0x0319, + 'enum': 'GENDER', + 'label': 'Gender' }, + + { 'key': 'unknown_31A', + 'type': 'BYTES', + 'off': 0x031A, + 'size': 5, + 'label': 'Unknown 31A' }, + + { 'key': 'alignment', + 'type': 'BYTE', + 'off': 0x031F, + 'enum': 'ALIGNMENT', + 'label': 'Alignment' }, + + { 'key': 'global_actor_enumeration', + 'type': 'WORD', + 'off': 0x0320, + 'label': 'Global actor enumeration value' }, + + { 'key': 'local_actor_enumeration', + 'type': 'WORD', + 'off': 0x0322, + 'label': 'Local (area) actor enumeration value' }, + + { 'key': 'death_var', + 'type': 'STR32', + 'off': 0x0324, + 'label': 'Death variable' }, + + { 'key': 'known_spell_off', + 'type': 'DWORD', + 'off': 0x0344, + 'label': 'Offset of known spells' }, + + { 'key': 'known_spell_cnt', + 'type': 'DWORD', + 'off': 0x0348, + 'label': 'Count of known spells' }, + + { 'key': 'spell_memorization_off', + 'type': 'DWORD', + 'off': 0x034C, + 'label': 'Offset of spell memorization infos' }, + + { 'key': 'spell_memorization_cnt', + 'type': 'DWORD', + 'off': 0x0350, + 'label': 'Count of spell memorization infos' }, + + { 'key': 'memorized_spell_off', + 'type': 'DWORD', + 'off': 0x0354, + 'label': 'Offset of memorized spells' }, + + { 'key': 'memorized_spell_cnt', + 'type': 'DWORD', + 'off': 0x0358, + 'label': 'Count of memorized spells' }, + + { 'key': 'item_slot_off', + 'type': 'DWORD', + 'off': 0x035C, + 'label': 'Offset of items slots' }, + + { 'key': 'item_off', + 'type': 'DWORD', + 'off': 0x0360, + 'label': 'Offset of items' }, + + { 'key': 'item_cnt', + 'type': 'DWORD', + 'off': 0x0364, + 'label': 'Count of items' }, + + { 'key': 'effect_off', + 'type': 'DWORD', + 'off': 0x0368, + 'label': 'Offset of effects' }, + + { 'key': 'effect_cnt', + 'type': 'DWORD', + 'off': 0x036C, + 'label': 'Count of effects' }, + + { 'key': 'dialog', + 'type': 'RESREF', + 'off': 0x0370, + 'label': 'Dialog resref' }, + + ) + + def __init__ (self): Format.__init__ (self) self.expect_signature = 'CRE' - self.window_list = [] - def read (self, stream): self.read_header (stream) return self @@ -505,7 +764,7 @@ def decode_window_record (self, offset, obj): self.decode_by_desc (offset, self.window_record_desc, obj) - + def print_window_record (self, obj): self.print_by_desc (obj, self.window_record_desc) @@ -549,5 +808,5 @@ fh = open (filename, 'w') fh.write (obj['data']) fh.close () - + register_format ('CRE', 'V1.2', CRE_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/stor.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/stor.py 2008-03-29 09:11:00 UTC (rev 5130) +++ ie_shell/branches/iesh-infinity/infinity/formats/stor.py 2008-04-01 07:56:44 UTC (rev 5131) @@ -294,7 +294,16 @@ self.read_list (stream, 'drink') self.read_list (stream, 'cure') + def write (self, stream): + off = self.get_struc_size (self.header_desc) + off = self.write_list (stream, off, 'sold_item') + off = self.write_list (stream, off, 'drink') + off = self.write_list (stream, off, 'cure') + off = self.write_list (stream, off, 'bought_item') + self.write_header (stream) + + def printme (self): self.print_header () Modified: ie_shell/branches/iesh-infinity/infinity/formats/wmap.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wmap.py 2008-03-29 09:11:00 UTC (rev 5130) +++ ie_shell/branches/iesh-infinity/infinity/formats/wmap.py 2008-04-01 07:56:44 UTC (rev 5131) @@ -322,57 +322,12 @@ def printme (self): self.print_header () - i = 0 - for obj in self.wmap_list: - print 'wmap #%d' %i - self.print_wmap_record (obj) - i = i + 1 + self.print_list ('wmap') + self.print_list ('arealink') + self.print_list ('area') - i = 0 - for obj in self.arealink_list: - print 'arealink #%d' %i - self.print_arealink_record (obj) - i = i + 1 - - i = 0 - for obj in self.area_list: - print 'area #%d' %i - self.print_area_record (obj) - i = i + 1 - - return - - def read_wmap_record (self, stream, offset, obj): - self.read_struc (stream, offset, self.wmap_record_desc, obj) - - def print_wmap_record (self, obj): - self.print_struc (obj, self.wmap_record_desc) - def read_area_record (self, stream, offset, obj): - self.read_struc (stream, offset, self.area_record_desc, obj) - - def print_area_record (self, obj): - self.print_struc (obj, self.area_record_desc) - - def read_arealink_record (self, stream, offset, obj): - self.read_struc (stream, offset, self.arealink_record_desc, obj) - - def print_arealink_record (self, obj): - self.print_struc (obj, self.arealink_record_desc) - - - -## def get_file_res_data (self, obj): -## obj['data'] = self.decode_blob (obj['data_offset'], obj['data_size']) -## -## def save_file_res (self, filename, obj): -## self.get_file_res_data (obj) -## fh = open (filename, 'w') -## fh.write (obj['data']) -## fh.close () - - register_format ('WMAP', 'V1.0', WMAP_Format) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <edh...@us...> - 2008-06-26 15:12:50
|
Revision: 5213 http://gemrb.svn.sourceforge.net/gemrb/?rev=5213&view=rev Author: edheldil Date: 2008-06-26 08:12:57 -0700 (Thu, 26 Jun 2008) Log Message: ----------- worked on CRE format, added 2da Modified Paths: -------------- ie_shell/branches/iesh-infinity/iesh.e3p ie_shell/branches/iesh-infinity/infinity/formats/__init__.py ie_shell/branches/iesh-infinity/infinity/formats/cre.py Modified: ie_shell/branches/iesh-infinity/iesh.e3p =================================================================== --- ie_shell/branches/iesh-infinity/iesh.e3p 2008-06-26 15:08:36 UTC (rev 5212) +++ ie_shell/branches/iesh-infinity/iesh.e3p 2008-06-26 15:12:57 UTC (rev 5213) @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Project SYSTEM "Project-3.9.dtd"> <!-- Project file for project iesh --> -<!-- Saved: 2008-03-07, 21:35:43 --> -<!-- Copyright (C) 2008 , --> +<!-- Saved: 2008-04-03, 11:51:51 --> +<!-- Copyright (C) 2008 Ed, --> <Project version="3.9"> <ProgLanguage mixed="0">Python</ProgLanguage> <UIType>Console</UIType> <Description></Description> <Version>0.1</Version> - <Author></Author> + <Author>Ed</Author> <Email></Email> <Sources> <Source> @@ -167,6 +167,21 @@ <Source> <Name>test_fmt.py</Name> </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>mos.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>stor.py</Name> + </Source> + <Source> + <Dir>infinity</Dir> + <Dir>formats</Dir> + <Name>d2a.py</Name> + </Source> </Sources> <Forms> </Forms> @@ -178,6 +193,9 @@ <Other> <Name>iesh</Name> </Other> + <Other> + <Name>TODO</Name> + </Other> </Others> <MainScript> <Name>iesh</Name> @@ -232,7 +250,7 @@ <FiletypeAssociation pattern="*.ui.h" type="FORMS" /> <FiletypeAssociation pattern="*.ui" type="FORMS" /> <FiletypeAssociation pattern="*.idl" type="INTERFACES" /> + <FiletypeAssociation pattern="*.ptl" type="SOURCES" /> <FiletypeAssociation pattern="*.py" type="SOURCES" /> - <FiletypeAssociation pattern="*.ptl" type="SOURCES" /> </FiletypeAssociations> </Project> Modified: ie_shell/branches/iesh-infinity/infinity/formats/__init__.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-06-26 15:08:36 UTC (rev 5212) +++ ie_shell/branches/iesh-infinity/infinity/formats/__init__.py 2008-06-26 15:12:57 UTC (rev 5213) @@ -5,6 +5,7 @@ import biff import chui import cre +import d2a import dlg import ids import itm Modified: ie_shell/branches/iesh-infinity/infinity/formats/cre.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-06-26 15:08:36 UTC (rev 5212) +++ ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-06-26 15:12:57 UTC (rev 5213) @@ -502,7 +502,7 @@ 'off': 0x0294, 'label': 'Offset to overlay section' }, - { 'key': 'overlay_size', + { 'key': 'overlay_cnt', 'type': 'DWORD', 'off': 0x0298, 'label': 'Size of overlay section' }, @@ -642,7 +642,7 @@ { 'key': 'alignment', 'type': 'BYTE', 'off': 0x031F, - 'enum': 'ALIGNMENT', + 'enum': 'ALIGNMEN', 'label': 'Alignment' }, { 'key': 'global_actor_enumeration', @@ -719,94 +719,154 @@ 'type': 'RESREF', 'off': 0x0370, 'label': 'Dialog resref' }, + ) - + overlay_desc = ( + { 'key': 'unknown_00', + 'type': 'BYTES', + 'off': 0x0000, + 'size': 36, + 'label': 'Unknown 00' }, ) + known_spell_desc = ( + { 'key': 'resref', + 'type': 'RESREF', + 'restype': 'SPL', + 'off': 0x0000, + 'label': 'SPL resref' }, + { 'key': 'level', + 'type': 'WORD', + 'off': 0x0008, + 'label': 'Spell level -1' }, - def __init__ (self): - Format.__init__ (self) - self.expect_signature = 'CRE' + { 'key': 'type', + 'type': 'WORD', + 'off': 0x000A, + 'enum': { 0: 'Priest', 1: 'Wizard', 2: 'Innate' }, + 'label': 'Spell type' }, + ) + spell_memorization_desc = ( + { 'key': 'level', + 'type': 'WORD', + 'off': 0x0000, + 'label': 'Spell level -1' }, - def read (self, stream): - self.read_header (stream) - return self + { 'key': 'num_memorizable', + 'type': 'WORD', + 'off': 0x0002, + 'label': 'Number of spells memorizable' }, -# off = self.header['window_offset'] -# for i in range (self.header['num_of_windows']): -# obj = {} -# self.decode_window_record (off, obj) -# self.window_list.append (obj) -# off = off + 28 + { 'key': 'num_memorizable_after_fx', + 'type': 'WORD', + 'off': 0x0004, + 'label': 'Number of spells memorizable after effects' }, -# off2 = self.header['control_table_offset'] + obj['control_ndx'] * 8 -# obj['control_list'] = [] + { 'key': 'type', + 'type': 'WORD', + 'off': 0x0006, + 'enum': { 0: 'Priest', 1: 'Wizard', 2: 'Innate' }, + 'label': 'Spell type' }, -# for j in range (obj['num_of_controls']): -# obj2 = {} -# self.decode_control_record (off2, obj2) -# obj['control_list'].append (obj2) -# off2 = off2 + 8 + { 'key': 'memorized_spell_ndx', + 'type': 'DWORD', + 'off': 0x0008, + 'label': 'Index to memorized spells' }, + { 'key': 'memorized_spell_cnt', + 'type': 'DWORD', + 'off': 0x000C, + 'label': 'Count of memorized spells' }, + ) + memorized_spell_desc = ( + { 'key': 'resref', + 'type': 'RESREF', + 'restype': 'SPL', + 'off': 0x0000, + 'label': 'SPL resref' }, - def printme (self): - self.print_header () + { 'key': 'memorized', + 'type': 'DWORD', + 'off': 0x0008, + 'label': 'Memorized' }, + ) -# i = 0 -# for obj in self.window_list: -# print '#%d' %i -# self.print_window_record (obj) -# i = i + 1 + item_desc = ( + { 'key': 'item_resref', + 'type': 'RESREF', + 'restype': 'ITM', + 'off': 0x0000, + 'label': 'ITM resref' }, - def decode_window_record (self, offset, obj): - self.decode_by_desc (offset, self.window_record_desc, obj) + { 'key': 'unknown_08', + 'type': 'WORD', + 'off': 0x0008, + 'label': 'Unknown 08' }, - def print_window_record (self, obj): - self.print_by_desc (obj, self.window_record_desc) + { 'key': 'usage_1', + 'type': 'WORD', + 'off': 0x000A, + 'label': 'Usage 1' }, - j = 0 - for ctl in obj['control_list']: - print 'C #%d' %j - self.print_control_record (ctl) - j = j + 1 + { 'key': 'usage_2', + 'type': 'WORD', + 'off': 0x000C, + 'label': 'Usage 2' }, + { 'key': 'usage_3', + 'type': 'WORD', + 'off': 0x000E, + 'label': 'Usage 3' }, - def control_type_to_desc (self, type): - if type == 0: return self.control_button_record_desc - elif type == 2: return self.control_slider_record_desc - elif type == 3: return self.control_textedit_record_desc - elif type == 5: return self.control_textarea_record_desc - elif type == 6: return self.control_label_record_desc - elif type == 7: return self.control_scrollbar_record_desc + { 'key': 'flags', + 'type': 'DWORD', + 'off': 0x0010, + 'mask': { 0x01: 'Identified', 0x02: 'Unstealable', 0x04: 'Stolen', 0x08: 'Undroppable' }, + 'label': 'Flags' }, + ) - def decode_control_record (self, offset, obj): - self.decode_by_desc (offset, self.control_table_record_desc, obj) - off2 = obj['control_offset'] - self.decode_by_desc (off2, self.control_common_record_desc, obj) + item_slot_desc = ( + { 'key': 'item', + 'type': 'WORD', + 'off': 0x0000, + 'count': 45, + 'label': 'Item' }, + ) - desc = self.control_type_to_desc (obj['type']) - self.decode_by_desc (off2, desc, obj) + def __init__ (self): + Format.__init__ (self) + self.expect_signature = 'CRE' - def print_control_record (self, obj): - self.print_by_desc (obj, self.control_table_record_desc) - self.print_by_desc (obj, self.control_common_record_desc) + self.overlay_list = [] + self.known_spell_list = [] + self.spell_memorization_list = [] + self.item_list = [] + self.memorized_spell_list = [] + self.slots = None - desc = self.control_type_to_desc (obj['type']) - self.print_by_desc (obj, desc) + def read (self, stream): + self.read_header (stream) + self.read_list (stream, 'overlay') + self.read_list (stream, 'known_spell') + self.read_list (stream, 'spell_memorization') + self.read_list (stream, 'memorized_spell') + self.read_list (stream, 'item') + self.slots = {} + self.read_struc (stream, self.header['item_slot_off'], self.item_slot_desc, self.slots) + def printme (self): + self.print_header () + self.print_list ('known_spell') + self.print_list ('overlay') + self.print_list ('memorized_spell') + self.print_list ('spell_memorization') + self.print_list ('item') - def get_file_res_data (self, obj): - obj['data'] = self.decode_blob (obj['data_offset'], obj['data_size']) + self.print_struc (self.slots, self.item_slot_desc) - def save_file_res (self, filename, obj): - self.get_file_res_data (obj) - fh = open (filename, 'w') - fh.write (obj['data']) - fh.close () - register_format ('CRE', 'V1.2', CRE_Format) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <edh...@us...> - 2008-07-01 05:33:36
|
Revision: 5229 http://gemrb.svn.sourceforge.net/gemrb/?rev=5229&view=rev Author: edheldil Date: 2008-06-30 22:33:38 -0700 (Mon, 30 Jun 2008) Log Message: ----------- Comments, cleanups Modified Paths: -------------- ie_shell/branches/iesh-infinity/README ie_shell/branches/iesh-infinity/iesh ie_shell/branches/iesh-infinity/infinity/builtins.py ie_shell/branches/iesh-infinity/infinity/core.py ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/stream.py Modified: ie_shell/branches/iesh-infinity/README =================================================================== --- ie_shell/branches/iesh-infinity/README 2008-06-29 11:59:02 UTC (rev 5228) +++ ie_shell/branches/iesh-infinity/README 2008-07-01 05:33:38 UTC (rev 5229) @@ -13,21 +13,18 @@ Package contents: iesh - the shell - ie_shell/ - python module(s) dealing with the reading of IE files + infinity - python module package dealing with the reading of IE files + infinity/formats/* - various modules for reading the IE data files + + infinity/stream.py + infinity/format.py + infinity/core.py + infinity/builtins.py + + data/ - directory for storing exported data, provided for convenience examples/ - some example code snippets - ie_shell/formats/format.py - ./formats/stream.py - ./formats/bam.py - ... - ./formats/wmap.py - ./plugins/core.py - ./plugins/builtins.py - ./plugins/... - ./data/ - directory for storing exported data, provided for convenience - - Configuration: -------------- @@ -61,17 +58,41 @@ Now you can load files, inspect their contents, search them and export objects out of them. +Getting help: +------------- +?, help +help (object) +help (infinity) +help (infinity.builtins) +... + The following resource formats are recognized in this version: - BAM - BIFF (only file records) - CHUI - CRE (only partial) + 2DA + AREA V1.0 + BAM V1 + BAMC V1 + BIFF V1 + BIF V1.0 + CHUI V1 + CRE V1.2 + DLG V1.0 IDS - ITM - KEY - TLK - WMAP + ITM V1.1 + KEY V1 + MOS V1 + MOSC V1 + PRO V1.0 + SPL V1 + STOR V1.1 + TIS V1 + TLK V1 + VVC V1.0 + WED V1.3 + WFX V1.0 + WMAP V1.0 +Type list_formats() to print list of recognized file formats. + Type `?' or `help' to get some online help and `q', `quit' or ^D to exit the program. Modified: ie_shell/branches/iesh-infinity/iesh =================================================================== --- ie_shell/branches/iesh-infinity/iesh 2008-06-29 11:59:02 UTC (rev 5228) +++ ie_shell/branches/iesh-infinity/iesh 2008-07-01 05:33:38 UTC (rev 5229) @@ -26,10 +26,10 @@ import sys import traceback +import infinity from infinity import core from infinity.builtins import * from infinity.stream import * - from infinity.formats import * ################################################### @@ -72,18 +72,21 @@ tries to find and load object from a file or resources. Returns format object, so the object type has to be supported - find_str ("^(?i)gemrb") - List strrefs for all strings starting with word GemRB, regardless - of case - + load_object ("AGOODY").printme () + export_obj ("GUICG", "GUICG.chu") Try to find resource GUICG and export it to file GUICG.chu. If the name is not unique, add third parameter, e.g. type=0x03ea to restrict the resource type + find_str ("^(?i)gemrb") + List strrefs for all strings starting with word GemRB, regardless + of case + + c = chui.CHUI_Format ("GUISAVE.chu") - c.decode_file () - c.print_file () + c.read () + c.printme () loads file GUISAVE.chu from the current dir, decodes it and prints its contents @@ -102,6 +105,10 @@ core.keys.print_bif_record (core.keys.bif_list[0]) core.strrefs.print_strref_record (core.strrefs.strref_list[0]) print first records from chitin.key or dialog.tlk file + + help (infinity) + help (infinity.builtins) + help on various topics !shell_cmd Runs command shell_cmd in your native shell. Useful to list Modified: ie_shell/branches/iesh-infinity/infinity/builtins.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-06-29 11:59:02 UTC (rev 5228) +++ ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-07-01 05:33:38 UTC (rev 5229) @@ -1,5 +1,8 @@ #-*-python-*- +"""Built-in functions for the iesh shell. This module contents +are imported directly into iesh's namespace.""" + import os.path from infinity import core @@ -7,7 +10,7 @@ ################################################### def load_game (game_dir, chitin_file = core.chitin_file, dialog_file = core.dialog_file): - """Loads key and dialog files from the specified directory. + """Loads key and dialog files from the 'game_dir' directory. The directory parameter is mandatory, the others are optional. Most of the other commands assume that these two files are already loaded. The loaded objects are stored in core.keys and @@ -34,7 +37,11 @@ ################################################### -def load_object (name, type = None): +def load_object (name, type = None, index = 0): + """Loads object from a file 'name' located in filesystem or in game's data + and returns Format object of appropriate type. If the name is not unique, + specify resource type with `type' and eventually `index' if + there's still more than one.""" try: fh = open (name) @@ -43,47 +50,27 @@ if fh: fh.close () - return FileStream(name).load_object () + return FileStream().open (name).load_object () else: - return ResourceStream(name, type).load_object () + return ResourceStream().open (name, type, index).load_object () ################################################### -def print_file (filename, type = None): - fs = FileStream ().open (filename) - obj = fs.load_object (type) +def print_object (name, type = None): + obj = load_object (name, type) obj.printme () - return obj ################################################### -def find_str (text): - """Finds all strings in loaded DIALOG.TLK file matching regular expression - and prints their STRREFs""" - - for o in core.strrefs.get_strref_by_str_re(text): - print core.strrefs.strref_list.index(o), o['string'] - -################################################### -def export_obj (name, filename, type = None, index = 0): +def export_object (name, filename, type = None, index = 0): """Exports resource `name' into file `filename'. If the `name' is not unique, specify resource type with `type' and eventually `index' if there's still more than one""" - - oo = core.keys.get_resref_by_name_re(name) - if type != None: - oo = filter (lambda o: o['type'] == type, oo) - if len (oo) > 1 and type == None: - print "More than one result" - return - - o = oo[index] - - src_file = core.keys.bif_list[o['locator_src_ndx']] - b = core.formats['BIFF'] (os.path.join (core.game_dir, src_file['file_name'])) - b.read () - b.save_file_data (filename, b.file_list[o['locator_ntset_ndx']]) - - + stream = ResourceStream ().open (name, type, index) + fh = open (filename, "w") + fh.write (stream.buffer) + fh.close () + stream.close () + ################################################### def iterate_objects_by_type (type, fn): @@ -102,16 +89,21 @@ ################################################### +def find_str (text): + """Finds all strings in loaded DIALOG.TLK file matching regular expression + 'text' and prints their STRREFs to stdout.""" + + for o in core.strrefs.get_strref_by_str_re(text): + print core.strrefs.strref_list.index(o), o['string'] + + +################################################### def sprintf (format_str, params): return format_str %(params) def printf (format_str, params): print sprintf (format_str, params) -def loaded_object (obj): - obj.read () - return obj - ################################################### def pok(): def p (obj): @@ -151,6 +143,12 @@ type = '??' print "0x%04x (%s):\t%5d" %(s, type, stats[s]) +################################################### +def list_formats (): + """List recognized/implemented IE file formats""" + for f in core.formats.items (): + print f + ################################################### # End of file builtins.py Modified: ie_shell/branches/iesh-infinity/infinity/core.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/core.py 2008-06-29 11:59:02 UTC (rev 5228) +++ ie_shell/branches/iesh-infinity/infinity/core.py 2008-07-01 05:33:38 UTC (rev 5229) @@ -1,5 +1,23 @@ # -*-python-*- +# iesh / ie_shell.py - Simple shell for Infinity Engine-based game files +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# RCS: $Id: ie_shell.py,v 1.5 2006/07/03 18:15:34 edheldil Exp $ + import string @@ -177,3 +195,4 @@ except: return None +# End of file core.py Modified: ie_shell/branches/iesh-infinity/infinity/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py 2008-06-29 11:59:02 UTC (rev 5228) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-07-01 05:33:38 UTC (rev 5229) @@ -18,6 +18,11 @@ # RCS: $Id: format.py,v 1.5 2006/07/08 14:29:26 edheldil Exp $ +"""This module implements Format, abstract class representing +IE file type. This object is futher subclassed +in infinity.formats package to the various IE file formats +like 2DA, BAM, TLK etc.""" + import os.path import re import string Modified: ie_shell/branches/iesh-infinity/infinity/stream.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/stream.py 2008-06-29 11:59:02 UTC (rev 5228) +++ ie_shell/branches/iesh-infinity/infinity/stream.py 2008-07-01 05:33:38 UTC (rev 5229) @@ -18,6 +18,11 @@ # RCS: $Id: stream.py,v 1.3 2006/07/08 14:29:27 edheldil Exp $ +"""This module implements Stream, abstract class for reading +IE files, and also various specialized subclasses for reading +files, memory buffers and files in BIFF archives.""" + + import gzip import os.path import re @@ -30,10 +35,12 @@ class Stream: def __init__ (self): self.is_open = False - + def open (self, mode = 'r'): # do the real open here self.is_open = True + self.coverage = {} + self.debug_coverage = False return self def close (self): @@ -220,6 +227,7 @@ def open (self, filename, mode = 'r'): # FIXME: reset offset? + Stream.open (self, mode) self.filename = filename self.fh = open (self.filename, mode) self.is_open = True @@ -234,11 +242,58 @@ def read (self, size = None): # FIXME: do some caching/buffering here? + + if self.debug_coverage: + off = self.fh.tell () + if size != None: - return self.fh.read (size) + value = self.fh.read (size) else: - return self.fh.read () + value = self.fh.read () + #if self.debug_coverage: + # sz = len (value) + # self.coverage_add + return value + + def coverage_add (self, offset, size, some_info_tbd): + si, ss = self.coverage_find_offset (offset) + ei, es = self.coverage_find_offset (offset + size) + + if si == ei: + if ss == 0: + if es == 0: + self.coverage.insert (i, (offset, offset + size, [])) + elif es == 1: + self.coverage[i] = (offset, colf.coverage[i][1], []) + else: + self.coverage[i] = (offset, colf.coverage[i][1], ['False']) + elif ss == 1 or ss == 2: + # for now + pass + else: # 3 + # should not happen, implies length=0 + pass + + else: + pass + + + def coverage_find_offset (self, offset): + for i in len (self.coverage): + if i < self.coverage[i][0]: + return (i, 0) + elif i == self.coverage[i][0]: + return (i, 1) + elif i < self.coverage[i][1]: + return (i, 2) + elif i == self.coverage[i][1]: + return (i, 3) + + return (len (self.coverage), 0) + + + def write (self, bytes, size = None): #if size != None: # self.fh.write (bytes, size) @@ -284,7 +339,7 @@ def __init__ (self): MemoryStream.__init__ (self) - def open (self, name, type = None): + def open (self, name, type = None, index = 0): self.resref = name self.type = type @@ -298,7 +353,7 @@ if len (oo) > 1 and self.type == None: raise RuntimeError, "More than one result" - o = oo[0] + o = oo[index] src_file = core.keys.bif_list[o['locator_src_ndx']] bif_stream = FileStream ().open (os.path.join (core.game_dir, src_file['file_name'])) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <edh...@us...> - 2008-07-05 21:20:34
|
Revision: 5231 http://gemrb.svn.sourceforge.net/gemrb/?rev=5231&view=rev Author: edheldil Date: 2008-07-05 14:20:31 -0700 (Sat, 05 Jul 2008) Log Message: ----------- Enhanced WED format slightly Some doc strings Simple coverage function Modified Paths: -------------- ie_shell/branches/iesh-infinity/iesh ie_shell/branches/iesh-infinity/infinity/builtins.py ie_shell/branches/iesh-infinity/infinity/core.py ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/formats/wed.py ie_shell/branches/iesh-infinity/infinity/stream.py Modified: ie_shell/branches/iesh-infinity/iesh =================================================================== --- ie_shell/branches/iesh-infinity/iesh 2008-07-04 15:24:30 UTC (rev 5230) +++ ie_shell/branches/iesh-infinity/iesh 2008-07-05 21:20:31 UTC (rev 5231) @@ -161,7 +161,14 @@ readline.insert_text (indent) readline.redisplay () +def suspend (): + # pickle strrefs and resrefs + # or maybe rather call suspend() method in various modules? + pass +def resume (): + pass + ################################################### ################################################### # main Modified: ie_shell/branches/iesh-infinity/infinity/builtins.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-07-04 15:24:30 UTC (rev 5230) +++ ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-07-05 21:20:31 UTC (rev 5231) @@ -121,21 +121,17 @@ iterate_objects_by_type (0x03f0, p) + ################################################### -def get_restype_stats (): +def print_restype_stats (): stats = {} + for o in core.keys.resref_list: if not stats.has_key (o['type']): stats[o['type']] = 1 else: stats[o['type']] = stats[o['type']] + 1 - return stats - - -################################################### -def print_restype_stats (): - stats = get_restype_stats () for s in stats.keys (): if core.restype_hash.has_key (s): type = core.restype_hash[s] @@ -143,12 +139,29 @@ type = '??' print "0x%04x (%s):\t%5d" %(s, type, stats[s]) + return stats + ################################################### -def list_formats (): +def print_formats (): """List recognized/implemented IE file formats""" - for f in core.formats.items (): - print f + + flist = filter (lambda a: a[0][1] != None, core.formats.items ()) + flist.sort (lambda a, b: 2 * cmp (a[0][0], b[0][0]) + cmp (a[0][1], b[0][1])) + print "sign vers class desc & status" + print "-----------------------------------------------" + for key, value in flist: + version = '' + desc = '' + if key[1] != None: + version = key[1] + if value[1] != None: + desc = '- ' + value[1] + klass_name = str (value[0]) + klass_name = klass_name.replace ('infinity.formats.', '') + + print "%-4s %-4s %-20s %s" %(key[0], version, klass_name, desc) + ################################################### # End of file builtins.py Modified: ie_shell/branches/iesh-infinity/infinity/core.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/core.py 2008-07-04 15:24:30 UTC (rev 5230) +++ ie_shell/branches/iesh-infinity/infinity/core.py 2008-07-05 21:20:31 UTC (rev 5231) @@ -176,14 +176,17 @@ } -def register_format (signature, version, klass): +def register_format (signature, version, klass, desc = None): #core.formats[(signature, version)] = klass - formats[signature] = klass + #formats[signature] = klass + formats[(signature, version)] = (klass, desc) + # FIXME: this is ugly temporary hack + formats[(signature, None)] = (klass, desc) def get_format (signature, version = None): try: - return formats[signature] + return formats[(signature, version)][0] except: return None Modified: ie_shell/branches/iesh-infinity/infinity/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py 2008-07-04 15:24:30 UTC (rev 5230) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-07-05 21:20:31 UTC (rev 5231) @@ -75,29 +75,33 @@ self.print_struc (self.header, self.header_desc) - def read_list (self, stream, name, desc = None, list = None): + def read_list (self, stream, name, header = None, desc = None, list = None): if desc == None: desc = self.__class__.__dict__ [name + '_desc'] if list == None: list = self.__dict__ [name + '_list'] + if header == None: + header = self.header - off = self.header[name + '_off'] + off = header[name + '_off'] size = self.get_struc_size (desc) - for i in range (self.header[name + '_cnt']): + for i in range (header[name + '_cnt']): obj = {} self.read_struc (stream, off, desc, obj) list.append (obj) off += size - def write_list (self, stream, offset, name, desc = None, list = None): + def write_list (self, stream, offset, name, header = None, desc = None, list = None): if desc == None: desc = self.__class__.__dict__ [name + '_desc'] if list == None: list = self.__dict__ [name + '_list'] + if header == None: + header = self.header - self.header[name + '_off'] = offset - self.header[name + '_cnt'] = len (list) + header[name + '_off'] = offset + header[name + '_cnt'] = len (list) size = self.get_struc_size (desc) for obj in list: Modified: ie_shell/branches/iesh-infinity/infinity/formats/wed.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-07-04 15:24:30 UTC (rev 5230) +++ ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-07-05 21:20:31 UTC (rev 5231) @@ -290,12 +290,14 @@ self.secondary_header = {} self.overlay_list = [] self.door_list = [] + self.polygon_list = [] def read (self, stream): self.read_header (stream) self.read_secondary_header (stream, self.header['secondary_header_off'], self.secondary_header) + off = self.header['overlay_off'] for i in range (self.header['overlay_cnt']): obj = {} @@ -303,6 +305,7 @@ self.overlay_list.append (obj) off = off + 24 + # NOTE: door is nested, so we can't use read_list () here off = self.header['door_off'] for i in range (self.header['door_cnt']): obj = {} @@ -321,28 +324,70 @@ print 'Overlay #%d' %i self.print_overlay (obj) i = i + 1 - + i = 0 for obj in self.door_list: print 'Door #%d' %i self.print_door (obj) i = i + 1 - + def read_secondary_header (self, stream, offset, obj): self.read_struc (stream, offset, self.secondary_header_desc, obj) + self.read_list (stream, 'polygon', self.secondary_header,) + # vertices + # wallgroups + # polygon indices LUT + def print_secondary_header (self): self.print_struc (self.secondary_header, self.secondary_header_desc) + self.print_list ('polygon') + # vertices + # wallgroups + # polygon indices LUT + - def read_overlay (self, stream, offset, obj): self.read_struc (stream, offset, self.overlay_desc, obj) + obj['tilemap_list'] = [] + cnt = obj['width'] * obj['height'] + size = self.get_struc_size (self.tilemap_desc) + + off2 = obj['tilemap_off'] + tile_index_cnt = 0 + for i in range (cnt): + obj2 = {} + self.read_tilemap (stream, off2, obj2, obj) + obj['tilemap_list'].append (obj2) + off2 = off2 + size + tile_index_cnt += obj2['tile_index_lut_cnt'] + + obj['tile_index_list'] = [] + size = 2 # FIXME: don't hardwire the size + off2 = obj['tile_index_lookup_off'] + + for i in range (tile_index_cnt): + print off2, ':', i + tile_index = stream.read_word (off2) + obj['tile_index_list'].append (tile_index) + off2 += size + + def print_overlay (self, obj): self.print_struc (obj, self.overlay_desc) - + i = 0 + for obj2 in obj['tilemap_list']: + print 'Tilemap #%d' %i + self.print_tilemap (obj2) + i = i + 1 + + print "Tile indices:", obj['tile_index_list'] + print + + def read_door (self, stream, offset, obj): self.read_struc (stream, offset, self.door_desc, obj) @@ -379,12 +424,11 @@ i = i + 1 - def read_tilemap (self, stream, offset, obj): + def read_tilemap (self, stream, offset, obj, overlay): self.read_struc (stream, offset, self.tilemap_desc, obj) def print_tilemap (self, obj): self.print_struc (obj, self.tilemap_desc) - def read_wallgroup (self, stream, offset, obj): self.read_struc (stream, offset, self.wallgroup_desc, obj) Modified: ie_shell/branches/iesh-infinity/infinity/stream.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/stream.py 2008-07-04 15:24:30 UTC (rev 5230) +++ ie_shell/branches/iesh-infinity/infinity/stream.py 2008-07-05 21:20:31 UTC (rev 5231) @@ -39,7 +39,8 @@ def open (self, mode = 'r'): # do the real open here self.is_open = True - self.coverage = {} + self.coverage = [] + #self.coverage = {} self.debug_coverage = False return self @@ -251,12 +252,24 @@ else: value = self.fh.read () - #if self.debug_coverage: - # sz = len (value) - # self.coverage_add + if self.debug_coverage: + sz = len (value) + self.coverage_add (off, size, None) return value def coverage_add (self, offset, size, some_info_tbd): + d = offset +size - len (self.coverage) + if d > 0: + self.coverage.extend ([0] * d) + for i in range (offset, offset + size): + self.coverage[i] += 1 + + def print_coverage (self): + for i in range (len (self.coverage)): + if self.coverage[i] != 1: + print "0x%04x: %d" %(i, self.coverage[i]) + + def xcoverage_add (self, offset, size, some_info_tbd): si, ss = self.coverage_find_offset (offset) ei, es = self.coverage_find_offset (offset + size) @@ -357,7 +370,7 @@ src_file = core.keys.bif_list[o['locator_src_ndx']] bif_stream = FileStream ().open (os.path.join (core.game_dir, src_file['file_name'])) - b = core.formats['BIFF'] () + b = core.get_format ('BIFF') () b.read (bif_stream) obj = b.file_list[o['locator_ntset_ndx']] b.get_file_data (bif_stream, obj) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <edh...@us...> - 2008-07-10 19:40:42
|
Revision: 5232 http://gemrb.svn.sourceforge.net/gemrb/?rev=5232&view=rev Author: edheldil Date: 2008-07-10 12:40:41 -0700 (Thu, 10 Jul 2008) Log Message: ----------- - Revamped options - implemented pager - some docstrings Modified Paths: -------------- ie_shell/branches/iesh-infinity/README ie_shell/branches/iesh-infinity/iesh ie_shell/branches/iesh-infinity/infinity/builtins.py ie_shell/branches/iesh-infinity/infinity/core.py ie_shell/branches/iesh-infinity/infinity/format.py ie_shell/branches/iesh-infinity/infinity/formats/are.py ie_shell/branches/iesh-infinity/infinity/formats/bam.py ie_shell/branches/iesh-infinity/infinity/formats/biff.py ie_shell/branches/iesh-infinity/infinity/formats/chui.py ie_shell/branches/iesh-infinity/infinity/formats/cre.py ie_shell/branches/iesh-infinity/infinity/formats/d2a.py ie_shell/branches/iesh-infinity/infinity/formats/dlg.py ie_shell/branches/iesh-infinity/infinity/formats/ids.py ie_shell/branches/iesh-infinity/infinity/formats/itm.py ie_shell/branches/iesh-infinity/infinity/formats/key.py ie_shell/branches/iesh-infinity/infinity/formats/mos.py ie_shell/branches/iesh-infinity/infinity/formats/pro.py ie_shell/branches/iesh-infinity/infinity/formats/spl.py ie_shell/branches/iesh-infinity/infinity/formats/stor.py ie_shell/branches/iesh-infinity/infinity/formats/tis.py ie_shell/branches/iesh-infinity/infinity/formats/tlk.py ie_shell/branches/iesh-infinity/infinity/formats/vvc.py ie_shell/branches/iesh-infinity/infinity/formats/wed.py ie_shell/branches/iesh-infinity/infinity/formats/wfx.py ie_shell/branches/iesh-infinity/infinity/formats/wmap.py ie_shell/branches/iesh-infinity/infinity/stream.py Added Paths: ----------- ie_shell/branches/iesh-infinity/infinity/defaults.py Modified: ie_shell/branches/iesh-infinity/README =================================================================== --- ie_shell/branches/iesh-infinity/README 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/README 2008-07-10 19:40:41 UTC (rev 5232) @@ -1,4 +1,4 @@ -iesh - Simple Python shell for exploring Infinity Engine-based game files +iesh - Simple Python shell for exploring Infinity Engine-based data files ========================================================================= @@ -14,7 +14,7 @@ Package contents: iesh - the shell infinity - python module package dealing with the reading of IE files - infinity/formats/* - various modules for reading the IE data files + infinity/formats/* - various modules for reading the specific IE file formats infinity/stream.py infinity/format.py @@ -41,6 +41,8 @@ Other files: $HOME/.iesh_profile $HOME/.iesh_history + $HOME/.iesh_save + $HOME/.iesh_save-* Running: @@ -117,4 +119,3 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - Modified: ie_shell/branches/iesh-infinity/iesh =================================================================== --- ie_shell/branches/iesh-infinity/iesh 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/iesh 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,13 +16,14 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: ie_shell.py,v 1.5 2006/07/03 18:15:34 edheldil Exp $ import atexit +import cPickle import os import os.path import rlcompleter import readline +import subprocess import sys import traceback @@ -33,6 +34,15 @@ from infinity.formats import * ################################################### +IESH_PROFILE_FILE = "~/.iesh_profile" +"""Load and execute this file at startup in interactive mode.""" + +IESH_HISTORY_FILE = "~/.iesh_history" +"""Command line history""" + +IESH_RESTORE_FILE = "~/.iesh_restore" +"""Save keys, strrefs and other core vars to this file for quick restore.""" + IESH_NORMAL_PROMPT = 'Cmd: ' IESH_COMPOUND_PROMPT = '.... ' IESH_INDENT = ' ' @@ -47,6 +57,9 @@ ## current compound command if non-empty compound_command = "" +pager = None +"""Pager process (as a Popen object)""" + ################################################### def help_on_shell (): print """ @@ -106,6 +119,7 @@ core.strrefs.print_strref_record (core.strrefs.strref_list[0]) print first records from chitin.key or dialog.tlk file + help (__name__) help (infinity) help (infinity.builtins) help on various topics @@ -122,6 +136,8 @@ ################################################### def read_command_file (filename, add_quit = False): + """Read commands to be executed from a file.""" + try: fh = open (filename) except: return False @@ -134,6 +150,9 @@ ################################################### def read_command (prompt): + """Return next command to be executed. + The command is read either from a file or from the command line.""" + if len (commands) != 0: return commands.pop (0) else: @@ -143,36 +162,53 @@ return 'quit' ################################################### -def readline_init (): - # Just enable history and tab completion for the command line +def _readline_init (): + """Enable history and tab completion for the command line.""" + readline.parse_and_bind ("tab: complete") - histfile = os.path.join (os.environ["HOME"], ".iesh_history") + histfile = os.path.expanduser (IESH_HISTORY_FILE) try: readline.read_history_file (histfile) except IOError: pass atexit.register (readline.write_history_file, histfile) - del histfile - readline.set_pre_input_hook (readline_hook) + #del histfile + readline.set_pre_input_hook (_readline_hook) ################################################### -def readline_hook (): +def _readline_hook (): readline.insert_text (indent) readline.redisplay () -def suspend (): - # pickle strrefs and resrefs - # or maybe rather call suspend() method in various modules? - pass +################################################### +def save (name = ''): + """Saves some core variables (especially keys and strrefs), so that they + can be later loaded faster than from IE data files. if `name' is specified, + it's added to filename where the data is stored, thus allowing more + save files than just one.""" + if name != '': + name = '-' + name + data = [core.game_dir, core.chitin_file, core.dialog_file, core.keys, core.strrefs] + fh = open (os.path.expanduser (IESH_RESTORE_FILE + name), 'w') + cPickle.dump (data, fh) + fh.close () -def resume (): - pass +################################################### +def restore (name = ''): + """Loads some core variables (especially keys and strrefs) saved + by save() function, much faster than from IE data files. if `name' + is specified, it's added to filename where the data is stored, thus + allowing more save files than just one.""" + if name != '': + name = '-' + name + fh = open (os.path.expanduser (IESH_RESTORE_FILE + name)) + data = cPickle.load (fh) + fh.close () + core.game_dir, core.chitin_file, core.dialog_file, core.keys, core.strrefs = data ################################################### ################################################### -# main -################################################### # # If the program is run with a file parameter, the contents of @@ -187,8 +223,8 @@ print "Can't read input file: %s" %sys.argv[1] sys.exit (1) else: - readline_init () - read_command_file (os.path.join (os.environ["HOME"], ".iesh_profile")) + _readline_init () + read_command_file (os.path.expanduser (IESH_PROFILE_FILE)) print "\n\nType `help' to print a short help, `quit' or ^D to exit the shell\n" # @@ -230,6 +266,16 @@ os.system (current_command[1:]) continue + # If `pager' option is set, run the `pager' and pipe command output to it + # That makes problems with e.g. help(), which runs pager as well, so + # try to avoid the situation. Ugly hack, there might be other such commands + # and moreover it's too easily fooled. + + if core.get_option ('pager') and not current_command.startswith ('help') and not current_command.startswith ('load_game'): + pager = subprocess.Popen (core.get_option ('pager'), shell = True, stdin=subprocess.PIPE) + save_stdout = sys.stdout + sys.stdout = pager.stdin + try: exec (current_command) except: @@ -237,7 +283,12 @@ traceback.print_exc () print + if pager is not None: + pager.stdin.close () + pager.wait () + sys.stdout = save_stdout + pager = None + ################################################### # End of file iesh - Modified: ie_shell/branches/iesh-infinity/infinity/builtins.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/builtins.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -1,21 +1,47 @@ #-*-python-*- +# ie_shell.py - Simple shell for Infinity Engine-based game files +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -"""Built-in functions for the iesh shell. This module contents -are imported directly into iesh's namespace.""" +"""Built-in functions for the iesh shell. +Functions which are ``built-into'' the iesh shell, meaning that this +module contents are automatically imported directly into iesh's +namespace on startup.""" + import os.path from infinity import core from infinity.stream import ResourceStream, FileStream ################################################### -def load_game (game_dir, chitin_file = core.chitin_file, dialog_file = core.dialog_file): - """Loads key and dialog files from the 'game_dir' directory. - The directory parameter is mandatory, the others are optional. - Most of the other commands assume that these two files are +def load_game (game_dir, chitin_file = None, dialog_file = None): + """Load key and dialog files from the 'game_dir' directory. + + The `game_dir' parameter is mandatory, the others are optional. + Many commands assume that these two files are already loaded. The loaded objects are stored in core.keys and core.strrefs.""" + if chitin_file is None: + chitin_file = core.get_option ('core.chitin_file') + + if dialog_file is None: + dialog_file = core.get_option ('core.dialog_file') + core.game_dir = game_dir core.chitin_file = chitin_file core.dialog_file = dialog_file @@ -26,42 +52,45 @@ core.keys.read_header (stream) print "Loading %d file refs and %d RESREFs. This may take ages" %(core.keys.header['num_of_bifs'], core.keys.header['num_of_resrefs']) core.keys.read (stream) + stream.close () - # LOAD STRREF index file (DIALOG.TLK) stream = FileStream ().open (os.path.join (game_dir, dialog_file)) core.strrefs = core.get_format ('TLK') () core.strrefs.read_header (stream) print "Loading %d STRREFs. This may take eternity" %(core.strrefs.header['num_of_strrefs']) core.strrefs.read (stream) + stream.close () - ################################################### def load_object (name, type = None, index = 0): - """Loads object from a file 'name' located in filesystem or in game's data - and returns Format object of appropriate type. If the name is not unique, - specify resource type with `type' and eventually `index' if - there's still more than one.""" + """Load named object from a file located in filesystem or in game's data. + Load file or resref `name' and return Format object of appropriate type. + If `name' is not unique, specify resource type with `type' and eventually + `index' if there's still more than one.""" + try: - fh = open (name) + stream = FileStream().open (name) except: - fh = None + stream = ResourceStream().open (name, type, index) + + res = stream.load_object () + stream.close () + return res - if fh: - fh.close () - return FileStream().open (name).load_object () - else: - return ResourceStream().open (name, type, index).load_object () - ################################################### -def print_object (name, type = None): - obj = load_object (name, type) +def print_object (name, type = None, index = 0): + """Load and print named object. See `load_object()' for details.""" + + obj = load_object (name, type, index) obj.printme () ################################################### def export_object (name, filename, type = None, index = 0): - """Exports resource `name' into file `filename'. If the `name' is not + """Export resource `name' into file `filename'. + + If the `name' is not unique, specify resource type with `type' and eventually `index' if there's still more than one""" @@ -73,7 +102,8 @@ ################################################### def iterate_objects_by_type (type, fn): - + """Execute function for each object of specified type.""" + # FIXME: this function opens and decodes a bif file EACH time some # object from it is accessed, so it's slow as hell. It should use # some caching @@ -89,10 +119,12 @@ ################################################### -def find_str (text): - """Finds all strings in loaded DIALOG.TLK file matching regular expression - 'text' and prints their STRREFs to stdout.""" +def find_str (regexp): + """Find all strings in core.strrefs matching regular expression. + Find all strings in loaded DIALOG.TLK file matching regular + expression 'regexp' and prints the STRREFs and strings to stdout.""" + for o in core.strrefs.get_strref_by_str_re(text): print core.strrefs.strref_list.index(o), o['string'] @@ -104,16 +136,11 @@ def printf (format_str, params): print sprintf (format_str, params) -################################################### -def pok(): - def p (obj): - obj.read () - obj.printme () - iterate_objects_by_type (0x03ed, p) - ################################################### def load_ids (): + """Load (or try to) all IDS files.""" + def p (obj): obj.read () print obj.stream.resref @@ -124,6 +151,8 @@ ################################################### def print_restype_stats (): + """Print list of RESREFs with count of objects of each type.""" + stats = {} for o in core.keys.resref_list: @@ -145,7 +174,7 @@ def print_formats (): """List recognized/implemented IE file formats""" - flist = filter (lambda a: a[0][1] != None, core.formats.items ()) + flist = filter (lambda a: a[0][1] is not None, core.formats.items ()) flist.sort (lambda a, b: 2 * cmp (a[0][0], b[0][0]) + cmp (a[0][1], b[0][1])) print "sign vers class desc & status" @@ -153,9 +182,9 @@ for key, value in flist: version = '' desc = '' - if key[1] != None: + if key[1] is not None: version = key[1] - if value[1] != None: + if value[1] is not None: desc = '- ' + value[1] klass_name = str (value[0]) klass_name = klass_name.replace ('infinity.formats.', '') @@ -164,4 +193,16 @@ ################################################### +def print_options (desc = True): + """List known options with their values. If `desc' is True, list their descriptions as well.""" + + options = core.options.items () + options.sort () + for key, opt in options: + if desc: + print "%-30s - %s [%s]" %(key, opt[1], repr (opt[0])) + else: + print "%-30s - %s" %(key, repr (opt[0])) + +################################################### # End of file builtins.py Modified: ie_shell/branches/iesh-infinity/infinity/core.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/core.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/core.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,11 +16,14 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: ie_shell.py,v 1.5 2006/07/03 18:15:34 edheldil Exp $ +""" +Core and global definitions for the `infinity' package +""" + import string +import defaults - global formats formats = {} @@ -31,19 +34,20 @@ keys = None global options -options = {} +options = defaults.options # Loaded IDS files global ids ids = {} +# These variables are filled after call to load_game() game_dir = None -chitin_file = 'CHITIN.KEY' -dialog_file = 'dialog.tlk' +chitin_file = None +dialog_file = None xor_key = "\x88\xa8\x8f\xba\x8a\xd3\xb9\xf5\xed\xb1\xcf\xea\xaa\xe4\xb5\xfb\xeb\x82\xf9\x90\xca\xc9\xb5\xe7\xdc\x8e\xb7\xac\xee\xf7\xe0\xca\x8e\xea\xca\x80\xce\xc5\xad\xb7\xc4\xd0\x84\x93\xd5\xf0\xeb\xc8\xb4\x9d\xcc\xaf\xa5\x95\xba\x99\x87\xd2\x9d\xe3\x91\xba\x90\xca" +"""Key used to `encrypt' some objects in IE files by XOR""" - global slash_trans slash_trans = string.maketrans ('\\', '/') @@ -177,6 +181,11 @@ def register_format (signature, version, klass, desc = None): + """Register class `klass' for reading, parsing and (possibly) writing + IE file format with given `signature' and `version'. `desc' allows + to specify text displayed in format list and should be used to + describe status/progress of implementation.""" + #core.formats[(signature, version)] = klass #formats[signature] = klass formats[(signature, version)] = (klass, desc) @@ -198,4 +207,21 @@ except: return None +def get_option (key): + try: + return options[key][0] + except KeyError: + raise RuntimeError ("Unknown option `%s'" %key) + +def set_option (key, value, desc = None): + try: + opt = options[key] + opt[0] = value + except KeyError: + # option does not exist yet, require desc and create it + if desc is None: + raise RuntimeError ("Unknown option `%s', `desc' required to create it" %key) + options[key] = [value, desc] + + # End of file core.py Added: ie_shell/branches/iesh-infinity/infinity/defaults.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/defaults.py (rev 0) +++ ie_shell/branches/iesh-infinity/infinity/defaults.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -0,0 +1,51 @@ +# -*-python-*- +# ie_shell.py - Simple shell for Infinity Engine-based game files +# Copyright (C) 2004-2008 by Jaroslav Benkovsky, <edh...@us...> +# +# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +# FIXME: add descriptions to the options + +options = { + 'core.chitin_file': ['CHITIN.KEY', ""], + 'core.dialog_file': ['dialog.tlk', ""], + 'pager': ['more', "Program to use for paging command output"], + + 'stream.debug_coverage': [False, "On stream close print info on offsets not read or read more than once"], + 'format.debug_read': [False, "Print each read op to stdout"], + 'format.debug_write': [False, "Print each write op to stdout"], + + 'format.bam.force_rle': [True, "Assume that frame data is always RLE encoded"], + 'format.bam.decode_frame_data': [True, "Decode BAM frame data"], + 'format.bam.print_frame_bitmap': [True, "Print BAM frame data"], + 'format.bam.print_palette': [True, "Print BAM frame palette" ], + + 'format.biff.read_data': [False, "When reading BIFF file read its data too"], + + 'format.key.tick_size': [ 100, "" ], + 'format.key.tack_size': [ 5000, "" ], + 'format.key.max_read_resrefs': [None, "Max # of RESREFs to read from KEY file"], + + 'format.mos.print_tiles': [True, "Print MOS tiles"], + 'format.mos.print_palettes': [False, "Print MOS palettes"], + + 'format.tlk.tick_size': [ 100, "" ], + 'format.tlk.tack_size': [ 5000, "" ], + 'format.tlk.decode_strrefs': [True, "Read TLK strrefs, not only header"], + +} + +# End of file defaults.py Modified: ie_shell/branches/iesh-infinity/infinity/format.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/format.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/format.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,10 +16,12 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: format.py,v 1.5 2006/07/08 14:29:26 edheldil Exp $ -"""This module implements Format, abstract class representing -IE file type. This object is futher subclassed +""" +Implements Format, abstract class representing IE file type. + +This modules implements Format, abstract base class +representing IE file types. This class is futher subclassed in infinity.formats package to the various IE file formats like 2DA, BAM, TLK etc.""" @@ -32,11 +34,7 @@ from infinity import core from infinity.stream import Stream, FileStream, ResourceStream -PAGE_SIZE = 4096 -TICK_SIZE = 100 -TACK_SIZE = 5000 - def ResolveFilePath (filename): if os.path.isfile (filename): return filename @@ -44,26 +42,13 @@ -class Format: - - default_options = {} - +class Format (object): def __init__ (self): self.header_size = 0 self.bitmask_cache = {} self.options = {} -## def load (self, source): -## if source != None: -## if not isinstance (source, Stream): -## source = FileStream (source) -## self.stream = source -## if not source.is_open: -## source.open (mode) - -## self.stream = source - def read_header (self, stream): self.header = {} self.read_struc (stream, 0x0000, self.header_desc, self.header) @@ -76,11 +61,11 @@ def read_list (self, stream, name, header = None, desc = None, list = None): - if desc == None: + if desc is None: desc = self.__class__.__dict__ [name + '_desc'] - if list == None: + if list is None: list = self.__dict__ [name + '_list'] - if header == None: + if header is None: header = self.header off = header[name + '_off'] @@ -93,11 +78,11 @@ off += size def write_list (self, stream, offset, name, header = None, desc = None, list = None): - if desc == None: + if desc is None: desc = self.__class__.__dict__ [name + '_desc'] - if list == None: + if list is None: list = self.__dict__ [name + '_list'] - if header == None: + if header is None: header = self.header header[name + '_off'] = offset @@ -112,9 +97,9 @@ def print_list (self, name, desc = None, list = None): - if desc == None: + if desc is None: desc = self.__class__.__dict__ [name + '_desc'] - if list == None: + if list is None: list = self.__dict__ [name + '_list'] i = 0 @@ -183,7 +168,7 @@ size = self.get_struc_size ([ d ]) - local_offset d['count'] = count - if self.get_option ('debug_read'): + if self.get_option ('format.debug_read'): print d for index in range (count): @@ -258,7 +243,7 @@ else: obj[key] = value - if self.get_option ('debug_read'): + if self.get_option ('format.debug_read'): self.print_date_by_desc (obj, d) @@ -275,7 +260,7 @@ value = obj[key] - if self.get_option ('debug_write'): + if self.get_option ('format.debug_write'): print '%05d' %(offset + local_offset), d, value if type == 'BYTE': @@ -430,7 +415,7 @@ elif rec_type == 'RGBA': try: value2 = '(' + '%08x' %value + ')' except: pass - elif enum != None: + elif enum is not None: if type (enum) == types.DictType: try: value2 = '(' + enum[value] + ')' except: pass @@ -449,7 +434,7 @@ except: pass - elif mask != None: + elif mask is not None: value2 = '(' + string.join (map (lambda m, mask=mask: mask[m], filter (lambda m, v=value: (m & v) == m, mask.keys ())), '|') + ')' if count > 1: @@ -458,26 +443,19 @@ print label + ':', value, value2 - def set_option_default (key, value): - Format.default_options[key] = value - - def set_option (self, key, value): - self.options[key] = value - def get_option (self, key): if self.options.has_key (key): return self.options[key] - elif core.options.has_key (key): - return core.options[key] else: - return Format.default_options[key] + return core.get_option (key) -Format.default_options['debug_read'] = 0 -Format.default_options['debug_write'] = 0 + def set_option (self, key, value): + self.options[key] = value + ctltype_hash = { 0 : 'button/pixmap', 2 : 'slider', @@ -491,3 +469,6 @@ def register_format (signature, version, klass): core.register_format (signature, version, klass) + + +# End of file format.py Modified: ie_shell/branches/iesh-infinity/infinity/formats/are.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/are.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: pro.py,v 1.1 2006/07/08 14:29:26 edheldil Exp $ from infinity import core from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/bam.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/bam.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/bam.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: bam.py,v 1.3 2006/07/08 14:29:26 edheldil Exp $ import struct import sys @@ -199,15 +198,15 @@ self.print_cycle (obj) i = i + 1 - if self.get_option ('bam_print_palette'): + if self.get_option ('format.bam.print_palette'): self.print_palette () def read_frame (self, stream, offset, obj): self.read_struc (stream, offset, self.frame_desc, obj) - if self.get_option ('bam_decode_frame_data'): - if self.get_option ('bam_force_rle') or obj['rle_encoded']: + if self.get_option ('format.bam.decode_frame_data'): + if self.get_option ('format.bam.force_rle') or obj['rle_encoded']: self.read_rle_frame_data (stream, obj) else: self.read_frame_data (stream, obj) @@ -215,7 +214,7 @@ def print_frame (self, obj): self.print_struc (obj, self.frame_desc) - if self.get_option ('bam_print_frame_bitmap'): + if self.get_option ('format.bam.print_frame_bitmap'): self.print_frame_bitmap (obj) def read_cycle (self, stream, offset, obj): @@ -242,12 +241,12 @@ self.read_struc (stream, offset, self.palette_entry_desc, obj) self.palette_entry_list.append (obj) - if transp_color == None and obj['r'] == 0 and obj['g'] == 255 and obj['b'] == 0: + if transp_color is None and obj['r'] == 0 and obj['g'] == 255 and obj['b'] == 0: transp_color = i offset = offset + 4 - if transp_color == None: + if transp_color is None: transp_color = 0 self.header['transp_color_ndx'] = transp_color @@ -363,14 +362,7 @@ -# assume frame data is always RLE encoded -BAM_Format.default_options['bam_force_rle'] = 1 -# decode and load frame data -BAM_Format.default_options['bam_decode_frame_data'] = 1 -BAM_Format.default_options['bam_print_frame_bitmap'] = 1 -BAM_Format.default_options['bam_print_palette'] = 1 - register_format ('BAM', 'V1', BAM_Format) register_format ('BAMC', 'V1 ', BAMC_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/biff.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/biff.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: biff.py,v 1.3 2006/07/08 14:29:26 edheldil Exp $ import gzip from infinity.format import Format, register_format @@ -136,7 +135,7 @@ self.tileset_list.append (obj) off = off + 20 - if self.get_option ('biff_read_data'): + if self.get_option ('format.biff.read_data'): self.read_all_data (stream) def printme (self): @@ -272,7 +271,5 @@ -BIFF_Format.default_options['biff_read_data'] = False - register_format ('BIFF', 'V1', BIFF_Format) register_format ('BIF ', 'V1.0', BIFC_V1_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/chui.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/chui.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/chui.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: chui.py,v 1.1 2005/03/02 20:44:22 edheldil Exp $ from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/cre.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/cre.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: cre.py,v 1.3 2006/07/03 18:15:35 edheldil Exp $ from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/d2a.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/d2a.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/d2a.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: ids.py,v 1.2 2006/07/08 14:29:26 edheldil Exp $ import re import sys @@ -47,9 +46,9 @@ self.cols = map (lambda s: s.strip (), s.split (None)) line_no = 3 - while s != None: + while s is not None: s = stream.get_line () - if s == None: + if s is None: break line_no = line_no + 1 @@ -162,7 +161,7 @@ values = self.get_row (row) print row + ':', for v in values: - if v == None: + if v is None: break print v, print Modified: ie_shell/branches/iesh-infinity/infinity/formats/dlg.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/dlg.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/dlg.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: dlg.py,v 1.1 2006/07/03 18:15:35 edheldil Exp $ from infinity import core from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/ids.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/ids.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: ids.py,v 1.2 2006/07/08 14:29:26 edheldil Exp $ import re import sys @@ -35,9 +34,9 @@ s = "" line_no = 0 - while s != None: + while s is not None: s = stream.get_line () - if s == None: + if s is None: break line_no = line_no + 1 Modified: ie_shell/branches/iesh-infinity/infinity/formats/itm.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/itm.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: itm.py,v 1.1 2005/03/02 20:44:23 edheldil Exp $ from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/key.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/key.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/key.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,12 +16,12 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: key.py,v 1.4 2006/07/08 14:29:26 edheldil Exp $ import re import sys -from infinity.format import Format, register_format, TICK_SIZE, TACK_SIZE +from infinity import core +from infinity.format import Format, register_format class KEY_Format (Format): header_desc = ( @@ -131,7 +131,6 @@ # when set to some number, read that number of resources at most #self.options['max_read_bifs'] = None - self.options['max_read_resrefs'] = None def read (self, stream): @@ -148,10 +147,12 @@ off = self.header['resref_offset'] max_read_resrefs = self.header['num_of_resrefs'] - if self.options['max_read_resrefs']: - max_read_resrefs = min (max_read_resrefs, self.options['max_read_resrefs']) + if self.get_option ('format.key.max_read_resrefs'): + max_read_resrefs = min (max_read_resrefs, self.get_option ('format.key.max_read_resrefs')) resref_record_size = self.get_struc_size (self.resref_record_desc) + tick_size = self.get_option ('format.key.tick_size') + tack_size = self.get_option ('format.key.tack_size') for i in range (max_read_resrefs): #if i == 1000: # break @@ -163,9 +164,9 @@ self.resref_hash[obj['resref_name']] = obj off = off + resref_record_size - if not (i % TICK_SIZE): + if not (i % tick_size): sys.stdout.write('.') - if not (i % TACK_SIZE): + if not (i % tack_size): sys.stdout.write('%d' %i) sys.stdout.flush () print Modified: ie_shell/branches/iesh-infinity/infinity/formats/mos.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/mos.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/mos.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: bam.py,v 1.3 2006/07/08 14:29:26 edheldil Exp $ import struct import sys @@ -142,14 +141,14 @@ def printme (self): self.print_header () - if self.get_option ('mos_print_palettes'): + if self.get_option ('format.mos.print_palettes'): i = 0 for obj in self.tile_list: print 'Palette #%d' %i self.print_palette (obj['palette']) i = i + 1 - if self.get_option ('mos_print_tiles'): + if self.get_option ('format.mos.print_tiles'): i = 0 for obj in self.tile_list: print 'Tile #%d' %i @@ -158,9 +157,6 @@ i = i + 1 - - - def read_palette (self, stream, offset, obj): for i in range (256): obj2 = {} @@ -272,14 +268,6 @@ -# assume frame data is always RLE encoded -#BAM_Format.default_options['bam_force_rle'] = 1 -# decode and load frame data -#BAM_Format.default_options['bam_decode_frame_data'] = 1 -MOS_Format.default_options['mos_print_tiles'] = True -MOS_Format.default_options['mos_print_palettes'] = False - - register_format ('MOS', 'V1', MOS_Format) register_format ('MOSC', 'V1 ', MOSC_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/pro.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/pro.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/pro.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: pro.py,v 1.1 2006/07/08 14:29:26 edheldil Exp $ from infinity import core from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/spl.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/spl.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/spl.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: spl.py,v 1.1 2005/03/02 20:44:23 edheldil Exp $ from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/stor.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/stor.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/stor.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: cre.py,v 1.3 2006/07/03 18:15:35 edheldil Exp $ from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/tis.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/tis.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/tis.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: tis.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ from infinity import core from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/tlk.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/tlk.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/tlk.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,14 +16,13 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: tlk.py,v 1.6 2006/07/08 14:29:27 edheldil Exp $ import re import string import sys from infinity import core -from infinity.format import Format, register_format, TICK_SIZE, TACK_SIZE +from infinity.format import Format, register_format class TLK_Format (Format): @@ -106,9 +105,12 @@ off = 0x0012 - if not self.get_option ('tlk_decode_strrefs'): + if not self.get_option ('format.tlk.decode_strrefs'): return + tick_size = core.get_option ('format.tlk.tick_size') + tack_size = core.get_option ('format.tlk.tack_size') + for i in range (self.header['num_of_strrefs']): obj = {} @@ -116,9 +118,9 @@ self.strref_list.append (obj) off = off + 26 - if not (i % TICK_SIZE): + if not (i % tick_size): sys.stdout.write('.') - if not (i % TACK_SIZE): + if not (i % tack_size): sys.stdout.write('%d' %i) sys.stdout.flush () print @@ -171,6 +173,5 @@ return filter (lambda s, rx=rx: rx.search (s['string']), self.strref_list) -TLK_Format.default_options['tlk_decode_strrefs'] = 1 register_format ('TLK', 'V1', TLK_Format) Modified: ie_shell/branches/iesh-infinity/infinity/formats/vvc.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/vvc.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/vvc.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: vvc.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ from infinity import core from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/wed.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/wed.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: wed.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ from infinity import core from infinity.format import Format, register_format @@ -369,7 +368,6 @@ off2 = obj['tile_index_lookup_off'] for i in range (tile_index_cnt): - print off2, ':', i tile_index = stream.read_word (off2) obj['tile_index_list'].append (tile_index) off2 += size Modified: ie_shell/branches/iesh-infinity/infinity/formats/wfx.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wfx.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/wfx.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,7 +16,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: wfx.py,v 1.1 2006/07/08 14:29:27 edheldil Exp $ from infinity import core from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/formats/wmap.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/formats/wmap.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/formats/wmap.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -17,7 +17,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: wmap.py,v 1.1 2005/03/02 20:44:23 edheldil Exp $ from infinity.format import Format, register_format Modified: ie_shell/branches/iesh-infinity/infinity/stream.py =================================================================== --- ie_shell/branches/iesh-infinity/infinity/stream.py 2008-07-05 21:20:31 UTC (rev 5231) +++ ie_shell/branches/iesh-infinity/infinity/stream.py 2008-07-10 19:40:41 UTC (rev 5232) @@ -16,13 +16,23 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# RCS: $Id: stream.py,v 1.3 2006/07/08 14:29:27 edheldil Exp $ -"""This module implements Stream, abstract class for reading -IE files, and also various specialized subclasses for reading -files, memory buffers and files in BIFF archives.""" +""" +Implement *Stream, classes for reading IE files. +Implement *Stream classes for reading IE data primitives +from normal files, memory buffers and from files in IE specific +`filesystem' addressed by RESREFs. +Classes: + Stream - base class implementing reading of IE primitives + FileStream - read from files contained in filesystem + MemoryStream - read from memory buffers (strings) + ResourceStream - read IE object referenced by RESREF + CompressedStream - read compressed buffer +""" + + import gzip import os.path import re @@ -32,39 +42,63 @@ from infinity import core -class Stream: +class Stream (object): + """ + Base abstract class for reading and writing IE files. + + It implements the basic open / read / write / seek / close + API to be implemented in the subclasses, as well as + functions for reading primitive IE data types like RESREF or WORD. + """ + def __init__ (self): self.is_open = False + self.options = {} - def open (self, mode = 'r'): + + def __del__ (self): + """Destructor""" + # FIXME: possibly close() only when autoclose flag is set + self.close () + + + def open (self, name, mode = 'r'): # do the real open here self.is_open = True + self.name = name self.coverage = [] - #self.coverage = {} - self.debug_coverage = False return self - + + def close (self): - pass - + if not self.is_open: + return + + if self.get_option ('stream.debug_coverage'): + self.print_coverage () + self.is_open = False + + def seek (self, offset): + """Set position for next read (current offset) to `offset'. + Override in subclasses.""" pass def read (self, count = None): + """Read `count' of bytes at the current offset and update the offset. + Override in subclasses.""" pass def write (self, data, count = None): + """Write `data' to current offset in file. + Override in subclasses.""" pass - def readline (self): - pass + # Methods for reading and writing primitive IE data types - def writeline (self, line): - pass - def get_char (self, offset = None): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) return self.read (1) @@ -73,7 +107,7 @@ def put_char (self, char, offset = None): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) self.write (char, 1) @@ -88,35 +122,35 @@ def read_word (self, offset): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) v = self.read (2) return struct.unpack ('H', v)[0] def write_word (self, value, offset = None): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) bytes = struct.pack ('H', value) self.write (bytes) def read_dword (self, offset): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) v = self.read (4) return struct.unpack ('I', v)[0] def write_dword (self, value, offset = None): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) bytes = struct.pack ('I', value) self.write (bytes) def read_sized_string (self, offset, size): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) v = self.read (size) # FIXME: remove the trailing zeros @@ -125,7 +159,7 @@ def write_sized_string (self, value, offset, size): # offset == None means "current offset" here - if offset != None: + if offset is not None: self.seek (offset) # FIXME: pad with zeros @@ -168,7 +202,7 @@ def read_blob (self, offset, size = None): # offset == None means "current offset" here # size == None means "till the end of stream" - if offset != None: + if offset is not None: self.seek (offset) return self.read (size) @@ -176,12 +210,14 @@ def write_blob (self, value, offset, size = None): # offset == None means "current offset" here # size == None means "till the end of stream" - if offset != None: + if offset is not None: self.seek (offset) return self.write (value) + # Helper methods + def get_signature (self): was_open = self.is_open #if not self.is_open: @@ -208,7 +244,7 @@ signature, version = self.get_signature () fmt = core.get_format (signature, version) - if fmt == None and type != 0: + if fmt is None and type != 0: fmt = core.get_format_by_type (type) return fmt @@ -221,22 +257,86 @@ return obj + def coverage_add (self, offset, size, some_info_tbd): + d = offset +size - len (self.coverage) + if d > 0: + self.coverage.extend ([0] * d) + for i in range (offset, offset + size): + self.coverage[i] += 1 + + def print_coverage (self): + def print_single (offset, value): + print " 0x%04x: %d" %(offset, value) + + def print_range (offset1, offset2, value): + if offset2 == offset1: + print_single (offset1, value) + else: + print " 0x%04x - 0x%04x: %d" %(offset1, offset2, value) + + print "Coverage (%s):" %self.name + from_offset = None + + for i in range (len (self.coverage)): + if self.coverage[i] == 0 and from_offset is None: + from_offset = i + elif self.coverage[i] == 0: + pass + elif self.coverage[i] > 1: + if from_offset is not None: + print_range (from_offset, i - 1, 0) + from_offset = None + print_single (i, self.coverage[i]) + else: + if from_offset is not None: + print_range (from_offset, i - 1, 0) + from_offset = None + + if from_offset is not None: + print_range (from_offset, i - 1, 0) + from_offset = None + + + def get_option (self, key): + if self.options.has_key (key): + return self.options[key] + else: + return core.get_option (key) + + + def set_option (self, key, value): + self.options[key] = value + + + + class FileStream (Stream): + """Specialized Stream for working with normal files in filesystem""" + def __init__ (self): Stream.__init__ (self) def open (self, filename, mode = 'r'): # FIXME: reset offset? - Stream.open (self, mode) + Stream.open (self, filename, mode) + self.is_open = False self.filename = filename self.fh = open (self.filename, mode) self.is_open = True + + if self.get_option ('stream.debug_coverage'): + size = os.stat (filename)[6] + self.coverage = [0] * size + return self def close (self): + if not self.is_open: + return + self.fh.close () - self.is_open = False + Stream.close (self) def seek (self, offset): self.fh.seek (offset) @@ -244,69 +344,23 @@ def read (self, size = None): # FIXME: do some caching/buffering here? - if self.debug_coverage: + #if size == None: + # raise RuntimeError () + + if self.get_option ('stream.debug_coverage'): off = self.fh.tell () - if size != None: - value = self.fh.read (size) - else: - value = self.fh.read () + #if size != None: + value = self.fh.read (size) + #else: + # value = self.fh.read () - if self.debug_coverage: - sz = len (value) + if self.get_option ('stream.debug_coverage'): + #sz = len (value) self.coverage_add (off, size, None) return value - def coverage_add (self, offset, size, some_info_tbd): - d = offset +size - len (self.coverage) - if d > 0: - self.coverage.extend ([0] * d) - for i in range (offset, offset + size): - self.coverage[i] += 1 - def print_coverage (self): - for i in range (len (self.coverage)): - if self.coverage[i] != 1: - print "0x%04x: %d" %(i, self.coverage[i]) - - def xcoverage_add (self, offset, size, some_info_tbd): - si, ss = self.coverage_find_offset (offset) - ei, es = self.coverage_find_offset (offset + size) - - if si == ei: - if ss == 0: - if es == 0: - self.coverage.insert (i, (offset, offset + size, [])) - elif es == 1: - self.coverage[i] = (offset, colf.coverage[i][1], []) - else: - self.coverage[i] = (offset, colf.coverage[i][1], ['False']) - elif ss == 1 or ss == 2: - # for now - pass - else: # 3 - # should not happen, implies length=0 - pass - - else: - pass - - - def coverage_find_offset (self, offset): - for i in len (self.coverage): - if i < self.coverage[i][0]: - return (i, 0) - elif i == self.coverage[i][0]: - return (i, 1) - elif i < self.coverage[i][1]: - return (i, 2) - elif i == self.coverage[i][1]: - return (i, 3) - - return (len (self.coverage), 0) - - - def write (self, bytes, size = None): #if size != None: # self.fh.write (bytes, size) @@ -318,27 +372,25 @@ class MemoryStream (Stream): + """Stream for working with memory buffers instead of files.""" def __init__ (self): Stream.__init__ (self) - def open (self, membuffer): + def open (self, membuffer, name = '<memory stream>'): + Stream.open (self, name, '') self.buffer = membuffer self.offset = 0 - self.is_open = True return self def decrypt (self): for i in range (len (self.buffer)): print chr (ord (self.buffer[i]) ^ ord (core.xor_key[i])) - def close (self): - self.is_open = False - def seek (self, offset): self.offset = offset def read (self, count = None): - if count != None: + if count is not None: data = self.buffer[self.offset:self.offset+count] else: data = self.buffer[self.offset:] @@ -349,6 +401,9 @@ class ResourceStream (MemoryStream): + """Stream for reading RESREFs (files in the IE data `filesystem'). + It requires that the KEY file is loaded in core.keys.""" + def __init__ (self): MemoryStream.__init__ (self) @@ -356,14 +411,14 @@ self.resref = name self.type = type - if core.keys == None: + if core.keys is None: raise RuntimeError, "Core game files are not loaded. See load_game ()." oo = core.keys.get_resref_by_name_re (self.resref) - if self.type != None: + if self.type is not None: oo = filter (lambda o: o['type'] == self.type, oo) - if len (oo) > 1 and self.type == None: + if len (oo) > 1 and self.type is None: raise RuntimeError, "More than one result" o = oo[index] @@ -376,7 +431,7 @@ b.get_file_data (bif_stream, obj) buffer = obj['data'] - return MemoryStream.open (self, buffer) + return MemoryStream.open (self, buffer, name = name) ... [truncated message content] |