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



Author: kyoshida
Date: Sat Jan 26 07:31:04 2008
New Revision: 11419
URL: http://svn.gnome.org/viewvc/ooo-build?rev=11419&view=rev

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

	* scratch/sc-xlsutil/src/formula.py: added formula parser.

	* scratch/sc-xlsutil/src/globals.py: a little cleanup.
	
	* scratch/sc-xlsutil/src/record.py:
	* scratch/sc-xlsutil/src/stream.py: added FORMULA record handler.
	
	* scratch/sc-xlsutil/xls_dump.py: added rudimentary usage output and 
	command line option framework.


Added:
   trunk/scratch/sc-xlsutil/src/formula.py
Modified:
   trunk/ChangeLog
   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

Added: trunk/scratch/sc-xlsutil/src/formula.py
==============================================================================
--- (empty file)
+++ trunk/scratch/sc-xlsutil/src/formula.py	Sat Jan 26 07:31:04 2008
@@ -0,0 +1,112 @@
+
+import globals
+
+
+class TokenBase(object):
+    def __init__ (self, tokens):
+        self.tokens = tokens
+
+    def parse (self, i):
+        return i
+
+    def getText (self):
+        return ''
+
+class Add(TokenBase): pass
+class Sub(TokenBase): pass
+class Mul(TokenBase): pass
+class Div(TokenBase): pass
+class Power(TokenBase): pass
+class Concat(TokenBase): pass
+class LT(TokenBase): pass
+class LE(TokenBase): pass
+class EQ(TokenBase): pass
+class GE(TokenBase): pass
+class GT(TokenBase): pass
+class NE(TokenBase): pass
+class Isect(TokenBase): pass
+class List(TokenBase): pass
+class Range(TokenBase): pass
+
+class Plus(TokenBase): pass
+class Minus(TokenBase): pass
+class Percent(TokenBase): pass
+
+class NameX(TokenBase):
+    """external name"""
+
+    def parse (self, i):
+        i += 1
+        self.refID = globals.getSignedInt(self.tokens[i:i+2])
+        i += 2
+        self.nameID = globals.getSignedInt(self.tokens[i:i+2])
+        i += 2
+        return i
+
+    def getText (self):
+        return "<externname externsheet ID: %d; name ID: %d>"%(self.refID, self.nameID)
+
+
+tokenMap = {
+    # binary operator
+    0x03: Add,
+    0x04: Sub,
+    0x05: Mul,
+    0x06: Div,
+    0x07: Power,
+    0x08: Concat,
+    0x09: LT,
+    0x0A: LE,
+    0x0B: EQ,
+    0x0C: GE,
+    0x0D: GT,
+    0x0E: NE,
+    0x0F: Isect,
+    0x10: List,
+    0x11: Range,
+
+    # unary operator
+    0x12: Plus,
+    0x13: Minus,
+    0x14: Percent,
+
+    # operand tokens
+    0x39: NameX,
+    0x59: NameX,
+    0x79: NameX,
+
+    # last item
+    0xFF: None
+}
+
+class FormulaParser(object):
+    def __init__ (self, tokens):
+        self.tokens = tokens
+        self.text = ''
+
+    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[2:2+length]
+        i = 0
+        while i < length:
+            tk = ftokens[i]
+            if type(tk) == type('c'):
+                # get the ordinal of the character.
+                tk = ord(tk)
+            if not tokenMap.has_key(tk):
+                i += 1
+                continue
+
+            o = tokenMap[tk](ftokens)
+            i = o.parse(i)
+            self.text += o.getText() + ' '
+
+            i += 1
+
+
+    def getText (self):
+        return self.text

Modified: trunk/scratch/sc-xlsutil/src/globals.py
==============================================================================
--- trunk/scratch/sc-xlsutil/src/globals.py	(original)
+++ trunk/scratch/sc-xlsutil/src/globals.py	Sat Jan 26 07:31:04 2008
@@ -6,6 +6,8 @@
 def output (msg):
     sys.stdout.write(msg)
 
+def error (msg):
+    sys.stderr.write(msg)
 
 def dumpBytes (chars, subDivide=None):
     line = 0
@@ -28,14 +30,7 @@
     return 512 + secID*secSize
 
 
-def char2byte (chars):
-    bytes = []
-    for c in chars:
-        bytes.append(ord(c))
-    return bytes
-
-
-def getRawBytes (bytes, spaced=True):
+def getRawBytes (bytes, spaced=True, reverse=True):
     text = ''
     for b in bytes:
         if type(b) == type(''):
@@ -43,25 +38,36 @@
         if len(text) == 0:
             text = "%2.2X"%b
         elif spaced:
-            text = "%2.2X "%b + text
+            if reverse:
+                text = "%2.2X "%b + text
+            else:
+                text += " %2.2X"%b
         else:
-            text = "%2.2X"%b + text
+            if reverse:
+                text = "%2.2X"%b + text
+            else:
+                text += "%2.2X"%b
     return text
 
 
-def getSignedInt (bytes):
-    # little endian
+def toTextBytes (bytes):
     n = len(bytes)
-    if n == 0:
-        return 0
-
     text = ''
     for i in xrange(0, n):
         b = bytes[i]
         if type(b) == type(0x00):
             b = struct.pack('B', b)
         text += b
+    return text
+
+
+def getSignedInt (bytes):
+    # little endian
+    n = len(bytes)
+    if n == 0:
+        return 0
 
+    text = toTextBytes(bytes)
     if n == 1:
         # byte - 1 byte
         return struct.unpack('b', text)[0]
