You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
8.4 KiB
245 lines
8.4 KiB
# -*- coding: windows-1252 -*-
|
|
|
|
from struct import unpack, pack
|
|
from . import BIFFRecords
|
|
from .compat import xrange
|
|
|
|
class StrCell(object):
|
|
__slots__ = ["rowx", "colx", "xf_idx", "sst_idx"]
|
|
|
|
def __init__(self, rowx, colx, xf_idx, sst_idx):
|
|
self.rowx = rowx
|
|
self.colx = colx
|
|
self.xf_idx = xf_idx
|
|
self.sst_idx = sst_idx
|
|
|
|
def get_biff_data(self):
|
|
# return BIFFRecords.LabelSSTRecord(self.rowx, self.colx, self.xf_idx, self.sst_idx).get()
|
|
return pack('<5HL', 0x00FD, 10, self.rowx, self.colx, self.xf_idx, self.sst_idx)
|
|
|
|
class BlankCell(object):
|
|
__slots__ = ["rowx", "colx", "xf_idx"]
|
|
|
|
def __init__(self, rowx, colx, xf_idx):
|
|
self.rowx = rowx
|
|
self.colx = colx
|
|
self.xf_idx = xf_idx
|
|
|
|
def get_biff_data(self):
|
|
# return BIFFRecords.BlankRecord(self.rowx, self.colx, self.xf_idx).get()
|
|
return pack('<5H', 0x0201, 6, self.rowx, self.colx, self.xf_idx)
|
|
|
|
class MulBlankCell(object):
|
|
__slots__ = ["rowx", "colx1", "colx2", "xf_idx"]
|
|
|
|
def __init__(self, rowx, colx1, colx2, xf_idx):
|
|
self.rowx = rowx
|
|
self.colx1 = colx1
|
|
self.colx2 = colx2
|
|
self.xf_idx = xf_idx
|
|
|
|
def get_biff_data(self):
|
|
return BIFFRecords.MulBlankRecord(self.rowx,
|
|
self.colx1, self.colx2, self.xf_idx).get()
|
|
|
|
class NumberCell(object):
|
|
__slots__ = ["rowx", "colx", "xf_idx", "number"]
|
|
|
|
def __init__(self, rowx, colx, xf_idx, number):
|
|
self.rowx = rowx
|
|
self.colx = colx
|
|
self.xf_idx = xf_idx
|
|
self.number = float(number)
|
|
|
|
def get_encoded_data(self):
|
|
rk_encoded = 0
|
|
num = self.number
|
|
|
|
# The four possible kinds of RK encoding are *not* mutually exclusive.
|
|
# The 30-bit integer variety picks up the most.
|
|
# In the code below, the four varieties are checked in descending order
|
|
# of bangs per buck, or not at all.
|
|
# SJM 2007-10-01
|
|
|
|
if -0x20000000 <= num < 0x20000000: # fits in 30-bit *signed* int
|
|
inum = int(num)
|
|
if inum == num: # survives round-trip
|
|
# print "30-bit integer RK", inum, hex(inum)
|
|
rk_encoded = 2 | (inum << 2)
|
|
return 1, rk_encoded
|
|
|
|
temp = num * 100
|
|
|
|
if -0x20000000 <= temp < 0x20000000:
|
|
# That was step 1: the coded value will fit in
|
|
# a 30-bit signed integer.
|
|
itemp = int(round(temp, 0))
|
|
# That was step 2: "itemp" is the best candidate coded value.
|
|
# Now for step 3: simulate the decoding,
|
|
# to check for round-trip correctness.
|
|
if itemp / 100.0 == num:
|
|
# print "30-bit integer RK*100", itemp, hex(itemp)
|
|
rk_encoded = 3 | (itemp << 2)
|
|
return 1, rk_encoded
|
|
|
|
if 0: # Cost of extra pack+unpack not justified by tiny yield.
|
|
packed = pack('<d', num)
|
|
w01, w23 = unpack('<2i', packed)
|
|
if not w01 and not(w23 & 3):
|
|
# 34 lsb are 0
|
|
# print "float RK", w23, hex(w23)
|
|
return 1, w23
|
|
|
|
packed100 = pack('<d', temp)
|
|
w01, w23 = unpack('<2i', packed100)
|
|
if not w01 and not(w23 & 3):
|
|
# 34 lsb are 0
|
|
# print "float RK*100", w23, hex(w23)
|
|
return 1, w23 | 1
|
|
|
|
#print "Number"
|
|
#print
|
|
return 0, pack('<5Hd', 0x0203, 14, self.rowx, self.colx, self.xf_idx, num)
|
|
|
|
def get_biff_data(self):
|
|
isRK, value = self.get_encoded_data()
|
|
if isRK:
|
|
return pack('<5Hi', 0x27E, 10, self.rowx, self.colx, self.xf_idx, value)
|
|
return value # NUMBER record already packed
|
|
|
|
class BooleanCell(object):
|
|
__slots__ = ["rowx", "colx", "xf_idx", "number"]
|
|
|
|
def __init__(self, rowx, colx, xf_idx, number):
|
|
self.rowx = rowx
|
|
self.colx = colx
|
|
self.xf_idx = xf_idx
|
|
self.number = number
|
|
|
|
def get_biff_data(self):
|
|
return BIFFRecords.BoolErrRecord(self.rowx,
|
|
self.colx, self.xf_idx, self.number, 0).get()
|
|
|
|
error_code_map = {
|
|
0x00: 0, # Intersection of two cell ranges is empty
|
|
0x07: 7, # Division by zero
|
|
0x0F: 15, # Wrong type of operand
|
|
0x17: 23, # Illegal or deleted cell reference
|
|
0x1D: 29, # Wrong function or range name
|
|
0x24: 36, # Value range overflow
|
|
0x2A: 42, # Argument or function not available
|
|
'#NULL!' : 0, # Intersection of two cell ranges is empty
|
|
'#DIV/0!': 7, # Division by zero
|
|
'#VALUE!': 36, # Wrong type of operand
|
|
'#REF!' : 23, # Illegal or deleted cell reference
|
|
'#NAME?' : 29, # Wrong function or range name
|
|
'#NUM!' : 36, # Value range overflow
|
|
'#N/A!' : 42, # Argument or function not available
|
|
}
|
|
|
|
class ErrorCell(object):
|
|
__slots__ = ["rowx", "colx", "xf_idx", "number"]
|
|
|
|
def __init__(self, rowx, colx, xf_idx, error_string_or_code):
|
|
self.rowx = rowx
|
|
self.colx = colx
|
|
self.xf_idx = xf_idx
|
|
try:
|
|
self.number = error_code_map[error_string_or_code]
|
|
except KeyError:
|
|
raise Exception('Illegal error value (%r)' % error_string_or_code)
|
|
|
|
def get_biff_data(self):
|
|
return BIFFRecords.BoolErrRecord(self.rowx,
|
|
self.colx, self.xf_idx, self.number, 1).get()
|
|
|
|
class FormulaCell(object):
|
|
__slots__ = ["rowx", "colx", "xf_idx", "frmla", "calc_flags"]
|
|
|
|
def __init__(self, rowx, colx, xf_idx, frmla, calc_flags=0):
|
|
self.rowx = rowx
|
|
self.colx = colx
|
|
self.xf_idx = xf_idx
|
|
self.frmla = frmla
|
|
self.calc_flags = calc_flags
|
|
|
|
def get_biff_data(self):
|
|
return BIFFRecords.FormulaRecord(self.rowx,
|
|
self.colx, self.xf_idx, self.frmla.rpn(), self.calc_flags).get()
|
|
|
|
# module-level function for *internal* use by the Row module
|
|
|
|
def _get_cells_biff_data_mul(rowx, cell_items):
|
|
# Return the BIFF data for all cell records in the row.
|
|
# Adjacent BLANK|RK records are combined into MUL(BLANK|RK) records.
|
|
pieces = []
|
|
nitems = len(cell_items)
|
|
i = 0
|
|
while i < nitems:
|
|
icolx, icell = cell_items[i]
|
|
if isinstance(icell, NumberCell):
|
|
isRK, value = icell.get_encoded_data()
|
|
if not isRK:
|
|
pieces.append(value) # pre-packed NUMBER record
|
|
i += 1
|
|
continue
|
|
muldata = [(value, icell.xf_idx)]
|
|
target = NumberCell
|
|
elif isinstance(icell, BlankCell):
|
|
muldata = [icell.xf_idx]
|
|
target = BlankCell
|
|
else:
|
|
pieces.append(icell.get_biff_data())
|
|
i += 1
|
|
continue
|
|
lastcolx = icolx
|
|
j = i
|
|
packed_record = ''
|
|
for j in xrange(i+1, nitems):
|
|
jcolx, jcell = cell_items[j]
|
|
if jcolx != lastcolx + 1:
|
|
nexti = j
|
|
break
|
|
if not isinstance(jcell, target):
|
|
nexti = j
|
|
break
|
|
if target == NumberCell:
|
|
isRK, value = jcell.get_encoded_data()
|
|
if not isRK:
|
|
packed_record = value
|
|
nexti = j + 1
|
|
break
|
|
muldata.append((value, jcell.xf_idx))
|
|
else:
|
|
muldata.append(jcell.xf_idx)
|
|
lastcolx = jcolx
|
|
else:
|
|
nexti = j + 1
|
|
if target == NumberCell:
|
|
if lastcolx == icolx:
|
|
# RK record
|
|
value, xf_idx = muldata[0]
|
|
pieces.append(pack('<5Hi', 0x027E, 10, rowx, icolx, xf_idx, value))
|
|
else:
|
|
# MULRK record
|
|
nc = lastcolx - icolx + 1
|
|
pieces.append(pack('<4H', 0x00BD, 6 * nc + 6, rowx, icolx))
|
|
pieces.append(b''.join(pack('<Hi', xf_idx, value) for value, xf_idx in muldata))
|
|
pieces.append(pack('<H', lastcolx))
|
|
else:
|
|
if lastcolx == icolx:
|
|
# BLANK record
|
|
xf_idx = muldata[0]
|
|
pieces.append(pack('<5H', 0x0201, 6, rowx, icolx, xf_idx))
|
|
else:
|
|
# MULBLANK record
|
|
nc = lastcolx - icolx + 1
|
|
pieces.append(pack('<4H', 0x00BE, 2 * nc + 6, rowx, icolx))
|
|
pieces.append(b''.join(pack('<H', xf_idx) for xf_idx in muldata))
|
|
pieces.append(pack('<H', lastcolx))
|
|
if packed_record:
|
|
pieces.append(packed_record)
|
|
i = nexti
|
|
return b''.join(pieces)
|
|
|