ooo-build r11433 - in trunk: . scratch/sc-xlsutil scratch/sc-xlsutil/src



Author: kyoshida
Date: Tue Jan 29 01:10:26 2008
New Revision: 11433
URL: http://svn.gnome.org/viewvc/ooo-build?rev=11433&view=rev

Log:
2008-01-28  Kohei Yoshida  <kyoshida novell com>

	* scratch/sc-xlsutil/src/formula.py:
	* scratch/sc-xlsutil/src/globals.py:
	* scratch/sc-xlsutil/src/record.py:
	* scratch/sc-xlsutil/src/stream.py:
	* scratch/sc-xlsutil/xls_dump.py: more work on handling external 
	reference related records.


Modified:
   trunk/ChangeLog
   trunk/scratch/sc-xlsutil/src/formula.py
   trunk/scratch/sc-xlsutil/src/globals.py
   trunk/scratch/sc-xlsutil/src/record.py
   trunk/scratch/sc-xlsutil/src/stream.py
   trunk/scratch/sc-xlsutil/xls_dump.py

Modified: trunk/scratch/sc-xlsutil/src/formula.py
==============================================================================
--- trunk/scratch/sc-xlsutil/src/formula.py	(original)
+++ trunk/scratch/sc-xlsutil/src/formula.py	Tue Jan 29 01:10:26 2008
@@ -1,6 +1,77 @@
 
+import struct, sys
 import globals
 
+class InvalidCellAddress(Exception): pass
+
+def toColName (colID):
+    if colID > 255:
+        raise InvalidCellAddress
+    n1 = colID % 26
+    n2 = int(colID/26)
+    name = struct.pack('b', n1 + ord('A'))
+    if n2 > 0:
+        name += struct.pack('b', n2 + ord('A'))
+    return name
+
+class CellAddress(object):
+    def __init__ (self, col=0, row=0, colRel=False, rowRel=False):
+        self.col = col
+        self.row = row
+        self.isColRelative = colRel
+        self.isRowRelative = rowRel
+
+    def getName (self):
+        colName = toColName(self.col)
+        rowName = "%d"%(self.row+1)
+        if not self.isColRelative:
+            colName = '$' + colName
+        if not self.isRowRelative:
+            rowName = '$' + rowName
+        return colName + rowName
+
+class CellRange(object):
+    def __init__ (self):
+        self.firstRow = 0
+        self.lastRow = 0
+        self.firstCol = 0
+        self.lastCol = 0
+        self.isFirstRowRelative = False
+        self.isLastRowRelative = False
+        self.isFirstColRelative = False
+        self.isLastColRelative = False
+
+def parseCellAddress (bytes):
+    if len(bytes) != 4:
+        raise InvalidCellAddress
+
+    row = globals.getSignedInt(bytes[0:2])
+    col = globals.getSignedInt(bytes[2:4])
+    colRelative = ((col & 0x4000) != 0)
+    rowRelative = ((col & 0x8000) != 0)
+    col = (col & 0x00FF)
+    obj = CellAddress(col, row)
+    return obj
+
+def parseCellRangeAddress (bytes):
+    if len(bytes) != 8:
+        raise InvalidCellAddress
+
+    obj = CellRange()
+    obj.firstRow = globals.getSignedInt(bytes[0:2])
+    obj.lastRow  = globals.getSignedInt(bytes[2:4])
+    obj.firstCol = globals.getSignedInt(bytes[4:6])
+    obj.lastCol  = globals.getSignedInt(bytes[6:8])
+
+    obj.isFirstColRelative = ((firstCol & 0x4000) != 0)
+    obj.isFirstRowRelative = ((firstCol & 0x8000) != 0)
+    obj.firstCol = (firstCol & 0x00FF)
+
+    obj.isLastColRelative = ((lastCol & 0x4000) != 0)
+    obj.isLastRowRelative = ((lastCol & 0x8000) != 0)
+    obj.lastCol = (lastCol & 0x00FF)
+    return obj
+
 
 class TokenBase(object):
     """base class for token handler
@@ -55,8 +126,23 @@
         return i
 
     def getText (self):
-        return "<externname externsheet ID: %d; name ID: %d>"%(self.refID, self.nameID)
+        return "<externname externSheetID='%d' nameID='%d'>"%(self.refID, self.nameID)
+
+
+class Ref3d(TokenBase):
+    """3D reference or external reference to a cell"""
+
+    def parse (self, i):
+        i += 1
+        self.refEntryId = globals.getSignedInt(self.tokens[i:i+2])
+        i += 2
+        self.cell = parseCellAddress(self.tokens[i:i+4])
+        i += 4
+        return i
 
+    def getText (self):
+        cellName = self.cell.getName()
+        return "<3dref externSheetID='%d' cellAddress='%s'>"%(self.refEntryId, cellName)
 
 tokenMap = {
     # binary operator
@@ -86,6 +172,11 @@
     0x59: NameX,
     0x79: NameX,
 
+    # 3d reference
+    0x3A: Ref3d,
+    0x5A: Ref3d,
+    0x7A: Ref3d,
+
     # last item
     0xFF: None
 }
@@ -97,17 +188,21 @@
 the constructor.  That series of bytes must also include the formula length
 which is usually the first 2 bytes.
 """
