├── .gitignore ├── README ├── colupatr ├── AUTHORS ├── COPYING ├── ChangeLog ├── cli.py ├── colupatr.py ├── hexview.py ├── midi.py └── utils.py └── oletoy ├── .gitignore ├── AUTHORS ├── App.py ├── ChangeLog ├── README ├── abr.py ├── bmi.py ├── c602.py ├── cdr.py ├── cdw.py ├── chdraw.py ├── clp.py ├── cmx.py ├── cpl.py ├── cpt.py ├── cvx.py ├── doc.py ├── drw.py ├── dsf.py ├── emfparse.py ├── emfplus.py ├── escher.py ├── fbx.py ├── fh.py ├── fh12.py ├── fhfind.py ├── fhrec.py ├── hexdump.py ├── hv2.py ├── icc.py ├── inflate.py ├── iwa.py ├── lit.py ├── lrf.py ├── mdb.py ├── mf.py ├── midi.py ├── nki.py ├── ole.py ├── oledump.py ├── oletoy.cfg ├── otxml.py ├── palm.py ├── pcap.py ├── pict.py ├── pkzip.py ├── plist.py ├── pm6.py ├── pngot.py ├── ppp.py ├── ppt.py ├── pub.py ├── pubblock.py ├── publisher1.py ├── qpw.py ├── quattro_wq.py ├── quill.py ├── qxp ├── __init__.py ├── qxp.py ├── qxp1.py ├── qxp2.py ├── qxp33.py └── qxp4.py ├── riff.py ├── rtf.py ├── rx2.py ├── sbimp.py ├── svm.py ├── t602.py ├── tree.py ├── uniview.py ├── utils.py ├── vba.py ├── vfb.py ├── view.py ├── viewCmd.py ├── vsd.py ├── vsd2.py ├── vsdblock.py ├── vsdchunks.py ├── vsdchunks5.py ├── vsdstream4.py ├── wld.py ├── wls.py ├── wmfparse.py ├── wt602.py ├── xls.py ├── yep.py ├── zbr.py └── zmf.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Re-lab is a project that focuses on doing clean-room reverse engineering 2 | of various proprietary file formats, so that developers of free/libre 3 | software could implement support for these file formats. 4 | 5 | We do not write end-user software, but we collaborate with projects like 6 | Inkscape, Scribus, and LibreOffice to make some popular proprietary file 7 | formats readable by those applications. 8 | 9 | This repository contains generic tools we developed for studying binary 10 | file formats, as well as parsers of specific file formats. 11 | 12 | Please refer to README of each tool for more information. 13 | -------------------------------------------------------------------------------- /colupatr/AUTHORS: -------------------------------------------------------------------------------- 1 | Valek Filippov 2 | -------------------------------------------------------------------------------- /colupatr/ChangeLog: -------------------------------------------------------------------------------- 1 | 2012-03-02 Valek Filippov 2 | 3 | * Fix comment remove/insert, fix off by 1 for files with %16 length. 4 | 5 | 2012-02-04 Valek Filippov 6 | 7 | * Improvements for 'goto'. 8 | * Search for selection. 9 | * Add "!" for "insert/remove comment". 10 | * Add "/" for "insert separator". 11 | * Fix 'copy to clipboard' 12 | * Switch focus by ^Space. 13 | 14 | 2012-01-27 Valek Filippov 15 | 16 | * Fixed 'goto' 17 | * Added search. 18 | * Added options. 19 | 20 | 2012-01-23 Valek Filippov 21 | 22 | * Added support for 'Tab' 23 | * +Alt in entry to send keys to hexview. 24 | 25 | 2012-01-22 Valek Filippov 26 | 27 | * Comments improvements 28 | * Fix status page problem 29 | 30 | 2012-01-20 Valek Filippov 31 | 32 | * Comments fixes and improvements 33 | * Fix open/save. 34 | 35 | 2012-01-16 Valek Filippov 36 | 37 | * Code reorg for on_key_pressed. 38 | * More code reorg, comments/separators temporary partly broken. 39 | 40 | 2012-01-08 Valek Filippov 41 | 42 | * Fix 'fmt' > maxaddr for not whole file 43 | * Implement 'fmt *'. 44 | 45 | 2012-01-08 Valek Filippov 46 | 47 | * Fix selection outside of dump 48 | * Improve column selection 49 | * Fix short files issue 50 | * Fix selection to left and multiline 51 | 52 | 2012-01-08 Valek Filippov 53 | 54 | * 'fmt' mostly fixed. 55 | 56 | 2012-01-04 Valek Filippov 57 | 58 | * Start to implement 'fmt'. 59 | 60 | 2012-01-03 Valek Filippov 61 | 62 | * Fix 'goto'. 63 | 64 | 2011-12-23 Valek Filippov 65 | 66 | * Comments landed. 67 | * Improved comments/breaks behavior 68 | 69 | 2011-12-23 Valek Filippov 70 | 71 | * Bold for hex cursor and selection size, 72 | semitransparent selection size BG, 73 | better place for selection size, 74 | small visual glitch with selection fix. 75 | * step toward comments 76 | 77 | 2011-12-22 Valek Filippov 78 | 79 | * "Start making this into a real package." (c) Jody 80 | -------------------------------------------------------------------------------- /colupatr/midi.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010-2013 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct 18 | 19 | pitches = { 20 | 0x0:'C(-1)',0x1:'Db(-1)',0x2:'D(-1)',0x3:'Eb(-1)', 21 | 0x4:'E(-1)',0x5:'F(-1)',0x6:'Gb(-1)',0x7:'G(-1)', 22 | 0x8:'Ab(-1)',0x9:'A(-1)',0x0A:'Bb(-1)',0x0B:'B(-1)', 23 | 0x0C:'C0',0x0D:'Db0',0x0E:'D0',0x0F:'Eb0', 24 | 0x10:'E0',0x11:'F0',0x12:'Gb0',0x13:'G0', 25 | 0x14:'Ab0',0x15:'A0',0x16:'Bb0',0x17:'B0', 26 | 0x18:'C1',0x19:'Db1',0x1A:'D1',0x1B:'Eb1', 27 | 0x1C:'E1',0x1D:'F1',0x1E:'Gb1',0x1F:'G1', 28 | 0x20:'Ab1',0x21:'A1',0x22:'Bb1',0x23:'B1', 29 | 0x24:'C2',0x25:'Db2',0x26:'D2',0x27:'Eb2', 30 | 0x28:'E2',0x29:'F2',0x2A:'Gb2',0x2B:'G2', 31 | 0x2C:'Ab2',0x2D:'A2',0x2E:'Bb2',0x2F:'B2', 32 | 0x30:'C3',0x31:'Db3',0x32:'D3',0x33:'Eb3', 33 | 0x34:'E3',0x35:'F3',0x36:'Gb3',0x37:'G3', 34 | 0x38:'Ab3',0x39:'A3',0x3A:'Bb3',0x3B:'B3', 35 | 0x3C:'C4',0x3D:'Db4',0x3E:'D4',0x3F:'Eb4', 36 | 0x40:'E4',0x41:'F4',0x42:'Gb4',0x43:'G4', 37 | 0x44:'Ab4',0x45:'A4',0x46:'Bb4',0x47:'B4', 38 | 0x48:'C5',0x49:'Db5',0x4A:'D5',0x4B:'Eb5', 39 | 0x4C:'E5',0x4D:'F5',0x4E:'Gb5',0x4F:'G5', 40 | 0x50:'Ab5',0x51:'A5',0x52:'Bb5',0x53:'B5', 41 | 0x54:'C6',0x55:'Db6',0x56:'D6',0x57:'Eb6', 42 | 0x58:'E6',0x59:'F6',0x5A:'Gb6',0x5B:'G6', 43 | 0x5C:'Ab6',0x5D:'A6',0x5E:'Bb6',0x5F:'B6', 44 | 0x60:'C7',0x61:'Db7',0x62:'D7',0x63:'Eb7', 45 | 0x64:'E7',0x65:'F7',0x66:'Gb7',0x67:'G7', 46 | 0x68:'Ab7',0x69:'A7',0x6A:'Bb7',0x6B:'B7', 47 | 0x6C:'C8',0x6D:'Db8',0x6E:'D8',0x6F:'Eb8', 48 | 0x70:'E8',0x71:'F8',0x72:'Gb8',0x73:'G8', 49 | 0x74:'Ab8',0x75:'A8',0x76:'Bb8',0x77:'B8', 50 | 0x78:'C9',0x79:'Db9',0x7A:'D9',0x7B:'Eb9', 51 | 0x7C:'E9',0x7D:'F9',0x7E:'Gb9',0x7F:'G9'} 52 | 53 | controllers = { 54 | 0x00:'Bank Select', 55 | 0x01:'Modulation', 56 | 0x02:'Breath Controller', 57 | 0x04:'Foot Controller', 58 | 0x05:'Portamento Time', 59 | 0x06:'Data Entry (MSB)', 60 | 0x07:'Main Volume', 61 | 0x08:'Balance', 62 | 0x0A:'Pan', 63 | 0x0B:'Expression Controller', 64 | 0x0C:'Effect Control 1', 65 | 0x0D:'Effect Control 2', 66 | 0x10:'General-Purpose Controller 1', 67 | 0x11:'General-Purpose Controller 2', 68 | 0x12:'General-Purpose Controller 3', 69 | 0x13:'General-Purpose Controller 4', 70 | 0x20:'LSB for controller 0', 71 | 0x21:'LSB for controller 1', 72 | 0x22:'LSB for controller 2', 73 | 0x23:'LSB for controller 3', 74 | 0x24:'LSB for controller 4', 75 | 0x25:'LSB for controller 5', 76 | 0x26:'LSB for controller 6', 77 | 0x27:'LSB for controller 7', 78 | 0x28:'LSB for controller 8', 79 | 0x29:'LSB for controller 9', 80 | 0x2A:'LSB for controller 10', 81 | 0x2B:'LSB for controller 11', 82 | 0x2C:'LSB for controller 12', 83 | 0x2D:'LSB for controller 13', 84 | 0x2E:'LSB for controller 14', 85 | 0x2F:'LSB for controller 15', 86 | 0x30:'LSB for controller 16', 87 | 0x31:'LSB for controller 17', 88 | 0x32:'LSB for controller 18', 89 | 0x33:'LSB for controller 19', 90 | 0x34:'LSB for controller 20', 91 | 0x35:'LSB for controller 21', 92 | 0x36:'LSB for controller 22', 93 | 0x37:'LSB for controller 23', 94 | 0x38:'LSB for controller 24', 95 | 0x39:'LSB for controller 25', 96 | 0x3A:'LSB for controller 26', 97 | 0x3B:'LSB for controller 27', 98 | 0x3C:'LSB for controller 28', 99 | 0x3D:'LSB for controller 29', 100 | 0x3E:'LSB for controller 30', 101 | 0x3F:'LSB for controller 31', 102 | 0x40:'Damper pedal', 103 | 0x41:'Portamento', 104 | 0x42:'Sostenuto', 105 | 0x43:'Soft Pedal', 106 | 0x44:'Legato Footswitch', 107 | 0x45:'Hold 2', 108 | 0x46:'Sound Controller 1', 109 | 0x47:'Sound Controller 2', 110 | 0x48:'Sound Controller 3', 111 | 0x49:'Sound Controller 4', 112 | 0x4A:'Sound Controller 5', 113 | 0x4B:'Sound Controller 6', 114 | 0x4C:'Sound Controller 7', 115 | 0x4D:'Sound Controller 8', 116 | 0x4E:'Sound Controller 9', 117 | 0x4F:'Sound Controller 10', 118 | 0x50:'General-Purpose Controller 5', 119 | 0x51:'General-Purpose Controller 6', 120 | 0x52:'General-Purpose Controller 7', 121 | 0x53:'General-Purpose Controller 8', 122 | 0x54:'Portamento Control', 123 | 0x5B:'Effects 1 Depth', 124 | 0x5C:'Effects 2 Depth', 125 | 0x5D:'Effects 3 Depth', 126 | 0x5E:'Effects 4 Depth', 127 | 0x5F:'Effects 5 Depth', 128 | 0x60:'Data Increment', 129 | 0x61:'Data Decrement', 130 | 0x62:'Non-Registered Parameter Number (LSB)', 131 | 0x63:'Non-Registered Parameter Number (MSB)', 132 | 0x64:'Registered Parameter Number (LSB)', 133 | 0x65:'Registered Parameter Number (MSB)', 134 | 0x79:'Reset All Controllers', 135 | 0x7A:'Local Control', 136 | 0x7B:'All Notes Off', 137 | 0x7C:'Omni Off', 138 | 0x7D:'Omni On', 139 | 0x7E:'Mono On (Poly Off)', 140 | 0x7F:'Poly On (Mono Off)' 141 | } 142 | -------------------------------------------------------------------------------- /colupatr/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2011 Valek Filippov (frob@df.ru) 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of version 3 or later of the GNU General Public 6 | # License as published by the Free Software Foundation. 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU Lesser General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 15 | # USA 16 | 17 | import struct 18 | import gtk, gobject 19 | 20 | def hex2d(data): 21 | res = '' 22 | data = data.replace(" ","") 23 | for i in range(len(data)/2): 24 | num = int(data[i*2:i*2+2],16) 25 | res += struct.pack("B",num) 26 | return res 27 | 28 | def d2hex(data,spc=""): 29 | s = "" 30 | for i in range(len(data)): 31 | s += "%02x%s"%(ord(data[i]),spc) 32 | return s 33 | 34 | def arg_conv (ctype,carg): 35 | data = '' 36 | if ctype.lower() == 'x': 37 | data = hex2d(carg) 38 | elif ctype.lower() == 'u': 39 | data = carg.encode("utf-16")[2:] 40 | elif ctype.lower() == 'a' or ctype.lower() == 'r': 41 | data = carg 42 | return data 43 | 44 | def find_line (doc,addr): 45 | if addr < doc.lines[len(doc.lines)-1][0]: 46 | lno = 0 47 | lnum = addr/16 48 | while lnum < len(doc.lines) and lno != lnum: 49 | lno = lnum 50 | if doc.lines[lnum][0] < addr: 51 | if doc.lines[lnum+1][0] > addr: 52 | break 53 | elif doc.lines[lnum+1][0] == addr: 54 | lnum += 1 55 | else: 56 | lnum += (addr - doc.lines[lnum+1][0])/16 57 | elif doc.lines[lnum][0] == addr: 58 | break 59 | else: 60 | lnum -= (doc.lines[lnum][0] - addr)/16 61 | if lnum < 0: 62 | break 63 | return lnum 64 | 65 | 66 | def cmd_parse(cmd, app,doc): 67 | if cmd[0] == "?": 68 | if len(cmd) > 1: 69 | ctype = cmd[1] 70 | carg = cmd[2:] 71 | # convert line to hex or unicode if required 72 | data = arg_conv(ctype,carg) 73 | elif doc.sel: 74 | r1,c1,r2,c2 = doc.sel 75 | data = doc.data[doc.lines[r1][0]+c1:doc.lines[r2][0]+c2] 76 | carg = "Selection" 77 | app.search = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING) 78 | sflag = 0 79 | p = doc.data.find(data) 80 | while p !=-1: 81 | s_iter = app.search.append(None,None) 82 | app.search.set_value(s_iter,2,"%02x"%p) 83 | p = doc.data.find(data,p+1) 84 | sflag = 1 85 | if sflag: 86 | app.show_search(carg) 87 | 88 | def html_export(app,doc,sline,doff,dlen): 89 | fname = app.file_open('Save',None,gtk.FILE_CHOOSER_ACTION_SAVE,doc.fname+".html") 90 | if fname: 91 | f = open(fname,'w') 92 | f.write("") 93 | f.write("\n\n") 94 | f.write("\n\n") 100 | f.write("\n"%doc.font) 101 | if app.options_htmlhdr: 102 | addrtxt = "" 103 | for i in range(doc.maxaddr): 104 | addrtxt += "%02x "%i 105 | f.write(""%addrtxt[:-1]) 106 | off = 0 107 | i = 0 108 | while off < dlen: 109 | so = doc.lines[sline+i][0] 110 | eo = doc.lines[sline+i+1][0] 111 | try: 112 | txt1 = doc.hvlines[sline+i][0] 113 | except: 114 | txt1 = doc.get_string(sline+i)[0] 115 | txt2 = doc.hvlines[sline+i][1] 116 | 117 | cmntest = doc.chk_comment(so,eo) 118 | cl = doc.lines[sline+i][1] 119 | if cl: 120 | f.write(""%cl) 121 | else: 122 | f.write("") 123 | txt3 = "" 124 | if len(cmntest) > 0: 125 | tmpoff = 0 126 | txthex = "" 127 | txtasc = "" 128 | txtcmnt = "" 129 | addr1 = 0 130 | addr2 = eo - so 131 | for cmnt in cmntest: 132 | clr = doc.comments[cmnt].clr 133 | cmntclr = "%d,%d,%d"%(clr[0]*255,clr[1]*255,clr[2]*255) 134 | 135 | if doff + off + tmpoff < doc.comments[cmnt].offset - 1: 136 | addr1 = doc.comments[cmnt].offset - doff - off - 1 137 | txthex += txt1[tmpoff*3:addr1*3] 138 | txtasc += txt2[tmpoff:addr1] 139 | 140 | if doc.comments[cmnt].length < eo - so - addr1: 141 | addr2 = addr1 + doc.comments[cmnt].length 142 | txthex += ""%cmntclr+txt1[addr1*3:addr2*3-1]+" " 143 | txtasc += ""%cmntclr+txt2[addr1:addr2]+"" 144 | tmpoff = addr2 145 | txtcmnt += ""%cmntclr+doc.comments[cmnt].text+" "+unicode("\xC2\xB7","utf8") + " " 146 | txthex += " " + txt1[addr2*3:] 147 | txtasc += txt2[addr2:] 148 | f.write(""%txthex) 149 | f.write(""%txtasc) 150 | f.write(""%txtcmnt[:-3]) 151 | else: 152 | f.write(""%(txt1,txt2)) 153 | f.write("\n") 154 | i += 1 155 | off += eo - so 156 | f.write("
%s
%s%s%s%s%s
") 157 | f.close() 158 | else: 159 | print("Nothing to export") 160 | 161 | -------------------------------------------------------------------------------- /oletoy/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *~ 3 | -------------------------------------------------------------------------------- /oletoy/AUTHORS: -------------------------------------------------------------------------------- 1 | Valek Filippov 2 | David Tardon 3 | Fridrich Strba 4 | -------------------------------------------------------------------------------- /oletoy/README: -------------------------------------------------------------------------------- 1 | OLE Toy is a set of Python scripts to parse and view contents of various 2 | binary file formats. Originally OLE Toy was developed for 3 | reverse-engineering of Microsoft Publisher file format, but later support 4 | for more of them was added, partially written from scratch, partially 5 | moved from our earlier work. 6 | 7 | As of now OLE Toy reads and parses: 8 | 9 | - PUB (Microsoft Publisher ver 98/2k and 2002 to 2010) 10 | - VSD, VSS (Microsoft Visio, ver 1-11) 11 | - DOC (Microsoft Word) 12 | - XLS (Microsoft Excel) 13 | - PPT (Microsoft PowerPoint) 14 | - MDB (Microsoft Access) 15 | - VBA (Microsoft Office) 16 | - RTF (Microsoft Office) 17 | - CLP (Microsoft clipboard) 18 | - FH (Macromedia Freehand ver.7 to 11) 19 | - QPW (QuattroPro spreadsheets) 20 | - SVM (StarOffice) 21 | - PPP (old PagePlus files, BIPU support) 22 | - CDR (CorelDRAW ver. 3 to 16) 23 | - WLD (CorelDRAW ver. 1 and 2) 24 | - CMX (CorelDRAW) 25 | - CPL (CorelDRAW palette) 26 | - CDW ("Kompas" unknown version, files were picked on Inet) 27 | - ABR/GRD (Adobe brushes and gradients) 28 | - ICC (colour profiles) 29 | - EMF, EMF+, WMF (Microsoft) 30 | - REX, RX2 (Propellerheads ReCycle) 31 | - XML 32 | - CDX (CambridgeSoft ChemDraw, BIPU support) 33 | - LRF (Sony BroadBand EBook, also known as BBeB) 34 | - PDB (various Palm-based e-book formats, currently eReader, Plucker, 35 | PalmDoc, TealDoc, zTXT, iSilo ver. 1 to 3 and TomeRaider3. iSilo 36 | and TomeRaider3 only shows basic structure, because the format is 37 | not known.) 38 | - WPD (Software602 602Text; this format has nothing in common with 39 | WordPerfect.) 40 | - IMP (SoftBook e-book) 41 | - ZMF (Zoner Callisto, also known as Zoner Draw) 42 | - ZBR (Zoner Zebra) 43 | - BMI (Zoner Bitmap) 44 | - IWA (Apple iWork '13. This format is used by Keynote 6, Pages 5 and 45 | Numbers 3, with a big chunk of the internals shared among all 46 | three applications. Support for Numbers is BIPU.) 47 | - WLS (Software602 602Tab, aka MagicTab) 48 | - TC6, GC6 (Software602 C602) 49 | - PLIST (Apple property list) 50 | - 602 (Software602 T602) 51 | 52 | Dependencies: 53 | - PyGTK (sudo apt-get install python-gtk2 for Ubuntu). 54 | - libgsf for OLE-based formats. You can find libgsf source code here: 55 | http://ftp.gnome.org/pub/GNOME/sources/libgsf/ 56 | (or sudo apt-get install libgsf-bin libgsf-1-dev for Ubuntu). 57 | 58 | To start OLE Toy just run: 59 | 60 | $ ./view.py 61 | 62 | All commercial software mentioned in this file and elsewhere in source code are 63 | trademarks of respective vendors. Re-lab team is not affiliated to those vendors 64 | in any way. All work on support for those file formats is a result of 65 | clean-room reverse-engineering. No DLL and EXE files have been looked at. 66 | -------------------------------------------------------------------------------- /oletoy/abr.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct,gtk 18 | from utils import * 19 | 20 | def p_patt(page,buf,offset,name,parent): 21 | # didn't rev.engineered yet 22 | return offset 23 | 24 | def p_desc(page,buf,offset,name,parent): 25 | # convert 4 bytes as big-endian unsigned long 26 | [size] = struct.unpack('>L',buf[offset:offset+4]) 27 | return offset+26 28 | 29 | def p_long(page,buf,offset,name,parent): 30 | [size] = struct.unpack('>L',buf[offset:offset+4]) 31 | add_pgiter(page,"%s (long) %d [0x%x]"%(name,size,offset-4),"abr","objc",buf[offset-4:offset+4],parent) 32 | return offset+4 33 | 34 | def p_vlls(page,buf,offset,name,parent): 35 | [size] = struct.unpack('>L',buf[offset:offset+4]) 36 | offset+=4 37 | o_iter = add_pgiter(page,"%s (VlLs) %d [0x%x]"%(name,size,offset-8),"abr","objc",buf[offset-8:offset],parent) 38 | for i in range(size): 39 | type = buf[offset:offset+4] 40 | offset+=4 41 | if type in types: 42 | offset = types[type](page,buf,offset,type,o_iter) 43 | else: 44 | p_unkn(buf,offset,"",o_iter) 45 | return offset 46 | 47 | def p_objc(page,buf,offset,name,parent): 48 | off = offset 49 | [objnamelen] = struct.unpack('>L',buf[offset:offset+4]) 50 | offset+=4 51 | objname = buf[offset:offset+objnamelen*2] 52 | if len(objname): 53 | objname = " " 54 | offset+= objnamelen*2 55 | [objtypelen] = struct.unpack('>L',buf[offset:offset+4]) 56 | if objtypelen == 0: 57 | objtypelen = 4 58 | offset+=4 59 | typename = buf[offset:offset+objtypelen] 60 | offset+=objtypelen 61 | [value] = struct.unpack('>L',buf[offset:offset+4]) 62 | offset+=4 63 | txt = "%s (Objc) %s %s %.2f [0x%x]"%(name,objname,typename,value,off-4) 64 | 65 | o_iter = add_pgiter(page,txt,"abr","objc",buf[off-4:offset],parent) 66 | 67 | for i in range(value): 68 | offset = parse_entry(page,buf,offset,o_iter) 69 | return offset 70 | 71 | def p_text(page,buf,offset,name,parent): 72 | [size] = struct.unpack('>L',buf[offset:offset+4]) 73 | string = "" 74 | for i in range(size-1): 75 | string = string + str(buf[offset+4+i*2+1:offset+4+i*2+2]) 76 | add_pgiter(page,"%s (TEXT %d) %s [0x%x]"%(name,size,string,offset-4),"abr","text",buf[offset-4:offset+4+size*2],parent) 77 | return offset+4+size*2 78 | 79 | def p_untf(page,buf,offset,name,parent): 80 | type = buf[offset:offset+4] 81 | [value] = struct.unpack('>d', buf[offset+4:offset+4+8]) 82 | add_pgiter(page,"%s (UntF) %.2f [0x%x]"%(name,value,offset-4),"abr","untf",buf[offset-4:offset+12],parent) 83 | return offset+12 84 | 85 | def p_bool(page,buf,offset,name,parent): 86 | # ord converts 1 byte number 87 | add_pgiter(page,"%s (bool) %d [0x%x]"%(name,ord(buf[offset:offset+1]),offset-4),"abr","bool",buf[offset-4:offset+1],parent) 88 | return offset+1 89 | 90 | def p_doub(page,buf,offset,name,parent): 91 | # unpack 8 bytes ieee 754 value to floating point number 92 | [value] = struct.unpack('>d', buf[offset:offset+8]) 93 | add_pgiter(page,"%s (doub) %.2f [0x%x]"%(name,value,offset-4),"abr","doub",buf[offset-4:offset+8],parent) 94 | return offset+8 95 | 96 | def p_enum(page,buf,offset,name,parent): 97 | off = offset 98 | [size1] = struct.unpack('>L', buf[offset:offset+4]) 99 | offset+=4 100 | if size1 == 0: 101 | size1 = 4 102 | name1 = buf[offset:offset+size1] 103 | offset+=size1 104 | [size2] = struct.unpack('>L', buf[offset:offset+4]) 105 | if size2 == 0: 106 | size2 = 4 107 | offset+=4 108 | name2 = buf[offset:offset+size2] 109 | offset+=size2 110 | add_pgiter(page,"%s (enum) %s %s [0x%x]"%(name,name1,name2,off-4),"abr","enum",buf[off-4:off+8+size1+size2],parent) 111 | return offset 112 | 113 | def p_unkn(page,buf,offset,name,parent): 114 | # assume 4 bytes value 115 | # in such case offset+4:offset+8 is next length 116 | # and offset+8:offset+12 is next enum 117 | # check for it 118 | name = buf[offset+8:offset+12] 119 | if name in types: 120 | # everything is fine 121 | [size] = struct.unpack('>L',buf[offset:offset+4]) 122 | return size,offset+4 123 | else: 124 | # print "Failed with simple case\n" 125 | str_hex="" 126 | str_asc="" 127 | ml = 15 128 | for i in range(ml): 129 | try: 130 | str_hex+="%02x " % ord(buf[offset+i]) 131 | if ord(buf[offset+i]) < 32 or 126L',buf[offset:offset+4]) 146 | if nlen == 0: 147 | nlen = 4 148 | offset = offset + 4 149 | name = buf[offset:offset+nlen] 150 | offset = offset + nlen 151 | type = buf[offset:offset+4] 152 | offset+=4 153 | if type in types: 154 | offset = types[type](page,buf,offset,name,parent) 155 | else: 156 | print("Unknown key:\t",name,type) 157 | p_unkn(page,buf,offset,name,parent) 158 | return offset 159 | 160 | bim_types = {"desc":p_desc 161 | } 162 | 163 | def unpack_samp (data,page,siter): 164 | top = struct.unpack(">I",data[0x131:0x135])[0] 165 | left = struct.unpack(">I",data[0x135:0x139])[0] 166 | bottom = struct.unpack(">I",data[0x139:0x13d])[0] 167 | right = struct.unpack(">I",data[0x13d:0x141])[0] 168 | depth = struct.unpack(">H",data[0x141:0x143])[0] 169 | cmpr = ord(data[143]) 170 | off = 0x144+(bottom-top)*2 171 | buf = "" 172 | if cmpr: 173 | for i in range(bottom-top): 174 | size = struct.unpack(">H",data[0x144+i*2:0x146+i*2])[0] 175 | j = 0 176 | while j < size: 177 | flag = ord(data[off]) 178 | off += 1 179 | if flag > 128: 180 | dlen = 257 - flag 181 | buf += data[off]*dlen 182 | off += 1 183 | j += 2 184 | else: 185 | dlen = flag + 1 186 | buf += data[off:off+dlen] 187 | off += dlen 188 | j += dlen + 1 189 | else: 190 | buf = data[0x144:] 191 | add_pgiter(page,"Uncmpr","abr","uncsamp",buf,siter) 192 | 193 | def read_8bim(buf,page,parent,off): 194 | tag = buf[off:off+4] 195 | if tag != "8BIM": 196 | print("Something wrong with 8BIM offsets") 197 | return len(buf) 198 | else: 199 | off += 4 200 | btype = buf[off:off+4] 201 | off += 4 202 | blen = struct.unpack(">I",buf[off:off+4])[0] 203 | off += 4 204 | adj = blen % 4 205 | if adj != 0: 206 | blen += 4 - adj 207 | piter = add_pgiter(page,btype,"abr",btype,buf[off-12:off+blen],parent) 208 | if btype == "desc": 209 | buf2 = buf[off-12:off+blen] 210 | add_pgiter(page,"Hdr","abr","hdr",buf2[0:0x22],piter) 211 | off2 = 0x22 212 | while off2 < len(buf2): 213 | off2 = parse_entry(page,buf2,off2,piter) 214 | elif btype == "samp": 215 | off2 = off 216 | while off2 < blen: 217 | slen = struct.unpack(">I",buf[off2:off2+4])[0] 218 | adj = slen % 4 219 | if adj != 0: 220 | slen += 4 - adj 221 | siter = add_pgiter(page,"Sample [%s]"%buf[off2+4:off2+4+37],"abr","samp",buf[off2:off2+slen+4],piter) 222 | # try: 223 | unpack_samp (buf[off2:off2+slen+4],page,siter) 224 | # except: 225 | # print 'unpack failed' 226 | off2 += slen+4 227 | 228 | off += blen 229 | return off 230 | 231 | 232 | 233 | def abr_open (buf,page,parent,ftype): 234 | f_iter = add_pgiter(page,"File","","",buf,parent) 235 | off = 0 236 | if ftype == "bgr": 237 | add_pgiter(page,"Hdr",ftype,"hdr",buf[0:28],f_iter) 238 | off = 28 239 | while off < len(buf): 240 | off = parse_entry(page,buf,off,f_iter) 241 | else: 242 | vmaj = struct.unpack(">H",buf[0:2])[0] 243 | vmin = struct.unpack(">H",buf[2:4])[0] 244 | add_pgiter(page,"Version %d.%d [0x%x]"%(vmaj,vmin,off),ftype,"vrsn",buf[0:4],f_iter) 245 | off += 4 246 | while off < len(buf): 247 | off = read_8bim(buf,page,f_iter,off) 248 | 249 | 250 | 251 | -------------------------------------------------------------------------------- /oletoy/bmi.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016 David Tardon (dtardon@redhat.com) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import zlib 18 | 19 | from utils import add_iter, add_pgiter, rdata, d2hex, key2txt 20 | 21 | stream_tags = { 22 | 0x1: 'Bitmap', 23 | 0x3: 'Comment', 24 | 0xff: 'EOF', 25 | } 26 | 27 | # defined later 28 | stream_parsers = {} 29 | 30 | def add_data(hd, size, data, width, height, depth): 31 | assert depth in (1, 4, 8, 24) 32 | bits = (width * depth) 33 | lsize = bits / 8 34 | if bits % 8 != 0: 35 | lsize += 1 36 | tail = lsize % 4 37 | padding = 0 38 | if tail != 0: 39 | padding = 4 - tail 40 | lsize += padding 41 | shift = (8 - min(depth, 8)) 42 | mask = (0xff >> shift) << shift 43 | off = 0 44 | for h in range(1, height + 1): 45 | lineiter = add_iter(hd, 'Line %d' % h, '', off, lsize, '%ds' % lsize) 46 | i = 1 47 | while i < width + 1: 48 | if depth == 24: 49 | (color, off) = rdata(data, off, '3s') 50 | add_iter(hd, 'Pixel %d (BGR)' % i, d2hex(color), off - 3, 3, '3s', parent=lineiter) 51 | i += 1 52 | else: 53 | (index, off) = rdata(data, off, '> shift, off - 1, 1, ' 0: 61 | add_iter(hd, 'Padding', '', off, padding, '%ds' % padding, parent=lineiter) 62 | off += padding 63 | 64 | class bmi_parser: 65 | def __init__(self, data, page=None, parent=None): 66 | self.page = page 67 | self.data = data 68 | self.parent = parent 69 | self.streams = [] 70 | self.eof = None 71 | 72 | def size(self): 73 | if self.eof: 74 | return self.eof 75 | else: 76 | return len(self.data) 77 | 78 | def parse(self): 79 | assert self.page 80 | (off, palette, depth, toc_count) = self.parse_header(0) 81 | if palette: 82 | off = self.parse_palette(off, depth, self.parent) 83 | off = self.parse_toc(off, toc_count) 84 | self.parse_streams() 85 | 86 | def parse_size(self): 87 | (off, palette, depth, toc_count) = self.parse_header(0) 88 | if palette: 89 | off = self.parse_palette(off, depth) 90 | self.parse_toc(off, toc_count) 91 | 92 | def parse_header(self, offset): 93 | if self.page: 94 | add_pgiter(self.page, 'Header', 'bmi', 'header', self.data[offset:offset + 0x15], self.parent) 95 | (palette, off) = rdata(self.data, offset + 0xd, ' 6: 32 | shift = 1 33 | off = 0xf 34 | chtype = data[off+4:off+6] 35 | try: 36 | while chtype != "\x00\x00": 37 | off_st = off 38 | bflag = ord(data[off+0xb]) 39 | tflag = ord(data[off+0xd+shift]) 40 | if tflag == 1: 41 | tlen = struct.unpack(" 0x2f and n0 < 0x39) or (n0 > 0x60 and n0 < 0x7f) and (n1 > 0x2f and n1 < 0x39) or (n1 > 0x60 and n1 < 0x7f) and (n2 > 0x2f and n2 < 0x39) or (n2 > 0x60 and n2 < 0x7f) and (n3 > 0x2f and n3 < 0x39) or (n3 > 0x60 and n3 < 0x7f): 36 | ch_name = name_cnvrt(name) 37 | offset += 4 38 | ch_data = buf[offset-8:offset+ch_len] 39 | 40 | name = ch_name+" (%02x)"%ch_len 41 | add_pgiter (page, name, "CPT", "BlkChnk%s"%ch_name, ch_data, p_iter,"[%04x]"%(offset+adj)) 42 | offset += ch_len 43 | 44 | else: 45 | # Hack! Probably it should check against list of chunk names or some flags 46 | # or use this procedure after some specific chunks (+ flags) 47 | # currently after 'path' (sometimes with 1 or two additional chunks between 48 | # 'path' and start of this garbage 49 | offset += 4 50 | offset2 = ch_len 51 | ch_set_off = {} 52 | ch_set_len = {} 53 | ch_set_off[0] = ch_len 54 | ch_set_len[0] = struct.unpack('",pos1) 29 | tag = buf[pos1+7:pos2-1] 30 | pos3 = buf.find(""%tag,off) 31 | if pos3 < pos4: 32 | piter = citer 33 | off = pos3+10+len(tag) 34 | add_pgiter(page,tag,"cvx",tag,buf[pos1+12+len(tag):pos3],piter) 35 | else: 36 | pos4 = pos3 37 | off = pos2 38 | pos2 = pos3 39 | piter = parent 40 | citer = add_pgiter(page,tag,"cvx",tag,buf[pos1+12+len(tag):pos3],piter) 41 | print(tag,pos1,pos2,pos3) 42 | else: 43 | off = len(buf) 44 | -------------------------------------------------------------------------------- /oletoy/drw.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010-2014 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import struct 18 | from utils import * 19 | 20 | rectypes = {1:"Background",2:"FaceName",3:"Version",4:"ID",\ 21 | 5:"Overlay",6:"Polygon",7:"Symbol",8:"Text",9:"Color",\ 22 | 10:"ColorFlag",11:"Preview (DIB)",14:"View",15:"OldGrid",16:"CurrOverlay",\ 23 | 17:"Visible",18:"Comment",19:"Info",20:"Bitmap",21:"Font",\ 24 | 22:"Grid",23:"OverlayName",24:"Dimensions",25:"Resolution",\ 25 | 26:"Ruler",27:"Page",28:"Pattern",29:"Locked",30:"Gradient",\ 26 | 31:"TextHdr",32:"Band",33:"SymbolVersion",34:"TextPara",\ 27 | 35:"ColorTable",36:"TextExtra",37:"MaxLinkID",\ 28 | 44:"ChartSkipSymbols", 29 | 51:"Multichunk OBJ",52:"DataChunk",56:"Layer", 30 | 60:"Group", 31 | 254:"EOF",255:"RecordVersion"} 32 | 33 | 34 | shapetypes = { 35 | 0:'0 (Elliptic Arc)', 36 | 1:'1 (Polygon)', 37 | 2:'2 (Group)', 38 | 3:'3 (Ellipse)', 39 | 5:'5 (Scale line)', 40 | 6:'6 (Line)', 41 | 8:'8 (Polyline)', 42 | 9:'9 (Pie)', 43 | 10:'10 (Rectangle)', 44 | 11:'11 (RoundRect)', 45 | 13:'13 (Ellipse)', 46 | 14:'14 (Arc)', 47 | 15:'15 (Parabolic Line)', 48 | 16:'16 (Quadratic Curve)', 49 | 17:'17 (Connect)', 50 | 18:'18 (Parabolic Line)', 51 | 19:'19 (Quadratic Spline)', 52 | 20:'20 (Polygon)', 53 | 22:'22 (Bitmap ?)', 54 | 23:'23 (Freeline)', 55 | 24:'24 (Bezier)', 56 | 25:'25 (Rich Text Block)', 57 | 26:'26 (Virtual Bitmap)', 58 | 27:'27 (Clip Path)', 59 | 28:'28 (Tiled Clip Path)', 60 | 29:'29 (Text on Curve?)',} 61 | 62 | def sym5_connect(): 63 | # 0x2b -- num of connected symbols 64 | pass 65 | 66 | def symbolversion(page,rdata): 67 | page.version = struct.unpack(' 96 and rtype < 160): 118 | rdata = buf[offset:offset+rlength] 119 | else: 120 | while len(rdata) < rlength: 121 | tv = buf[offset] 122 | offset+=1 123 | if ord(tv) == 0xff: 124 | vlen = ord(buf[offset]) 125 | offset += 1 126 | vval = buf[offset] 127 | offset += 1 128 | for i in range(vlen): 129 | rdata = rdata + vval 130 | else: 131 | rdata = rdata + tv 132 | rname = rtype 133 | if rtype in rectypes: 134 | rname = rectypes[rtype] 135 | else: 136 | print("DRW: unknown record type",rtype) 137 | if rtype == 4: # ID 138 | rname += " [%s]"%rdata[:0x10] 139 | if rtype == 7: # Symbol 140 | stype = ord(rdata[0]) 141 | sname = " (%02x)"%stype 142 | if stype in shapetypes.keys(): 143 | sname = " " +shapetypes[stype] 144 | rname += sname 145 | riter = add_pgiter(page, rname, "drw",rtype,rdata,parent) 146 | if rtype == 33: 147 | symbolversion(page,rdata) 148 | 149 | 150 | -------------------------------------------------------------------------------- /oletoy/dsf.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010-2014 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import struct,zlib 18 | from utils import * 19 | 20 | def parse_dsf_toc(page, data, toc, dsfditer): 21 | off = 0 22 | old_chid = 0 23 | while off < len(data): 24 | chtype = ord(data[off]) 25 | chid = ord(data[off+1]) 26 | shift = 2 27 | if chid == 0x80: 28 | chid = ord(data[off+2]) 29 | shift = 3 30 | chlen = struct.unpack(" 0: 73 | name = buf[off+13:off+13+namelen] 74 | piter = add_pgiter(page,"%s"%name,"fbx","record",buf[off:off+13+namelen+proplen],parent) 75 | if propnum == 0: 76 | iters.append(piter) 77 | parent = piter 78 | elif propnum < 1000: #FIXME! Takes to long to parse everything 79 | parse_props(page,buf,off+13+namelen,propnum,piter) 80 | 81 | else: 82 | try: 83 | iters.pop() 84 | parent = iters[-1] 85 | except: 86 | parent = p2 87 | off+=13+namelen+proplen 88 | 89 | 90 | def open (buf,page,parent,off=0): 91 | add_pgiter(page,"FBX Header","fbx","header",buf[0:23],parent) 92 | off += 23 93 | ver = struct.unpack("L', buf[offset+8:offset+12])[0] 12 | offset = offset + size 13 | dictoffset = offset 14 | 15 | dictsize = struct.unpack('>h', buf[offset:offset+2])[0] 16 | offset+=4 17 | rkey = -1 18 | for i in range(dictsize): 19 | key = struct.unpack('>h', buf[offset:offset+2])[0] 20 | k = 0 21 | while ord(buf[offset+k+2]) != 0: 22 | k+=1 23 | value = buf[offset+2:offset+k+2] 24 | if value == rname: 25 | rkey = key 26 | offset = offset+k+3 27 | 28 | size = struct.unpack('>L', buf[offset:offset+4])[0] 29 | offset+= 4 30 | agdoffset = 0 31 | length = 0 32 | 33 | for i in range(size): 34 | key = struct.unpack('>h', buf[offset:offset+2])[0] 35 | offset+= 2 36 | if key == rkey: 37 | return 1 38 | return 0 39 | 40 | def main(): 41 | if len(sys.argv) >= 3: 42 | filename = sys.argv[2] 43 | rname = sys.argv[1] 44 | 45 | try: 46 | input = open(filename) 47 | buf = input.read() 48 | if parse(buf,rname): 49 | print(filename) 50 | except: 51 | print("No file") 52 | return 0 53 | else: 54 | print("Use filename as an option") 55 | return 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /oletoy/fhrec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys,struct,zlib 4 | import fh 5 | 6 | ver = {0x31:5,0x32:7,0x33:8,0x34:9,0x35:10,0x36:11,'mcl':-1} 7 | 8 | def d2hex(data,space="",ln=0): 9 | s = "" 10 | for i in range(len(data)): 11 | s += "%02x%s"%(ord(data[i]),space) 12 | if ln != 0 and (i % ln) == 0: 13 | s += "\n" 14 | 15 | return s 16 | 17 | 18 | def parse_agd (FHDoc,rname,dumpsize): 19 | offset = 0 20 | j = 0 21 | for i in FHDoc.reclist: 22 | j += 1 23 | if FHDoc.dictitems[i] in FHDoc.chunks: 24 | try: 25 | res = FHDoc.chunks[FHDoc.dictitems[i]](offset,j) 26 | if -1 < res <= len(FHDoc.data)-offset: 27 | if rname == "*" or FHDoc.dictitems[i] == rname: 28 | print("%-16s [%4x] "%(FHDoc.dictitems[i],res),"%02x\t"%j,d2hex(FHDoc.data[offset:offset+dumpsize]," ")) 29 | offset += res 30 | else: 31 | print("Failed on record %d (%s)"%(j,FHDoc.dictitems[i]),res) 32 | print("Next is",FHDoc.dictitems[FHDoc.reclist[j+1]]) 33 | return 34 | except: 35 | print("Failed on record %d (%s)"%(j,FHDoc.dictitems[i])) 36 | print("Next is",FHDoc.dictitems[FHDoc.reclist[j+1]]) 37 | return 38 | 39 | else: 40 | print("Unknown record type: %s (%02x)"%(FHDoc.dictitems[i],j)) 41 | return 42 | print("FH Tail!") 43 | 44 | def parse_dict (FHDoc,data,offset): 45 | if FHDoc.version > 8: 46 | dictsize = struct.unpack('>h', data[offset:offset+2])[0] 47 | print('Dict size:\t%u'%dictsize) 48 | offset+=4 49 | for i in range(dictsize): 50 | key = struct.unpack('>h', data[offset:offset+2])[0] 51 | k = 0 52 | while ord(data[offset+k+2]) != 0: 53 | k+=1 54 | value = data[offset+2:offset+k+2] 55 | offset = offset+k+3 56 | FHDoc.dictitems[key] = value 57 | return offset 58 | 59 | def parse(buf,rname,dumpsize=8): 60 | offset = buf.find('AGD') 61 | version = ver[ord(buf[offset+3])] 62 | size = struct.unpack('>L', buf[offset+8:offset+12])[0] 63 | if version > 8: 64 | output = zlib.decompress(buf[offset+14:offset+14+size],-15) 65 | else: 66 | output = buf[offset+12:offset+size] 67 | doc = fh.FHDoc(output,None,None) 68 | doc.version = version 69 | offset = offset + size 70 | offset = parse_dict(doc,buf,offset) 71 | doc.parse_list(buf,offset) 72 | parse_agd(doc,rname,dumpsize) 73 | 74 | 75 | def main(): 76 | if len(sys.argv) >= 3: 77 | filename = sys.argv[2] 78 | rname = sys.argv[1] 79 | print(filename) 80 | try: 81 | input = open(filename) 82 | buf = input.read() 83 | if parse(buf,rname): 84 | print(filename) 85 | except: 86 | print("No file") 87 | return 0 88 | else: 89 | print("Use filename as an option") 90 | return 91 | 92 | if __name__ == '__main__': 93 | main() 94 | -------------------------------------------------------------------------------- /oletoy/hexdump.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import gtk 18 | import tree 19 | import hv2 20 | import utils 21 | 22 | class hexdump: 23 | def __init__(self): 24 | self.vpaned = gtk.VPaned() 25 | self.model, self.hdview, self.hdscrolled, self.hdrend = tree.make_view2() 26 | self.hbox0 =gtk.HBox() 27 | self.da = None 28 | self.hbox0.pack_start(self.hdscrolled) 29 | self.vpaned.add1(self.hbox0) 30 | self.hdscrolled.set_size_request(300, 300) 31 | self.version = None # to support vsdchunks for different versions 32 | self.context = None 33 | self.width = 0 34 | self.height = 0 35 | self.dispscale = 1. 36 | 37 | self.hv = hv2.HexView() 38 | self.vpaned.add2(self.hv.table) 39 | 40 | def update(): 41 | pass 42 | 43 | def disp_expose(self,da,event): 44 | utils.disp_expose(da,event,self,self.dispscale) 45 | 46 | def disp_on_button_press(self,da,event): 47 | if event.type == gtk.gdk.BUTTON_PRESS: 48 | if event.button == 1: 49 | self.dispscale *= 1.4 50 | self.disp_expose(da,event) 51 | if event.button == 2: 52 | self.dispscale = 1 53 | self.da.hide() 54 | self.da.show() 55 | if event.button == 3: 56 | self.dispscale *= .7 57 | self.da.hide() 58 | self.da.show() 59 | -------------------------------------------------------------------------------- /oletoy/icc.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010-2012 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct 18 | import gtk 19 | from utils import * 20 | 21 | def header (hd,size,data): 22 | pass 23 | 24 | def element (hd,size,data): 25 | pass 26 | 27 | def parse (page, data, parent): 28 | off = 0 29 | add_pgiter(page,"Header","icc","hdr",data[0:0x80],parent) 30 | off = 0x80 31 | num = struct.unpack(">I",data[off:off+4])[0] 32 | ttiter = add_pgiter(page,"Tag Table","icc","tagtable",data[off:off+4],parent) 33 | off += 4 34 | eliter = add_pgiter(page,"Elements","icc","elems",data[off+num*12:],parent) 35 | 36 | for i in range(num): 37 | toff = struct.unpack(">I",data[off+4:off+8])[0] 38 | tlen = struct.unpack(">I",data[off+8:off+12])[0] 39 | add_pgiter(page,"%s [%02x %02x]"%(data[off:off+4],toff,tlen),"icc","tag",data[off:off+12],ttiter) 40 | off += 12 41 | add_pgiter(page,data[off:off+4],"icc","elem",data[toff:toff+tlen],eliter) 42 | -------------------------------------------------------------------------------- /oletoy/inflate.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import struct 18 | 19 | def inflate_vba_stream (data): 20 | i = 0 21 | pos = 0 22 | buf = "" 23 | res = "" 24 | while i < len(data): 25 | flag = ord(data[i]) 26 | i += 1 27 | for mask in (1,2,4,8,16,32,64,128): 28 | try: 29 | if flag&mask: 30 | addr = struct.unpack("> shift 59 | clean = True 60 | for j in range(blen): 61 | srcpos = (pos - distance - 1) % 4096 62 | c = buf[srcpos] 63 | buf = buf[:pos % 4096] + c + buf[pos % 4096 + 1:] 64 | pos +=1 65 | else: 66 | if pos != 0 and pos % 4096 == 0 and clean: 67 | i += 2 # why? (check gsf_msole_inflate) 68 | clean = False 69 | res += buf 70 | break 71 | if i < len(data): 72 | c = data[i] 73 | buf = buf[:pos % 4096] + c + buf[pos % 4096 + 1:] 74 | pos += 1 75 | i += 1 76 | clean = True 77 | except: 78 | # FIXME! Better handling of LZ stream ends? 79 | print("Not enough bytes to decompress. Flag/Mask were %02x/%02x"%(flag,mask)) 80 | i += 1 81 | break 82 | if pos % 4096: 83 | res += buf 84 | return res 85 | 86 | def inflate_vba_oletoy (data,ptype): 87 | if ord(data[0]) != 1: 88 | print("Attempt to inflate wrong stream") 89 | return "" 90 | 91 | off = 1 92 | res = "" 93 | while off < len(data): 94 | flags = struct.unpack(" 0 and ((ptype[:3] != "XLS" and len(data)-off < 4096) or ptype[:3] == "XLS"): 102 | res += inflate_vba_stream(data[off+2:off+2+clen+1]) 103 | off += clen+3 104 | else: 105 | res += inflate_vba_stream(data[off+2:off+4096]) 106 | off += 4096 107 | return res 108 | 109 | def inflate_vba_gsf (data,ptype): 110 | import ctypes as C 111 | cgsf = C.cdll.LoadLibrary('libgsf-1.so') 112 | cgsf.gsf_init() 113 | cgsf.gsf_input_memory_new.restype = C.c_void_p 114 | src = cgsf.gsf_input_memory_new (data,len(data),False) 115 | size = C.create_string_buffer(4) 116 | cgsf.gsf_vba_inflate.argtypes = [C.c_void_p,C.c_double,C.c_void_p,C.c_int] 117 | res = C.string_at(cgsf.gsf_vba_inflate(src,C.c_double(0),size,C.c_int(0)),struct.unpack(" ptr.length - 2: 148 | break 149 | addr1 = ord(vsd[offset]) 150 | offset=offset+1 151 | addr2 = ord(vsd[offset]) 152 | offset=offset+1 153 | dlen = (addr2&15) + 3 154 | point = (addr2&240)*16+addr1 155 | i = i + 2 156 | if point > 4078: 157 | point = point - 4078 158 | else: 159 | point = point + 18 160 | for j in range (dlen): 161 | buff[(pos+j)&4095]=buff[(point+j)&4095] 162 | res = res + buff[(point+j)&4095] 163 | pos = pos + dlen 164 | except: 165 | print('Inflate failed',i,ptr.length) 166 | return res 167 | return res 168 | 169 | # vsd deflate 170 | def deflate_piastre (buf, flavour=0): 171 | # 'compression' function which increase size of the result by 12.5% 172 | if flavour == 0: 173 | token = '\xFF' 174 | else: 175 | token = '\x00' 176 | i = 0 177 | res = '' 178 | while i< len(buf): 179 | res += token+buf[i:i+8] 180 | i +=8 181 | n = len(buf)-(len(buf)/8)*8 182 | res += '\x00'*n 183 | return res 184 | 185 | def deflate (buf, flavour): 186 | # wrapper to avoid later renaming if I implement something better then 'piastre' ;-) 187 | return deflate_piastre (buf, flavour) 188 | -------------------------------------------------------------------------------- /oletoy/lit.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or 2 | # modify it under the terms of version 3 or later of the GNU General Public 3 | # License as published by the Free Software Foundation. 4 | # This program is distributed in the hope that it will be useful, 5 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 6 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7 | # GNU General Public License for more details. 8 | # 9 | # You should have received a copy of the GNU Lesser General Public License 10 | # along with this program; if not, write to the Free Software 11 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 12 | # USA 13 | 14 | # Started from partial spec here: 15 | # http://www.russotto.net/chm/itolitlsformat.html 16 | 17 | import struct 18 | from utils import * 19 | 20 | def open (buf,page,parent,off=0): 21 | add_pgiter(page,"LIT Header","lit","header",buf[off:off+0x28],parent) 22 | off += 0x10 23 | cnt = struct.unpack(" maxoff: 35 | maxoff = entoff+entlen 36 | add_pgiter(page,"Section #%d"%i,"lit","sect%d"%i,buf[entoff:entoff+entlen],parent) 37 | 38 | add_pgiter(page,"Tail","lit","tail",buf[maxoff:],parent) 39 | 40 | -------------------------------------------------------------------------------- /oletoy/mdb.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct,gtk 18 | from utils import * 19 | 20 | 21 | def hd_data_hdr(hd,buf): 22 | offset = 0 23 | free_space = struct.unpack("0x1000 recoff 182 | 183 | def table (buf,page,offset,parent): 184 | pass 185 | 186 | def int_idx (buf,page,offset,parent): 187 | pass 188 | 189 | def leaf_idx (buf,page,offset,parent): 190 | pass 191 | 192 | def usage_bmp (buf,page,offset,parent): 193 | pass 194 | 195 | 196 | block_types = {0x100:('DB',db),0x101:('Data',data),0x102:('Table',table),0x103:('IntMed IDX',int_idx), 197 | 0x104:('Leaf IDX',leaf_idx),0x105:('Pg Usage Bitmaps',usage_bmp)} 198 | 199 | def parse (buf,page,parent): 200 | offset = 0 201 | i = 0 202 | while offset < len(buf): 203 | iter1 = page.model.append(parent,None) 204 | page.model.set_value(iter1,0,"Block %02x"%i) 205 | page.model.set_value(iter1,1,("mdb",0)) 206 | page.model.set_value(iter1,2,0x1000) 207 | page.model.set_value(iter1,3,buf[offset:offset+0x1000]) 208 | bt = struct.unpack("80: 89 | file.write("%s%s%s\n"%(prefix,"" if i==0 else "[_%d]"%i,text)) 90 | i+=1 91 | text="" 92 | if len(text): 93 | file.write("%s%s%s\n"%(prefix,"" if i==0 else "[_%d]"%i,text)) 94 | 95 | def dump_rec(self,doc,model,iter,level,file): 96 | prefix=' '*level 97 | suffix="" 98 | if model.get_value(iter,2)>2000: 99 | suffix=binascii.hexlify(model.get_value(iter,3)[0:2000]) 100 | suffix+="...[+%dbytes]"%(model.get_value(iter,2)-2000) 101 | elif model.get_value(iter,3): 102 | suffix=binascii.hexlify(model.get_value(iter,3)) 103 | type=model.get_value(iter,1)[1] 104 | if self.m_showData: 105 | for i in range((len(suffix)+199)//200): 106 | file.write("%s%s:%s%s\n"%(prefix,type,"" if i==0 else "[_x%d]"%i,suffix[i*200:(i+1)*200])) 107 | if model.get_value(iter,2): 108 | try: 109 | self.dump_rec_content(doc,model,iter,level,file) 110 | except: 111 | pass 112 | elif not self.m_showData: 113 | file.write("%s%s\n"%(prefix,type)) 114 | for i in range(model.iter_n_children(iter)): 115 | self.dump_rec(doc,model,model.iter_nth_child(iter,i),level+1,file) 116 | 117 | def dump(self,doc,model,file): 118 | iter = model.get_iter_first() 119 | if iter == None: 120 | print ("can not find any iter") 121 | return 122 | while iter != None: 123 | self.dump_rec(doc,model,iter,1,file) 124 | iter = model.iter_next(iter) 125 | 126 | def main(): 127 | parser = argparse.ArgumentParser() 128 | parser.add_argument('--hidehexa', action='store_true') 129 | parser.add_argument('infile') 130 | parser.add_argument('outfile') 131 | args = parser.parse_args() 132 | try: 133 | fs=open(args.infile,"rb") 134 | except: 135 | print ("can not open %s"%args.infile) 136 | return 137 | buf = fs.read() 138 | if buf: 139 | myAppl=MiniAppl() 140 | doc=App.Page(myAppl) 141 | doc.fname=args.infile 142 | if doc.fload(buf)==0: 143 | if doc.type=="FH": 144 | # fh.py use idle function, so we must called them by hand 145 | try: 146 | doc.appdoc.parse_agd_iter(10000).next() 147 | except: 148 | print ("incomplete parsing") 149 | model=doc.view.get_model() 150 | try: 151 | output=open(args.outfile,"w") 152 | except: 153 | print ("can not open output %s"%args.outfile) 154 | return 155 | dumper=OleDump() 156 | dumper.m_showData=not args.hidehexa 157 | dumper.dump(doc,model,output) 158 | output.close() 159 | else: 160 | print ("can not read the file") 161 | else: 162 | print ("can not retrieve the file content") 163 | fs.close() 164 | 165 | if __name__ == "__main__": 166 | main() 167 | -------------------------------------------------------------------------------- /oletoy/oletoy.cfg: -------------------------------------------------------------------------------- 1 | # Monospace font for HexView 2 | self.font='Monospace' 3 | 4 | # Font size for HexView 5 | self.fontsize=14 6 | 7 | # Name of the libgsf 8 | self.gsfname='libgsf-1.so' 9 | 10 | -------------------------------------------------------------------------------- /oletoy/otxml.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2013 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct,gtk 18 | from utils import * 19 | 20 | def open (buf,page,parent): 21 | print("Probably XML",page.model.get_value(parent,0)) 22 | if buf[0:2] == '\xff\xfe': 23 | buf = unicode(buf[2:], 'utf_16le') 24 | elif buf[0:2] == '\xfe\xff': 25 | buf = unicode(buf[2:], 'utf_16be') 26 | t = buf.split("<") 27 | piter = parent 28 | citer = [] 29 | 30 | for i in range(len(t)-1): 31 | foo = t[i+1].split() 32 | if len(foo) > 0: 33 | bar = foo[0] 34 | else: 35 | bar = foo[:-1] 36 | 37 | if bar[0] == "?": 38 | id = bar[1:] 39 | else: 40 | id = bar 41 | 42 | if id[-1] == ">": 43 | id = id[:-1] 44 | else: 45 | id = id.replace(">",": ") 46 | 47 | data = "<"+t[i+1].replace("\x0d\x0a","") # all from tag start till next tag 48 | 49 | if bar[0] != "/": 50 | if t[i+1][-2:-1] != "/": 51 | d = data.split(">") 52 | niter = add_pgiter (page,id,"xml","",d[0]+">",piter) 53 | if len(d)>1 and len(d[1]) > 0: 54 | add_pgiter (page,id,"xml","sub",d[1],niter) 55 | citer.append(piter) 56 | piter = niter 57 | else: 58 | niter = add_pgiter (page,id,"xml","",data,piter) 59 | else: 60 | piter = citer.pop() 61 | 62 | return "xml" 63 | -------------------------------------------------------------------------------- /oletoy/pcap.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011, Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import struct 18 | from utils import * 19 | 20 | def open (page,buf,parent,off=0): 21 | add_pgiter(page,"PCAP Header","pcap","header",buf[0:0x18],parent) 22 | off = 0x18 23 | cnt = 0 24 | while off < len(buf)- 16: 25 | # ts = buf[off:off+4] 26 | off += 4 27 | # tms = buf[off:off+4] 28 | off += 4 29 | size = struct.unpack("H",data[off:off+2])[0] 260 | 261 | def pktbitrect(data,off): 262 | res = off 263 | rowbytes = (struct.unpack(">H",data[off:off+2])[0])&0x3fff 264 | off += 2 265 | bounds = struct.unpack(">HHHH",data[off:off+8]) 266 | off += 8 267 | # skip others 268 | off += 18 269 | if rowbytes < 8: 270 | res = rowbytes*(bounds[2]-bounds[0])+28 271 | else: 272 | f,t = '>B',1 273 | if rowbytes > 250: 274 | f,t = '>H',2 275 | for i in range(bounds[2]-bounds[0]): 276 | off += struct.unpack(f,data[off:off+t])[0] + t 277 | res = off - res 278 | return res 279 | 280 | 281 | def dirbitsrect(data,off): 282 | res = off 283 | #pixmap 284 | off += 4 # handle 285 | rowbytes = (struct.unpack(">H",data[off:off+2])[0])&0x3fff 286 | off += 2 287 | bounds = struct.unpack(">HHHH",data[off:off+8]) 288 | off += 8 289 | # skip version 290 | off += 2 291 | packtype = struct.unpack(">H",data[off:off+2])[0] 292 | off += 2 293 | # skip others 294 | off += 32 295 | #skip src/dst rects 296 | off += 16 297 | #skip mode 298 | off += 2 299 | # docs p.741 300 | if rowbytes < 8 or packtype == 1: 301 | res = rowbytes*(bounds[2]-bounds[0])+68 302 | elif packtype == 2: 303 | res = rowbytes*(bounds[2]-bounds[0])*0.75+68 304 | elif packtype > 2: 305 | f,t = '>B',1 306 | if rowbytes > 250: 307 | f,t = '>H',2 308 | for i in range(bounds[2]-bounds[0]): 309 | off += struct.unpack(f,data[off:off+t])[0] + t 310 | res = off - res 311 | return res 312 | 313 | def longcmnt(data,off): 314 | return struct.unpack(">H",data[off+2:off+4])[0]+4 315 | 316 | 317 | op_funcs = { 318 | 0x0001:clip, 319 | 0x0098:pktbitrect, 320 | 0x009a:dirbitsrect, 321 | 0x00a1:longcmnt 322 | } 323 | 324 | def opsize(op,data,off): 325 | if op > 0xff and op != 0x2ff: 326 | return (op>>8)*2 327 | else: 328 | if op in opsizes: 329 | return opsizes[op] 330 | elif op in op_funcs: 331 | return op_funcs[op](data,off) 332 | else: 333 | return 254 334 | 335 | def parse(page,data,parent): 336 | off = 0x20a 337 | while off < len(data): 338 | opc = struct.unpack(">H",data[off:off+2])[0] 339 | opn = key2txt(opc,opcodes,"Rsrvd by Apple") 340 | ops = opsize(opc,data,off+2) # skip opc 341 | add_pgiter(page,opn,"pict",opc,data[off:off+2+ops],parent) 342 | off += 2+ops 343 | -------------------------------------------------------------------------------- /oletoy/pkzip.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import zipfile 18 | from utils import * 19 | 20 | class PkzipPackage: 21 | def __init__(self, names): 22 | self.listNames = [] 23 | for n in names: 24 | self.listNames.append(n.filename) 25 | 26 | def namelist(self): 27 | return self.listNames 28 | 29 | def open(fname,page,parent=None): 30 | try: 31 | dirstruct = {} 32 | iters = [] 33 | root_itr = None 34 | z = zipfile.ZipFile(fname,"r") 35 | page.fdata = {} 36 | package = PkzipPackage(z.filelist) 37 | for i in z.filelist: 38 | fn = i.filename 39 | data = z.read(fn) 40 | print(fn) 41 | pos = fn.rfind("/") 42 | if pos == -1: 43 | name = fn 44 | else: 45 | name = "[%s]%s"%(fn[:pos],fn[pos:]) 46 | itr = add_pgiter(page,name,"pkzip",0,data) 47 | if len(data) > 0: 48 | if "root.dat" in name: 49 | root_itr = (data, itr) 50 | else: 51 | iters.append((data, itr)) 52 | if root_itr: 53 | iters.append(root_itr) 54 | for (data, itr) in iters: 55 | page.fload(data, itr, package) 56 | 57 | except zipfile.BadZipfile: 58 | print("Open as PKZIP failed") 59 | except zipfile.LargeZipFile: 60 | print("Open as PKZIP failed") 61 | -------------------------------------------------------------------------------- /oletoy/pngot.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2013 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct,zlib 18 | import gtk 19 | from utils import * 20 | 21 | def firewrk_mkbs (page, buf, parent=None): 22 | piters = [] 23 | if parent: 24 | piters.append(parent) 25 | spl = buf.split("{") 26 | ind = 0 27 | while len(spl) > 1: 28 | name = spl[0] 29 | value = spl[1] 30 | print(ind,name,value,len(spl),"%02x"%(len(buf)-len(" ".join(spl))),"%d%%"%(100-100*len(" ".join(spl))/len(buf))) 31 | ind += 1 32 | spl.remove(name) 33 | spl.remove(value) 34 | flag = 0 35 | if name[3] == "s": 36 | print("STR",name) 37 | vlen = struct.unpack(">H",value[:2])[0]*2 38 | while vlen > len(value[2:]): 39 | rval = spl[0] 40 | value += "{"+rval 41 | spl.remove(rval) 42 | flag = 1 43 | if "}" in value: 44 | pos = value.find("}") 45 | v = "" 46 | if name[3] == "s": 47 | v = value[2:pos+flag].decode('utf-16-be') 48 | elif len(value[:pos]): 49 | v = str(value[:pos]) 50 | add_pgiter(page,"%s [%s]"%(name,v),"mk*s","",value[:pos+flag],parent) 51 | if not flag: 52 | if pos+1 < len(value): 53 | cnt = value.count("}") 54 | if cnt > 1: 55 | for i in range(cnt-1): 56 | piters.pop() 57 | parent = piters[-1] 58 | spl.insert(0,value[pos+cnt:]) 59 | else: 60 | parent = piters.pop() 61 | else: 62 | parent = add_pgiter(page,name,"mk*s","","",parent) 63 | spl.insert(0,value) 64 | piters.append(parent) 65 | 66 | def open (page, buf, parent=None): 67 | if buf[:8] != "\x89PNG\x0d\x0a\x1a\x0a": 68 | print('No PNG signature') 69 | return 70 | if parent: 71 | page.model.set_value(parent,1,("escher","odraw","Blip")) 72 | add_pgiter(page,"Signature","png","sig",buf[:8],parent) 73 | off = 8 74 | while off < len(buf): 75 | chlen = struct.unpack(">I",buf[off:off+4])[0] 76 | chtype = buf[off+4:off+8] 77 | off += 8 78 | chdata = buf[off:off+chlen] 79 | off += chlen 80 | chcrc = struct.unpack(">I",buf[off:off+4])[0] 81 | off += 4 82 | chiter = add_pgiter(page,chtype,"png",chtype,buf[off-12-chlen:off],parent) 83 | if chtype[0] > 0x60: # private chunk 84 | zipoff = -1 85 | if (len(chdata) > 12 and chdata[0] == '\x78'): 86 | zipoff = 0 87 | elif (chdata[:4] == "\xfa\xce\xca\xfe" and len(chdata) > 0x4c and chdata[0x4c] == '\x78'): 88 | zipoff = 0x4c 89 | # probably deflated 90 | if zipoff > -1: 91 | try: 92 | decobj = zlib.decompressobj() 93 | output = decobj.decompress(chdata[zipoff:]) 94 | add_pgiter (page,"[Decompressed data]","",0,output,chiter) 95 | tail = decobj.unused_data 96 | if len(tail) > 0: 97 | add_pgiter (page,"[Tail]","",0,tail,chiter) 98 | except: 99 | print("Failed to decompress") 100 | 101 | -------------------------------------------------------------------------------- /oletoy/ppp.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2012, Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | 16 | import sys,struct,zlib,gtk,cdr 17 | from utils import * 18 | 19 | def bmp (hd,size,data,page): 20 | # naive version, not always works as needed 21 | w = struct.unpack(" 12700 and v < 220370400: 104 | # couldn't be EMU if less than 1 point or more than 241 inch 105 | name += " (%.2f pt)"%(v/12700.) 106 | else: 107 | name += " (%02d)"%v 108 | 109 | if type == 0x48: 110 | value = data[off:off+24] 111 | off += 24 112 | dlen = 0 113 | 114 | if type == 0x22 or type == 0x58 or type == 0x68 or type == 0x70: 115 | value = data[off:off+4] 116 | dlen = 4 117 | v = struct.unpack(" 4: 158 | try: 159 | name += " %s"%unicode(value,'utf-16') 160 | except: 161 | name += value 162 | print("UCode failed",model.get_string_from_iter(parent)) 163 | if type == 0xFF: # current len just to pass parsing 164 | value = ord(data[off+1]) 165 | dlen = 1 166 | j += 1 167 | if ptype in block_ids: 168 | bid = block_ids[ptype] 169 | if id in bid: 170 | name += " (%s)"%bid[id] 171 | 172 | if dlen == -1: 173 | print("Unknown type %02x at block %d %d %02x"%(type,i,j,off)) 174 | iter1 = add_pgiter (page,"Unkn block","pub",0,"",parent) 175 | model.set_value(iter1,5,"#FF0000") 176 | print("Path",model.get_string_from_iter(iter1)) 177 | return 178 | else: 179 | if type != 0x78 or j > 0xFF: 180 | iter1 = add_pgiter (page,name,"pub",disp_id,value,parent) 181 | if dlen > 4 and type != 0xc0 and type != 0x80 and type != 0x38 and type != 0x28: 182 | parser = block_parser if block_parser else parse 183 | parser(page,data[off+4:off+dlen],iter1,i,j-2) 184 | off += dlen 185 | except: 186 | print("Failed at parsing block %d "%i,"val: ",value," off: ",off,model.get_string_from_iter(parent)) 187 | -------------------------------------------------------------------------------- /oletoy/qpw.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import sys,struct,gtk 18 | from utils import * 19 | 20 | def parse (page, data, parent): 21 | off = 0 22 | while off < len(data) - 2: 23 | type = struct.unpack('i/2: 146 | iter1 = add_pgiter (page,"Ch %02x Pr %02x"%(i,struct.unpack("" with greater than 0 235 | if name[0:4] == "FDPC" or name[0:4] == "FDPP": 236 | parse_fdpc (page,data,doffset,iter1) # we can have more than one "FDPC/FDPCx" 237 | if name[0:4] == "SYID": 238 | txtid = parse_syid(page,data,doffset,iter1,txtiter,txtid) 239 | if name[0:4] == "STSH": 240 | parse_stsh (page,data[doffset:doffset+dlen],iter1,name[9]) #STSH/STSH1 looks slightly different 241 | if name[0:4] == "STRS": 242 | parse_strs (page,data[doffset:doffset+dlen],iter1,txtiter) 243 | if name[0:4] == "TCD ": 244 | parse_tcd (page,data[doffset:doffset+dlen],iter1,txtiter) 245 | if name[0:4] == "PL ": 246 | parse_pl (page,data[doffset:doffset+dlen],iter1) 247 | if name[0:4] == "FONT": 248 | parse_font (page,data[doffset:doffset+dlen],iter1) 249 | if name[0:4] == "MCLD": 250 | parse_mcld (page,data[doffset:doffset+dlen],iter1) 251 | 252 | model.set_value(iter1,0,name) 253 | model.set_value(iter1,1,("quill",name[0:4])) 254 | model.set_value(iter1,2,dlen) 255 | model.set_value(iter1,3,data[doffset:doffset+dlen]) 256 | model.set_value(iter1,6,model.get_string_from_iter(iter1)) 257 | off += 24 258 | if nxt_chblk != 0xffFFffFF: 259 | off = nxt_chblk 260 | ch_num = struct.unpack('I",data[off:off+4])[0]/4.)*4) 27 | off += 4 28 | add_pgiter(page,"%s"%fourcc,"yep",fourcc,data[off:off+length],parent) 29 | off += length 30 | 31 | # RIFF with lists 32 | 33 | def parse2 (page, data, parent): 34 | off = 0 35 | if data[0:4] == "RIFF": 36 | dsize = struct.unpack("H",buf[off:off+2])[0] 75 | value += ch 76 | add_pgiter (page,name2,"rtf",name,buf[off:off+2+size],parent) 77 | off += size+2 78 | else: 79 | value += ch 80 | else: 81 | name2 = "" 82 | value += ch 83 | else: 84 | value += ch 85 | 86 | if name == "pict": 87 | pflag = 1 88 | else: 89 | pflag = 0 90 | except: 91 | print("failed","%02x"%off,name) 92 | 93 | def recode(buf, enc): 94 | off = 0 95 | strbuf = "" 96 | tbuf = buf.replace("\x0d\x0a","\\n") 97 | while off < len(tbuf)-3: 98 | pos = tbuf.find("\'",off) 99 | if pos != -1: 100 | pos+=1 101 | if pos > off+2: 102 | strbuf += tbuf[off:pos-2] 103 | try: 104 | strbuf += struct.pack("B",int(tbuf[pos:pos+2],16)).decode(enc) 105 | except: 106 | pass 107 | off = pos+2 108 | else: 109 | break 110 | return strbuf 111 | 112 | def open(buf,page,parent): 113 | off = 0 114 | rtf_read (buf[1:],off,page,parent) 115 | return "RTF" 116 | -------------------------------------------------------------------------------- /oletoy/svm.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007,2010,2011 Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | # 18 | # Based on SPEC from Inge Wallin/Pierre Ducroquet 19 | # 20 | 21 | import struct 22 | 23 | def Line (hd, size, value): 24 | iter1 = hd.model.append(None, None) 25 | hd.model.set (iter1, 0, "X", 1, struct.unpack(" 0: 56 | end = eol + 2 57 | else: 58 | end = len(self.data) 59 | data = self.data[off:end] 60 | off = end 61 | if data[0] == '@': 62 | add_pgiter(self.page, key2txt(data[1:3], controls, 'Control'), 't602', 'control', data, self.parent) 63 | elif data[0] == '.': 64 | (cmd, dummy) = read_command(data) 65 | add_pgiter(self.page, key2txt(cmd.upper(), commands, 'Command'), 't602', 'command', data, self.parent) 66 | else: 67 | add_pgiter(self.page, 'Paragraph', 't602', 'paragraph', data, self.parent) 68 | 69 | def add_control(hd, size, data): 70 | off = 1 71 | (name, off) = rdata(data, off, '2s') 72 | add_iter(hd, 'Name', key2txt(name, controls), off - 2, 2, '2s') 73 | if data[-1] == '\x1a': 74 | end = len(data) - 1 75 | else: 76 | end = len(data) - 2 77 | off += 1 78 | if off < end: 79 | value = data[off:end] 80 | encoding_map = {'0': 'KEYBCS2', '1': 'LATIN2', '2': 'KOI8CS'} 81 | line_height_map = {'6': '100%', '4': '150%', '3': '200%'} 82 | if name == 'CT': 83 | value = key2txt(value.strip(), encoding_map) 84 | elif name == 'LH': 85 | value = key2txt(value.strip(), line_height_map) 86 | add_iter(hd, 'Value', value, off, end - off, '%ds' % (end - off)) 87 | off = end 88 | add_iter(hd, 'End of control', data[off:], off, len(data) - off, '%ds' % (len(data) - off)) 89 | 90 | def add_paragraph(hd, size, data): 91 | fmt = { 92 | 0x2: 'Switch bold', 93 | 0x4: 'Switch italics', 94 | 0xa: 'Line break', 95 | 0xf: 'Switch wide', 96 | 0x10: 'Switch high', 97 | 0x13: 'Switch underline', 98 | 0x14: 'Switch subscript', 99 | 0x16: 'Switch superscript', 100 | 0x1a: 'End of file', 101 | 0x1d: 'Switch big', 102 | } 103 | off = 0 104 | mark = 0 105 | while off < len(data): 106 | (c, off) = rdata(data, off, ' 1: 109 | length = off - mark - 1 110 | add_iter(hd, 'Text', data[mark:off - 1], mark, length, '%ds' % length) 111 | mark = off 112 | if c == 0xd and off == len(data) - 1: 113 | add_iter(hd, 'End of paragraph', data[-2:], off - 1, 2, '2s') 114 | off += 1 115 | else: 116 | add_iter(hd, key2txt(c, fmt), '', off - 1, 1, ' 126: 118 | ch = rch 119 | asc += ch 120 | if ln != 0 and i > 0 and (i+1)%ln == 0: 121 | asc += "\n" 122 | return asc 123 | 124 | def d2hex(data,space="",ln=0): 125 | s = "" 126 | for i in range(len(data)): 127 | s += "%02x%s"%(ord(data[i]),space) 128 | if ln != 0 and i > 0 and (i+1)%ln == 0: 129 | s += "\n" 130 | return s 131 | 132 | def d2bin(data): 133 | return ' '.join(format(ord(x), 'b').zfill(8) for x in data) 134 | 135 | def key2txt(key,data,txt="Unknown"): 136 | if key in data: 137 | return data[key] 138 | else: 139 | return txt 140 | 141 | def bflag2txt(flag,data,txt=""): 142 | if flag != 0: 143 | for i in [1 << s for s in range(0, 32)]: # flag sets 32 bits wide should be enough 144 | if flag < i: 145 | break; 146 | if flag&i == i: 147 | txt += key2txt(i,data,"") + "/" 148 | if len(txt) > 0: 149 | txt = txt[:len(txt)-1] 150 | return txt 151 | 152 | def lcid2txt(lcid): 153 | if useicu: 154 | try: 155 | return icu.Locale(lcid).getDisplayName() 156 | except: 157 | return "Unknown" 158 | else: 159 | locale_id = {1029: 'Czech', 1033: 'English (US)',} 160 | return key2txt(lcid, locale_id) 161 | 162 | def dib2bmp(data,strict=0): 163 | flag = struct.unpack(" sq: 265 | dx = 1 266 | dy += 1 267 | return devs 268 | 269 | gv_colors = { 270 | "FHTail":"red", 271 | "Block":"orange", 272 | "PropLst":"yellow", 273 | "Layer":"green", 274 | "Path":"blue" 275 | } 276 | 277 | def gv_layout(nodes,edges,mode="dot"): 278 | G = gv.graph("root") 279 | s = gv.graph(G,"test") 280 | for i in nodes: 281 | sg = "%02x %s"%(i,nodes[i][0]) 282 | n = gv.node(s,sg) 283 | if nodes[i][0] in gv_colors: 284 | gv.setv(n,"color",gv_colors[nodes[i][0]]) 285 | gv.setv(n,"style","filled") 286 | 287 | for i in edges: 288 | if i[0] in nodes and i[1] in nodes: 289 | e = gv.edge(G,"%02x %s"%(i[0],nodes[i[0]][0]),"%02x %s"%(i[1],nodes[i[1]][0])) 290 | gv.setv(e,"dir","none") 291 | gv.layout(G, mode) 292 | gv.render(G) 293 | # for debugging purposes 294 | gv.render(G,'svg','test.svg') 295 | devs = {} 296 | fn = gv.firstnode(G) 297 | try: 298 | devs[gv.nameof(fn)] = gv.getv(fn,"pos").split(",") 299 | except: 300 | print('Failed in gv_render') 301 | for i in range(len(nodes)-1): 302 | fn = gv.nextnode(G,fn) 303 | devs[gv.nameof(fn)] = gv.getv(fn,"pos").split(",") 304 | 305 | return devs 306 | 307 | 308 | 309 | def graph_layout (app, doc, algo): 310 | if usegraphviz and algo in ("fdp","sfdp","neato","circo","osage","dot","twopi"): 311 | devs = gv_layout(doc.nodes,doc.edges,algo) 312 | else: 313 | # hinted random placement 314 | devs = hr_layout(doc.nodes) 315 | -------------------------------------------------------------------------------- /oletoy/vba.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011, Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | 16 | import sys,struct 17 | import gtk 18 | import tree 19 | import hexdump 20 | import inflate 21 | from utils import * 22 | 23 | 24 | def rt_0 (data): 25 | return "" 26 | 27 | def rt_2 (data): 28 | return "%02x"%struct.unpack(" 0x26: 60 | vsdblock.parse5(hd, size, value, 0x26) 61 | 62 | def XForm (hd, size, value): 63 | vn = {0:"PinX",1:"PinY",2:"Width",3:"Height",4:"LocPinX",5:"LocPinY",6:"Angle",7:"FlipX",8:"FlipY",9:"ResizeMode"} 64 | for i in range(7): 65 | add_iter (hd, vn[i], "%.2f"%struct.unpack(" 20: 82 | vsdblock.parse5(hd, size, value, 20) 83 | 84 | def LineTo (hd, size, value): 85 | vn = {0:"X",1:"Y"} 86 | for i in range(2): 87 | add_iter (hd, vn[i], "%.2f"%struct.unpack(" 20: 89 | vsdblock.parse5(hd, size, value, 20) 90 | 91 | def EllArcTo (hd, size, value): 92 | vn = {0:"X",1:"Y",2:"A",3:"B",4:"C",5:"D"} 93 | for i in range(6): 94 | add_iter (hd, vn[i], "%.2f"%struct.unpack(" 17: 127 | vsdblock.parse5(hd, size, value, 17) 128 | 129 | 130 | def NameIDX (hd, size, value): 131 | numofrec = struct.unpack("0xe: 151 | vsdblock.parse5(hd, size, value, 0xe) 152 | 153 | chnk_func = { 154 | # 0xe:Text, 155 | # 0x15:Page, 156 | # 0x19:Font, 157 | # 0x28:ShapeStencil, 158 | # 0xd:List,0x2c:List, 159 | 0x34:NameIDXv123, # ONLY v123 160 | # 0x46:Shape,0x47:Shape, 0x48:Shape, 0x4a:Shape,0x4d:Shape, 0x4e:Shape,0x4f:Shape, 161 | # 0x64:List,0x65:List,0x66:List,0x67:List,0x68:List,0x69:List,0x6a:List,0x6b:List,0x6c:List, 162 | # 0x6d:List,0x6e:List,0x6f:List,0x70:List,0x71:List,0x72:List,0x76:List, 163 | 0x85:Line, 164 | 0x86:Fill, 165 | 0x87:TextBlock, 166 | # 0x89:Geometry, 167 | 0x8a:MoveTo, 0x8b:LineTo, 168 | # 0x8c:ArcTo,0x8d:InfLine, 169 | # 0x8f:Ellipse, 170 | 0x90:EllArcTo, 0x92:PageProps, 171 | # 0x93:StyleProps, 172 | 0x94:CharIX,0x95:ParaIX, 173 | # 0x98:FrgnType, 174 | 0x9b:XForm,0x9c:TxtXForm, 0x9d:XForm1D, 175 | 0xa1:TextField, 176 | 0xa4:Misc, 177 | # 0xa5:SplineStart,0xa6:SplineKnot,0xa8:LayerIX,0xaa:Control, 178 | # 0xc0:PageLayout,0xc1:Polyline,0xc3:NURBS, 179 | 0xc9:NameIDX, 180 | # 0xd1:ShapeData 181 | } 182 | -------------------------------------------------------------------------------- /oletoy/vsdstream4.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011, Valek Filippov (frob@df.ru) 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of version 3 or later of the GNU General Public 5 | # License as published by the Free Software Foundation. 6 | # This program is distributed in the hope that it will be useful, 7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | # GNU General Public License for more details. 10 | # 11 | # You should have received a copy of the GNU Lesser General Public License 12 | # along with this program; if not, write to the Free Software 13 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 14 | # USA 15 | # 16 | 17 | import struct 18 | from utils import * 19 | from math import ceil 20 | 21 | win_types = {0x15:'Drawing',0x1d:'Stencil'} 22 | 23 | def EventItem (hd, size, value): 24 | iter1 = hd.model.append(None, None) 25 | hd.model.set (iter1, 0, "ID", 1, "%d"%struct.unpack("5: 113 | recnum = struct.unpack(" 0: 104 | patt_num = struct.unpack("