@@ -79,12 +85,8 @@
     n = len(bytes)
     if n == 0:
         return 0.0
-    text = ''
-    for i in xrange(0, n):
-        b = bytes[i]
-        if type(b) == type(0x00):
-            b = struct.pack('B', b)
-        text += b
+
+    text = toTextBytes(bytes)
     return struct.unpack('d', text)[0]
 
 

Modified: trunk/scratch/sc-xlsutil/src/record.py
==============================================================================
--- trunk/scratch/sc-xlsutil/src/record.py	(original)
+++ trunk/scratch/sc-xlsutil/src/record.py	Sat Jan 26 07:31:04 2008
@@ -1,5 +1,5 @@
 
-import globals
+import globals, formula
 
 # -------------------------------------------------------------------
 # record handler classes
@@ -13,6 +13,12 @@
         self.lines = []
 
     def parseBytes (self):
+        """Parse the original bytes and generate human readable output.
+
+The derived class should only worry about overwriting this function.  The
+bytes are given as self.bytes, and call self.appendLine([new line]) to
+append a line to be displayed.
+"""
         pass
 
     def output (self):
@@ -53,6 +59,33 @@
         self.appendLine("lowest Excel version: %d"%lowestExcelVer)
 
 
+class Formula(BaseRecordHandler):
+
+    def parseBytes (self):
+        row  = globals.getSignedInt(self.bytes[0:2])
+        col  = globals.getSignedInt(self.bytes[2:4])
+        xf   = globals.getSignedInt(self.bytes[4:6])
+        fval = globals.getDouble(self.bytes[6:14])
+
+        flags          = globals.getSignedInt(self.bytes[14:16])
+        recalc         = (flags & 0x0001) != 0
+        calcOnOpen     = (flags & 0x0002) != 0
+        sharedFormula  = (flags & 0x0008) != 0
+
+        tokens = self.bytes[20:]
+        fparser = formula.FormulaParser(tokens)
+        fparser.parse()
+        ftext = fparser.getText()
+
+        self.appendLine("cell position: (col: %d; row: %d)"%(col, row))
+        self.appendLine("XF record ID: %d"%xf)
+        self.appendLine("formula result: %g"%fval)
+        self.appendLine("recalculate always: %d"%recalc)
+        self.appendLine("calculate on open: %d"%calcOnOpen)
+        self.appendLine("shared formula: %d"%sharedFormula)
+        self.appendLine("tokens: "+ftext)
+
+
 class Number(BaseRecordHandler):
 
     def parseBytes (self):
@@ -62,7 +95,7 @@
         fval = globals.getDouble(self.bytes[6:14])
         self.appendLine("cell position: (col: %d; row: %d)"%(col, row))
         self.appendLine("XF record ID: %d"%xf)
-        self.appendLine("value (IEEE 754): %g"%fval)
+        self.appendLine("value: %g"%fval)
 
 # -------------------------------------------------------------------
 # 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	Sat Jan 26 07:31:04 2008
@@ -8,7 +8,7 @@
     # opcode: [canonical name, description, handler (optional)]
 
 recData = {
-    0x0006: ["FORMULA", "Formula Token Array and Result"],
+    0x0006: ["FORMULA", "Formula Token Array and Result", record.Formula],
     0x000A: ["EOF", "End of File"],
     0x000C: ["CALCCOUNT", "Iteration Count"],
     0x000D: ["CALCMODE", "Calculation Mode"],
@@ -176,7 +176,6 @@
     0x0236: ["TABLE", "Data Table"],
     0x023E: ["WINDOW2", "Sheet Window Information"],
     0x0293: ["STYLE", "Style Information"],
-    0x0406: ["FORMULA", "Cell Formula"],
     0x041E: ["FORMAT", "Number Format"],
     0x0809: ["BOF", "Beginning of File", record.BOF],
     0x0862: ["SHEETLAYOUT", "Tab Color below Sheet Name"],

Modified: trunk/scratch/sc-xlsutil/xls_dump.py
==============================================================================
--- trunk/scratch/sc-xlsutil/xls_dump.py	(original)
+++ trunk/scratch/sc-xlsutil/xls_dump.py	Sat Jan 26 07:31:04 2008
@@ -1,9 +1,21 @@
 #!/usr/bin/env python
 
-import sys, os.path
+import sys, os.path, getopt
 sys.path.append(sys.path[0]+"/src")
 import ole, stream, globals
 
+from globals import error
+
+def usage (exname):
+    exname = os.path.basename(exname)
+    msg = """Usage: %s [options] [xls file]
+
+Options:
+  --help        displays this help message.
+"""%exname
+    print msg
+
+
 class XLDumper(object):
 
     def __init__ (self, filepath):
@@ -62,17 +74,31 @@
         except stream.EndOfStream:
             return False
 
-def usage ():
-    pass
 
 def main (args):
+    exname, args = args[0], args[1:]
     if len(args) < 1:
         print("takes at least one argument")
-        usage()
+        usage(exname)
+        return
+
+    try:
+        opts, args = getopt.getopt(args, "h", ["help"])
+        for opt, arg in opts:
+            if opt in ['-h', '--help']:
+                usage(exname)
+                return
+            else:
+                error("unknown option %s\n"%opt)
+                usage()
+
+    except getopt.GetoptError:
+        error("error parsing input options\n")
+        usage(exname)
         return
 
     dumper = XLDumper(args[0])
     dumper.dump()
 
 if __name__ == '__main__':
-    main(sys.argv[1:])
+    main(sys.argv)



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