msodumper/xlsrecord.py |  302 +++++++++++++++++++++++++++++++++++++++----------
 msodumper/xlsstream.py |    2 
 2 files changed, 242 insertions(+), 62 deletions(-)

New commits:
commit 55071d1b98419a506a7f67cbfa44d0bd595af5cf
Author: Kohei Yoshida <kohei.yosh...@gmail.com>
Date:   Tue Sep 16 14:58:32 2014 -0400

    Start parsing FEATURE11 record. Still work in progress.

diff --git a/msodumper/xlsrecord.py b/msodumper/xlsrecord.py
index 38e15af..c3f5588 100644
--- a/msodumper/xlsrecord.py
+++ b/msodumper/xlsrecord.py
@@ -339,10 +339,74 @@ class DXFN12NoCB(object):
     def appendLines (self, hdl):
         self.dxfn.appendLines(hdl)
 
-class BaseRecordHandler(globals.ByteStream):
 
-    def __init__ (self, header, size, bytes, strmData, roflist = []):
+class XLStream(globals.ByteStream):
+
+    def __init__ (self, bytes):
         globals.ByteStream.__init__(self, bytes)
+
+    def readXLUnicodeString (self):
+        return self.readUnicodeString()
+
+    def readShortXLUnicodeString (self):
+        cch = self.readUnsignedInt(1)
+        return self.readUnicodeString(cch)
+
+    def readXLUnicodeStringNoCch (self, cch):
+        return self.readUnicodeString(cch)
+
+    def readXLUnicodeRichExtendedString (self):
+        cch = self.readUnsignedInt(2)
+        flags = self.readUnsignedInt(1)
+        fHighByte = (flags & 0x01) != 0  # double byte string
+        fExtSt    = (flags & 0x04) != 0  # phonetic string data
+        fRichSt   = (flags & 0x08) != 0  # rich text
+
+        cRun = 0
+        if fRichSt:
+            cRun = self.readUnsignedInt(2) # number of elemetns in rgRun
+
+        cbExtRst = 0
+        if fExtSt:
+            cbExtRst = self.readSignedInt(4) # byte count of ExtRst
+
+        if fHighByte:
+            rgb = unicode(self.readBytes(2*cch), 'UTF-16LE', errors='replace')
+        elif globals.params.utf8:
+            # Compressed Unicode-> latin1
+            rgb = self.readBytes(cch).decode('cp1252')
+        else:
+            # Old behaviour with hex dump
+            rgb = self.readBytes(cch)
+
+        # optional FormatRun array.  Ignore this for now.
+        self.readBytes(cRun*4) # Each FormatRun is 4-byte long.
+
+        # optional ExtRst.  Ignore this for now.
+        self.readBytes(cbExtRst)
+        return rgb
+
+    def readLongRGB (self):
+        r = self.readUnsignedInt(1)
+        g = self.readUnsignedInt(1)
+        b = self.readUnsignedInt(1)
+        self.readBytes(1) # reserved
+        return LongRGB(r, g, b)
+
+    def readICV (self):
+        return ICV(self.readUnsignedInt(2))
+
+    def readCFRTID (self):
+        return CFRTID(self.readUnsignedInt(2),self.readUnsignedInt(2))
+
+    def readFrtHeader (self):
+        return FrtHeader(self.readUnsignedInt(2), self.readUnsignedInt(2))
+
+
+class BaseRecordHandler(XLStream):
+
+    def __init__ (self, header, size, bytes, strmData, roflist = []):
+        XLStream.__init__(self, bytes)
         self.header = header
         self.lines = []
         self.strmData = strmData