-    def __init__ (self, tokens):
+    def __init__ (self, tokens, sizeField=True):
         self.tokens = tokens
         self.text = ''
+        self.sizeField = sizeField
 
     def parse (self):
-        # first 2-bytes contain the length of the formula tokens
-        length = globals.getSignedInt(self.tokens[0:2])
-        if length <= 0:
-            return
+        ftokens = self.tokens
+        length = len(ftokens)
+        if self.sizeField:
+            # first 2-bytes contain the length of the formula tokens
+            length = globals.getSignedInt(self.tokens[0:2])
+            if length <= 0:
+                return
+            ftokens = self.tokens[2:2+length]
 
-        ftokens = self.tokens[2:2+length]
         i = 0
         while i < length:
             tk = ftokens[i]

Modified: trunk/scratch/sc-xlsutil/src/globals.py
==============================================================================
--- trunk/scratch/sc-xlsutil/src/globals.py	(original)
+++ trunk/scratch/sc-xlsutil/src/globals.py	Tue Jan 29 01:10:26 2008
@@ -9,6 +9,53 @@
 def error (msg):
     sys.stderr.write(msg)
 
+
+def decodeName (name):
+    """decode name that contains unprintable characters."""
+
+    if len(name) == 0:
+        return name
+
+    if ord(name[0]) <= 5:
+        name = "<%2.2Xh>"%ord(name[0]) + name[1:]
+
+    return name
+
+
+def getRichText (bytes, textLen=None):
+    """parse a string of the rich-text format that Excel uses."""
+
+    flags = bytes[0]
+    if type(flags) == type('c'):
+        flags = ord(flags)
+    is16Bit   = (flags & 0x01)
+    isFarEast = (flags & 0x04)
+    isRich    = (flags & 0x08)
+
+    i = 1
+    formatRuns = 0
+    if isRich:
+        formatRuns = getSignedInt(bytes[i:i+2])
+        i += 2
+
+    extInfo = 0
+    if isFarEast:
+        extInfo = getSignedInt(bytes[i:i+4])
+        i += 4
+
+    extraBytes = 0
+    if textLen == None:
+        extraBytes = formatRuns*4 + extInfo
+        textLen = len(bytes) - extraBytes - i
+
+    totalByteLen = i + textLen + extraBytes
+    if is16Bit:
+        return ("<16-bit strings not supported yet>", totalByteLen)
+
+    text = toTextBytes(bytes[i:i+textLen])
+    return (text, totalByteLen)
+
+
 def dumpBytes (chars, subDivide=None):
     line = 0
     subDivideLine = None
@@ -50,6 +97,10 @@
     return text
 
 
+def getTextBytes (bytes):
+    return toTextBytes(bytes)
+
+
 def toTextBytes (bytes):
     n = len(bytes)
     text = ''

Modified: trunk/scratch/sc-xlsutil/src/record.py
==============================================================================
--- trunk/scratch/sc-xlsutil/src/record.py	(original)
+++ trunk/scratch/sc-xlsutil/src/record.py	Tue Jan 29 01:10:26 2008
@@ -165,6 +165,192 @@
             self.appendLine("row height type: custom")
 
 
