[Libreoffice-commits] mso-dumper.git: 25 commits - compress.py decompress.py src/ole.py src/oletool.py src/vbahelper.py vbadump.py

Noel Power noelp at kemper.freedesktop.org
Fri Oct 11 09:13:14 PDT 2013


 compress.py      |   48 ++++
 decompress.py    |   48 ++++
 src/ole.py       |  174 +++++++++++++++++
 src/oletool.py   |  171 ----------------
 src/vbahelper.py |  282 +++++++++++++++++++++++++++
 vbadump.py       |  555 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 1110 insertions(+), 168 deletions(-)

New commits:
commit 7c8934719fcb31d319d68ab477d37464b02f49af
Author: Noel Power <noel.power at suse.com>
Date:   Fri Oct 11 11:54:55 2013 +0100

    Added remaining record readers for dir stream, added licences hdrs to files
    
    Some notes:
    a) yes the formatted output is not as good as it should be ( feel free to improve )
      * e.g. GUID it's just bytes outputted no formating at all.
      * nested messages like a REFERENCECONTROL can contain a REFERENCEORIGINAL and
    a REFERENCENAME as subrecords. ( this is not reflected in the formatted output )
    b) there is a separate record reader for every 'Dir' stream record type, lots of
    records are similar, it's sure that better design here would allow more code sharing
    to be achieved and the amount of readers could be reduced.
    c) probably some interpretation of the information in the ProjectXXXX streams could
    be done ( infact we don't yet parse anything out of PROJECTlk ( its just a bunch of
    GUIDs with some extra blobs for licence info ) ( doesn't appear in excel files that
    I examined so I ignored it for now )
    
    add licences

diff --git a/compress.py b/compress.py
index 1c98005..7ab4a9a 100755
--- a/compress.py
+++ b/compress.py
@@ -1,4 +1,30 @@
 #!/usr/bin/env python2
+########################################################################
+#
+#  Copyright (c) 2013 Noel Power
+#  
+#  Permission is hereby granted, free of charge, to any person
+#  obtaining a copy of this software and associated documentation
+#  files (the "Software"), to deal in the Software without
+#  restriction, including without limitation the rights to use,
+#  copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the
+#  Software is furnished to do so, subject to the following
+#  conditions:
+#  
+#  The above copyright notice and this permission notice shall be
+#  included in all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#  OTHER DEALINGS IN THE SOFTWARE.
+#
+########################################################################
 
 import sys, os.path, optparse
 sys.path.append(sys.path[0]+"/src")
diff --git a/decompress.py b/decompress.py
index ce7c854..50e7401 100755
--- a/decompress.py
+++ b/decompress.py
@@ -1,4 +1,30 @@
 #!/usr/bin/env python2
+########################################################################
+#
+#  Copyright (c) 2013 Noel Power
+#  
+#  Permission is hereby granted, free of charge, to any person
+#  obtaining a copy of this software and associated documentation
+#  files (the "Software"), to deal in the Software without
+#  restriction, including without limitation the rights to use,
+#  copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the
+#  Software is furnished to do so, subject to the following
+#  conditions:
+#  
+#  The above copyright notice and this permission notice shall be
+#  included in all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#  OTHER DEALINGS IN THE SOFTWARE.
+#
+########################################################################
 
 import sys, os.path, optparse
 sys.path.append(sys.path[0]+"/src")
diff --git a/src/vbahelper.py b/src/vbahelper.py
index face96c..c47e6ef 100644
--- a/src/vbahelper.py
+++ b/src/vbahelper.py
@@ -1,3 +1,30 @@
+########################################################################
+#
+#  Copyright (c) 2013 Noel Power
+#  
+#  Permission is hereby granted, free of charge, to any person
+#  obtaining a copy of this software and associated documentation
+#  files (the "Software"), to deal in the Software without
+#  restriction, including without limitation the rights to use,
+#  copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the
+#  Software is furnished to do so, subject to the following
+#  conditions:
+#  
+#  The above copyright notice and this permission notice shall be
+#  included in all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#  OTHER DEALINGS IN THE SOFTWARE.
+#
+########################################################################
+
 import  sys, struct
 class VBAStreamBase:
     CHUNKSIZE = 4096
diff --git a/vbadump.py b/vbadump.py
index a606e9f..b8b2aa2 100755
--- a/vbadump.py
+++ b/vbadump.py
@@ -1,4 +1,30 @@
 #!/usr/bin/env python2
+########################################################################
+#
+#  Copyright (c) 2013 Noel Power
+#  
+#  Permission is hereby granted, free of charge, to any person
+#  obtaining a copy of this software and associated documentation
+#  files (the "Software"), to deal in the Software without
+#  restriction, including without limitation the rights to use,
+#  copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the
+#  Software is furnished to do so, subject to the following
+#  conditions:
+#  
+#  The above copyright notice and this permission notice shall be
+#  included in all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+#  OTHER DEALINGS IN THE SOFTWARE.
+#
+########################################################################
 
 import sys, os.path, optparse, math
 sys.path.append(sys.path[0]+"/src")
@@ -77,24 +103,6 @@ codePageMap = {
     65001: "utf_8",      #UTF8;
 }
 
-# alot of records follow the id, sizeofrecord pattern
-# many of the dir records though seem to be id, sizeofstring,
-# stringbuffer, reserved, sizeofstring(unicode), stringbuffer(unicode)
-class DefaultBuffReservedBuffReader:
-    def __init__ (self, reader ):
-        self.reader = reader
-    def parse(self):
-        # pos before header
-        print ("  skipping")
-        # buffer
-        size = self.reader.readUnsignedInt( 4 )
-        self.reader.readBytes(size)        
-        # reserved
-        self.reader.readBytes(2)        
-        # buffer
-        size = self.reader.readUnsignedInt( 4 )
-        self.reader.readBytes(size)    
-
 class StdReader:
     def __init__ (self, reader ):
         self.reader = reader
@@ -109,8 +117,8 @@ class ProjectVersionReader( StdReader ):
         # major
         major = self.reader.readUnsignedInt( 4 )
         minor = self.reader.readUnsignedInt( 2 )
-        print("  major: 0x%x"%major)
-        print("  minor: 0x%x"%minor)
+        print("  major: %i"%major)
+        print("  minor: %i"%minor)
 
 class CodePageReader(StdReader):
     def parse(self):
@@ -139,7 +147,21 @@ class DocStringRecordReader(StdReader):
         #unicode docstring
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("  DocString(utf-16): %s size[0x%x]"%(bytes.decode("utf-16").decode(self.reader.codepageName), size ))
+        print("  DocStringUnicode: %s size[0x%x]"%(bytes.decode("utf-16").decode(self.reader.codepageName), size ))
+
+class ReferenceProjectReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        sizeOfLibidAbsolute = self.reader.readUnsignedInt( 4 )
+        sLibidAbsolute =  self.reader.readBytes( sizeOfLibidAbsolute )
+        nSizeOfLibidRelative =   self.reader.readUnsignedInt( 4 )
+        sLibidRelative =  self.reader.readBytes( nSizeOfLibidRelative )
+        majorVersion = self.reader.readUnsignedInt( 4 )
+        minorVersion = self.reader.readUnsignedInt( 2 )
+        print("  LibidAbsolute: %s"%sLibidAbsolute.decode( self.reader.codepageName ) )
+        print("  LibidRelative: %s"%sLibidRelative.decode( self.reader.codepageName ) )
+        print("  MajorVersion: %i"%majorVersion )
+        print("  MinorVersion: %i"%minorVersion )
 
 class ConstantsRecordReader(StdReader):
     def parse(self):
@@ -203,7 +225,34 @@ class ModuleStreamNameReader(StdReader):
         size = self.reader.readUnsignedInt( 4 )
         nameUnicodeBytes = self.reader.readBytes( size )
         nameUnicode = nameUnicodeBytes.decode("utf-16").decode( self.reader.codepageName)
-        print("  ModuleStreamName(utf-16): %s"%nameUnicode)
+        print("  ModuleStreamNameUnicode: %s"%nameUnicode)
+
+class ReferenceNameRecordReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        nameBytes = self.reader.readBytes( size )
+        print("  ReferenceName: %s"%nameBytes.decode( self.reader.codepageName ))
+        #reserved
+        self.reader.readBytes( 2 )
+        size = self.reader.readUnsignedInt( 4 )
+        nameUnicodeBytes = self.reader.readBytes( size )
+        nameUnicode = nameUnicodeBytes.decode("utf-16").decode( self.reader.codepageName)
+        print("  ReferenceNameUnicode: %s"%nameUnicode)
+
+class ReferenceRegisteredReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        sizeOfLibid = self.reader.readUnsignedInt( 4 )
+        libidBytes = self.reader.readBytes( sizeOfLibid )
+        print("  Libid: %s"%libidBytes.decode( self.reader.codepageName ))
+        #reserved1 & reserved2
+        self.reader.readBytes( 6 )
+class ModuleNameUnicodeReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        nameUnicodeBytes = self.reader.readBytes( size )
+        nameUnicode = nameUnicodeBytes.decode("utf-16").decode( self.reader.codepageName)
+        print("  ModuleNameUnicode: %s"%nameUnicode)
 
 class ModuleOffSetReader(StdReader):
     def parse(self):
@@ -266,6 +315,61 @@ class LibFlagReader(StdReader):
         val = self.reader.readUnsignedInt( size )
         print("  LIBFLAGS: 0x%x"%val)
 