@@ -447,62 +511,6 @@ Like parseBytes(), the derived classes must overwrite this 
method."""
         else:
             return falseStr
 
-    def readXLUnicodeString (self):
-        return self.readUnicodeString()
-
-    def readShortXLUnicodeString (self):
-        cch = self.readUnsignedInt(1)
-        return self.readUnicodeString(cch)
-
-    def readXLUnicodeStringNoCch (self, cch):
-        return self.readUnicodeString(cch)
-
-    def readXLUnicodeRichExtendedString (self):
-        cch = self.readUnsignedInt(2)
-        flags = self.readUnsignedInt(1)
-        fHighByte = (flags & 0x01) != 0  # double byte string
-        fExtSt    = (flags & 0x04) != 0  # phonetic string data
-        fRichSt   = (flags & 0x08) != 0  # rich text
-
-        cRun = 0
-        if fRichSt:
-            cRun = self.readUnsignedInt(2) # number of elemetns in rgRun
-
-        cbExtRst = 0
-        if fExtSt:
-            cbExtRst = self.readSignedInt(4) # byte count of ExtRst
-
-        if fHighByte:
-            rgb = unicode(self.readBytes(2*cch), 'UTF-16LE', errors='replace')
-        elif globals.params.utf8:
-            # Compressed Unicode-> latin1
-            rgb = self.readBytes(cch).decode('cp1252')
-        else:
-            # Old behaviour with hex dump
-            rgb = self.readBytes(cch)
-
-        # optional FormatRun array.  Ignore this for now.
-        self.readBytes(cRun*4) # Each FormatRun is 4-byte long.
-
-        # optional ExtRst.  Ignore this for now.
-        self.readBytes(cbExtRst)
-        return rgb
-
-    def readLongRGB (self):
-        r = self.readUnsignedInt(1)
-        g = self.readUnsignedInt(1)
-        b = self.readUnsignedInt(1)
-        self.readBytes(1) # reserved
-        return LongRGB(r, g, b)
-
-    def readICV (self):
-        return ICV(self.readUnsignedInt(2))
-
-    def readCFRTID (self):
-        return CFRTID(self.readUnsignedInt(2),self.readUnsignedInt(2))
-
-    def readFrtHeader (self):
-        return FrtHeader(self.readUnsignedInt(2), self.readUnsignedInt(2))
 
 class AutofilterInfo(BaseRecordHandler):
 
@@ -2749,6 +2757,129 @@ class XF(BaseRecordHandler):
             pass
 
 
+class SharedFeatureType(object):
+
+    ISFPROTECTION = 0x0002
+    ISFFEC2       = 0x0003
+    ISFFACTOID    = 0x0004
+    ISFLIST       = 0x0005
+
+    @staticmethod
+    def toString (val):
+        if val == SharedFeatureType.ISFPROTECTION:
+            return "ISFPROTECTION (enhanced protection)"
+        elif val == SharedFeatureType.ISFFEC2:
+            return "ISFFEC2 (ignore formula errors)"
+        elif val == SharedFeatureType.ISFFACTOID:
+            return "ISFFACTOID (smart tag)"
+        elif val == SharedFeatureType.ISFLIST:
+            return "ISFLIST (list)"
+        else:
+            return ""
+
+
+class SourceType(object):
+
+    LTRANGE        = 0x00000000 # Range
+    LTSHAREPOINT   = 0x00000001 # Read/write Web-based data provider list
+    LTXML          = 0x00000002 # XML Mapper data
+    LTEXTERNALDATA = 0x00000003 # External data source (query table)
+
+    @staticmethod
+    def toString (val):
+        if val == SourceType.LTRANGE:
+            return "LTRANGE"
+        elif val == SourceType.LTSHAREPOINT:
+            return "LTSHAREPOINT"
+        elif val == SourceType.LTXML:
+            return "LTXML"
+        elif val == SourceType.LTEXTERNALDATA:
+            return "LTEXTERNALDATA"
+        else:
+            return ""
+
+
+class TableFeatureType(object):
+
+    def __init__ (self, strm):
+        self.lt = strm.readUnsignedInt(4)
+        self.idList = strm.readUnsignedInt(4)
+        self.crwHeader = strm.readUnsignedInt(4) != 0
+        self.crwTotals = strm.readUnsignedInt(4) != 0
+        self.idFieldNext = strm.readUnsignedInt(4)
+        self.cbFSData = strm.readUnsignedInt(4) # must be equal to 64
+        self.rupBuild = strm.readUnsignedInt(2)
+        strm.readBytes(2) # ignored
+
+        flags = strm.readUnsignedInt(2)
+        # unused2                      = (flags & 0x0001) != 0 # A
+        self.fAutoFilter               = (flags & 0x0002) != 0 # B
+        self.fPersistAutoFilter        = (flags & 0x0004) != 0 # C
+        self.fShowInsertRow            = (flags & 0x0008) != 0 # D
+        self.fInsertRowInsCells        = (flags & 0x0010) != 0 # E
+        self.fLoadPldwIdDeleted        = (flags & 0x0020) != 0 # F
+        self.fShownTotalRow            = (flags & 0x0040) != 0 # G
+        # reserved1                    = (flags & 0x0080) != 0 # H
+        self.fNeedsCommit              = (flags & 0x0100) != 0 # I
+        self.fSingleCell               = (flags & 0x0200) != 0 # J
+        # reserved2                    = (flags & 0x0400) != 0 # K
+        self.fApplyAutoFilter          = (flags & 0x0800) != 0 # L
+        self.fForceInsertToBeVis       = (flags & 0x1000) != 0 # M
+        self.fCompressedXml            = (flags & 0x2000) != 0 # N
+        self.fLoadCSPName              = (flags & 0x4000) != 0 # O
+        self.fLoadPldwIdChanged        = (flags & 0x8000) != 0 # P
+
+        flags = strm.readUnsignedInt(2)
+        self.verXL = (flags & 0x000F)
+
+        self.fLoadEntryId              = (flags & 0x0010) != 0 # Q
+        self.fLoadPllstclInvalid       = (flags & 0x0020) != 0 # R
+        self.fGoodRupBld               = (flags & 0x0040) != 0 # S
+        # unused3                      = (flags & 0x0080) != 0 # T
+        self.fPublished                = (flags & 0x0100) != 0 # U
+
+        self.lPosStmCache = strm.readUnsignedInt(4)
+        self.cbStmCache = strm.readUnsignedInt(4)
+        self.cchStmCache = strm.readUnsignedInt(4)
+
+        self.lem = strm.readUnsignedInt(4) # table edit mode
+        self.rgbHashParam = strm.readBytes(16)
+        self.rgbName = strm.readXLUnicodeString()
+
+    def appendLines (self, hdl):
+        hdl.appendLineString("source type", SourceType.toString(self.lt))
+        hdl.appendLineInt("table ID", self.idList)
+        hdl.appendLineBoolean("table has a header", self.crwHeader)
+        hdl.appendLineBoolean("table has a total row", self.crwTotals)
+        hdl.appendLineInt("next ID to use", self.idFieldNext)
+        hdl.appendLineInt("structure size", self.cbFSData)
+        hdl.appendLineInt("build ID", self.rupBuild)
+        hdl.appendLineBoolean("has autofilter", self.fAutoFilter)
+        hdl.appendLineBoolean("autofilter preserved on refresh", 
self.fPersistAutoFilter)
+        hdl.appendLineBoolean("insert row visible", self.fShowInsertRow)
+        hdl.appendLineBoolean("rows below shifted down", 
self.fInsertRowInsCells)
+        hdl.appendLineBoolean("idDeleted field is present", 
self.fLoadPldwIdDeleted)
+        hdl.appendLineBoolean("total row was ever visible", 
self.fShownTotalRow)
+        hdl.appendLineBoolean("table mods needs commit to source", 
self.fNeedsCommit)
+        hdl.appendLineBoolean("single cell table", self.fSingleCell)
+        hdl.appendLineBoolean("auto filter applied", self.fApplyAutoFilter)
+        hdl.appendLineBoolean("insert row forced visible", 
self.fForceInsertToBeVis)
+        hdl.appendLineBoolean("cached data compressed", self.fCompressedXml)
+        hdl.appendLineBoolean("cSPName field present", self.fLoadCSPName)
+        hdl.appendLineBoolean("idChanged field present", 
self.fLoadPldwIdChanged)
+        hdl.appendLineInt("Excel version", self.verXL)
+        hdl.appendLineBoolean("entryId field present", self.fLoadEntryId)
+        hdl.appendLineBoolean("cellInvalid field present", 
self.fLoadPllstclInvalid)
+        hdl.appendLineBoolean("rupBuild field valid", self.fGoodRupBld)
+        hdl.appendLineBoolean("table published", self.fPublished)
+        hdl.appendLineInt("cached data position in List Data stream", 
self.lPosStmCache)
+        hdl.appendLineInt("cached data size in List Data stream", 
self.cbStmCache)
+        hdl.appendLineInt("number of characters in cached data", 
self.cchStmCache)
+
+        # TODO : dump more data
+
+        hdl.appendLineString("table name", self.rgbName)
+
 class FeatureHeader(BaseRecordHandler):
     """Beginning of a collection of records."""
 
@@ -2868,6 +2999,39 @@ class FeatureData(BaseRecordHandler):
 
         return
 
+
+class Feature11(BaseRecordHandler):
+
+    def __parseBytes (self):
+        self.frtRefHeaderU = FrtRefHeaderU(self)
+        self.isf = self.readUnsignedInt(2) # SharedFeatureType
+        self.readBytes(5) # ignored
+        self.cref2 = self.readUnsignedInt(2)
+        self.cbFeatData = self.readUnsignedInt(4) # size of rgbFeat
+        self.readBytes(2) # ignored
+        self.refs2 = []
+        for i in xrange(0, self.cref2):
+            ref = Ref8U(self)
+            self.refs2.append(ref)
+
+        if self.cbFeatData == 0:
+            bytes = self.readRemainingBytes()
+        else:
+            bytes = self.readBytes(self.cbFeatData)
+        strm = XLStream(bytes)
+
+        self.rgbFeat = TableFeatureType(strm)
+
+
+    def parseBytes (self):
+        self.__parseBytes()
+        self.frtRefHeaderU.appendLines(self)
+        self.appendLineString("feature data type", 
SharedFeatureType.toString(self.isf))
+        for ref in self.refs2:
+            self.appendLineString("reference", ref.toString())
+        self.rgbFeat.appendLines(self)
+
+
 class ShrFmla(BaseRecordHandler):
 
     def __parseBytes (self):
@@ -2903,11 +3067,27 @@ class FrtFlags(object):
 
     def __init__ (self, strm):
         grbitFrt = strm.readUnsignedInt(2)
-        self.fFrtRef   = (grbitFrt & 0x0001) # record specifies a range of 
cells
-        self.fFrtAlert = (grbitFrt & 0x0002) # whether to alert the user of 
possible problems when saving the file
+        self.flag = grbitFrt
+        self.fFrtRef   = (grbitFrt & 0x0001) != 0 # record specifies a range 
of cells
+        self.fFrtAlert = (grbitFrt & 0x0002) != 0 # whether to alert the user 
of possible problems when saving the file
 
     def appendLines (self, hdl):
-        pass
+        hdl.appendLine("flag value: 0x%4.4X"%self.flag)
+        hdl.appendLineBoolean("range of cells", self.fFrtRef)
+        hdl.appendLineBoolean("alert when saving", self.fFrtAlert)
+
+
+class FrtRefHeaderU(object):
+
+    def __init__ (self, strm):
+        self.rt = strm.readUnsignedInt(2)
+        self.grbitFrt = FrtFlags(strm)
+        self.ref8 = Ref8U(strm)
+
+    def appendLines (self, hdl):
+        hdl.appendLine("header value: 0x%4.4X"%self.rt)
+        self.grbitFrt.appendLines(hdl)
+        hdl.appendLineString("reference", self.ref8.toString())
 
 
 class XLUnicodeStringSegmentedSXAddl(object):
diff --git a/msodumper/xlsstream.py b/msodumper/xlsstream.py
index 63f9827..d25a561 100644
--- a/msodumper/xlsstream.py
+++ b/msodumper/xlsstream.py
@@ -226,7 +226,7 @@ recData = {
     0x086B: ["DATALABEXTCONTENTS", "Contents of an extended data label", 
xlsrecord.DataLabExtContents],
     0x086C: ["CELLWATCH", "Reference to a watched cell"],
     0x0871: ["FEATHDR11", "Common information for all tables on a sheet"],
-    0x0872: ["FEATURE11", "Shared feature data for a table in a worksheet"],
+    0x0872: ["FEATURE11", "Shared feature data for a table in a worksheet", 
xlsrecord.Feature11],
     0x0873: ["DROPDOWNOBJIDS", "Object identifiers of autofilter dropdown 
objects"],
     0x0875: ["CONTINUEFRT11", "Continuation of the data in a preceding Future 
Record Type record that has data longer than 8,224 bytes"],
     0x0876: ["DCONN", "Information for a single data connection"],
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to