+
+class Name(BaseRecordHandler):
+    """internal defined name"""
+
+    def __getInt (self, offset, size):
+        return globals.getSignedInt(self.bytes[offset:offset+size])
+
+    def __parseOptionFlags (self, flags):
+        self.appendLine("option flags:")
+        isHidden       = (flags & 0x0001) != 0
+        isFuncMacro    = (flags & 0x0002) != 0
+        isVBMacro      = (flags & 0x0004) != 0
+        isMacroName    = (flags & 0x0008) != 0
+        isComplFormula = (flags & 0x0010) != 0
+        isBuiltinName  = (flags & 0x0020) != 0
+        funcGrp        = (flags & 0x0FC0) / 64
+        isBinary       = (flags & 0x1000) != 0
+
+        if isHidden:
+            self.appendLine("  hidden")
+        else:
+            self.appendLine("  visible")
+
+        if isMacroName:
+            self.appendLine("  macro name")
+            if isFuncMacro:
+                self.appendLine("  function macro")
+                self.appendLine("  function group: %d"%funcGrp)
+            else:
+                self.appendLine("  command macro")
+            if isVBMacro:
+                self.appendLine("  visual basic macro")
+            else:
+                self.appendLine("  sheet macro")
+        else:
+            self.appendLine("  standard name")
+
+        if isComplFormula:
+            self.appendLine("  complex formula")
+        else:
+            self.appendLine("  simple formula")
+        if isBuiltinName:
+            self.appendLine("  built-in name")
+        else:
+            self.appendLine("  user-defined name")
+        if isBinary:
+            self.appendLine("  binary data")
+        else:
+            self.appendLine("  formula definition")
+
+
+    def parseBytes (self):
+        optionFlags = self.__getInt(0, 2)
+
+        keyShortCut = self.__getInt(2, 1)
+        nameLen     = self.__getInt(3, 1)
+        formulaLen  = self.__getInt(4, 2)
+        sheetId     = self.__getInt(8, 2)
+
+        # these optional texts may come after the formula token bytes.
+        menuTextLen = self.__getInt(10, 1)
+        descTextLen = self.__getInt(11, 1)
+        helpTextLen = self.__getInt(12, 1)
+        statTextLen = self.__getInt(13, 1)
+
+        name, byteLen = globals.getRichText(self.bytes[14:], nameLen)
+        tokenPos = 14 + byteLen
+        tokenText = globals.getRawBytes(self.bytes[tokenPos:tokenPos+formulaLen], True, False)
+        o = formula.FormulaParser(self.bytes[tokenPos:tokenPos+formulaLen], False)
+        o.parse()
+        self.appendLine("name: %s"%name)
+        self.__parseOptionFlags(optionFlags)
+
+        self.appendLine("sheet ID: %d"%sheetId)
+        self.appendLine("menu text length: %d"%menuTextLen)
+        self.appendLine("description length: %d"%descTextLen)
+        self.appendLine("help tip text length: %d"%helpTextLen)
+        self.appendLine("status bar text length: %d"%statTextLen)
+        self.appendLine("formula length: %d"%formulaLen)
+        self.appendLine("formula bytes: " + tokenText)
+        self.appendLine("formula: " + o.getText())
+
+
+
+class SupBook(BaseRecordHandler):
+    """Supporting workbook"""
+
+    def __parseSpecial (self):
+        if self.bytes[2:4] == [0x01, 0x04]:
+            # internal reference
+            num = globals.getSignedInt(self.bytes[0:2])
+            self.appendLine("sheet name count: %d (internal reference)"%num)
+        elif self.bytes[0:4] == [0x00, 0x01, 0x01, 0x3A]:
+            # add-in function
+            self.appendLine("add-in function name stored in the following EXERNNAME record.")
+
+    def __parseDDE (self):
+        # not implemented yet.
+        pass
+
+    def parseBytes (self):
+        if self.size == 4:
+            self.__parseSpecial()
+            return
+
+        if self.bytes[0:2] == [0x00, 0x00]:
+            self.__parseDDE()
+            return
+
+        num = globals.getSignedInt(self.bytes[0:2])
+        self.appendLine("sheet name count: %d"%num)
+        i = 2
+        isFirst = True
+        while i < self.size:
+            nameLen = globals.getSignedInt(self.bytes[i:i+2])
+            i += 2
+            flags = globals.getSignedInt(self.bytes[i:i+1])
+            i += 1
+            name = globals.getTextBytes(self.bytes[i:i+nameLen])
+            name = globals.decodeName(name)
+            i += nameLen
+            if isFirst:
+                isFirst = False
+                self.appendLine("document URL: %s"%name)
+            else:
+                self.appendLine("sheet name: %s"%name)
+
+
+class ExternSheet(BaseRecordHandler):
+
+    def parseBytes (self):
+        num = globals.getSignedInt(self.bytes[0:2])
+        for i in xrange(0, num):
+            offset = 2 + i*6
+            book = globals.getSignedInt(self.bytes[offset:offset+2])
+            firstSheet = globals.getSignedInt(self.bytes[offset+2:offset+4])
+            lastSheet  = globals.getSignedInt(self.bytes[offset+4:offset+6])
+            self.appendLine("SUPBOOK record ID: %d  (sheet ID range: %d - %d)"%(book, firstSheet, lastSheet))
+
+
+class ExternName(BaseRecordHandler):
+
+    def __parseOptionFlags (self, flags):
+        self.isBuiltinName = (flags & 0x0001) != 0
+        self.isAutoDDE     = (flags & 0x0002) != 0
+        self.isStdDocName  = (flags & 0x0008) != 0
+        self.isOLE         = (flags & 0x0010) != 0
+        # 5 - 14 bits stores last successful clip format
+        self.lastClipFormat = (flags & 0x7FE0)
+
+    def parseBytes (self):
+        # first 2 bytes are option flags for external name.
+        optionFlags = globals.getSignedInt(self.bytes[0:2])
+        self.__parseOptionFlags(optionFlags)
+
+        if self.isOLE:
+            # next 4 bytes are 32-bit storage ID
+            storageID = globals.getSignedInt(self.bytes[2:6])
+            nameLen = globals.getSignedInt(self.bytes[6:7])
+            name, byteLen = globals.getRichText(self.bytes[7:], nameLen)
+            self.appendLine("type: OLE")
+            self.appendLine("storage ID: %d"%storageID)
+            self.appendLine("name: %s"%name)
+        else:
+            # assume external defined name (could be DDE link).
+            # TODO: differentiate DDE link from external defined name.
+
+            supbookID = globals.getSignedInt(self.bytes[2:4])
+            nameLen = globals.getSignedInt(self.bytes[6:7])
+            name, byteLen = globals.getRichText(self.bytes[7:], nameLen)
+            tokenText = globals.getRawBytes(self.bytes[7+byteLen:], True, False)
+            self.appendLine("type: defined name")
+            if supbookID == 0:
+                self.appendLine("sheet ID: 0 (global defined names)")
+            else:
+                self.appendLine("sheet ID: %d"%supbookID)
+            self.appendLine("name: %s"%name)
+            self.appendLine("formula bytes: %s"%tokenText)
+
+            # parse formula tokens
+            o = formula.FormulaParser(self.bytes[7+byteLen:])
+            o.parse()
+            ftext = o.getText()
+            self.appendLine("formula: %s"%ftext)
+
+
 # -------------------------------------------------------------------
 # CT - Change Tracking
 

