# -*- coding: cp1252 -*- from struct import pack from .UnicodeUtils import upack1, upack2, upack2rt from .compat import basestring, unicode, unicode_type, xrange, iteritems class SharedStringTable(object): _SST_ID = 0x00FC _CONTINUE_ID = 0x003C def __init__(self, encoding): self.encoding = encoding self._str_indexes = {} self._rt_indexes = {} self._tally = [] self._add_calls = 0 # Following 3 attrs are used for temporary storage in the # get_biff_record() method and methods called by it. The pseudo- # initialisation here is for documentation purposes only. self._sst_record = None self._continues = None self._current_piece = None def add_str(self, s): if self.encoding != 'ascii' and not isinstance(s, unicode_type): s = unicode(s, self.encoding) self._add_calls += 1 if s not in self._str_indexes: idx = len(self._str_indexes) + len(self._rt_indexes) self._str_indexes[s] = idx self._tally.append(1) else: idx = self._str_indexes[s] self._tally[idx] += 1 return idx def add_rt(self, rt): rtList = [] for s, xf in rt: if self.encoding != 'ascii' and not isinstance(s, unicode_type): s = unicode(s, self.encoding) rtList.append((s, xf)) rt = tuple(rtList) self._add_calls += 1 if rt not in self._rt_indexes: idx = len(self._str_indexes) + len(self._rt_indexes) self._rt_indexes[rt] = idx self._tally.append(1) else: idx = self._rt_indexes[rt] self._tally[idx] += 1 return idx def del_str(self, idx): # This is called when we are replacing the contents of a string cell. # handles both regular and rt strings assert self._tally[idx] > 0 self._tally[idx] -= 1 self._add_calls -= 1 def str_index(self, s): return self._str_indexes[s] def rt_index(self, rt): return self._rt_indexes[rt] def get_biff_record(self): self._sst_record = b'' self._continues = [None, None] self._current_piece = pack(' 0x2020: # limit for BIFF7/8 chunks = [] pos = 0 while pos < len(data): chunk_pos = pos + 0x2020 chunk = data[pos:chunk_pos] chunks.append(chunk) pos = chunk_pos continues = pack('<2H', self._REC_ID, len(chunks[0])) + chunks[0] for chunk in chunks[1:]: continues += pack('<2H%ds'%len(chunk), 0x003C, len(chunk), chunk) # 0x003C -- CONTINUE record id return continues else: return self.get_rec_header() + data class Biff8BOFRecord(BiffRecord): """ Offset Size Contents 0 2 Version, contains 0600H for BIFF8 and BIFF8X 2 2 Type of the following data: 0005H = Workbook globals 0006H = Visual Basic module 0010H = Worksheet 0020H = Chart 0040H = Macro sheet 0100H = Workspace file 4 2 Build identifier 6 2 Build year 8 4 File history flags 12 4 Lowest Excel version that can read all records in this file """ _REC_ID = 0x0809 # stream types BOOK_GLOBAL = 0x0005 VB_MODULE = 0x0006 WORKSHEET = 0x0010 CHART = 0x0020 MACROSHEET = 0x0040 WORKSPACE = 0x0100 def __init__(self, rec_type): version = 0x0600 build = 0x0DBB year = 0x07CC file_hist_flags = 0x00 ver_can_read = 0x06 self._rec_data = pack('<4H2I', version, rec_type, build, year, file_hist_flags, ver_can_read) class InteraceHdrRecord(BiffRecord): _REC_ID = 0x00E1 def __init__(self): self._rec_data = pack('BB', 0xB0, 0x04) class InteraceEndRecord(BiffRecord): _REC_ID = 0x00E2 def __init__(self): self._rec_data = b'' class MMSRecord(BiffRecord): _REC_ID = 0x00C1 def __init__(self): self._rec_data = pack('> 15 c = low_15 | high_15 passwd_hash ^= c passwd_hash ^= len(plaintext) passwd_hash ^= 0xCE4B return passwd_hash def __init__(self, passwd = ""): self._rec_data = pack('