Lib.xlwt.BIFFRecords.py Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sikulixapi Show documentation
Show all versions of sikulixapi Show documentation
... for visual testing and automation
# -*- coding: cp1252 -*-
from struct import pack
from UnicodeUtils import upack1, upack2, upack2rt
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):
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):
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 = ''
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 = 0x00L
ver_can_read = 0x06L
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 = ''
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('=8
2 var. List of OFFSET structures for all portions. Each OFFSET contains the following data:
Offset Size Contents
0 4 Absolute stream position of first string of the portion
4 2 Position of first string of the portion inside of current record,
including record header. This counter restarts at zero, if the SST
record is continued with a CONTINUE record.
6 2 Not used
"""
_REC_ID = 0x00FF
def __init__(self, sst_stream_pos, str_placement, portions_len):
extsst = {}
abs_stream_pos = sst_stream_pos
str_counter = 0
portion_counter = 0
while str_counter < len(str_placement):
str_chunk_num, pos_in_chunk = str_placement[str_counter]
if str_chunk_num <> portion_counter:
portion_counter = str_chunk_num
abs_stream_pos += portions_len[portion_counter-1]
#print hex(abs_stream_pos)
str_stream_pos = abs_stream_pos + pos_in_chunk + 4 # header
extsst[str_counter] = (pos_in_chunk, str_stream_pos)
str_counter += 1
exsst_str_count_delta = max(8, len(str_placement)*8/0x2000) # maybe smth else?
self._rec_data = pack(' last_used_row or first_used_col > last_used_col:
# Special case: empty worksheet
first_used_row = first_used_col = 0
last_used_row = last_used_col = -1
self._rec_data = pack('<2L3H',
first_used_row, last_used_row + 1,
first_used_col, last_used_col + 1,
0x00)
class Window2Record(BiffRecord):
"""
Record WINDOW2, BIFF8:
Offset Size Contents
0 2 Option flags (see below)
2 2 Index to first visible row
4 2 Index to first visible column
6 2 Colour index of grid line colour. Note that in BIFF2-BIFF7 an RGB colour is
written instead.
8 2 Not used
10 2 Cached magnification factor in page break preview (in percent); 0 = Default (60%)
12 2 Cached magnification factor in normal view (in percent); 0 = Default (100%)
14 4 Not used
In BIFF8 this record stores used magnification factors for page break
preview and normal view. These values are used to restore the
magnification, when the view is changed. The real magnification of the
currently active view is stored in the SCL record. The type of the
active view is stored in the option flags field (see below).
0 0001H 0 = Show formula results 1 = Show formulas
1 0002H 0 = Do not show grid lines 1 = Show grid lines
2 0004H 0 = Do not show sheet headers 1 = Show sheet headers
3 0008H 0 = Panes are not frozen 1 = Panes are frozen (freeze)
4 0010H 0 = Show zero values as empty cells 1 = Show zero values
5 0020H 0 = Manual grid line colour 1 = Automatic grid line colour
6 0040H 0 = Columns from left to right 1 = Columns from right to left
7 0080H 0 = Do not show outline symbols 1 = Show outline symbols
8 0100H 0 = Keep splits if pane freeze is removed 1 = Remove splits if pane freeze is removed
9 0200H 0 = Sheet not selected 1 = Sheet selected (BIFF5-BIFF8)
10 0400H 0 = Sheet not visible 1 = Sheet visible (BIFF5-BIFF8)
11 0800H 0 = Show in normal view 1 = Show in page break preview (BIFF8)
The freeze flag specifies, if a following PANE record describes unfrozen or frozen panes.
*** This class appends the optional SCL record ***
Record SCL, BIFF4-BIFF8:
This record stores the magnification of the active view of the current worksheet.
In BIFF8 this can be either the normal view or the page break preview.
This is determined in the WINDOW2 record. The SCL record is part of the
Sheet View Settings Block.
Offset Size Contents
0 2 Numerator of the view magnification fraction (num)
2 2 Denumerator [denominator] of the view magnification fraction (den)
The magnification is stored as reduced fraction. The magnification results from num/den.
SJM note: Excel expresses (e.g.) 25% in reduced form i.e. 1/4. Reason unknown. This code
writes 25/100, and Excel is happy with that.
"""
_REC_ID = 0x023E
def __init__(self, options, first_visible_row, first_visible_col,
grid_colour, preview_magn, normal_magn, scl_magn):
self._rec_data = pack('<7HL', options,
first_visible_row, first_visible_col,
grid_colour,
0x00,
preview_magn, normal_magn,
0x00L)
if scl_magn is not None:
self._scl_rec = pack('<4H', 0x00A0, 4, scl_magn, 100)
else:
self._scl_rec = ''
def get(self):
return self.get_rec_header() + self._rec_data + self._scl_rec
class PanesRecord(BiffRecord):
"""
This record stores the position of window panes. It is part of the Sheet
View Settings Block. If the sheet does not contain any splits, this
record will not occur.
A sheet can be split in two different ways, with unfrozen panes or with
frozen panes. A flag in the WINDOW2 record specifies, if the panes are
frozen, which affects the contents of this record.
Record PANE, BIFF2-BIFF8:
Offset Size Contents
0 2 Position of the vertical split
(px, 0 = No vertical split):
Unfrozen pane: Width of the left pane(s)
(in twips = 1/20 of a point)
Frozen pane: Number of visible
columns in left pane(s)
2 2 Position of the horizontal split
(py, 0 = No horizontal split):
Unfrozen pane: Height of the top pane(s)
(in twips = 1/20 of a point)
Frozen pane: Number of visible
rows in top pane(s)
4 2 Index to first visible row
in bottom pane(s)
6 2 Index to first visible column
in right pane(s)
8 1 Identifier of pane with active
cell cursor
[9] 1 Not used (BIFF5-BIFF8 only, not written
in BIFF2-BIFF4)
If the panes are frozen, pane?0 is always active, regardless
of the cursor position. The correct identifiers for all possible
combinations of visible panes are shown in the following pictures.
px = 0, py = 0 px = 0, py > 0
-------------------------- ------------|-------------
| | | |
| | | 3 |
| | | |
- 3 - --------------------------
| | | |
| | | 2 |
| | | |
-------------------------- ------------|-------------
px > 0, py = 0 px > 0, py > 0
------------|------------- ------------|-------------
| | | | | |
| | | | 3 | 2 |
| | | | | |
- 3 | 1 - --------------------------
| | | | | |
| | | | 1 | 0 |
| | | | | |
------------|------------- ------------|-------------
"""
_REC_ID = 0x0041
valid_active_pane = {
# entries are of the form:
# (int(px > 0),int(px>0)) -> allowed values
(0,0):(3,),
(0,1):(2,3),
(1,0):(1,3),
(1,1):(0,1,2,3),
}
def __init__(self, px, py, first_row_bottom, first_col_right, active_pane):
allowed = self.valid_active_pane.get(
(int(px > 0),int(py > 0))
)
if active_pane not in allowed:
raise ValueError('Cannot set active_pane to %i, must be one of %s' % (
active_pane, ', '.join(allowed)
))
self._rec_data = pack('<5H',
px, py,
first_row_bottom, first_col_right,
active_pane)
class RowRecord(BiffRecord):
"""
This record contains the properties of a single row in a sheet. Rows
and cells in a sheet are divided into blocks of 32 rows.
Record ROW, BIFF3-BIFF8:
Offset Size Contents
0 2 Index of this row
2 2 Index to column of the first cell which is described by a cell record
4 2 Index to column of the last cell which is described by a cell record,
increased by 1
6 2 Bit Mask Contents
14-0 7FFFH Height of the row, in twips = 1/20 of a point
15 8000H 0 = Row has custom height; 1 = Row has default height
8 2 Not used
10 2 In BIFF3-BIFF4 this field contains a relative offset
to calculate stream position of the first cell record
for this row. In BIFF5-BIFF8 this field is not used
anymore, but the DBCELL record instead.
12 4 Option flags and default row formatting:
Bit Mask Contents
2-0 00000007H Outline level of the row
4 00000010H 1 = Outline group starts or ends here (depending
on where the outline buttons are located,
see WSBOOL record), and is collapsed
5 00000020H 1 = Row is hidden (manually, or by a filter or outline group)
6 00000040H 1 = Row height and default font height do not match
7 00000080H 1 = Row has explicit default format (fl)
8 00000100H Always 1
27-16 0FFF0000H If fl=1: Index to default XF record
28 10000000H 1 = Additional space above the row. This flag is set,
if the upper border of at least one cell in this row
or if the lower border of at least one cell in the row
above is formatted with a thick line style.
Thin and medium line styles are not taken into account.
29 20000000H 1 = Additional space below the row. This flag is set,
if the lower border of at least one cell in this row
or if the upper border of at least one cell in the row
below is formatted with a medium or thick line style.
Thin line styles are not taken into account.
"""
_REC_ID = 0x0208
def __init__(self, index, first_col, last_col, height_options, options):
self._rec_data = pack('<6HL', index, first_col, last_col + 1,
height_options,
0x00, 0x00,
options)
class LabelSSTRecord(BiffRecord):
"""
This record represents a cell that contains a string. It replaces the
LABEL record and RSTRING record used in BIFF2-BIFF7.
"""
_REC_ID = 0x00FD
def __init__(self, row, col, xf_idx, sst_idx):
self._rec_data = pack('<3HL', row, col, xf_idx, sst_idx)
class MergedCellsRecord(BiffRecord):
"""
This record contains all merged cell ranges of the current sheet.
Record MERGEDCELLS, BIFF8:
Offset Size Contents
0 var. Cell range address list with all merged ranges
------------------------------------------------------------------
A cell range address list consists of a field with the number of ranges
and the list of the range addresses.
Cell range address list, BIFF8:
Offset Size Contents
0 2 Number of following cell range addresses (nm)
2 8*nm List of nm cell range addresses
---------------------------------------------------------------------
Cell range address, BIFF8:
Offset Size Contents
0 2 Index to first row
2 2 Index to last row
4 2 Index to first column
6 2 Index to last column
"""
_REC_ID = 0x00E5
def __init__(self, merged_list):
i = len(merged_list) - 1
while i >= 0:
j = 0
merged = ''
while (i >= 0) and (j < 0x403):
r1, r2, c1, c2 = merged_list[i]
merged += pack('<4H', r1, r2, c1, c2)
i -= 1
j += 1
self._rec_data += pack('<3H', self._REC_ID, len(merged) + 2, j) + \
merged
# for some reason Excel doesn't use CONTINUE
def get(self):
return self._rec_data
class MulBlankRecord(BiffRecord):
"""
This record represents a cell range of empty cells. All cells are
located in the same row.
Record MULBLANK, BIFF5-BIFF8:
Offset Size Contents
0 2 Index to row
2 2 Index to first column (fc)
4 2*nc List of nc=lc-fc+1 16-bit indexes to XF records
4+2*nc 2 Index to last column (lc)
"""
_REC_ID = 0x00BE
def __init__(self, row, first_col, last_col, xf_index):
blanks_count = last_col-first_col+1
self._rec_data = pack('<%dH' % blanks_count, *([xf_index] * blanks_count))
self._rec_data = pack('<2H', row, first_col) + self._rec_data + pack('" Set new font
&","
Set new font with specified style .
The style is in most cases one of
"Regular", "Bold", "Italic", or "Bold Italic".
But this setting is dependent on the used font,
it may differ (localised style names, or "Standard",
"Oblique", ...). (BIFF5-BIFF8)
& Set font height in points ( is a decimal value).
If this command is followed by a plain number to be printed
in the header, it will be separated from the font height
with a space character.
"""
_REC_ID = 0x0014
def __init__(self, header_str):
self._rec_data = upack2(header_str)
class FooterRecord(BiffRecord):
"""
Semantic is equal to HEADER record
"""
_REC_ID = 0x0015
def __init__(self, footer_str):
self._rec_data = upack2(footer_str)
class HCenterRecord(BiffRecord):
"""
This record is part of the Page Settings Block. It specifies if the
sheet is centred horizontally when printed.
Record HCENTER, BIFF3-BIFF8:
Offset Size Contents
0 2 0 = Print sheet left aligned
1 = Print sheet centred horizontally
"""
_REC_ID = 0x0083
def __init__(self, is_horz_center):
self._rec_data = pack(' 0) Menu text (Unicode string without length field, 3.4)
[var.] var. (optional, only if ld > 0) Description text (Unicode string without length field, 3.4)
[var.] var. (optional, only if lh > 0) Help topic text (Unicode string without length field, 3.4)
[var.] var. (optional, only if ls > 0) Status bar text (Unicode string without length field, 3.4)
"""
_REC_ID = 0x0018
def __init__(self, options, keyboard_shortcut, name, sheet_index, rpn, menu_text='', desc_text='', help_text='', status_text=''):
if type(name) == int:
uname = chr(name)
else:
uname = upack1(name)[1:]
uname_len = len(uname)
#~ self._rec_data = pack('", see 3.9.1)
"""
def __init__(self, num_sheets):
self._rec_data = pack('