Modified: trunk/scratch/sc-xlsutil/src/stream.py
==============================================================================
--- trunk/scratch/sc-xlsutil/src/stream.py	(original)
+++ trunk/scratch/sc-xlsutil/src/stream.py	Tue Jan 29 01:10:26 2008
@@ -21,13 +21,15 @@
     0x0014: ["HEADER", "Print Header on Each Page"],
     0x0015: ["FOOTER", "Print Footer on Each Page"],
     0x0016: ["EXTERNCOUNT", "Number of External References"],
-    0x0017: ["EXTERNSHEET", "External Reference"],
+    0x0017: ["EXTERNSHEET", "External Reference", record.ExternSheet],
+    0x0018: ["NAME", "Internal Defined Name", record.Name],
     0x0019: ["WINDOWPROTECT", "Windows Are Protected"],
     0x001A: ["VERTICALPAGEBREAKS", "Explicit Column Page Breaks"],
     0x001B: ["HORIZONTALPAGEBREAKS", "Explicit Row Page Breaks"],
     0x001C: ["NOTE", "Comment Associated with a Cell"],
     0x001D: ["SELECTION", "Current Selection"],
     0x0022: ["DATEMODE", "Base Date for Displaying Date Values"],
+    0x0023: ["EXTERNNAME", "Externally Defined Name", record.ExternName],
     0x0026: ["LEFTMARGIN", "Left Margin Measurement"],
     0x0027: ["RIGHTMARGIN", "Right Margin Measurement"],
     0x0028: ["TOPMARGIN", "Top Margin Measurement"],
@@ -147,7 +149,7 @@
     0x01AA: ["USERSVIEWBEGIN", "Custom View Settings"],
     0x01AB: ["USERSVIEWEND", "End of Custom View Records"],
     0x01AD: ["QSI", "External Data Range"],
-    0x01AE: ["SUPBOOK", "Supporting Workbook"],
+    0x01AE: ["SUPBOOK", "Supporting Workbook", record.SupBook],
     0x01AF: ["PROT4REV", "Shared Workbook Protection Flag"],
     0x01B0: ["CONDFMT", "Conditional Formatting Range Information"],
     0x01B1: ["CF", "Conditional Formatting Conditions"],

Modified: trunk/scratch/sc-xlsutil/xls_dump.py
==============================================================================
--- trunk/scratch/sc-xlsutil/xls_dump.py	(original)
+++ trunk/scratch/sc-xlsutil/xls_dump.py	Tue Jan 29 01:10:26 2008
@@ -22,8 +22,7 @@
         self.filepath = filepath
 
     def __printDirHeader (self, dirname, byteLen):
-        if ord(dirname[0]) <= 5:
-            dirname = "<%2.2Xh>%s"%(ord(dirname[0]), dirname[1:])
+        dirname = globals.decodeName(dirname)
         print("")
         print("="*68)
         print("%s (size: %d bytes)"%(dirname, byteLen))



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]