+class ModuleCookieReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        print("  ModuleCookie: 0x%x"%val)
+
+class ModuleHelpContextReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        print("  HelpConext: 0x%x"%val)
+
+class ProjectCookieReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        print("  ProjectCookie: 0x%x"%val)
+
+class ReferenceOriginalRecord(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        sLibidOriginalBytes = self.reader.readBytes( size )
+        print("  LibIdOriginal: %s"%sLibidOriginalBytes.decode( self.reader.codepageName))
+
+class ReferenceControlReaderPart1(StdReader):
+    def parse(self):
+        sizeOfTwiddled = self.reader.readUnsignedInt( 4 )
+        sizeOfLibidTwiddled =  self.reader.readUnsignedInt( 4 )
+        sLibidTwiddledBytes =  self.reader.readBytes( sizeOfLibidTwiddled )
+        print("  LibIdTwiddled: %s"%sLibidTwiddledBytes.decode( self.reader.codepageName))
+        
+        # Reserved1 & Reserved2 ( suppose we could really read these and assert if 
+        # they don't conform to expected values ( 0x00000000 & 0x00000000 )
+        self.reader.readBytes( 6 )
+
+class ReferenceControlReaderPart2(StdReader):
+    def parse(self):
+        sizeExtended = self.reader.readUnsignedInt( 4 )
+        sizeOfLibidExtended =  self.reader.readUnsignedInt( 4 )
+        sLibidExtendedBytes =  self.reader.readBytes( sizeOfLibidExtended )
+        print("  LibidExtended: %s"%sLibidExtendedBytes.decode( self.reader.codepageName))
+        
+        # Reserved4 & Reserved5 ( suppose we could really read these and assert if 
+        # they don't conform to expected values ( 0x00000000 & 0x00000000 )
+        self.reader.readBytes( 6 )
+        origTypeLib = self.reader.readBytes( 16 )
+        sys.stdout.write("  GUID: " )
+        for i in xrange( 0, 16 ):
+            if i:
+                sys.stdout.write(" ")
+            sys.stdout.write("0x%x"%origTypeLib[ i ])
+        print("")
+        cookie = self.reader.readUnsignedInt( 4 )
+        print("  cookie: 0x%x"%cookie)
+
 # map of record id to array containing description of records and optional
 # a handler ( inspired by xlsstream.py )
 dirRecordData = {
@@ -286,26 +390,26 @@ dirRecordData = {
     0x0014: ["PROJECTLCIDINVOKE", "LcidInvokeRecord",LcidInvokeReader],
     #PROJECTREFERENCES
     # which contains any of the following sub records
-    0x0016: ["REFERENCENAME", "NameRecord", DefaultBuffReservedBuffReader ],
-    0x000D: ["REFERENCEREGISTERED", "ReferenceRegistered"],
-    0x000E: ["REFERENCEPROJECT", "ReferenceProject"],
-    0x002F: ["REFERENCECONTROL", "ReferenceControl"],
-    #the following "FAKE-#FIXME record is not really a record but actually
+    0x0016: ["REFERENCENAME", "NameRecord", ReferenceNameRecordReader ],
+    0x000D: ["REFERENCEREGISTERED", "ReferenceRegistered", ReferenceRegisteredReader],
+    0x000E: ["REFERENCEPROJECT", "ReferenceProject", ReferenceProjectReader],
+    0x002F: ["REFERENCECONTROL-Part1", "ReferenceControl", ReferenceControlReaderPart1],
+    #the following record is not really a record but actually
     #is a reserved word ( with fixed value 0x0030 ) in the middle of a
     #REFEREBCECONTROL record
-    0x0030: ["FAKE-#FIXME", "Fake record"],
-    0x0033: ["REFERENCEORIGINAL", "ReferenceOriginal"],
+    0x0030: ["REFERENCECONTROL-Part2", "ReferenceControl", ReferenceControlReaderPart2 ],
+    0x0033: ["REFERENCEORIGINAL", "ReferenceOriginal",ReferenceOriginalRecord],
     #
     0x000F: ["PROJECTMODULES", "ModulesRecord", ProjectModulesReader],
-    0x0013: ["PROJECTCOOKIE", "CookieRecord"],
+    0x0013: ["PROJECTCOOKIE", "CookieRecord", ProjectCookieReader],
     0x002B: ["PROJECTMODULETERM", "ModuleTerminator", ProjectModuleTermReader],
     0x0019: ["MODULENAME", "ModuleName",ModuleNameReader],
-    0x0047: ["MODULENAMEUNICODE", "ModuleNameUnicode"],
+    0x0047: ["MODULENAMEUNICODE", "ModuleNameUnicode", ModuleNameUnicodeReader ],
     0x001A: ["MODULESTREAMNAME", "ModuleStreamName", ModuleStreamNameReader],
-    0x001C: ["MODULEDOCSTRING", "ModuleDocString", DefaultBuffReservedBuffReader],
+    0x001C: ["MODULEDOCSTRING", "ModuleDocString", DocStringRecordReader],
     0x0031: ["MODULEOFFSET", "ModuleOffSet", ModuleOffSetReader],
-    0x001E: ["MODULEHELPCONTEXT", "ModuleHelpContext"],
-    0x002C: ["MODULECOOKIE", "ModuleCookie"],
+    0x001E: ["MODULEHELPCONTEXT", "ModuleHelpContext", ModuleHelpContextReader],
+    0x002C: ["MODULECOOKIE", "ModuleCookie", ModuleCookieReader ],
     0x0021: ["MODULETYPE", "ModuleTypeProcedural", ModuleTypeProceduralReader],
     0x0022: ["MODULETYPE", "ModuleTypeDocClassOrDesgn", ModuleTypeOtherReader],
     0x0025: ["MODULEREADONLY", "ModuleReadOnly"],
@@ -347,7 +451,6 @@ class DirStreamReader( globals.ByteStream ):
                 reader = dirRecordData[ recordID ][2]( self )
                 reader.parse()
             else:
-                print ("  skipping")
                 size = self.readUnsignedInt( 4 )
                 if size:
                     self.readBytes(size)        
commit dc3f334106a628dc818a3e18d4d87cf03a6fe3ae
Author: Noel Power <noel.power at suse.com>
Date:   Fri Oct 11 10:28:22 2013 +0100

    get rid of dodgy write to some random harcoded file
    
    now you can do the following on the cmd line
    
    cat SourceData | ./compress.py | ./decompress.py
    
    and you should get your SourceData back

diff --git a/compress.py b/compress.py
index ffd6d32..1c98005 100755
--- a/compress.py
+++ b/compress.py
@@ -5,26 +5,17 @@ sys.path.append(sys.path[0]+"/src")
 import vbahelper
 
 def main():
-    if ( len ( sys.argv ) <= 1 ):
-        print("usage: compress: file [offset]")
-        sys.exit(1) 
 
     offset = 0
-    if len ( sys.argv ) > 2:
-        offset = int(sys.argv[2])
+    if len ( sys.argv ) > 1:
+        offset = int(sys.argv[1])
 
-    file = open(sys.argv[1],'rb')
-    chars = file.read()
-    file.close()
+    chars = sys.stdin.read()
 
     decompressed = vbahelper.UnCompressedVBAStream( chars, offset )
     compressed = decompressed.compress()
-
-    out = open( sys.argv[1] + ".compressed", 'wb' );
-    out.write( compressed );
-    out.flush()
-    out.close()
-
+    sys.stdout.write(compressed)
+    
     exit(0)
 
 if __name__ == '__main__':
diff --git a/decompress.py b/decompress.py
index 78ed262..ce7c854 100755
--- a/decompress.py
+++ b/decompress.py
@@ -5,25 +5,16 @@ sys.path.append(sys.path[0]+"/src")
 import vbahelper
 
 def main():
-    if ( len ( sys.argv ) <= 1 ):
-        print("usage: decompress: file [offset]")
-        sys.exit(1) 
 
     offset = 0
-    if len ( sys.argv ) > 2:
-        offset = int(sys.argv[2])
+    if len ( sys.argv ) > 1:
+        offset = int(sys.argv[1])
 
-    file = open(sys.argv[1],'rb')
-    chars = file.read()
-    file.close()
+    chars = sys.stdin.read()
 
     compressed = vbahelper.CompressedVBAStream( chars, offset )
     decompressed = compressed.decompress()
-
-    out = open( sys.argv[1] + ".decompress", 'wb' );
-    out.write( decompressed );
-    out.flush()
-    out.close()
+    sys.stdout.write(decompressed)
 
     exit(0)
 
commit d071d8f0c5038cdf1572168806b549a35c9a9169
Author: Noel Power <noel.power at suse.com>
Date:   Fri Oct 11 09:57:38 2013 +0100

    move helper to base class, variable names consistenty & fix exception msg

diff --git a/src/vbahelper.py b/src/vbahelper.py
index 6634ff4..face96c 100644
--- a/src/vbahelper.py
+++ b/src/vbahelper.py
@@ -4,10 +4,24 @@ class VBAStreamBase:
     def __init__(self, chars, offset):
         self.mnOffset = offset
         self.chars = chars
+ 
+    def copyTokenHelp(self):
+        difference = self.DecompressedCurrent - self.DecompressedChunkStart
+        bitCount = 0
+        while( ( 1 << bitCount ) < difference ):
+            bitCount +=1
+
+        if bitCount < 4:
+            bitCount = 4;
+
+        lengthMask = 0xFFFF >> bitCount
+        offSetMask = ~lengthMask
+        maximumLength = ( 0xFFFF >> bitCount ) + 3
+        return lengthMask, offSetMask, bitCount, maximumLength
 
 class UnCompressedVBAStream(VBAStreamBase):
     def __packCopyToken(self, offset, length ):
-        lengthMask, offSetMask, bitCount, maximumLength = self.__copyTokenHelp()
+        lengthMask, offSetMask, bitCount, maximumLength = self.copyTokenHelp()
         temp1 = offset - 1
         temp2 = 16 - bitCount
         temp3 = length - 3
@@ -17,127 +31,113 @@ class UnCompressedVBAStream(VBAStreamBase):
     def __compressRawChunk(self):
         self.CompressedCurrent = self.CompressedChunkStart + 2
         self.DecompressedCurrent  = self.DecompressedChunkStart
-        PadCount = self.CHUNKSIZE
-        LastByte = self.DecompressedChunkStart + PadCount
-        if self.DecompressedBufferEnd < LastByte:
-           LastByte =  self.DecompressedBufferEnd
+        padCount = self.CHUNKSIZE
+        lastByte = self.DecompressedChunkStart + padCount
+        if self.DecompressedBufferEnd < lastByte:
+           lastByte =  self.DecompressedBufferEnd
 
-        for index in xrange( self.DecompressedChunkStart,  LastByte ):
+        for index in xrange( self.DecompressedChunkStart,  lastByte ):
             self.CompressedContainer[ self.CompressedCurrent ] = self.chars[ index ]
             self.CompressedCurrent = self.CompressedCurrent + 1
             self.DecompressedCurrent = self.DecompressedCurrent + 1
-            PadCount = PadCount - 1
+            padCount = padCount - 1
 
-        for index in xrange( 0, PadCount ):
+        for index in xrange( 0, padCount ):
             self.CompressedContainer[ self.CompressedCurrent ] = 0x0;   
             self.CompressedCurrent = self.CompressedCurrent + 1
 
-    # #FIXME move to base class
-    def __copyTokenHelp(self):
-        difference = self.DecompressedCurrent - self.DecompressedChunkStart
-        bitCount = 0
-        while( ( 1 << bitCount ) < difference ):
-            bitCount +=1
-
-        if bitCount < 4:
-            bitCount = 4;
-
-        lengthMask = 0xFFFF >> bitCount
-        offSetMask = ~lengthMask
-        maximumLength = ( 0xFFFF >> bitCount ) + 3
-        return lengthMask, offSetMask, bitCount, maximumLength
-
-    def __matching( self, DecompressedEnd ):
-        Candidate = self.DecompressedCurrent - 1
-        BestLength = 0
-        while Candidate >= self.DecompressedChunkStart:
-            C = Candidate
-            D = self.DecompressedCurrent
-            Len = 0
-            while  D < DecompressedEnd and ( self.chars[ D ] == self.chars[ C ] ):
-                Len = Len + 1
-                C = C + 1
-                D = D + 1
-            if Len > BestLength:
-                BestLength = Len
-                BestCandidate = Candidate
-            Candidate = Candidate - 1
-        if BestLength >=  3:
-            lengthMask, offSetMask, bitCount, maximumLength = self.__copyTokenHelp()
-            Length = BestLength
-            if ( maximumLength < BestLength ):
-                Length = maximumLength 
-            Offset = self.DecompressedCurrent - BestCandidate
+    def __matching( self, decompressedEnd ):
+        candidate = self.DecompressedCurrent - 1
+        bestLength = 0
+        while candidate >= self.DecompressedChunkStart:
+            c = candidate
+            d = self.DecompressedCurrent
+            nLen = 0
+            while  d < decompressedEnd and ( self.chars[ d ] == self.chars[ c ] ):
+                nLen = nLen + 1
+                c = c + 1
+                d = d + 1
+            if nLen > bestLength:
+                bestLength = nLen
+                bestCandidate = candidate
+            candidate = candidate - 1
+        if bestLength >=  3:
+            lengthMask, offSetMask, bitCount, maximumLength = self.copyTokenHelp()
+            length = bestLength
+            if ( maximumLength < bestLength ):
+                length = maximumLength 
+            offset = self.DecompressedCurrent - bestCandidate
         else:
-            Length = 0
-            Offset = 0
-        return Offset, Length
-
-    def __compressToken( self, CompressedEnd, DecompressedEnd, index, Flags ):
-        Offset = 0
-        Offset, Length = self.__matching( DecompressedEnd )
-        if Offset:
-            if (self.CompressedCurrent + 1) < CompressedEnd:
-                copyToken = self.__packCopyToken( Offset, Length )
+            length = 0
+            offset = 0
+        return offset, length
+
+    def __compressToken( self, compressedEnd, decompressedEnd, index, flags ):
+        offset = 0
+        offset, length = self.__matching( decompressedEnd )
+        if offset:
+            if (self.CompressedCurrent + 1) < compressedEnd:
+                copyToken = self.__packCopyToken( offset, length )
                 struct.pack_into("<H", self.CompressedContainer, self.CompressedCurrent, copyToken )
 
                 temp1 = ( 1 << index )
-                temp2 = Flags & ~temp1
-                Flags = temp2 | temp1
+                temp2 = flags & ~temp1
+                flags = temp2 | temp1
 
                 self.CompressedCurrent = self.CompressedCurrent + 2
-                self.DecompressedCurrent = self.DecompressedCurrent + Length
+                self.DecompressedCurrent = self.DecompressedCurrent + length
             else:
-                self.CompressedCurrent = CompressedEnd
+                self.CompressedCurrent = compressedEnd
         else:
-            if self.CompressedCurrent < CompressedEnd:
+            if self.CompressedCurrent < compressedEnd:
                 self.CompressedContainer[ self.CompressedCurrent ] = self.chars[ self.DecompressedCurrent ]
                 self.CompressedCurrent = self.CompressedCurrent + 1
                 self.DecompressedCurrent = self.DecompressedCurrent + 1
             else:
-                self.CompressedCurrent = CompressedEnd
-        return Flags
+                self.CompressedCurrent = compressedEnd
+        return flags
 
-    def __compressTokenSequence(self, CompressedEnd, DecompressedEnd ):
-        FlagByteIndex = self.CompressedCurrent
-        TokenFlags = 0
+    def __compressTokenSequence(self, compressedEnd, decompressedEnd ):
+        flagByteIndex = self.CompressedCurrent
+        tokenFlags = 0
         self.CompressedCurrent = self.CompressedCurrent + 1
         for index in xrange(0,8): 
-            if ( ( self.DecompressedCurrent < DecompressedEnd )
-                and (self.CompressedCurrent < CompressedEnd) ):
+            if ( ( self.DecompressedCurrent < decompressedEnd )
+                and (self.CompressedCurrent < compressedEnd) ):
+
+                tokenFlags = self.__compressToken( compressedEnd, decompressedEnd, index, tokenFlags )
+        self.CompressedContainer[ flagByteIndex ] = tokenFlags
 
-                TokenFlags = self.__compressToken( CompressedEnd, DecompressedEnd, index, TokenFlags )
-        self.CompressedContainer[ FlagByteIndex ] = TokenFlags
     def __CompressDecompressedChunk(self):
         self.CompressedContainer.extend(  bytearray(self.CHUNKSIZE + 2) )
-        CompressedEnd = self.CompressedChunkStart + 4098
+        compressedEnd = self.CompressedChunkStart + 4098
         self.CompressedCurrent = self.CompressedChunkStart + 2
-        DecompressedEnd = self.DecompressedBufferEnd
+        decompressedEnd = self.DecompressedBufferEnd
         if  (self.DecompressedChunkStart + self.CHUNKSIZE) <  self.DecompressedBufferEnd:
-            DecompressedEnd = (self.DecompressedChunkStart + self.CHUNKSIZE)
+            decompressedEnd = (self.DecompressedChunkStart + self.CHUNKSIZE)
 
-        while (self.DecompressedCurrent < DecompressedEnd) and (self.CompressedCurrent < CompressedEnd):
-                self.__compressTokenSequence( CompressedEnd, DecompressedEnd)
+        while (self.DecompressedCurrent < decompressedEnd) and (self.CompressedCurrent < compressedEnd):
+                self.__compressTokenSequence( compressedEnd, decompressedEnd)
 
-        if self.DecompressedCurrent < DecompressedEnd:
-            self.__compressRawChunk( DecompressedEnd - 1 )
-            CompressedFlag = 0
+        if self.DecompressedCurrent < decompressedEnd:
+            self.__compressRawChunk( decompressedEnd - 1 )
+            compressedFlag = 0
         else:
-            CompressedFlag = 1
-        Size = self.CompressedCurrent - self.CompressedChunkStart
-        Header = 0x0000
+            compressedFlag = 1
+        size = self.CompressedCurrent - self.CompressedChunkStart
+        header = 0x0000
         #Pack CompressedChunkSize with Size and Header
-        temp1=Header & 0xF000
-        temp2 = Size - 3
-        Header = temp1 | temp2
+        temp1=header & 0xF000
+        temp2 = size - 3
+        header = temp1 | temp2
         #Pack CompressedChunkFlag with CompressedFlag and Header
-        temp1 = Header & 0x7FFF
-        temp2 = CompressedFlag << 15
-        Header = temp1 | temp2
-        #CALL Pack CompressedChunkSignature with Header
-        temp1 = Header & 0x8FFF
+        temp1 = header & 0x7FFF
+        temp2 = compressedFlag << 15
+        header = temp1 | temp2
+        #Pack CompressedChunkSignature with Header
+        temp1 = header & 0x8FFF
         Header = temp1 | 0x3000
-        #SET the CompressedChunkHeader located at CompressedChunkStart TO Header
+        #CompressedChunkHeader located at CompressedChunkStart TO Header
         struct.pack_into("<H", self.CompressedContainer, self.CompressedChunkStart, Header )
 
         # trim buffer to size
@@ -168,22 +168,8 @@ class CompressedVBAStream(VBAStreamBase):
         self.CompressedCurrent += self.CHUNKSIZE
         self.DecompressedCurrent += self.CHUNKSIZE
 
-    def __copyTokenHelp(self):
-        difference = self.DecompressedCurrent - self.DecompressedChunkStart
-        bitCount = 0
-        while( ( 1 << bitCount ) < difference ):
-            bitCount +=1
-
-        if bitCount < 4:
-            bitCount = 4;
-
-        lengthMask = 0xFFFF >> bitCount
-        offSetMask = ~lengthMask
-#        maximumLength = ( 0xFFFF >> bitCOunt ) + 3
-        return lengthMask, offSetMask, bitCount
-
     def __unPackCopyToken (self, copyToken ):
-       lengthMask, offSetMask, bitCount = self.__copyTokenHelp() 
+       lengthMask, offSetMask, bitCount, maximumLength = self.copyTokenHelp() 
        length = ( copyToken & lengthMask ) + 3
        temp1 = copyToken & offSetMask
        temp2 = 16 - bitCount
@@ -263,7 +249,7 @@ class CompressedVBAStream(VBAStreamBase):
                 self.decompressCompressedChunk()
             return self.DecompressedContainer
         else:
-            raise Exception("error decompressing container invalid signature byte %i"% val)
+            raise Exception("error decompressing container invalid signature byte %i"%val)
          
         return None
 
commit 92ede480f043411ac92e396bb73911e5c15c9e67
Author: Noel Power <noel.power at suse.com>
Date:   Thu Oct 10 21:20:55 2013 +0100

    add Compression support ( and ropey compress.py cmdline tool )
    
    The compression algorithm seems to work, e.g. the Compress/Decompress in
    testing seems symmetrical. Also the examples in [MS-OVBA].pdf
    give the expected results, looking good....

diff --git a/compress.py b/compress.py
new file mode 100755
index 0000000..ffd6d32
--- /dev/null
+++ b/compress.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python2
+
+import sys, os.path, optparse
+sys.path.append(sys.path[0]+"/src")
+import vbahelper
+
+def main():
+    if ( len ( sys.argv ) <= 1 ):
+        print("usage: compress: file [offset]")
+        sys.exit(1) 
+
+    offset = 0
+    if len ( sys.argv ) > 2:
+        offset = int(sys.argv[2])
+
+    file = open(sys.argv[1],'rb')
+    chars = file.read()
+    file.close()
+
+    decompressed = vbahelper.UnCompressedVBAStream( chars, offset )
+    compressed = decompressed.compress()
+
+    out = open( sys.argv[1] + ".compressed", 'wb' );
+    out.write( compressed );
+    out.flush()
+    out.close()
+
+    exit(0)
+
+if __name__ == '__main__':
+    main()
diff --git a/src/vbahelper.py b/src/vbahelper.py
index 3e792bf..6634ff4 100644
--- a/src/vbahelper.py
+++ b/src/vbahelper.py
@@ -1,12 +1,167 @@
 import  sys, struct
-
-class CompressedVBAStream(object):
-    
+class VBAStreamBase:
     CHUNKSIZE = 4096
-    def __init__ (self,chars, offset):
-        self.chars = chars
+    def __init__(self, chars, offset):
         self.mnOffset = offset
+        self.chars = chars
+
+class UnCompressedVBAStream(VBAStreamBase):
+    def __packCopyToken(self, offset, length ):
+        lengthMask, offSetMask, bitCount, maximumLength = self.__copyTokenHelp()
+        temp1 = offset - 1
+        temp2 = 16 - bitCount
+        temp3 = length - 3
+        copyToken = (temp1 << temp2) | temp3
+        return copyToken
+
+    def __compressRawChunk(self):
+        self.CompressedCurrent = self.CompressedChunkStart + 2
+        self.DecompressedCurrent  = self.DecompressedChunkStart
+        PadCount = self.CHUNKSIZE
+        LastByte = self.DecompressedChunkStart + PadCount
+        if self.DecompressedBufferEnd < LastByte:
+           LastByte =  self.DecompressedBufferEnd
+
+        for index in xrange( self.DecompressedChunkStart,  LastByte ):
+            self.CompressedContainer[ self.CompressedCurrent ] = self.chars[ index ]
+            self.CompressedCurrent = self.CompressedCurrent + 1
+            self.DecompressedCurrent = self.DecompressedCurrent + 1
+            PadCount = PadCount - 1
+
+        for index in xrange( 0, PadCount ):
+            self.CompressedContainer[ self.CompressedCurrent ] = 0x0;   
+            self.CompressedCurrent = self.CompressedCurrent + 1
+
+    # #FIXME move to base class
+    def __copyTokenHelp(self):
+        difference = self.DecompressedCurrent - self.DecompressedChunkStart
+        bitCount = 0
+        while( ( 1 << bitCount ) < difference ):
+            bitCount +=1
 
+        if bitCount < 4:
+            bitCount = 4;
+
+        lengthMask = 0xFFFF >> bitCount
+        offSetMask = ~lengthMask
+        maximumLength = ( 0xFFFF >> bitCount ) + 3
+        return lengthMask, offSetMask, bitCount, maximumLength
+
+    def __matching( self, DecompressedEnd ):
+        Candidate = self.DecompressedCurrent - 1
+        BestLength = 0
+        while Candidate >= self.DecompressedChunkStart:
+            C = Candidate
+            D = self.DecompressedCurrent
+            Len = 0
+            while  D < DecompressedEnd and ( self.chars[ D ] == self.chars[ C ] ):
+                Len = Len + 1
+                C = C + 1
+                D = D + 1
+            if Len > BestLength:
+                BestLength = Len
+                BestCandidate = Candidate
+            Candidate = Candidate - 1
+        if BestLength >=  3:
+            lengthMask, offSetMask, bitCount, maximumLength = self.__copyTokenHelp()
+            Length = BestLength
+            if ( maximumLength < BestLength ):
+                Length = maximumLength 
+            Offset = self.DecompressedCurrent - BestCandidate
+        else:
+            Length = 0
+            Offset = 0
+        return Offset, Length
+
+    def __compressToken( self, CompressedEnd, DecompressedEnd, index, Flags ):
+        Offset = 0
+        Offset, Length = self.__matching( DecompressedEnd )
+        if Offset:
+            if (self.CompressedCurrent + 1) < CompressedEnd:
+                copyToken = self.__packCopyToken( Offset, Length )
+                struct.pack_into("<H", self.CompressedContainer, self.CompressedCurrent, copyToken )
+
+                temp1 = ( 1 << index )
+                temp2 = Flags & ~temp1
+                Flags = temp2 | temp1
+
+                self.CompressedCurrent = self.CompressedCurrent + 2
+                self.DecompressedCurrent = self.DecompressedCurrent + Length
+            else:
+                self.CompressedCurrent = CompressedEnd
+        else:
+            if self.CompressedCurrent < CompressedEnd:
+                self.CompressedContainer[ self.CompressedCurrent ] = self.chars[ self.DecompressedCurrent ]
+                self.CompressedCurrent = self.CompressedCurrent + 1
+                self.DecompressedCurrent = self.DecompressedCurrent + 1
+            else:
+                self.CompressedCurrent = CompressedEnd
+        return Flags
+
+    def __compressTokenSequence(self, CompressedEnd, DecompressedEnd ):
+        FlagByteIndex = self.CompressedCurrent
+        TokenFlags = 0
+        self.CompressedCurrent = self.CompressedCurrent + 1
+        for index in xrange(0,8): 
+            if ( ( self.DecompressedCurrent < DecompressedEnd )
+                and (self.CompressedCurrent < CompressedEnd) ):
+
+                TokenFlags = self.__compressToken( CompressedEnd, DecompressedEnd, index, TokenFlags )
+        self.CompressedContainer[ FlagByteIndex ] = TokenFlags
+    def __CompressDecompressedChunk(self):
+        self.CompressedContainer.extend(  bytearray(self.CHUNKSIZE + 2) )
+        CompressedEnd = self.CompressedChunkStart + 4098
+        self.CompressedCurrent = self.CompressedChunkStart + 2
+        DecompressedEnd = self.DecompressedBufferEnd
+        if  (self.DecompressedChunkStart + self.CHUNKSIZE) <  self.DecompressedBufferEnd:
+            DecompressedEnd = (self.DecompressedChunkStart + self.CHUNKSIZE)
+
+        while (self.DecompressedCurrent < DecompressedEnd) and (self.CompressedCurrent < CompressedEnd):
+                self.__compressTokenSequence( CompressedEnd, DecompressedEnd)
+
+        if self.DecompressedCurrent < DecompressedEnd:
+            self.__compressRawChunk( DecompressedEnd - 1 )
+            CompressedFlag = 0
+        else:
+            CompressedFlag = 1
+        Size = self.CompressedCurrent - self.CompressedChunkStart
+        Header = 0x0000
+        #Pack CompressedChunkSize with Size and Header
+        temp1=Header & 0xF000
+        temp2 = Size - 3
+        Header = temp1 | temp2
+        #Pack CompressedChunkFlag with CompressedFlag and Header
+        temp1 = Header & 0x7FFF
+        temp2 = CompressedFlag << 15
+        Header = temp1 | temp2
+        #CALL Pack CompressedChunkSignature with Header
+        temp1 = Header & 0x8FFF
+        Header = temp1 | 0x3000
+        #SET the CompressedChunkHeader located at CompressedChunkStart TO Header
+        struct.pack_into("<H", self.CompressedContainer, self.CompressedChunkStart, Header )
+
+        # trim buffer to size
+        if ( self.CompressedCurrent ):
+            self.CompressedContainer = self.CompressedContainer[ 0:self.CompressedCurrent ]
+
+    def compress(self):
+        self.CompressedContainer = bytearray()
+        self.CompressedCurrent = 0
+        self.CompressedChunkStart = 0
+        self.DecompressedCurrent = 0
+        self.DecompressedBufferEnd = len(self.chars)
+        self.DecompressedChunkStart = 0
+        SignatureByte = 0x01
+        self.CompressedContainer.append( SignatureByte )
+        self.CompressedCurrent = self.CompressedCurrent + 1
+        while self.DecompressedCurrent < self.DecompressedBufferEnd:
+            self.CompressedChunkStart = self.CompressedCurrent
+            self.DecompressedChunkStart = self.DecompressedCurrent
+            self.__CompressDecompressedChunk()
+        return self.CompressedContainer
+
+class CompressedVBAStream(VBAStreamBase):
+    
     def __decompressRawChunk (self):
         for i in xrange(0,self.CHUNKSIZE):
             self.DecompressedChunk[ self.DecompressedCurrent + i ] =  self.chars[self.CompressedCurrent + i ]
@@ -99,7 +254,7 @@ class CompressedVBAStream(object):
         self.CompressedCurrent = self.mnOffset
         self.CompressedRecordEnd = len(self.chars )
         self.DeCompressedBufferEnd = 0
-        self.DecompressedChunkStart = self.CompressedCurrent 
+        self.DecompressedChunkStart = 0
         val = struct.unpack("b", self.chars[self.CompressedCurrent])[0]
         if val == 1:
             self.CompressedCurrent += 1
diff --git a/vbadump.py b/vbadump.py
index 576d541..a606e9f 100755
--- a/vbadump.py
+++ b/vbadump.py
@@ -26,7 +26,7 @@ codePageMap = {
     869: "cp869",        #IBM_869;
     874: "cp874",        #MS_874;
     932: "cp932",        #MS_932;
-#    936: "".             #MS_936;
+    936: "cp936",        #MS_936;
     949: "cp949",        #MS_949;
     950: "cp950",        #MS_950;
     1250: "cp1250",      #MS_1250;
commit ed0bf5c9459223fc65209295175c9296fc202a25
Author: Noel Power <noel.power at suse.com>
Date:   Thu Oct 10 11:47:48 2013 +0100

    add map of codepage values to python codecnames

diff --git a/vbadump.py b/vbadump.py
index e9a8312..576d541 100755
--- a/vbadump.py
+++ b/vbadump.py
@@ -4,6 +4,79 @@ import sys, os.path, optparse, math
 sys.path.append(sys.path[0]+"/src")
 import ole, globals, node, olestream, vbahelper
 
+#codepage -> codepagename map
+# note: there are some missing entries ( the commented out ones ) that
+# I couldn't find in python docs ... library/codecs.html
+codePageMap = {
+    437: "cp437",        #IBM_437
+    708: "iso8859_6",    #ISO_8859_6
+    737: "cp737",        #IBM_737
+    775: "cp775",        #IBM_775;
+    850: "cp850",        #IBM_850;
+    852: "cp852",        #IBM_852;
+    855: "cp855",        #IBM_855;
+    857: "cp857",        #IBM_857;
+    860: "cp860",        #IBM_860;
+    861: "cp861",        #IBM_861;
+    862: "cp862",        #IBM_862;
+    863: "cp863",        #IBM_863;
+    864: "cp864",        #IBM_864;
+    865: "cp865",        #IBM_865;
+    866: "cp866",        #IBM_866;
+    869: "cp869",        #IBM_869;
+    874: "cp874",        #MS_874;
+    932: "cp932",        #MS_932;
+#    936: "".             #MS_936;
+    949: "cp949",        #MS_949;
+    950: "cp950",        #MS_950;
+    1250: "cp1250",      #MS_1250;
+    1251: "cp1251",      #MS_1251;
+    1252: "cp1252",      #MS_1252;
+    1253: "cp1253",      #MS_1253;
+    1254: "cp1254",      #MS_1254;
+    1255: "cp1255",      #MS_1255;
+    1256: "cp1256",      #MS_1256;
+    1257: "cp1257",      #MS_1257;
+    1258: "cp1258",      #MS_1258;
+    1361: "cp1361",      #MS_1361;
+    10000: "macroman",   #APPLE_ROMAN;
+#    10001: "",           #APPLE_JAPANESE;
+#    10002: "",           #APPLE_CHINTRAD;
+#    10003: "",           #APPLE_KOREAN;
+    10004: "mac_arabic", #APPLE_ARABIC;
+#    10005: "",           #APPLE_HEBREW;
+    10006: "mac_greek",    #APPLE_GREEK;
+    10007: "mac_cyrillic", #APPLE_CYRILLIC;
+#    10008: "",           #APPLE_CHINSIMP;
+#    10010: "",           #APPLE_ROMANIAN;
+#    10017: "",           #APPLE_UKRAINIAN;
+    10029: "mac_latin2", #APPLE_CENTEURO;
+    10079: "mac_iceland",#APPLE_ICELAND;
+    10081: "mac_turkish",#APPLE_TURKISH;
+#    10082: "",           #APPLE_CROATIAN;
+    20127: "ascii",      #ASCII_US;
+    20866: "koi8",       #KOI8_R;
+    21866: "koi8",       #KOI8_U;
+    28591: "latin_1",    #ISO_8859_1;
+    28592: "iso8859_2",  #ISO_8859_2;
+    28593: "iso8859_3",  #ISO_8859_3;
+    28594: "iso8859_4",  #ISO_8859_4;
+    28595: "iso8859_5",  #ISO_8859_5;
+    28596: "iso8859_6",  #ISO_8859_6;
+    28597: "iso8859_7",  #ISO_8859_7;
+    28598: "iso8859_8",  #ISO_8859_8;
+    28599: "iso8859_9",  #ISO_8859_9;
+    28605: "iso8859_15", #ISO_8859_15;
+    50220: "iso2022_jp", #ISO_2022_JP;
+    50225: "iso2022_kr", #ISO_2022_KR;
+    51932: "euc_jp",     #EUC_JP;
+    51936: "gb2312",     #EUC_CN;
+    51949: "euc_kr",     #EUC_KR;
+#    57002: "",           #ISCII_DEVANAGARI;
+    65000: "utf_7",      #UTF7;
+    65001: "utf_8",      #UTF8;
+}
+
 # alot of records follow the id, sizeofrecord pattern
 # many of the dir records though seem to be id, sizeofstring,
 # stringbuffer, reserved, sizeofstring(unicode), stringbuffer(unicode)
@@ -25,10 +98,11 @@ class DefaultBuffReservedBuffReader:
 class StdReader:
     def __init__ (self, reader ):
         self.reader = reader
+    # subclass needs to implement this
+    def parse(self): 
+        pass
 
-class ProjectVersionReader:
-    def __init__ (self, reader ):
-        self.reader = reader
+class ProjectVersionReader( StdReader ):
     def parse(self):
         # reserved
         self.reader.readBytes(4)
@@ -43,9 +117,10 @@ class CodePageReader(StdReader):
         size = self.reader.readUnsignedInt( 4 )
         self.reader.codepage = self.reader.readUnsignedInt( size )
 
-        #need a map of codepage code (int) to codepage alias(s) from
-        # #FIXME codepage is hardcoded below
+        #default codepage to something reasonable
         self.reader.codepageName = "cp1252"
+        if codePageMap.has_key( self.reader.codepage ):
+            self.reader.codepageName = codePageMap[  self.reader.codepage ]
         print("  codepage: %i"%self.reader.codepage)
      
 class ProjectNameReader(StdReader):
commit a22826f1536752f48f1f9321aa2261a079c38cd7
Author: Noel Power <noel.power at suse.com>
Date:   Thu Oct 10 10:16:33 2013 +0100

    reorganise code
    
    moved OleContainer to ole module
    moved VBA dumper functionality from oletool.py to vbadump.py
    adapted oletool.py

diff --git a/src/ole.py b/src/ole.py
index 150b1cc..cc4c584 100644
--- a/src/ole.py
+++ b/src/ole.py
@@ -762,3 +762,177 @@ entire file stream.
 
         return entry
 
+class DateTime:
+    def __init__(self):
+        self.day = 0
+        self.month = 0 
+        self.year = 0
+        self.hour = 0
+        self.second = 0
+
+class DirNode:
+
+    def __init__(self, entry, olecontainer):
+        self.Nodes = []
+        self.Entry = entry;
+        self.HierachicalName = ''
+        self.OleContainer = olecontainer
+    def isStorage(self):
+        return self.Entry.DirIDRoot > 0
+
+    def getName(self):
+        return self.Entry.Name
+
+    def getHierarchicalName(self):
+        return self.HierachicalName
+
+    def getChildren(self):
+        return self.Nodes  
+
+    def getStream(self):
+        return self.OleContainer.getStreamForEntry( self.Entry )
+
+class OleContainer:
+
+    def __init__(self,filePath, params ):
+        self.filePath = filePath
+        self.header = None
+        self.rootNode = None
+        self.params = params
+        
+    def __getModifiedTime(self, entry):
+        # need parse/decode Entry.TimeModified
+        # ( although the documentation indicates that it might not be
+        # worth it 'cause they are not universally used
+        modified  = DateTime
+        modified.day = 0
+        modified.month = 0 
+        modified.year = 0
+        modified.hour = 0
+        modified.second = 0
+        return modified
+
+    def __parseFile (self):
+        if self.rootNode == None:
+            file = open(self.filePath, 'rb')
+            self.chars = file.read()
+            file.close()    
+            self.header = Header(self.chars, self.params)
+            self.header.parse()
+            self.obj = self.header.getDirectory()
+            self.obj.parseDirEntries()
+            count = 0
+            self.rootNode = self.__buildTree( self.obj.entries )   
+
+    def __addSiblings( self, entries, parent, child ):
+        # add left siblings
+        nextLeft = child.Entry.DirIDLeft
+        if ( nextLeft > 0 ):
+            newEntry = DirNode( entries[ nextLeft ], self )
+#            newEntry.HierachicalName = parent.HierachicalName + globals.encodeName( newEntry.Entry.Name )
+            newEntry.HierachicalName = parent.HierachicalName + newEntry.Entry.Name
+            if  newEntry.Entry.DirIDRoot > 0:
+                newEntry.HierachicalName = newEntry.HierachicalName + '/'
+
+            self.__addSiblings( entries, parent, newEntry ) 
+            parent.Nodes.insert( 0, newEntry )
+
+        nextRight = child.Entry.DirIDRight
+        # add children to the right 
+        if ( nextRight > 0 ):
+            newEntry = DirNode( entries[ nextRight ], self )
+#            newEntry.HierachicalName = parent.HierachicalName + globals.encodeName( newEntry.Entry.Name )
+            newEntry.HierachicalName = parent.HierachicalName + newEntry.Entry.Name
+            if  newEntry.Entry.DirIDRoot > 0:
+                newEntry.HierachicalName = newEntry.HierachicalName + '/'
+            self.__addSiblings( entries, parent, newEntry ) 
+            parent.Nodes.append( newEntry )
+
+    def __buildTreeImpl(self, entries, parent ):
+
+        if ( parent.Entry.DirIDRoot > 0 ):
+            newEntry = DirNode( entries[ parent.Entry.DirIDRoot ], self )
+#            newEntry.HierachicalName = parent.HierachicalName + globals.encodeName( newEntry.Entry.Name )
+            newEntry.HierachicalName = parent.HierachicalName +  newEntry.Entry.Name
+            if ( newEntry.Entry.DirIDRoot > 0 ):
+                newEntry.HierachicalName =  newEntry.HierachicalName + '/'
+
+            self.__addSiblings( entries, parent, newEntry )
+            parent.Nodes.append( newEntry )
+            
+        for child in parent.Nodes:
+            if child.Entry.DirIDRoot > 0:
+                self.__buildTreeImpl( entries, child )
+
+    def __buildTree(self, entries ):
+        treeRoot = DirNode( entries[0], self ) 
+        self.__buildTreeImpl( entries, treeRoot )
+        return treeRoot
+
+    def __findEntryByHierachicalName( self, node, name ):
+        if node.HierachicalName == name:
+            return node.Entry
+        else:
+            for child in node.Nodes:
+                result = self.__findEntryByHierachicalName( child, name )
+                if result != None:
+                    return result 
+        return None 
+
+    def __printListReport( self, treeNode ):
+
+        dateInfo = self.__getModifiedTime( treeNode.Entry )
+
+        if len( treeNode.HierachicalName ) > 0 :
+            print '{0:8d}  {1:0<2d}-{2:0<2d}-{3:0<2d} {4:0<2d}:{5:0<2d}   {6}'.format(treeNode.Entry.StreamSize, dateInfo.day, dateInfo.month, dateInfo.year, dateInfo.hour, dateInfo.second, treeNode.HierachicalName )
+     
+        for node in treeNode.Nodes:
+            # ignore the root
+            self.__printListReport( node )
+
+    def __printHeader(self):
+        print ("OLE: %s")%self.filePath
+        print (" Length     Date   Time    Name")
+        print ("--------    ----   ----    ----")
+
+    def list(self):
+        # need to share the inititialisation and parse stuff between the different options
+       
+        self.__parseFile()
+        if  self.rootNode != None:
+            self.__printHeader()
+            self.__printListReport( self.rootNode )
+            # need to print a footer ( total bytes, total files like unzip )
+
+    def getStreamForEntry( self, entry ):
+        if  entry == None or entry.DirIDRoot > 0 :
+            raise Exception("can't get stream for invalid entry")
+        bytes = bytearray()
+        bytes = self.obj.getRawStream( entry )
+        bytes = bytes[0:entry.StreamSize]
+        return bytes
+
+    def getStreamForName( self, name ):
+        self.__parseFile()
+        if  self.rootNode != None:
+            entry = self.__findEntryByHierachicalName( self.rootNode, name )
+            return self.getStreamForEntry( entry )
+
+    def extract(self, name):
+        self.__parseFile()
+        if  self.rootNode != None:
+            entry = self.__findEntryByHierachicalName( self.rootNode, name )
+            bytes = self.getStreamForEntry( entry )
+            file = open(entry.Name, 'wb') 
+            file.write( bytes )
+            file.close
+        else:
+            print("failed to initialise ole container")
+
+    def read(self):
+        self.__parseFile()
+
+    def getRoot(self):
+        self.__parseFile()
+        return self.rootNode 
+
diff --git a/src/oletool.py b/src/oletool.py
index ac0a57a..b11d78e 100755
--- a/src/oletool.py
+++ b/src/oletool.py
@@ -26,538 +26,16 @@
 #
 ########################################################################
 
-import sys, os.path, optparse, math
+import sys, os.path, optparse
 sys.path.append(sys.path[0]+"/src")
 
-import ole, globals, vbahelper
+import ole, globals
 
-class DateTime:
-    def __init__(self):
-        self.day = 0
-        self.month = 0 
-        self.year = 0
-        self.hour = 0
-        self.second = 0
-
-class DirNode:
-
-    def __init__(self, entry, olecontainer):
-        self.Nodes = []
-        self.Entry = entry;
-        self.HierachicalName = ''
-        self.OleContainer = olecontainer
-    def isStorage(self):
-        return self.Entry.DirIDRoot > 0
-
-    def getName(self):
-        return self.Entry.Name
-
-    def getHierarchicalName(self):
-        return self.HierachicalName
-
-    def getChildren(self):
-        return self.Nodes  
-
-    def getStream(self):
-        return self.OleContainer.getStreamForEntry( self.Entry )
-
-class OleContainer:
-
-    def __init__(self,filePath, params ):
-        self.filePath = filePath
-        self.header = None
-        self.rootNode = None
-        self.params = params
-        
-    def __getModifiedTime(self, entry):
-        # need parse/decode Entry.TimeModified
-        # ( although the documentation indicates that it might not be
-        # worth it 'cause they are not universally used
-        modified  = DateTime
-        modified.day = 0
-        modified.month = 0 
-        modified.year = 0
-        modified.hour = 0
-        modified.second = 0
-        return modified
-
-    def __parseFile (self):
-        if self.rootNode == None:
-            file = open(self.filePath, 'rb')
-            self.chars = file.read()
-            file.close()    
-            self.header = ole.Header(self.chars, self.params)
-            self.header.parse()
-            self.obj = self.header.getDirectory()
-            self.obj.parseDirEntries()
-            count = 0
-            self.rootNode = self.__buildTree( self.obj.entries )   
-
-    def __addSiblings( self, entries, parent, child ):
-        # add left siblings
-        nextLeft = child.Entry.DirIDLeft
-        if ( nextLeft > 0 ):
-            newEntry = DirNode( entries[ nextLeft ], self )
-#            newEntry.HierachicalName = parent.HierachicalName + globals.encodeName( newEntry.Entry.Name )
-            newEntry.HierachicalName = parent.HierachicalName + newEntry.Entry.Name
-            if  newEntry.Entry.DirIDRoot > 0:
-                newEntry.HierachicalName = newEntry.HierachicalName + '/'
-
-            self.__addSiblings( entries, parent, newEntry ) 
-            parent.Nodes.insert( 0, newEntry )
-
-        nextRight = child.Entry.DirIDRight
-        # add children to the right 
-        if ( nextRight > 0 ):
-            newEntry = DirNode( entries[ nextRight ], self )
-#            newEntry.HierachicalName = parent.HierachicalName + globals.encodeName( newEntry.Entry.Name )
-            newEntry.HierachicalName = parent.HierachicalName + newEntry.Entry.Name
-            if  newEntry.Entry.DirIDRoot > 0:
-                newEntry.HierachicalName = newEntry.HierachicalName + '/'
-            self.__addSiblings( entries, parent, newEntry ) 
-            parent.Nodes.append( newEntry )
-
-    def __buildTreeImpl(self, entries, parent ):
-
-        if ( parent.Entry.DirIDRoot > 0 ):
-            newEntry = DirNode( entries[ parent.Entry.DirIDRoot ], self )
-#            newEntry.HierachicalName = parent.HierachicalName + globals.encodeName( newEntry.Entry.Name )
-            newEntry.HierachicalName = parent.HierachicalName +  newEntry.Entry.Name
-            if ( newEntry.Entry.DirIDRoot > 0 ):
-                newEntry.HierachicalName =  newEntry.HierachicalName + '/'
-
-            self.__addSiblings( entries, parent, newEntry )
-            parent.Nodes.append( newEntry )
-            
-        for child in parent.Nodes:
-            if child.Entry.DirIDRoot > 0:
-                self.__buildTreeImpl( entries, child )
-
-    def __buildTree(self, entries ):
-        treeRoot = DirNode( entries[0], self ) 
-        self.__buildTreeImpl( entries, treeRoot )
-        return treeRoot
-
-    def __findEntryByHierachicalName( self, node, name ):
-        if node.HierachicalName == name:
-            return node.Entry
-        else:
-            for child in node.Nodes:
-                result = self.__findEntryByHierachicalName( child, name )
-                if result != None:
-                    return result 
-        return None 
-
-    def __printListReport( self, treeNode ):
-
-        dateInfo = self.__getModifiedTime( treeNode.Entry )
-
-        if len( treeNode.HierachicalName ) > 0 :
-            print '{0:8d}  {1:0<2d}-{2:0<2d}-{3:0<2d} {4:0<2d}:{5:0<2d}   {6}'.format(treeNode.Entry.StreamSize, dateInfo.day, dateInfo.month, dateInfo.year, dateInfo.hour, dateInfo.second, treeNode.HierachicalName )
-     
-        for node in treeNode.Nodes:
-            # ignore the root
-            self.__printListReport( node )
-
-    def __printHeader(self):
-        print ("OLE: %s")%self.filePath
-        print (" Length     Date   Time    Name")
-        print ("--------    ----   ----    ----")
-
-    def list(self):
-        # need to share the inititialisation and parse stuff between the different options
-       
-        self.__parseFile()
-        if  self.rootNode != None:
-            self.__printHeader()
-            self.__printListReport( self.rootNode )
-            # need to print a footer ( total bytes, total files like unzip )
-
-    def getStreamForEntry( self, entry ):
-        if  entry == None or entry.DirIDRoot > 0 :
-            raise Exception("can't get stream for invalid entry")
-        bytes = bytearray()
-        bytes = self.obj.getRawStream( entry )
-        bytes = bytes[0:entry.StreamSize]
-        return bytes
-
-    def getStreamForName( self, name ):
-        self.__parseFile()
-        if  self.rootNode != None:
-            entry = self.__findEntryByHierachicalName( self.rootNode, name )
-            return self.getStreamForEntry( entry )
-
-    def extract(self, name):
-        self.__parseFile()
-        if  self.rootNode != None:
-            entry = self.__findEntryByHierachicalName( self.rootNode, name )
-            bytes = self.getStreamForEntry( entry )
-            file = open(entry.Name, 'wb') 
-            file.write( bytes )
-            file.close
-        else:
-            print("failed to initialise ole container")
-
-    def read(self):
-        self.__parseFile()
-
-    def getRoot(self):
-        self.__parseFile()
-        return self.rootNode 
-
-# alot of records follow the id, sizeofrecord pattern
-# many of the dir records though seem to be id, sizeofstring,
-# stringbuffer, reserved, sizeofstring(unicode), stringbuffer(unicode)
-class DefaultBuffReservedBuffReader:
-    def __init__ (self, reader ):
-        self.reader = reader
-    def parse(self):
-        # pos before header
-        print ("  skipping")
-        # buffer
-        size = self.reader.readUnsignedInt( 4 )
-        self.reader.readBytes(size)        
-        # reserved
-        self.reader.readBytes(2)        
-        # buffer
-        size = self.reader.readUnsignedInt( 4 )
-        self.reader.readBytes(size)    
-
-class StdReader:
-    def __init__ (self, reader ):
-        self.reader = reader
-
-class ProjectVersionReader:
-    def __init__ (self, reader ):
-        self.reader = reader
-    def parse(self):
-        # reserved
-        self.reader.readBytes(4)
-        # major
-        major = self.reader.readUnsignedInt( 4 )
-        minor = self.reader.readUnsignedInt( 2 )
-        print("  major: 0x%x"%major)
-        print("  minor: 0x%x"%minor)
-
-class CodePageReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        self.reader.codepage = self.reader.readUnsignedInt( size )
-
-        #need a map of codepage code (int) to codepage alias(s) from
-        # #FIXME codepage is hardcoded below
-        self.reader.codepageName = "cp1252"
-        print("  codepage: %i"%self.reader.codepage)
-     
-class ProjectNameReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  ProjectName: %s"%bytes.decode(self.reader.codepageName))
-                 
-class DocStringRecordReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  DocString: %s size[0x%x]"%(bytes.decode(self.reader.codepageName),size))
-        #reserved
-        self.reader.readBytes( 2 )
-        #unicode docstring
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  DocString(utf-16): %s size[0x%x]"%(bytes.decode("utf-16").decode(self.reader.codepageName), size ))
-
-class ConstantsRecordReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  Constants: size[0x%x]"%size)
-        if size:
-            print("%s"%bytes.decode(self.reader.codepageName))
-        #reserved
-        self.reader.readBytes( 2 )
-        #unicode docstring
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  Constants(Utf-16): size[0x%x]"%size)
-        if size:
-            print("%s"%bytes.decode("uft-16").decode(self.reader.codepageName))
-
-class ProjectHelpFilePathReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  HelpFile1: %s size[0x%x]"%(bytes.decode(self.reader.codepageName),size))
-        #reserved
-        self.reader.readBytes( 2 )
-        #unicode docstring
-        size = self.reader.readUnsignedInt( 4 )
-        bytes = self.reader.readBytes( size )
-        print("  HelpFile2: %s size[0x%x]"%(bytes.decode(self.reader.codepageName), size ))
-
-class ProjectHelpFileContextReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        context = self.reader.readUnsignedInt( size )
-        print("  HelpContext: 0x%x"%context)
-
-class ProjectModulesReader(StdReader):
-    def parse(self):
-        # start of module specific data
-        size = self.reader.readUnsignedInt( 4 )
-        count = self.reader.readUnsignedInt( size )
-        self.reader.CurrentModule = ModuleInfo()
-        print("  Num Modules: %i"%count) 
-
-class ModuleNameReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        nameBytes = self.reader.readBytes( size )
-        moduleInfo = self.reader.CurrentModule
-        moduleInfo.name = nameBytes.decode( self.reader.codepageName )
-        print("  ModuleName: %s"%moduleInfo.name)
-
-class ModuleStreamNameReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        nameBytes = self.reader.readBytes( size )
-        moduleInfo = self.reader.CurrentModule
-        moduleInfo.streamname = nameBytes.decode( self.reader.codepageName )
-        print("  ModuleStreamName: %s"%moduleInfo.name)
-        #reserved
-        self.reader.readBytes( 2 )
-        size = self.reader.readUnsignedInt( 4 )
-        nameUnicodeBytes = self.reader.readBytes( size )
-        nameUnicode = nameUnicodeBytes.decode("utf-16").decode( self.reader.codepageName)
-        print("  ModuleStreamName(utf-16): %s"%nameUnicode)
-
-class ModuleOffSetReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        moduleInfo = self.reader.CurrentModule
-        moduleInfo.offset = self.reader.readUnsignedInt( size )
-     
-        print("  Offset: 0x%x"%moduleInfo.offset) 
-
-class ProjectModuleTermReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        # size must be zero ( assert? )
-        moduleInfo = self.reader.CurrentModule
-        self.reader.CurrentModule = ModuleInfo()
-        # add current module to list
-        self.reader.Modules.append( moduleInfo )
-
-class ModuleTypeProceduralReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        # size must be zero ( assert? )
-        print("  Module Type: procedure")
-
-class ModuleTypeOtherReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        # size must be zero ( assert? )
-        print("  Module Type: document, class or design")
-
-class SysKindReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        val = self.reader.readUnsignedInt( size )
-        sysKind = "Unknown" 
-        if val == 0:
-           sysKind = "16 bit windows" 
-        elif val == 1:
-           sysKind = "32 bit windows" 
-        elif val == 2:
-           sysKind = "Macintosh" 
-        print("  SysType: %s"%sysKind)
-
-class LcidReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        val = self.reader.readUnsignedInt( size )
-        print("  LCID: 0x%x ( expected 0x409 )"%val)
-   
-class LcidInvokeReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        val = self.reader.readUnsignedInt( size )
-        print("  LCIDINVOKE: 0x%x ( expected 0x409 )"%val)
-   
-
-class LibFlagReader(StdReader):
-    def parse(self):
-        size = self.reader.readUnsignedInt( 4 )
-        val = self.reader.readUnsignedInt( size )
-        print("  LIBFLAGS: 0x%x"%val)
-
-# map of record id to array containing description of records and optional
-# a handler ( inspired by xlsstream.py )
-dirRecordData = {
-    #dir stream contains........
-    #PROJECTINFORMATION RECORD
-    #  which contains any of the following sub records
-    0x0001: ["PROJECTSYSKIND", "SysKindRecord",SysKindReader],
-    0x0002: ["PROJECTLCID", "LcidRecord",LcidReader],
-    0x0003: ["PROJECTCODEPAGE", "CodePageRecord", CodePageReader ],
-    0x0004: ["PROJECTNAME", "NameRecord", ProjectNameReader],
-    0x0005: ["PROJECTDOCSTRING", "DocStringRecord", DocStringRecordReader ],
-    0x0006: ["PROJECTHELPFILEPATH", "HelpFilePathRecord", ProjectHelpFilePathReader],
-    0x0007: ["PROJECTHELPCONTEXT", "HelpContextRecord", ProjectHelpFileContextReader],
-    0x0008: ["PROJECTLIBFLAGS", "LibFlagsRecord",LibFlagReader],
-    0x0009: ["PROJECTVERSION", "VersionRecord",ProjectVersionReader],
-    0x0010: ["DIRTERMINATOR", "DirTerminator"],
-    0x000C: ["PROJECTCONSTANTS", "ConstantsRecord", ConstantsRecordReader],
-    0x0014: ["PROJECTLCIDINVOKE", "LcidInvokeRecord",LcidInvokeReader],
-    #PROJECTREFERENCES
-    # which contains any of the following sub records
-    0x0016: ["REFERENCENAME", "NameRecord", DefaultBuffReservedBuffReader ],
-    0x000D: ["REFERENCEREGISTERED", "ReferenceRegistered"],
-    0x000E: ["REFERENCEPROJECT", "ReferenceProject"],
-    0x002F: ["REFERENCECONTROL", "ReferenceControl"],
-    #the following "FAKE-#FIXME record is not really a record but actually
-    #is a reserved word ( with fixed value 0x0030 ) in the middle of a
-    #REFEREBCECONTROL record
-    0x0030: ["FAKE-#FIXME", "Fake record"],
-    0x0033: ["REFERENCEORIGINAL", "ReferenceOriginal"],
-    #
-    0x000F: ["PROJECTMODULES", "ModulesRecord", ProjectModulesReader],
-    0x0013: ["PROJECTCOOKIE", "CookieRecord"],
-    0x002B: ["PROJECTMODULETERM", "ModuleTerminator", ProjectModuleTermReader],
-    0x0019: ["MODULENAME", "ModuleName",ModuleNameReader],
-    0x0047: ["MODULENAMEUNICODE", "ModuleNameUnicode"],
-    0x001A: ["MODULESTREAMNAME", "ModuleStreamName", ModuleStreamNameReader],
-    0x001C: ["MODULEDOCSTRING", "ModuleDocString", DefaultBuffReservedBuffReader],
-    0x0031: ["MODULEOFFSET", "ModuleOffSet", ModuleOffSetReader],
-    0x001E: ["MODULEHELPCONTEXT", "ModuleHelpContext"],
-    0x002C: ["MODULECOOKIE", "ModuleCookie"],
-    0x0021: ["MODULETYPE", "ModuleTypeProcedural", ModuleTypeProceduralReader],
-    0x0022: ["MODULETYPE", "ModuleTypeDocClassOrDesgn", ModuleTypeOtherReader],
-    0x0025: ["MODULEREADONLY", "ModuleReadOnly"],
-    0x0028: ["MODULEPRIVATE", "ModulePrivate"],
-}    
-
-
-class ModuleInfo:
-    def __init__(self):
-        self.name = ""
-        self.offset = 0
-        self.streamname = "" 
-        
-class DirStreamReader( globals.ByteStream ): 
-    def __init__ (self, bytes ):
-        globals.ByteStream.__init__(self, bytes)
-        self.Modules = []
-        self.CodePage = None
-        self.CurrentModule = None
-
-    def parse(self):
-        print("============ Dir Stream (inflated) size: 0x%x bytes ============"%len(self.bytes))
-        print("")
-        print("Offset  [recId]  RecordName")
-        print("------- -------  -----------")
-        while self.isEndOfRecord() == False:
-            pos = self.getCurrentPos()
-            recordID = self.readUnsignedInt( 2 )
-            name = "Unknown"
-            if dirRecordData.has_key( recordID ):
-                name = dirRecordData[ recordID ][0]
-            # if we have a handler let it deal with the record
-            labelWidth = int(math.ceil(math.log(len(self.bytes), 10)))
-            fmt = "0x%%%d.%dx: "%(labelWidth, labelWidth)
-            sys.stdout.write(fmt%pos)
-#            print ("%s [0x%x] "%(name,recordID))
-            print '[0x{0:0>4x}] {1}'.format(recordID,name)
-            if ( dirRecordData.has_key( recordID ) and len( dirRecordData[ recordID ] ) > 2 ):
-                reader = dirRecordData[ recordID ][2]( self )
-                reader.parse()
-            else:
-                print ("  skipping")
-                size = self.readUnsignedInt( 4 )
-                if size:
-                    self.readBytes(size)        
-
-class VBAContainer:
-    def __init__( self, root ):
-        # we'll take a storage DirNode
-        # and try and find the VBA container
-        # relative to that. That way we should
-        # be able to cater for the normal 'word' or
-        # 'excel' compound documents or indeed any arbitrary
-        # storage that contains a 'VBA' sub-folder
-        self.oleRoot = root
-        self.vbaRoot = None
-
-    def __findNodeByHierarchicalName( self, node, name ):
-        if ( node.getHierarchicalName() == name ):
-            return node
-        else:
-            for child in node.getChildren():
-                result = self.__findNodeByHierarchicalName( child, name )
-                if result != None:
-                    return result
-        return None
-
-    def __findNodeContainingLeafName( self, parentNode, name ):
-        for child in parentNode.getChildren():
-            if name == child.Entry.Name:
-                return parentNode
-            node = self.__findNodeContainingLeafName( child, name )
-            if node != None:
-                return node
-        return None
-
-    def findVBARoot(self):
-        # find the node that containes 'VBA' storage
-        return self.__findNodeContainingLeafName( self.oleRoot, "VBA" )
-
-    def dump( self ):
-        self.vbaRoot = self.findVBARoot()
-        if self.vbaRoot == None:
-            print("Can't find VBA subcontainer")
-            exit(1)
-        # need to read the dir stream
-        dirName = self.vbaRoot.getHierarchicalName() + "VBA/dir"
-        dirNode = self.__findNodeByHierarchicalName( self.vbaRoot, dirName )
-        if dirNode != None:
-            #decompress 
-            bytes = dirNode.getStream()
-            compressed = vbahelper.CompressedVBAStream( bytes, 0 )
-            bytes = compressed.decompress()
-            reader = DirStreamReader( bytes )
-            reader.parse()
-
-            # dump the PROJECTxxx streams ( need to codepage from dir )
-            for child in self.vbaRoot.getChildren():
-                # first level children are PROJECT, PROJECTwm & PROJECTlk
-                if child.isStorage() == False:
-                    bytes = child.getStream()
-                    print("")
-                    print("============ %s Stream size: 0x%x bytes)============"%(child.getName(), len(bytes)))
-                    print("")
-                    if child.getName() == "PROJECT":
-                        #straight text file
-                        print("%s"%bytes.decode(reader.codepageName))
-                    else:
-                        globals.dumpBytes( bytes, 512) 
-            for module in reader.Modules:
-                fullStreamName = self.vbaRoot.getHierarchicalName() + "VBA/" + module.streamname
-                moduleNode = self.__findNodeByHierarchicalName( self.vbaRoot, fullStreamName )
-                bytes = moduleNode.getStream()
-                print("============ %s Stream (inflated) size: 0x%x bytes offset: 0x%x ============"%(module.streamname,len(bytes), module.offset) )
-                compressed = vbahelper.CompressedVBAStream( bytes, module.offset )
-                bytes = compressed.decompress()
-                source = bytes.decode( reader.codepageName )
-                print("")
-                print(source)
-                print("")
 
 def main ():
     parser = optparse.OptionParser()
     parser.add_option("-l", "--list", action="store_true", dest="list", default=False, help="lists ole contents")
     parser.add_option("-x", "--extract", action="store_true", dest="extract", default=False, help="extract file")
-    parser.add_option("-b", "--basic", action="store_true", dest="dumpbasic", default=False, help="dump basic related info")
 
 
     options, args = parser.parse_args()
@@ -566,14 +44,13 @@ def main ():
 
     params.list =  options.list
     params.extract =  options.extract
-    params.dumpbasic =  options.dumpbasic
 
     if len(args) < 1:
         globals.error("takes at least one argument\n")
         parser.print_help()
         sys.exit(1)
 
-    container = OleContainer( args[ 0 ], params )
+    container = ole.OleContainer( args[ 0 ], params )
 
     if params.list == True:
         container.list() 
@@ -584,11 +61,5 @@ def main ():
        for file in files:
            container.extract( file ) 
 
-    if params.dumpbasic:
-        container.read()
-        root = container.getRoot()
-        vba = VBAContainer( root ) 
-        vba.dump()
-
 if __name__ == '__main__':
     main()
diff --git a/vbadump.py b/vbadump.py
index 458f9e3..e9a8312 100755
--- a/vbadump.py
+++ b/vbadump.py
@@ -1,35 +1,376 @@
 #!/usr/bin/env python2
 
-import sys, os.path, optparse
+import sys, os.path, optparse, math
 sys.path.append(sys.path[0]+"/src")
-import ole, globals, node, olestream
-
-class VBADumper(object):
-    
-    def __init__ (self,filepath):
-        print("init - file to dump from %s"%filepath)
-        self.filepath = filepath
-    def __parseHeader(self,chars,params):    
-        self.header = ole.Header(chars, params) 
-        self.header.parse()
-    def __getDirectoryObj(self):
-        obj = self.header.getDirectory()
-        if  obj != None:
-            obj.parseDirEntries()
-        return obj
-    def parse(self):
-        params = globals.Params()
-        file = open(self.filepath, 'rb')
-        self.__parseHeader(file.read(), params )
-        self.obj = self.__getDirectoryObj()
-#        obj.output()
-         
+import ole, globals, node, olestream, vbahelper
+
+# alot of records follow the id, sizeofrecord pattern
+# many of the dir records though seem to be id, sizeofstring,
+# stringbuffer, reserved, sizeofstring(unicode), stringbuffer(unicode)
+class DefaultBuffReservedBuffReader:
+    def __init__ (self, reader ):
+        self.reader = reader
+    def parse(self):
+        # pos before header
+        print ("  skipping")
+        # buffer
+        size = self.reader.readUnsignedInt( 4 )
+        self.reader.readBytes(size)        
+        # reserved
+        self.reader.readBytes(2)        
+        # buffer
+        size = self.reader.readUnsignedInt( 4 )
+        self.reader.readBytes(size)    
+
+class StdReader:
+    def __init__ (self, reader ):
+        self.reader = reader
+
+class ProjectVersionReader:
+    def __init__ (self, reader ):
+        self.reader = reader
+    def parse(self):
+        # reserved
+        self.reader.readBytes(4)
+        # major
+        major = self.reader.readUnsignedInt( 4 )
+        minor = self.reader.readUnsignedInt( 2 )
+        print("  major: 0x%x"%major)
+        print("  minor: 0x%x"%minor)
+
+class CodePageReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        self.reader.codepage = self.reader.readUnsignedInt( size )
+
+        #need a map of codepage code (int) to codepage alias(s) from
+        # #FIXME codepage is hardcoded below
+        self.reader.codepageName = "cp1252"
+        print("  codepage: %i"%self.reader.codepage)
+     
+class ProjectNameReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  ProjectName: %s"%bytes.decode(self.reader.codepageName))
+                 
+class DocStringRecordReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  DocString: %s size[0x%x]"%(bytes.decode(self.reader.codepageName),size))
+        #reserved
+        self.reader.readBytes( 2 )
+        #unicode docstring
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  DocString(utf-16): %s size[0x%x]"%(bytes.decode("utf-16").decode(self.reader.codepageName), size ))
+
+class ConstantsRecordReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  Constants: size[0x%x]"%size)
+        if size:
+            print("%s"%bytes.decode(self.reader.codepageName))
+        #reserved
+        self.reader.readBytes( 2 )
+        #unicode docstring
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  Constants(Utf-16): size[0x%x]"%size)
+        if size:
+            print("%s"%bytes.decode("uft-16").decode(self.reader.codepageName))
+
+class ProjectHelpFilePathReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  HelpFile1: %s size[0x%x]"%(bytes.decode(self.reader.codepageName),size))
+        #reserved
+        self.reader.readBytes( 2 )
+        #unicode docstring
+        size = self.reader.readUnsignedInt( 4 )
+        bytes = self.reader.readBytes( size )
+        print("  HelpFile2: %s size[0x%x]"%(bytes.decode(self.reader.codepageName), size ))
+
+class ProjectHelpFileContextReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        context = self.reader.readUnsignedInt( size )
+        print("  HelpContext: 0x%x"%context)
+
+class ProjectModulesReader(StdReader):
+    def parse(self):
+        # start of module specific data
+        size = self.reader.readUnsignedInt( 4 )
+        count = self.reader.readUnsignedInt( size )
+        self.reader.CurrentModule = ModuleInfo()
+        print("  Num Modules: %i"%count) 
+
+class ModuleNameReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        nameBytes = self.reader.readBytes( size )
+        moduleInfo = self.reader.CurrentModule
+        moduleInfo.name = nameBytes.decode( self.reader.codepageName )
+        print("  ModuleName: %s"%moduleInfo.name)
+
+class ModuleStreamNameReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        nameBytes = self.reader.readBytes( size )
+        moduleInfo = self.reader.CurrentModule
+        moduleInfo.streamname = nameBytes.decode( self.reader.codepageName )
+        print("  ModuleStreamName: %s"%moduleInfo.name)
+        #reserved
+        self.reader.readBytes( 2 )
+        size = self.reader.readUnsignedInt( 4 )
+        nameUnicodeBytes = self.reader.readBytes( size )
+        nameUnicode = nameUnicodeBytes.decode("utf-16").decode( self.reader.codepageName)
+        print("  ModuleStreamName(utf-16): %s"%nameUnicode)
+
+class ModuleOffSetReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        moduleInfo = self.reader.CurrentModule
+        moduleInfo.offset = self.reader.readUnsignedInt( size )
+     
+        print("  Offset: 0x%x"%moduleInfo.offset) 
+
+class ProjectModuleTermReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        # size must be zero ( assert? )
+        moduleInfo = self.reader.CurrentModule
+        self.reader.CurrentModule = ModuleInfo()
+        # add current module to list
+        self.reader.Modules.append( moduleInfo )
+
+class ModuleTypeProceduralReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        # size must be zero ( assert? )
+        print("  Module Type: procedure")
+
+class ModuleTypeOtherReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        # size must be zero ( assert? )
+        print("  Module Type: document, class or design")
+
+class SysKindReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        sysKind = "Unknown" 
+        if val == 0:
+           sysKind = "16 bit windows" 
+        elif val == 1:
+           sysKind = "32 bit windows" 
+        elif val == 2:
+           sysKind = "Macintosh" 
+        print("  SysType: %s"%sysKind)
+
+class LcidReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        print("  LCID: 0x%x ( expected 0x409 )"%val)
+   
+class LcidInvokeReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        print("  LCIDINVOKE: 0x%x ( expected 0x409 )"%val)
+   
+
+class LibFlagReader(StdReader):
+    def parse(self):
+        size = self.reader.readUnsignedInt( 4 )
+        val = self.reader.readUnsignedInt( size )
+        print("  LIBFLAGS: 0x%x"%val)
+
+# map of record id to array containing description of records and optional
+# a handler ( inspired by xlsstream.py )
+dirRecordData = {
+    #dir stream contains........
+    #PROJECTINFORMATION RECORD
+    #  which contains any of the following sub records
+    0x0001: ["PROJECTSYSKIND", "SysKindRecord",SysKindReader],
+    0x0002: ["PROJECTLCID", "LcidRecord",LcidReader],
+    0x0003: ["PROJECTCODEPAGE", "CodePageRecord", CodePageReader ],
+    0x0004: ["PROJECTNAME", "NameRecord", ProjectNameReader],
+    0x0005: ["PROJECTDOCSTRING", "DocStringRecord", DocStringRecordReader ],
+    0x0006: ["PROJECTHELPFILEPATH", "HelpFilePathRecord", ProjectHelpFilePathReader],
+    0x0007: ["PROJECTHELPCONTEXT", "HelpContextRecord", ProjectHelpFileContextReader],
+    0x0008: ["PROJECTLIBFLAGS", "LibFlagsRecord",LibFlagReader],
+    0x0009: ["PROJECTVERSION", "VersionRecord",ProjectVersionReader],
+    0x0010: ["DIRTERMINATOR", "DirTerminator"],
+    0x000C: ["PROJECTCONSTANTS", "ConstantsRecord", ConstantsRecordReader],
+    0x0014: ["PROJECTLCIDINVOKE", "LcidInvokeRecord",LcidInvokeReader],
+    #PROJECTREFERENCES
+    # which contains any of the following sub records
+    0x0016: ["REFERENCENAME", "NameRecord", DefaultBuffReservedBuffReader ],
+    0x000D: ["REFERENCEREGISTERED", "ReferenceRegistered"],
+    0x000E: ["REFERENCEPROJECT", "ReferenceProject"],
+    0x002F: ["REFERENCECONTROL", "ReferenceControl"],
+    #the following "FAKE-#FIXME record is not really a record but actually
+    #is a reserved word ( with fixed value 0x0030 ) in the middle of a
+    #REFEREBCECONTROL record
+    0x0030: ["FAKE-#FIXME", "Fake record"],
+    0x0033: ["REFERENCEORIGINAL", "ReferenceOriginal"],
+    #
+    0x000F: ["PROJECTMODULES", "ModulesRecord", ProjectModulesReader],
+    0x0013: ["PROJECTCOOKIE", "CookieRecord"],
+    0x002B: ["PROJECTMODULETERM", "ModuleTerminator", ProjectModuleTermReader],
+    0x0019: ["MODULENAME", "ModuleName",ModuleNameReader],
+    0x0047: ["MODULENAMEUNICODE", "ModuleNameUnicode"],
+    0x001A: ["MODULESTREAMNAME", "ModuleStreamName", ModuleStreamNameReader],
+    0x001C: ["MODULEDOCSTRING", "ModuleDocString", DefaultBuffReservedBuffReader],
+    0x0031: ["MODULEOFFSET", "ModuleOffSet", ModuleOffSetReader],
+    0x001E: ["MODULEHELPCONTEXT", "ModuleHelpContext"],
+    0x002C: ["MODULECOOKIE", "ModuleCookie"],
+    0x0021: ["MODULETYPE", "ModuleTypeProcedural", ModuleTypeProceduralReader],
+    0x0022: ["MODULETYPE", "ModuleTypeDocClassOrDesgn", ModuleTypeOtherReader],
+    0x0025: ["MODULEREADONLY", "ModuleReadOnly"],
+    0x0028: ["MODULEPRIVATE", "ModulePrivate"],
+}    
+
+
+class ModuleInfo:
+    def __init__(self):
+        self.name = ""
+        self.offset = 0
+        self.streamname = "" 
+        
+class DirStreamReader( globals.ByteStream ): 
+    def __init__ (self, bytes ):
+        globals.ByteStream.__init__(self, bytes)
+        self.Modules = []
+        self.CodePage = None
+        self.CurrentModule = None
+
+    def parse(self):
+        print("============ Dir Stream (inflated) size: 0x%x bytes ============"%len(self.bytes))
+        print("")
+        print("Offset  [recId]  RecordName")
+        print("------- -------  -----------")
+        while self.isEndOfRecord() == False:
+            pos = self.getCurrentPos()
+            recordID = self.readUnsignedInt( 2 )
+            name = "Unknown"
+            if dirRecordData.has_key( recordID ):
+                name = dirRecordData[ recordID ][0]
+            # if we have a handler let it deal with the record
+            labelWidth = int(math.ceil(math.log(len(self.bytes), 10)))
+            fmt = "0x%%%d.%dx: "%(labelWidth, labelWidth)
+            sys.stdout.write(fmt%pos)
+#            print ("%s [0x%x] "%(name,recordID))
+            print '[0x{0:0>4x}] {1}'.format(recordID,name)
+            if ( dirRecordData.has_key( recordID ) and len( dirRecordData[ recordID ] ) > 2 ):
+                reader = dirRecordData[ recordID ][2]( self )
+                reader.parse()
+            else:
+                print ("  skipping")
+                size = self.readUnsignedInt( 4 )
+                if size:
+                    self.readBytes(size)        
+
+class VBAContainer:
+    def __init__( self, root ):
+        # we'll take a storage DirNode
+        # and try and find the VBA container
+        # relative to that. That way we should
+        # be able to cater for the normal 'word' or
+        # 'excel' compound documents or indeed any arbitrary
+        # storage that contains a 'VBA' sub-folder
+        self.oleRoot = root
+        self.vbaRoot = None
+
+    def __findNodeByHierarchicalName( self, node, name ):
+        if ( node.getHierarchicalName() == name ):
+            return node
+        else:
+            for child in node.getChildren():
+                result = self.__findNodeByHierarchicalName( child, name )
+                if result != None:
+                    return result
+        return None
+
+    def __findNodeContainingLeafName( self, parentNode, name ):
+        for child in parentNode.getChildren():
+            if name == child.Entry.Name:
+                return parentNode
+            node = self.__findNodeContainingLeafName( child, name )
+            if node != None:
+                return node
+        return None
+
+    def findVBARoot(self):
+        # find the node that containes 'VBA' storage
+        return self.__findNodeContainingLeafName( self.oleRoot, "VBA" )
+
+    def dump( self ):
+        self.vbaRoot = self.findVBARoot()
+        if self.vbaRoot == None:
+            print("Can't find VBA subcontainer")
+            exit(1)
+        # need to read the dir stream
+        dirName = self.vbaRoot.getHierarchicalName() + "VBA/dir"
+        dirNode = self.__findNodeByHierarchicalName( self.vbaRoot, dirName )
+        if dirNode != None:
+            #decompress 
+            bytes = dirNode.getStream()
+            compressed = vbahelper.CompressedVBAStream( bytes, 0 )
+            bytes = compressed.decompress()
+            reader = DirStreamReader( bytes )
+            reader.parse()
+
+            # dump the PROJECTxxx streams ( need to codepage from dir )
+            for child in self.vbaRoot.getChildren():
+                # first level children are PROJECT, PROJECTwm & PROJECTlk
+                if child.isStorage() == False:
+                    bytes = child.getStream()
+                    print("")
+                    print("============ %s Stream size: 0x%x bytes)============"%(child.getName(), len(bytes)))
+                    print("")
+                    if child.getName() == "PROJECT":
+                        #straight text file
+                        print("%s"%bytes.decode(reader.codepageName))
+                    else:
+                        globals.dumpBytes( bytes, 512) 
+            for module in reader.Modules:
+                fullStreamName = self.vbaRoot.getHierarchicalName() + "VBA/" + module.streamname
+                moduleNode = self.__findNodeByHierarchicalName( self.vbaRoot, fullStreamName )
+                bytes = moduleNode.getStream()
+                print("============ %s Stream (inflated) size: 0x%x bytes offset: 0x%x ============"%(module.streamname,len(bytes), module.offset) )
+                compressed = vbahelper.CompressedVBAStream( bytes, module.offset )
+                bytes = compressed.decompress()
+                source = bytes.decode( reader.codepageName )
+                print("")
+                print(source)
+                print("")
+
+
 def main():
+    parser = optparse.OptionParser()
+
     if ( len ( sys.argv ) <= 1 ):
         print("usage: vbadump: file")
         sys.exit(1) 
-    dumper = VBADumper( sys.argv[1] )
-    dumper.parse()
+    # prepare for supporting more options
+    options, args = parser.parse_args()
+
+    params = globals.Params()    
+
+    container = ole.OleContainer( args[ 0 ], params )
+
+    container.read()
+    root = container.getRoot()
+    vba = VBAContainer( root ) 
+    vba.dump()
+
     exit(0)
 
 if __name__ == '__main__':
commit 679a7e81165fc3bd6ec04d1d58b73a764e08a51c
Author: Noel Power <noel.power at suse.com>
Date:   Thu Oct 10 09:40:37 2013 +0100

    some more formatting changes

diff --git a/src/oletool.py b/src/oletool.py
index 8615ca3..ac0a57a 100755
--- a/src/oletool.py
+++ b/src/oletool.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python2
 ########################################################################
 #
-#  Copyright (c) 2011 Noel Power
+#  Copyright (c) 2013 Noel Power
 #  
 #  Permission is hereby granted, free of charge, to any person
 #  obtaining a copy of this software and associated documentation
@@ -213,7 +213,7 @@ class DefaultBuffReservedBuffReader:
         self.reader = reader
     def parse(self):
         # pos before header
-        print ("    skipping record")
+        print ("  skipping")
         # buffer
         size = self.reader.readUnsignedInt( 4 )
         self.reader.readBytes(size)        
@@ -236,8 +236,8 @@ class ProjectVersionReader:
         # major
         major = self.reader.readUnsignedInt( 4 )
         minor = self.reader.readUnsignedInt( 2 )
-        print("    major: 0x%x"%major)
-        print("    minor: 0x%x"%minor)
+        print("  major: 0x%x"%major)
+        print("  minor: 0x%x"%minor)
 
 class CodePageReader(StdReader):
     def parse(self):
@@ -247,31 +247,31 @@ class CodePageReader(StdReader):
         #need a map of codepage code (int) to codepage alias(s) from
         # #FIXME codepage is hardcoded below
         self.reader.codepageName = "cp1252"
-        print("    codepage: %i"%self.reader.codepage)
+        print("  codepage: %i"%self.reader.codepage)
      
 class ProjectNameReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    ProjectName: %s"%bytes.decode(self.reader.codepageName))
+        print("  ProjectName: %s"%bytes.decode(self.reader.codepageName))
                  
 class DocStringRecordReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    DocString: %s size[%i]"%(bytes.decode(self.reader.codepageName),size))
+        print("  DocString: %s size[0x%x]"%(bytes.decode(self.reader.codepageName),size))
         #reserved
         self.reader.readBytes( 2 )
         #unicode docstring
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    DocString(utf-16): %s size[%i]"%(bytes.decode("utf-16").decode(self.reader.codepageName), size ))
+        print("  DocString(utf-16): %s size[0x%x]"%(bytes.decode("utf-16").decode(self.reader.codepageName), size ))
 
 class ConstantsRecordReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    Constants: size[%i]"%size)
+        print("  Constants: size[0x%x]"%size)
         if size:
             print("%s"%bytes.decode(self.reader.codepageName))
         #reserved
@@ -279,7 +279,7 @@ class ConstantsRecordReader(StdReader):
         #unicode docstring
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    Constants(Utf-16): size[%i]"%size)
+        print("  Constants(Utf-16): size[0x%x]"%size)
         if size:
             print("%s"%bytes.decode("uft-16").decode(self.reader.codepageName))
 
@@ -287,19 +287,19 @@ class ProjectHelpFilePathReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    HelpFile1: %s size[%i]"%(bytes.decode(self.reader.codepageName),size))
+        print("  HelpFile1: %s size[0x%x]"%(bytes.decode(self.reader.codepageName),size))
         #reserved
         self.reader.readBytes( 2 )
         #unicode docstring
         size = self.reader.readUnsignedInt( 4 )
         bytes = self.reader.readBytes( size )
-        print("    HelpFile2: %s size[%i]"%(bytes.decode(self.reader.codepageName), size ))
+        print("  HelpFile2: %s size[0x%x]"%(bytes.decode(self.reader.codepageName), size ))
 
 class ProjectHelpFileContextReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         context = self.reader.readUnsignedInt( size )
-        print("    HelpContext: 0x%x"%context)
+        print("  HelpContext: 0x%x"%context)
 
 class ProjectModulesReader(StdReader):
     def parse(self):
@@ -307,7 +307,7 @@ class ProjectModulesReader(StdReader):
         size = self.reader.readUnsignedInt( 4 )
         count = self.reader.readUnsignedInt( size )
         self.reader.CurrentModule = ModuleInfo()
-        print("    Num Modules: %i"%count) 
+        print("  Num Modules: %i"%count) 
 
 class ModuleNameReader(StdReader):
     def parse(self):
@@ -315,7 +315,7 @@ class ModuleNameReader(StdReader):
         nameBytes = self.reader.readBytes( size )
         moduleInfo = self.reader.CurrentModule
         moduleInfo.name = nameBytes.decode( self.reader.codepageName )
-        print("    ModuleName: %s"%moduleInfo.name)
+        print("  ModuleName: %s"%moduleInfo.name)
 
 class ModuleStreamNameReader(StdReader):
     def parse(self):
@@ -323,13 +323,13 @@ class ModuleStreamNameReader(StdReader):
         nameBytes = self.reader.readBytes( size )
         moduleInfo = self.reader.CurrentModule
         moduleInfo.streamname = nameBytes.decode( self.reader.codepageName )
-        print("    ModuleStreamName: %s"%moduleInfo.name)
+        print("  ModuleStreamName: %s"%moduleInfo.name)
         #reserved
         self.reader.readBytes( 2 )
         size = self.reader.readUnsignedInt( 4 )
         nameUnicodeBytes = self.reader.readBytes( size )
         nameUnicode = nameUnicodeBytes.decode("utf-16").decode( self.reader.codepageName)
-        print("    ModuleStreamName(utf-16): %s"%nameUnicode)
+        print("  ModuleStreamName(utf-16): %s"%nameUnicode)
 
 class ModuleOffSetReader(StdReader):
     def parse(self):
@@ -337,7 +337,7 @@ class ModuleOffSetReader(StdReader):
         moduleInfo = self.reader.CurrentModule
         moduleInfo.offset = self.reader.readUnsignedInt( size )
      
-        print("    Offset: %i"%moduleInfo.offset) 
+        print("  Offset: 0x%x"%moduleInfo.offset) 
 
 class ProjectModuleTermReader(StdReader):
     def parse(self):
@@ -352,13 +352,13 @@ class ModuleTypeProceduralReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         # size must be zero ( assert? )
-        print("    Module Type: procedure")
+        print("  Module Type: procedure")
 
 class ModuleTypeOtherReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         # size must be zero ( assert? )
-        print("    Module Type: document, class or design")
+        print("  Module Type: document, class or design")
 
 class SysKindReader(StdReader):
     def parse(self):
@@ -371,26 +371,26 @@ class SysKindReader(StdReader):
            sysKind = "32 bit windows" 
         elif val == 2:
            sysKind = "Macintosh" 
-        print("    SysType: %s"%sysKind)
+        print("  SysType: %s"%sysKind)
 
 class LcidReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         val = self.reader.readUnsignedInt( size )
-        print("   LCID: 0x%x ( expected 0x409 )"%val)
+        print("  LCID: 0x%x ( expected 0x409 )"%val)
    
 class LcidInvokeReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         val = self.reader.readUnsignedInt( size )
-        print("   LCIDINVOKE: 0x%x ( expected 0x409 )"%val)
+        print("  LCIDINVOKE: 0x%x ( expected 0x409 )"%val)
    
 
 class LibFlagReader(StdReader):
     def parse(self):
         size = self.reader.readUnsignedInt( 4 )
         val = self.reader.readUnsignedInt( size )
-        print("   LIBFLAGS: 0x%x"%val)
+        print("  LIBFLAGS: 0x%x"%val)
 
 # map of record id to array containing description of records and optional
 # a handler ( inspired by xlsstream.py )
@@ -453,8 +453,10 @@ class DirStreamReader( globals.ByteStream ):
         self.CurrentModule = None
 
     def parse(self):
+        print("============ Dir Stream (inflated) size: 0x%x bytes ============"%len(self.bytes))
         print("")
-        print("============ Dir Stream (inflated) size: %d bytes ============"%len(self.bytes))
+        print("Offset  [recId]  RecordName")
+        print("------- -------  -----------")
         while self.isEndOfRecord() == False:
             pos = self.getCurrentPos()
             recordID = self.readUnsignedInt( 2 )
@@ -463,7 +465,7 @@ class DirStreamReader( globals.ByteStream ):
                 name = dirRecordData[ recordID ][0]
             # if we have a handler let it deal with the record
             labelWidth = int(math.ceil(math.log(len(self.bytes), 10)))
-            fmt = "%%%d.%dd: "%(labelWidth, labelWidth)
+            fmt = "0x%%%d.%dx: "%(labelWidth, labelWidth)
             sys.stdout.write(fmt%pos)
 #            print ("%s [0x%x] "%(name,recordID))
             print '[0x{0:0>4x}] {1}'.format(recordID,name)
@@ -471,18 +473,18 @@ class DirStreamReader( globals.ByteStream ):
                 reader = dirRecordData[ recordID ][2]( self )
                 reader.parse()
             else:
-                print ("    skipping")
+                print ("  skipping")
                 size = self.readUnsignedInt( 4 )
                 if size:
                     self.readBytes(size)        
 
 class VBAContainer:

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list