1# -*- coding: windows-1252 -*- 2 3from struct import unpack, pack 4from . import BIFFRecords 5from .compat import xrange 6 7class StrCell(object): 8 __slots__ = ["rowx", "colx", "xf_idx", "sst_idx"] 9 10 def __init__(self, rowx, colx, xf_idx, sst_idx): 11 self.rowx = rowx 12 self.colx = colx 13 self.xf_idx = xf_idx 14 self.sst_idx = sst_idx 15 16 def get_biff_data(self): 17 # return BIFFRecords.LabelSSTRecord(self.rowx, self.colx, self.xf_idx, self.sst_idx).get() 18 return pack('<5HL', 0x00FD, 10, self.rowx, self.colx, self.xf_idx, self.sst_idx) 19 20class BlankCell(object): 21 __slots__ = ["rowx", "colx", "xf_idx"] 22 23 def __init__(self, rowx, colx, xf_idx): 24 self.rowx = rowx 25 self.colx = colx 26 self.xf_idx = xf_idx 27 28 def get_biff_data(self): 29 # return BIFFRecords.BlankRecord(self.rowx, self.colx, self.xf_idx).get() 30 return pack('<5H', 0x0201, 6, self.rowx, self.colx, self.xf_idx) 31 32class MulBlankCell(object): 33 __slots__ = ["rowx", "colx1", "colx2", "xf_idx"] 34 35 def __init__(self, rowx, colx1, colx2, xf_idx): 36 self.rowx = rowx 37 self.colx1 = colx1 38 self.colx2 = colx2 39 self.xf_idx = xf_idx 40 41 def get_biff_data(self): 42 return BIFFRecords.MulBlankRecord(self.rowx, 43 self.colx1, self.colx2, self.xf_idx).get() 44 45class NumberCell(object): 46 __slots__ = ["rowx", "colx", "xf_idx", "number"] 47 48 def __init__(self, rowx, colx, xf_idx, number): 49 self.rowx = rowx 50 self.colx = colx 51 self.xf_idx = xf_idx 52 self.number = float(number) 53 54 def get_encoded_data(self): 55 rk_encoded = 0 56 num = self.number 57 58 # The four possible kinds of RK encoding are *not* mutually exclusive. 59 # The 30-bit integer variety picks up the most. 60 # In the code below, the four varieties are checked in descending order 61 # of bangs per buck, or not at all. 62 # SJM 2007-10-01 63 64 if -0x20000000 <= num < 0x20000000: # fits in 30-bit *signed* int 65 inum = int(num) 66 if inum == num: # survives round-trip 67 # print "30-bit integer RK", inum, hex(inum) 68 rk_encoded = 2 | (inum << 2) 69 return 1, rk_encoded 70 71 temp = num * 100 72 73 if -0x20000000 <= temp < 0x20000000: 74 # That was step 1: the coded value will fit in 75 # a 30-bit signed integer. 76 itemp = int(round(temp, 0)) 77 # That was step 2: "itemp" is the best candidate coded value. 78 # Now for step 3: simulate the decoding, 79 # to check for round-trip correctness. 80 if itemp / 100.0 == num: 81 # print "30-bit integer RK*100", itemp, hex(itemp) 82 rk_encoded = 3 | (itemp << 2) 83 return 1, rk_encoded 84 85 if 0: # Cost of extra pack+unpack not justified by tiny yield. 86 packed = pack('<d', num) 87 w01, w23 = unpack('<2i', packed) 88 if not w01 and not(w23 & 3): 89 # 34 lsb are 0 90 # print "float RK", w23, hex(w23) 91 return 1, w23 92 93 packed100 = pack('<d', temp) 94 w01, w23 = unpack('<2i', packed100) 95 if not w01 and not(w23 & 3): 96 # 34 lsb are 0 97 # print "float RK*100", w23, hex(w23) 98 return 1, w23 | 1 99 100 #print "Number" 101 #print 102 return 0, pack('<5Hd', 0x0203, 14, self.rowx, self.colx, self.xf_idx, num) 103 104 def get_biff_data(self): 105 isRK, value = self.get_encoded_data() 106 if isRK: 107 return pack('<5Hi', 0x27E, 10, self.rowx, self.colx, self.xf_idx, value) 108 return value # NUMBER record already packed 109 110class BooleanCell(object): 111 __slots__ = ["rowx", "colx", "xf_idx", "number"] 112 113 def __init__(self, rowx, colx, xf_idx, number): 114 self.rowx = rowx 115 self.colx = colx 116 self.xf_idx = xf_idx 117 self.number = number 118 119 def get_biff_data(self): 120 return BIFFRecords.BoolErrRecord(self.rowx, 121 self.colx, self.xf_idx, self.number, 0).get() 122 123error_code_map = { 124 0x00: 0, # Intersection of two cell ranges is empty 125 0x07: 7, # Division by zero 126 0x0F: 15, # Wrong type of operand 127 0x17: 23, # Illegal or deleted cell reference 128 0x1D: 29, # Wrong function or range name 129 0x24: 36, # Value range overflow 130 0x2A: 42, # Argument or function not available 131 '#NULL!' : 0, # Intersection of two cell ranges is empty 132 '#DIV/0!': 7, # Division by zero 133 '#VALUE!': 36, # Wrong type of operand 134 '#REF!' : 23, # Illegal or deleted cell reference 135 '#NAME?' : 29, # Wrong function or range name 136 '#NUM!' : 36, # Value range overflow 137 '#N/A!' : 42, # Argument or function not available 138} 139 140class ErrorCell(object): 141 __slots__ = ["rowx", "colx", "xf_idx", "number"] 142 143 def __init__(self, rowx, colx, xf_idx, error_string_or_code): 144 self.rowx = rowx 145 self.colx = colx 146 self.xf_idx = xf_idx 147 try: 148 self.number = error_code_map[error_string_or_code] 149 except KeyError: 150 raise Exception('Illegal error value (%r)' % error_string_or_code) 151 152 def get_biff_data(self): 153 return BIFFRecords.BoolErrRecord(self.rowx, 154 self.colx, self.xf_idx, self.number, 1).get() 155 156class FormulaCell(object): 157 __slots__ = ["rowx", "colx", "xf_idx", "frmla", "calc_flags"] 158 159 def __init__(self, rowx, colx, xf_idx, frmla, calc_flags=0): 160 self.rowx = rowx 161 self.colx = colx 162 self.xf_idx = xf_idx 163 self.frmla = frmla 164 self.calc_flags = calc_flags 165 166 def get_biff_data(self): 167 return BIFFRecords.FormulaRecord(self.rowx, 168 self.colx, self.xf_idx, self.frmla.rpn(), self.calc_flags).get() 169 170# module-level function for *internal* use by the Row module 171 172def _get_cells_biff_data_mul(rowx, cell_items): 173 # Return the BIFF data for all cell records in the row. 174 # Adjacent BLANK|RK records are combined into MUL(BLANK|RK) records. 175 pieces = [] 176 nitems = len(cell_items) 177 i = 0 178 while i < nitems: 179 icolx, icell = cell_items[i] 180 if isinstance(icell, NumberCell): 181 isRK, value = icell.get_encoded_data() 182 if not isRK: 183 pieces.append(value) # pre-packed NUMBER record 184 i += 1 185 continue 186 muldata = [(value, icell.xf_idx)] 187 target = NumberCell 188 elif isinstance(icell, BlankCell): 189 muldata = [icell.xf_idx] 190 target = BlankCell 191 else: 192 pieces.append(icell.get_biff_data()) 193 i += 1 194 continue 195 lastcolx = icolx 196 j = i 197 packed_record = '' 198 for j in xrange(i+1, nitems): 199 jcolx, jcell = cell_items[j] 200 if jcolx != lastcolx + 1: 201 nexti = j 202 break 203 if not isinstance(jcell, target): 204 nexti = j 205 break 206 if target == NumberCell: 207 isRK, value = jcell.get_encoded_data() 208 if not isRK: 209 packed_record = value 210 nexti = j + 1 211 break 212 muldata.append((value, jcell.xf_idx)) 213 else: 214 muldata.append(jcell.xf_idx) 215 lastcolx = jcolx 216 else: 217 nexti = j + 1 218 if target == NumberCell: 219 if lastcolx == icolx: 220 # RK record 221 value, xf_idx = muldata[0] 222 pieces.append(pack('<5Hi', 0x027E, 10, rowx, icolx, xf_idx, value)) 223 else: 224 # MULRK record 225 nc = lastcolx - icolx + 1 226 pieces.append(pack('<4H', 0x00BD, 6 * nc + 6, rowx, icolx)) 227 pieces.append(b''.join(pack('<Hi', xf_idx, value) for value, xf_idx in muldata)) 228 pieces.append(pack('<H', lastcolx)) 229 else: 230 if lastcolx == icolx: 231 # BLANK record 232 xf_idx = muldata[0] 233 pieces.append(pack('<5H', 0x0201, 6, rowx, icolx, xf_idx)) 234 else: 235 # MULBLANK record 236 nc = lastcolx - icolx + 1 237 pieces.append(pack('<4H', 0x00BE, 2 * nc + 6, rowx, icolx)) 238 pieces.append(b''.join(pack('<H', xf_idx) for xf_idx in muldata)) 239 pieces.append(pack('<H', lastcolx)) 240 if packed_record: 241 pieces.append(packed_record) 242 i = nexti 243 return b''.join(pieces) 244 245