diff options
| author | Claude Paroz <claude@2xlibre.net> | 2017-02-20 21:29:22 +0100 |
|---|---|---|
| committer | Iuri de Silvio <iurisilvio@gmail.com> | 2017-02-20 17:29:22 -0300 |
| commit | 0ca5520bbc1474dbd872a3f330c681a5201336fd (patch) | |
| tree | 84225bc603981a073c53e90d8ca12d250a9a94b5 /tablib/packages | |
| parent | e66eb4a18967dd4d35e6e9da265622e9e4015103 (diff) | |
| download | tablib-0ca5520bbc1474dbd872a3f330c681a5201336fd.tar.gz | |
Replaced vendored xlrd/xlwt by dependencies (#277)
Refs #273.
Diffstat (limited to 'tablib/packages')
91 files changed, 0 insertions, 42745 deletions
diff --git a/tablib/packages/xlrd/__init__.py b/tablib/packages/xlrd/__init__.py deleted file mode 100644 index 9097d9d..0000000 --- a/tablib/packages/xlrd/__init__.py +++ /dev/null @@ -1,1720 +0,0 @@ -# -*- coding: cp1252 -*- - -__VERSION__ = "0.7.1" # 2009-05-31 - -# <p>Copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a -# BSD-style licence.</p> - -import licences - -## -# <p><b>A Python module for extracting data from MS Excel ™ spreadsheet files. -# <br /><br /> -# Version 0.7.1 -- 2009-05-31 -# </b></p> -# -# <h2>General information</h2> -# -# <h3>Acknowledgements</h3> -# -# <p> -# Development of this module would not have been possible without the document -# "OpenOffice.org's Documentation of the Microsoft Excel File Format" -# ("OOo docs" for short). -# The latest version is available from OpenOffice.org in -# <a href=http://sc.openoffice.org/excelfileformat.pdf> PDF format</a> -# and -# <a href=http://sc.openoffice.org/excelfileformat.odt> ODT format.</a> -# Small portions of the OOo docs are reproduced in this -# document. A study of the OOo docs is recommended for those who wish a -# deeper understanding of the Excel file layout than the xlrd docs can provide. -# </p> -# -# <p>Backporting to Python 2.1 was partially funded by -# <a href=http://journyx.com/> -# Journyx - provider of timesheet and project accounting solutions. -# </a> -# </p> -# -# <p>Provision of formatting information in version 0.6.1 was funded by -# <a href=http://www.simplistix.co.uk> -# Simplistix Ltd. -# </a> -# </p> -# -# <h3>Unicode</h3> -# -# <p>This module presents all text strings as Python unicode objects. -# From Excel 97 onwards, text in Excel spreadsheets has been stored as Unicode. -# Older files (Excel 95 and earlier) don't keep strings in Unicode; -# a CODEPAGE record provides a codepage number (for example, 1252) which is -# used by xlrd to derive the encoding (for same example: "cp1252") which is -# used to translate to Unicode.</p> -# <small> -# <p>If the CODEPAGE record is missing (possible if the file was created -# by third-party software), xlrd will assume that the encoding is ascii, and keep going. -# If the actual encoding is not ascii, a UnicodeDecodeError exception will be raised and -# you will need to determine the encoding yourself, and tell xlrd: -# <pre> -# book = xlrd.open_workbook(..., encoding_override="cp1252") -# </pre></p> -# <p>If the CODEPAGE record exists but is wrong (for example, the codepage -# number is 1251, but the strings are actually encoded in koi8_r), -# it can be overridden using the same mechanism. -# The supplied runxlrd.py has a corresponding command-line argument, which -# may be used for experimentation: -# <pre> -# runxlrd.py -e koi8_r 3rows myfile.xls -# </pre></p> -# <p>The first place to look for an encoding ("codec name") is -# <a href=http://docs.python.org/lib/standard-encodings.html> -# the Python documentation</a>. -# </p> -# </small> -# -# <h3>Dates in Excel spreadsheets</h3> -# -# <p>In reality, there are no such things. What you have are floating point -# numbers and pious hope. -# There are several problems with Excel dates:</p> -# -# <p>(1) Dates are not stored as a separate data type; they are stored as -# floating point numbers and you have to rely on -# (a) the "number format" applied to them in Excel and/or -# (b) knowing which cells are supposed to have dates in them. -# This module helps with (a) by inspecting the -# format that has been applied to each number cell; -# if it appears to be a date format, the cell -# is classified as a date rather than a number. Feedback on this feature, -# especially from non-English-speaking locales, would be appreciated.</p> -# -# <p>(2) Excel for Windows stores dates by default as the number of -# days (or fraction thereof) since 1899-12-31T00:00:00. Excel for -# Macintosh uses a default start date of 1904-01-01T00:00:00. The date -# system can be changed in Excel on a per-workbook basis (for example: -# Tools -> Options -> Calculation, tick the "1904 date system" box). -# This is of course a bad idea if there are already dates in the -# workbook. There is no good reason to change it even if there are no -# dates in the workbook. Which date system is in use is recorded in the -# workbook. A workbook transported from Windows to Macintosh (or vice -# versa) will work correctly with the host Excel. When using this -# module's xldate_as_tuple function to convert numbers from a workbook, -# you must use the datemode attribute of the Book object. If you guess, -# or make a judgement depending on where you believe the workbook was -# created, you run the risk of being 1462 days out of kilter.</p> -# -# <p>Reference: -# http://support.microsoft.com/default.aspx?scid=KB;EN-US;q180162</p> -# -# -# <p>(3) The Excel implementation of the Windows-default 1900-based date system works on the -# incorrect premise that 1900 was a leap year. It interprets the number 60 as meaning 1900-02-29, -# which is not a valid date. Consequently any number less than 61 is ambiguous. Example: is 59 the -# result of 1900-02-28 entered directly, or is it 1900-03-01 minus 2 days? The OpenOffice.org Calc -# program "corrects" the Microsoft problem; entering 1900-02-27 causes the number 59 to be stored. -# Save as an XLS file, then open the file with Excel -- you'll see 1900-02-28 displayed.</p> -# -# <p>Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;214326</p> -# -# <p>(4) The Macintosh-default 1904-based date system counts 1904-01-02 as day 1 and 1904-01-01 as day zero. -# Thus any number such that (0.0 <= number < 1.0) is ambiguous. Is 0.625 a time of day (15:00:00), -# independent of the calendar, -# or should it be interpreted as an instant on a particular day (1904-01-01T15:00:00)? -# The xldate_* functions in this module -# take the view that such a number is a calendar-independent time of day (like Python's datetime.time type) for both -# date systems. This is consistent with more recent Microsoft documentation -# (for example, the help file for Excel 2002 which says that the first day -# in the 1904 date system is 1904-01-02). -# -# <p>(5) Usage of the Excel DATE() function may leave strange dates in a spreadsheet. Quoting the help file, -# in respect of the 1900 date system: "If year is between 0 (zero) and 1899 (inclusive), -# Excel adds that value to 1900 to calculate the year. For example, DATE(108,1,2) returns January 2, 2008 (1900+108)." -# This gimmick, semi-defensible only for arguments up to 99 and only in the pre-Y2K-awareness era, -# means that DATE(1899, 12, 31) is interpreted as 3799-12-31.</p> -# -# <p>For further information, please refer to the documentation for the xldate_* functions.</p> -# -# <h3> Named references, constants, formulas, and macros</h3> -# -# <p> -# A name is used to refer to a cell, a group of cells, a constant -# value, a formula, or a macro. Usually the scope of a name is global -# across the whole workbook. However it can be local to a worksheet. -# For example, if the sales figures are in different cells in -# different sheets, the user may define the name "Sales" in each -# sheet. There are built-in names, like "Print_Area" and -# "Print_Titles"; these two are naturally local to a sheet. -# </p><p> -# To inspect the names with a user interface like MS Excel, OOo Calc, -# or Gnumeric, click on Insert/Names/Define. This will show the global -# names, plus those local to the currently selected sheet. -# </p><p> -# A Book object provides two dictionaries (name_map and -# name_and_scope_map) and a list (name_obj_list) which allow various -# ways of accessing the Name objects. There is one Name object for -# each NAME record found in the workbook. Name objects have many -# attributes, several of which are relevant only when obj.macro is 1. -# </p><p> -# In the examples directory you will find namesdemo.xls which -# showcases the many different ways that names can be used, and -# xlrdnamesAPIdemo.py which offers 3 different queries for inspecting -# the names in your files, and shows how to extract whatever a name is -# referring to. There is currently one "convenience method", -# Name.cell(), which extracts the value in the case where the name -# refers to a single cell. More convenience methods are planned. The -# source code for Name.cell (in __init__.py) is an extra source of -# information on how the Name attributes hang together. -# </p> -# -# <p><i>Name information is <b>not</b> extracted from files older than -# Excel 5.0 (Book.biff_version < 50)</i></p> -# -# <h3>Formatting</h3> -# -# <h4>Introduction</h4> -# -# <p>This collection of features, new in xlrd version 0.6.1, is intended -# to provide the information needed to (1) display/render spreadsheet contents -# (say) on a screen or in a PDF file, and (2) copy spreadsheet data to another -# file without losing the ability to display/render it.</p> -# -# <h4>The Palette; Colour Indexes</h4> -# -# <p>A colour is represented in Excel as a (red, green, blue) ("RGB") tuple -# with each component in range(256). However it is not possible to access an -# unlimited number of colours; each spreadsheet is limited to a palette of 64 different -# colours (24 in Excel 3.0 and 4.0, 8 in Excel 2.0). Colours are referenced by an index -# ("colour index") into this palette. -# -# Colour indexes 0 to 7 represent 8 fixed built-in colours: black, white, red, green, blue, -# yellow, magenta, and cyan.<p> -# -# The remaining colours in the palette (8 to 63 in Excel 5.0 and later) -# can be changed by the user. In the Excel 2003 UI, Tools/Options/Color presents a palette -# of 7 rows of 8 colours. The last two rows are reserved for use in charts.<br /> -# The correspondence between this grid and the assigned -# colour indexes is NOT left-to-right top-to-bottom.<br /> -# Indexes 8 to 15 correspond to changeable -# parallels of the 8 fixed colours -- for example, index 7 is forever cyan; -# index 15 starts off being cyan but can be changed by the user.<br /> -# -# The default colour for each index depends on the file version; tables of the defaults -# are available in the source code. If the user changes one or more colours, -# a PALETTE record appears in the XLS file -- it gives the RGB values for *all* changeable -# indexes.<br /> -# Note that colours can be used in "number formats": "[CYAN]...." and "[COLOR8]...." refer -# to colour index 7; "[COLOR16]...." will produce cyan -# unless the user changes colour index 15 to something else.<br /> -# -# <p>In addition, there are several "magic" colour indexes used by Excel:<br /> -# 0x18 (BIFF3-BIFF4), 0x40 (BIFF5-BIFF8): System window text colour for border lines -# (used in XF, CF, and WINDOW2 records)<br /> -# 0x19 (BIFF3-BIFF4), 0x41 (BIFF5-BIFF8): System window background colour for pattern background -# (used in XF and CF records )<br /> -# 0x43: System face colour (dialogue background colour)<br /> -# 0x4D: System window text colour for chart border lines<br /> -# 0x4E: System window background colour for chart areas<br /> -# 0x4F: Automatic colour for chart border lines (seems to be always Black)<br /> -# 0x50: System ToolTip background colour (used in note objects)<br /> -# 0x51: System ToolTip text colour (used in note objects)<br /> -# 0x7FFF: System window text colour for fonts (used in FONT and CF records)<br /> -# Note 0x7FFF appears to be the *default* colour index. It appears quite often in FONT -# records.<br /> -# -# <h4>Default Formatting</h4> -# -# Default formatting is applied to all empty cells (those not described by a cell record). -# Firstly row default information (ROW record, Rowinfo class) is used if available. -# Failing that, column default information (COLINFO record, Colinfo class) is used if available. -# As a last resort the worksheet/workbook default cell format will be used; this -# should always be present in an Excel file, -# described by the XF record with the fixed index 15 (0-based). By default, it uses the -# worksheet/workbook default cell style, described by the very first XF record (index 0). -# -# <h4> Formatting features not included in xlrd version 0.6.1</h4> -# <ul> -# <li>Rich text i.e. strings containing partial <b>bold</b> <i>italic</i> -# and <u>underlined</u> text, change of font inside a string, etc. -# See OOo docs s3.4 and s3.2</li> -# <li>Asian phonetic text (known as "ruby"), used for Japanese furigana. See OOo docs -# s3.4.2 (p15)</li> -# <li>Conditional formatting. See OOo docs -# s5.12, s6.21 (CONDFMT record), s6.16 (CF record)</li> -# <li>Miscellaneous sheet-level and book-level items e.g. printing layout, screen panes. </li> -# <li>Modern Excel file versions don't keep most of the built-in -# "number formats" in the file; Excel loads formats according to the -# user's locale. Currently xlrd's emulation of this is limited to -# a hard-wired table that applies to the US English locale. This may mean -# that currency symbols, date order, thousands separator, decimals separator, etc -# are inappropriate. Note that this does not affect users who are copying XLS -# files, only those who are visually rendering cells.</li> -# </ul> -# -# <h3>Loading worksheets on demand</h3> -# -# <p>This feature, new in version 0.7.1, is governed by the on_demand argument -# to the open_workbook() function and allows saving memory and time by loading -# only those sheets that the caller is interested in, and releasing sheets -# when no longer required.</p> -# -# <p>on_demand=False (default): No change. open_workbook() loads global data -# and all sheets, releases resources no longer required (principally the -# str or mmap object containing the Workbook stream), and returns.</p> -# -# <p>on_demand=True and BIFF version < 5.0: A warning message is emitted, -# on_demand is recorded as False, and the old process is followed.</p> -# -# <p>on_demand=True and BIFF version >= 5.0: open_workbook() loads global -# data and returns without releasing resources. At this stage, the only -# information available about sheets is Book.nsheets and Book.sheet_names().</p> -# -# <p>Book.sheet_by_name() and Book.sheet_by_index() will load the requested -# sheet if it is not already loaded.</p> -# -# <p>Book.sheets() will load all/any unloaded sheets.</p> -# -# <p>The caller may save memory by calling -# Book.unload_sheet(sheet_name_or_index) when finished with the sheet. -# This applies irrespective of the state of on_demand.</p> -# -# <p>The caller may re-load an unloaded sheet by calling Book.sheet_by_xxxx() -# -- except if those required resources have been released (which will -# have happened automatically when on_demand is false). This is the only -# case where an exception will be raised.</p> -# -# <p>The caller may query the state of a sheet: -# Book.sheet_loaded(sheet_name_or_index) -> a bool</p> -# -## - -# 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo -# 2008-11-23 SJM Support dumping FILEPASS and EXTERNNAME records; extra info from SUPBOOK records -# 2008-11-23 SJM colname utility function now supports more than 256 columns -# 2008-04-24 SJM Recovery code for file with out-of-order/missing/wrong CODEPAGE record needed to be called for EXTERNSHEET/BOUNDSHEET/NAME/SHEETHDR records. -# 2008-02-08 SJM Preparation for Excel 2.0 support -# 2008-02-03 SJM Minor tweaks for IronPython support -# 2008-02-02 SJM Previous change stopped dump() and count_records() ... fixed -# 2007-12-25 SJM Decouple Book initialisation & loading -- to allow for multiple loaders. -# 2007-12-20 SJM Better error message for unsupported file format. -# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -# 2007-11-20 SJM Wasn't handling EXTERNSHEET record that needed CONTINUE record(s) -# 2007-07-07 SJM Version changed to 0.7.0 (alpha 1) -# 2007-07-07 SJM Logfile arg wasn't being passed from open_workbook to compdoc.CompDoc -# 2007-05-21 SJM If no CODEPAGE record in pre-8.0 file, assume ascii and keep going. -# 2007-04-22 SJM Removed antique undocumented Book.get_name_dict method. - -from timemachine import * -from biffh import * -from struct import unpack -import sys -import time -import sheet -import compdoc -from xldate import xldate_as_tuple, XLDateError -from formula import * -import formatting -if sys.version.startswith("IronPython"): - # print >> sys.stderr, "...importing encodings" - import encodings - -empty_cell = sheet.empty_cell # for exposure to the world ... - -DEBUG = 0 - -USE_FANCY_CD = 1 - -TOGGLE_GC = 0 -import gc -# gc.set_debug(gc.DEBUG_STATS) - -try: - import mmap - MMAP_AVAILABLE = 1 -except ImportError: - MMAP_AVAILABLE = 0 -USE_MMAP = MMAP_AVAILABLE - -MY_EOF = 0xF00BAAA # not a 16-bit number - -SUPBOOK_UNK, SUPBOOK_INTERNAL, SUPBOOK_EXTERNAL, SUPBOOK_ADDIN, SUPBOOK_DDEOLE = range(5) - -SUPPORTED_VERSIONS = (80, 70, 50, 45, 40, 30, 21, 20) - -code_from_builtin_name = { - u"Consolidate_Area": u"\x00", - u"Auto_Open": u"\x01", - u"Auto_Close": u"\x02", - u"Extract": u"\x03", - u"Database": u"\x04", - u"Criteria": u"\x05", - u"Print_Area": u"\x06", - u"Print_Titles": u"\x07", - u"Recorder": u"\x08", - u"Data_Form": u"\x09", - u"Auto_Activate": u"\x0A", - u"Auto_Deactivate": u"\x0B", - u"Sheet_Title": u"\x0C", - u"_FilterDatabase": u"\x0D", - } -builtin_name_from_code = {} -for _bin, _bic in code_from_builtin_name.items(): - builtin_name_from_code[_bic] = _bin -del _bin, _bic - -## -# -# Open a spreadsheet file for data extraction. -# -# @param filename The path to the spreadsheet file to be opened. -# -# @param logfile An open file to which messages and diagnostics are written. -# -# @param verbosity Increases the volume of trace material written to the logfile. -# -# @param pickleable Default is true. In Python 2.4 or earlier, setting to false -# will cause use of array.array objects which save some memory but can't be pickled. -# In Python 2.5, array.arrays are used unconditionally. Note: if you have large files that -# you need to read multiple times, it can be much faster to cPickle.dump() the xlrd.Book object -# once, and use cPickle.load() multiple times. -# @param use_mmap Whether to use the mmap module is determined heuristically. -# Use this arg to override the result. Current heuristic: mmap is used if it exists. -# -# @param file_contents ... as a string or an mmap.mmap object or some other behave-alike object. -# If file_contents is supplied, filename will not be used, except (possibly) in messages. -# -# @param encoding_override Used to overcome missing or bad codepage information -# in older-version files. Refer to discussion in the <b>Unicode</b> section above. -# <br /> -- New in version 0.6.0 -# -# @param formatting_info Governs provision of a reference to an XF (eXtended Format) object -# for each cell in the worksheet. -# <br /> Default is <i>False</i>. This is backwards compatible and saves memory. -# "Blank" cells (those with their own formatting information but no data) are treated as empty -# (by ignoring the file's BLANK and MULBLANK records). -# It cuts off any bottom "margin" of rows of empty (and blank) cells and -# any right "margin" of columns of empty (and blank) cells. -# Only cell_value and cell_type are available. -# <br /> <i>True</i> provides all cells, including empty and blank cells. -# XF information is available for each cell. -# <br /> -- New in version 0.6.1 -# -# @param on_demand Governs whether sheets are all loaded initially or when demanded -# by the caller. Please refer back to the section "Loading worksheets on demand" for details. -# -- New in version 0.7.1 -# -# @return An instance of the Book class. - -def open_workbook(filename=None, - logfile=sys.stdout, verbosity=0, pickleable=True, use_mmap=USE_MMAP, - file_contents=None, - encoding_override=None, - formatting_info=False, on_demand=False, - ): - t0 = time.clock() - if TOGGLE_GC: - orig_gc_enabled = gc.isenabled() - if orig_gc_enabled: - gc.disable() - bk = Book() - bk.biff2_8_load( - filename=filename, file_contents=file_contents, - logfile=logfile, verbosity=verbosity, pickleable=pickleable, use_mmap=use_mmap, - encoding_override=encoding_override, - formatting_info=formatting_info, - on_demand=on_demand, - ) - t1 = time.clock() - bk.load_time_stage_1 = t1 - t0 - biff_version = bk.getbof(XL_WORKBOOK_GLOBALS) - if not biff_version: - raise XLRDError("Can't determine file's BIFF version") - if biff_version not in SUPPORTED_VERSIONS: - raise XLRDError( - "BIFF version %s is not supported" - % biff_text_from_num[biff_version] - ) - bk.biff_version = biff_version - if biff_version <= 40: - # no workbook globals, only 1 worksheet - if on_demand: - fprintf(bk.logfile, - "*** WARNING: on_demand is not supported for this Excel version.\n" - "*** Setting on_demand to False.\n") - bk.on_demand = on_demand = False - bk.fake_globals_get_sheet() - elif biff_version == 45: - # worksheet(s) embedded in global stream - bk.parse_globals() - if on_demand: - fprintf(bk.logfile, "*** WARNING: on_demand is not supported for this Excel version.\n" - "*** Setting on_demand to False.\n") - bk.on_demand = on_demand = False - else: - bk.parse_globals() - bk._sheet_list = [None for sh in bk._sheet_names] - if not on_demand: - bk.get_sheets() - bk.nsheets = len(bk._sheet_list) - if biff_version == 45 and bk.nsheets > 1: - fprintf(bk.logfile, - "*** WARNING: Excel 4.0 workbook (.XLW) file contains %d worksheets.\n" - "*** Book-level data will be that of the last worksheet.\n", - bk.nsheets - ) - if not on_demand: - bk.release_resources() - if TOGGLE_GC: - if orig_gc_enabled: - gc.enable() - t2 = time.clock() - bk.load_time_stage_2 = t2 - t1 - return bk - -## -# For debugging: dump the file's BIFF records in char & hex. -# @param filename The path to the file to be dumped. -# @param outfile An open file, to which the dump is written. -# @param unnumbered If true, omit offsets (for meaningful diffs). - -def dump(filename, outfile=sys.stdout, unnumbered=False): - bk = Book() - bk.biff2_8_load(filename=filename, logfile=outfile, ) - biff_dump(bk.mem, bk.base, bk.stream_len, 0, outfile, unnumbered) - -## -# For debugging and analysis: summarise the file's BIFF records. -# I.e. produce a sorted file of (record_name, count). -# @param filename The path to the file to be summarised. -# @param outfile An open file, to which the summary is written. - -def count_records(filename, outfile=sys.stdout): - bk = Book() - bk.biff2_8_load(filename=filename, logfile=outfile, ) - biff_count_records(bk.mem, bk.base, bk.stream_len, outfile) - -## -# Information relating to a named reference, formula, macro, etc. -# <br /> -- New in version 0.6.0 -# <br /> -- <i>Name information is <b>not</b> extracted from files older than -# Excel 5.0 (Book.biff_version < 50)</i> - -class Name(BaseObject): - - _repr_these = ['stack'] - book = None # parent - - ## - # 0 = Visible; 1 = Hidden - hidden = 0 - - ## - # 0 = Command macro; 1 = Function macro. Relevant only if macro == 1 - func = 0 - - ## - # 0 = Sheet macro; 1 = VisualBasic macro. Relevant only if macro == 1 - vbasic = 0 - - ## - # 0 = Standard name; 1 = Macro name - macro = 0 - - ## - # 0 = Simple formula; 1 = Complex formula (array formula or user defined)<br /> - # <i>No examples have been sighted.</i> - complex = 0 - - ## - # 0 = User-defined name; 1 = Built-in name - # (common examples: Print_Area, Print_Titles; see OOo docs for full list) - builtin = 0 - - ## - # Function group. Relevant only if macro == 1; see OOo docs for values. - funcgroup = 0 - - ## - # 0 = Formula definition; 1 = Binary data<br /> <i>No examples have been sighted.</i> - binary = 0 - - ## - # The index of this object in book.name_obj_list - name_index = 0 - - ## - # A Unicode string. If builtin, decoded as per OOo docs. - name = u"" - - ## - # An 8-bit string. - raw_formula = "" - - ## - # -1: The name is global (visible in all calculation sheets).<br /> - # -2: The name belongs to a macro sheet or VBA sheet.<br /> - # -3: The name is invalid.<br /> - # 0 <= scope < book.nsheets: The name is local to the sheet whose index is scope. - scope = -1 - - ## - # The result of evaluating the formula, if any. - # If no formula, or evaluation of the formula encountered problems, - # the result is None. Otherwise the result is a single instance of the - # Operand class. - # - result = None - - ## - # This is a convenience method for the frequent use case where the name - # refers to a single cell. - # @return An instance of the Cell class. - # @throws XLRDError The name is not a constant absolute reference - # to a single cell. - def cell(self): - res = self.result - if res: - # result should be an instance of the Operand class - kind = res.kind - value = res.value - if kind == oREF and len(value) == 1: - ref3d = value[0] - if (0 <= ref3d.shtxlo == ref3d.shtxhi - 1 - and ref3d.rowxlo == ref3d.rowxhi - 1 - and ref3d.colxlo == ref3d.colxhi - 1): - sh = self.book.sheet_by_index(ref3d.shtxlo) - return sh.cell(ref3d.rowxlo, ref3d.colxlo) - self.dump(self.book.logfile, - header="=== Dump of Name object ===", - footer="======= End of dump =======", - ) - raise XLRDError("Not a constant absolute reference to a single cell") - - ## - # This is a convenience method for the use case where the name - # refers to one rectangular area in one worksheet. - # @param clipped If true (the default), the returned rectangle is clipped - # to fit in (0, sheet.nrows, 0, sheet.ncols) -- it is guaranteed that - # 0 <= rowxlo <= rowxhi <= sheet.nrows and that the number of usable rows - # in the area (which may be zero) is rowxhi - rowxlo; likewise for columns. - # @return a tuple (sheet_object, rowxlo, rowxhi, colxlo, colxhi). - # @throws XLRDError The name is not a constant absolute reference - # to a single area in a single sheet. - def area2d(self, clipped=True): - res = self.result - if res: - # result should be an instance of the Operand class - kind = res.kind - value = res.value - if kind == oREF and len(value) == 1: # only 1 reference - ref3d = value[0] - if 0 <= ref3d.shtxlo == ref3d.shtxhi - 1: # only 1 usable sheet - sh = self.book.sheet_by_index(ref3d.shtxlo) - if not clipped: - return sh, ref3d.rowxlo, ref3d.rowxhi, ref3d.colxlo, ref3d.colxhi - rowxlo = min(ref3d.rowxlo, sh.nrows) - rowxhi = max(rowxlo, min(ref3d.rowxhi, sh.nrows)) - colxlo = min(ref3d.colxlo, sh.ncols) - colxhi = max(colxlo, min(ref3d.colxhi, sh.ncols)) - assert 0 <= rowxlo <= rowxhi <= sh.nrows - assert 0 <= colxlo <= colxhi <= sh.ncols - return sh, rowxlo, rowxhi, colxlo, colxhi - self.dump(self.book.logfile, - header="=== Dump of Name object ===", - footer="======= End of dump =======", - ) - raise XLRDError("Not a constant absolute reference to a single area in a single sheet") - -## -# Contents of a "workbook". -# <p>WARNING: You don't call this class yourself. You use the Book object that -# was returned when you called xlrd.open_workbook("myfile.xls").</p> - -class Book(BaseObject): - - ## - # The number of worksheets present in the workbook file. - # This information is available even when no sheets have yet been loaded. - nsheets = 0 - - ## - # Which date system was in force when this file was last saved.<br /> - # 0 => 1900 system (the Excel for Windows default).<br /> - # 1 => 1904 system (the Excel for Macintosh default).<br /> - datemode = 0 # In case it's not specified in the file. - - ## - # Version of BIFF (Binary Interchange File Format) used to create the file. - # Latest is 8.0 (represented here as 80), introduced with Excel 97. - # Earliest supported by this module: 2.0 (represented as 20). - biff_version = 0 - - ## - # List containing a Name object for each NAME record in the workbook. - # <br /> -- New in version 0.6.0 - name_obj_list = [] - - ## - # An integer denoting the character set used for strings in this file. - # For BIFF 8 and later, this will be 1200, meaning Unicode; more precisely, UTF_16_LE. - # For earlier versions, this is used to derive the appropriate Python encoding - # to be used to convert to Unicode. - # Examples: 1252 -> 'cp1252', 10000 -> 'mac_roman' - codepage = None - - ## - # The encoding that was derived from the codepage. - encoding = None - - ## - # A tuple containing the (telephone system) country code for:<br /> - # [0]: the user-interface setting when the file was created.<br /> - # [1]: the regional settings.<br /> - # Example: (1, 61) meaning (USA, Australia). - # This information may give a clue to the correct encoding for an unknown codepage. - # For a long list of observed values, refer to the OpenOffice.org documentation for - # the COUNTRY record. - countries = (0, 0) - - ## - # What (if anything) is recorded as the name of the last user to save the file. - user_name = u'' - - ## - # A list of Font class instances, each corresponding to a FONT record. - # <br /> -- New in version 0.6.1 - font_list = [] - - ## - # A list of XF class instances, each corresponding to an XF record. - # <br /> -- New in version 0.6.1 - xf_list = [] - - ## - # A list of Format objects, each corresponding to a FORMAT record, in - # the order that they appear in the input file. - # It does <i>not</i> contain builtin formats. - # If you are creating an output file using (for example) pyExcelerator, - # use this list. - # The collection to be used for all visual rendering purposes is format_map. - # <br /> -- New in version 0.6.1 - format_list = [] - - ## - # The mapping from XF.format_key to Format object. - # <br /> -- New in version 0.6.1 - format_map = {} - - ## - # This provides access via name to the extended format information for - # both built-in styles and user-defined styles.<br /> - # It maps <i>name</i> to (<i>built_in</i>, <i>xf_index</i>), where:<br /> - # <i>name</i> is either the name of a user-defined style, - # or the name of one of the built-in styles. Known built-in names are - # Normal, RowLevel_1 to RowLevel_7, - # ColLevel_1 to ColLevel_7, Comma, Currency, Percent, "Comma [0]", - # "Currency [0]", Hyperlink, and "Followed Hyperlink".<br /> - # <i>built_in</i> 1 = built-in style, 0 = user-defined<br /> - # <i>xf_index</i> is an index into Book.xf_list.<br /> - # References: OOo docs s6.99 (STYLE record); Excel UI Format/Style - # <br /> -- New in version 0.6.1 - style_name_map = {} - - ## - # This provides definitions for colour indexes. Please refer to the - # above section "The Palette; Colour Indexes" for an explanation - # of how colours are represented in Excel.<br /> - # Colour indexes into the palette map into (red, green, blue) tuples. - # "Magic" indexes e.g. 0x7FFF map to None. - # <i>colour_map</i> is what you need if you want to render cells on screen or in a PDF - # file. If you are writing an output XLS file, use <i>palette_record</i>. - # <br /> -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) - colour_map = {} - - ## - # If the user has changed any of the colours in the standard palette, the XLS - # file will contain a PALETTE record with 56 (16 for Excel 4.0 and earlier) - # RGB values in it, and this list will be e.g. [(r0, b0, g0), ..., (r55, b55, g55)]. - # Otherwise this list will be empty. This is what you need if you are - # writing an output XLS file. If you want to render cells on screen or in a PDF - # file, use colour_map. - # <br /> -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) - palette_record = [] - - ## - # Time in seconds to extract the XLS image as a contiguous string (or mmap equivalent). - load_time_stage_1 = -1.0 - - ## - # Time in seconds to parse the data from the contiguous string (or mmap equivalent). - load_time_stage_2 = -1.0 - - ## - # @return A list of all sheets in the book. - # All sheets not already loaded will be loaded. - def sheets(self): - for sheetx in xrange(self.nsheets): - if not self._sheet_list[sheetx]: - self.get_sheet(sheetx) - return self._sheet_list[:] - - ## - # @param sheetx Sheet index in range(nsheets) - # @return An object of the Sheet class - def sheet_by_index(self, sheetx): - return self._sheet_list[sheetx] or self.get_sheet(sheetx) - - ## - # @param sheet_name Name of sheet required - # @return An object of the Sheet class - def sheet_by_name(self, sheet_name): - try: - sheetx = self._sheet_names.index(sheet_name) - except ValueError: - raise XLRDError('No sheet named <%r>' % sheet_name) - return self.sheet_by_index(sheetx) - - ## - # @return A list of the names of all the worksheets in the workbook file. - # This information is available even when no sheets have yet been loaded. - def sheet_names(self): - return self._sheet_names[:] - - ## - # @param sheet_name_or_index Name or index of sheet enquired upon - # @return true if sheet is loaded, false otherwise - # <br /> -- New in version 0.7.1 - def sheet_loaded(self, sheet_name_or_index): - # using type(1) because int won't work with Python 2.1 - if isinstance(sheet_name_or_index, type(1)): - sheetx = sheet_name_or_index - else: - try: - sheetx = self._sheet_names.index(sheet_name_or_index) - except ValueError: - raise XLRDError('No sheet named <%r>' % sheet_name_or_index) - return self._sheet_list[sheetx] and True or False # Python 2.1 again - - ## - # @param sheet_name_or_index Name or index of sheet to be unloaded. - # <br /> -- New in version 0.7.1 - def unload_sheet(self, sheet_name_or_index): - # using type(1) because int won't work with Python 2.1 - if isinstance(sheet_name_or_index, type(1)): - sheetx = sheet_name_or_index - else: - try: - sheetx = self._sheet_names.index(sheet_name_or_index) - except ValueError: - raise XLRDError('No sheet named <%r>' % sheet_name_or_index) - self._sheet_list[sheetx] = None - - ## - # A mapping from (lower_case_name, scope) to a single Name object. - # <br /> -- New in version 0.6.0 - name_and_scope_map = {} - - ## - # A mapping from lower_case_name to a list of Name objects. The list is - # sorted in scope order. Typically there will be one item (of global scope) - # in the list. - # <br /> -- New in version 0.6.0 - name_map = {} - - def __init__(self): - self._sheet_list = [] - self._sheet_names = [] - self._sheet_visibility = [] # from BOUNDSHEET record - self.nsheets = 0 - self._sh_abs_posn = [] # sheet's absolute position in the stream - self._sharedstrings = [] - self.raw_user_name = False - self._sheethdr_count = 0 # BIFF 4W only - self.builtinfmtcount = -1 # unknown as yet. BIFF 3, 4S, 4W - self.initialise_format_info() - self._all_sheets_count = 0 # includes macro & VBA sheets - self._supbook_count = 0 - self._supbook_locals_inx = None - self._supbook_addins_inx = None - self._all_sheets_map = [] # maps an all_sheets index to a calc-sheets index (or -1) - self._externsheet_info = [] - self._externsheet_type_b57 = [] - self._extnsht_name_from_num = {} - self._sheet_num_from_name = {} - self._extnsht_count = 0 - self._supbook_types = [] - self._resources_released = 0 - self.addin_func_names = [] - self.name_obj_list = [] - self.colour_map = {} - self.palette_record = [] - self.xf_list = [] - self.style_name_map = {} - - def biff2_8_load(self, filename=None, file_contents=None, - logfile=sys.stdout, verbosity=0, pickleable=True, use_mmap=USE_MMAP, - encoding_override=None, - formatting_info=False, - on_demand=False, - ): - # DEBUG = 0 - self.logfile = logfile - self.verbosity = verbosity - self.pickleable = pickleable - self.use_mmap = use_mmap and MMAP_AVAILABLE - self.encoding_override = encoding_override - self.formatting_info = formatting_info - self.on_demand = on_demand - - need_close_filestr = 0 - if not file_contents: - if python_version < (2, 2) and self.use_mmap: - # need to open for update - open_mode = "r+b" - else: - open_mode = "rb" - retry = False - try: - f = open(filename, open_mode) - except IOError: - e, v = sys.exc_info()[:2] - if open_mode == "r+b" \ - and (v.errno == 13 or v.strerror == "Permission denied"): - # Maybe the file is read-only - retry = True - self.use_mmap = False - else: - raise - if retry: - f = open(filename, "rb") - if self.use_mmap: - f.seek(0, 2) # EOF - size = f.tell() - f.seek(0, 0) # BOF - if python_version < (2, 2): - filestr = mmap.mmap(f.fileno(), size) - else: - filestr = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ) - need_close_filestr = 1 - self.stream_len = size - else: - filestr = f.read() - self.stream_len = len(filestr) - f.close() - else: - filestr = file_contents - self.stream_len = len(file_contents) - - self.base = 0 - if filestr[:8] != compdoc.SIGNATURE: - # got this one at the antique store - self.mem = filestr - else: - cd = compdoc.CompDoc(filestr, logfile=self.logfile) - if USE_FANCY_CD: - for qname in [u'Workbook', u'Book']: - self.mem, self.base, self.stream_len = cd.locate_named_stream(qname) - if self.mem: break - else: - raise XLRDError("Can't find workbook in OLE2 compound document") - else: - for qname in [u'Workbook', u'Book']: - self.mem = cd.get_named_stream(qname) - if self.mem: break - else: - raise XLRDError("Can't find workbook in OLE2 compound document") - self.stream_len = len(self.mem) - del cd - if self.mem is not filestr: - if need_close_filestr: - filestr.close() - del filestr - self._position = self.base - if DEBUG: - print >> self.logfile, "mem: %s, base: %d, len: %d" % (type(self.mem), self.base, self.stream_len) - - def initialise_format_info(self): - # needs to be done once per sheet for BIFF 4W :-( - self.format_map = {} - self.format_list = [] - self.xfcount = 0 - self.actualfmtcount = 0 # number of FORMAT records seen so far - self._xf_index_to_xl_type_map = {} - self._xf_epilogue_done = 0 - self.xf_list = [] - self.font_list = [] - - def release_resources(self): - self._resources_released = 1 - del self.mem - del self._sharedstrings - - def get2bytes(self): - pos = self._position - buff_two = self.mem[pos:pos+2] - lenbuff = len(buff_two) - self._position += lenbuff - if lenbuff < 2: - return MY_EOF - lo, hi = buff_two - return (ord(hi) << 8) | ord(lo) - - def get_record_parts(self): - pos = self._position - mem = self.mem - code, length = unpack('<HH', mem[pos:pos+4]) - pos += 4 - data = mem[pos:pos+length] - self._position = pos + length - return (code, length, data) - - def get_record_parts_conditional(self, reqd_record): - pos = self._position - mem = self.mem - code, length = unpack('<HH', mem[pos:pos+4]) - if code != reqd_record: - return (None, 0, '') - pos += 4 - data = mem[pos:pos+length] - self._position = pos + length - return (code, length, data) - - def get_sheet(self, sh_number, update_pos=True): - if self._resources_released: - raise XLRDError("Can't load sheets after releasing resources.") - if update_pos: - self._position = self._sh_abs_posn[sh_number] - _unused_biff_version = self.getbof(XL_WORKSHEET) - # assert biff_version == self.biff_version ### FAILS - # Have an example where book is v7 but sheet reports v8!!! - # It appears to work OK if the sheet version is ignored. - # Confirmed by Daniel Rentz: happens when Excel does "save as" - # creating an old version file; ignore version details on sheet BOF. - sh = sheet.Sheet(self, - self._position, - self._sheet_names[sh_number], - sh_number, - ) - sh.read(self) - self._sheet_list[sh_number] = sh - return sh - - def get_sheets(self): - # DEBUG = 0 - if DEBUG: print >> self.logfile, "GET_SHEETS:", self._sheet_names, self._sh_abs_posn - for sheetno in xrange(len(self._sheet_names)): - if DEBUG: print >> self.logfile, "GET_SHEETS: sheetno =", sheetno, self._sheet_names, self._sh_abs_posn - self.get_sheet(sheetno) - - def fake_globals_get_sheet(self): # for BIFF 4.0 and earlier - formatting.initialise_book(self) - fake_sheet_name = u'Sheet 1' - self._sheet_names = [fake_sheet_name] - self._sh_abs_posn = [0] - self._sheet_visibility = [0] # one sheet, visible - self._sheet_list.append(None) # get_sheet updates _sheet_list but needs a None beforehand - self.get_sheets() - - def handle_boundsheet(self, data): - # DEBUG = 1 - bv = self.biff_version - self.derive_encoding() - if DEBUG: - fprintf(self.logfile, "BOUNDSHEET: bv=%d data %r\n", bv, data); - if bv == 45: # BIFF4W - #### Not documented in OOo docs ... - # In fact, the *only* data is the name of the sheet. - sheet_name = unpack_string(data, 0, self.encoding, lenlen=1) - visibility = 0 - sheet_type = XL_BOUNDSHEET_WORKSHEET # guess, patch later - if len(self._sh_abs_posn) == 0: - abs_posn = self._sheetsoffset + self.base - # Note (a) this won't be used - # (b) it's the position of the SHEETHDR record - # (c) add 11 to get to the worksheet BOF record - else: - abs_posn = -1 # unknown - else: - offset, visibility, sheet_type = unpack('<iBB', data[0:6]) - abs_posn = offset + self.base # because global BOF is always at posn 0 in the stream - if bv < BIFF_FIRST_UNICODE: - sheet_name = unpack_string(data, 6, self.encoding, lenlen=1) - else: - sheet_name = unpack_unicode(data, 6, lenlen=1) - - if DEBUG or self.verbosity >= 2: - fprintf(self.logfile, - "BOUNDSHEET: inx=%d vis=%r sheet_name=%r abs_posn=%d sheet_type=0x%02x\n", - self._all_sheets_count, visibility, sheet_name, abs_posn, sheet_type) - self._all_sheets_count += 1 - if sheet_type != XL_BOUNDSHEET_WORKSHEET: - self._all_sheets_map.append(-1) - descr = { - 1: 'Macro sheet', - 2: 'Chart', - 6: 'Visual Basic module', - }.get(sheet_type, 'UNKNOWN') - - fprintf(self.logfile, - "NOTE *** Ignoring non-worksheet data named %r (type 0x%02x = %s)\n", - sheet_name, sheet_type, descr) - else: - snum = len(self._sheet_names) - self._all_sheets_map.append(snum) - self._sheet_names.append(sheet_name) - self._sh_abs_posn.append(abs_posn) - self._sheet_visibility.append(visibility) - self._sheet_num_from_name[sheet_name] = snum - - def handle_builtinfmtcount(self, data): - ### N.B. This count appears to be utterly useless. - # DEBUG = 1 - builtinfmtcount = unpack('<H', data[0:2])[0] - if DEBUG: fprintf(self.logfile, "BUILTINFMTCOUNT: %r\n", builtinfmtcount) - self.builtinfmtcount = builtinfmtcount - - def derive_encoding(self): - if self.encoding_override: - self.encoding = self.encoding_override - elif self.codepage is None: - if self.biff_version < 80: - fprintf(self.logfile, - "*** No CODEPAGE record, no encoding_override: will use 'ascii'\n") - self.encoding = 'ascii' - else: - self.codepage = 1200 # utf16le - if self.verbosity >= 2: - fprintf(self.logfile, "*** No CODEPAGE record; assuming 1200 (utf_16_le)\n") - else: - codepage = self.codepage - if encoding_from_codepage.has_key(codepage): - encoding = encoding_from_codepage[codepage] - elif 300 <= codepage <= 1999: - encoding = 'cp' + str(codepage) - else: - encoding = 'unknown_codepage_' + str(codepage) - if DEBUG or (self.verbosity and encoding != self.encoding) : - fprintf(self.logfile, "CODEPAGE: codepage %r -> encoding %r\n", codepage, encoding) - self.encoding = encoding - if self.codepage != 1200: # utf_16_le - # If we don't have a codec that can decode ASCII into Unicode, - # we're well & truly stuffed -- let the punter know ASAP. - try: - _unused = unicode('trial', self.encoding) - except: - ei = sys.exc_info()[:2] - fprintf(self.logfile, - "ERROR *** codepage %r -> encoding %r -> %s: %s\n", - self.codepage, self.encoding, ei[0].__name__.split(".")[-1], ei[1]) - raise - if self.raw_user_name: - strg = unpack_string(self.user_name, 0, self.encoding, lenlen=1) - strg = strg.rstrip() - # if DEBUG: - # print "CODEPAGE: user name decoded from %r to %r" % (self.user_name, strg) - self.user_name = strg - self.raw_user_name = False - return self.encoding - - def handle_codepage(self, data): - # DEBUG = 0 - codepage = unpack('<H', data[0:2])[0] - self.codepage = codepage - self.derive_encoding() - - def handle_country(self, data): - countries = unpack('<HH', data[0:4]) - if self.verbosity: print >> self.logfile, "Countries:", countries - # Note: in BIFF7 and earlier, country record was put (redundantly?) in each worksheet. - assert self.countries == (0, 0) or self.countries == countries - self.countries = countries - - def handle_datemode(self, data): - datemode = unpack('<H', data[0:2])[0] - if DEBUG or self.verbosity: - fprintf(self.logfile, "DATEMODE: datemode %r\n", datemode) - assert datemode in (0, 1) - self.datemode = datemode - - def handle_externname(self, data): - blah = DEBUG or self.verbosity >= 2 - if self.biff_version >= 80: - option_flags, other_info =unpack("<HI", data[:6]) - pos = 6 - name, pos = unpack_unicode_update_pos(data, pos, lenlen=1) - extra = data[pos:] - if self._supbook_types[-1] == SUPBOOK_ADDIN: - self.addin_func_names.append(name) - if blah: - fprintf(self.logfile, - "EXTERNNAME: sbktype=%d oflags=0x%04x oinfo=0x%08x name=%r extra=%r\n", - self._supbook_types[-1], option_flags, other_info, name, extra) - - def handle_externsheet(self, data): - self.derive_encoding() # in case CODEPAGE record missing/out of order/wrong - self._extnsht_count += 1 # for use as a 1-based index - blah1 = DEBUG or self.verbosity >= 1 - blah2 = DEBUG or self.verbosity >= 2 - if self.biff_version >= 80: - num_refs = unpack("<H", data[0:2])[0] - bytes_reqd = num_refs * 6 + 2 - while len(data) < bytes_reqd: - if blah1: - fprintf( - self.logfile, - "INFO: EXTERNSHEET needs %d bytes, have %d\n", - bytes_reqd, len(data), - ) - code2, length2, data2 = self.get_record_parts() - if code2 != XL_CONTINUE: - raise XLRDError("Missing CONTINUE after EXTERNSHEET record") - data += data2 - pos = 2 - for k in xrange(num_refs): - info = unpack("<HHH", data[pos:pos+6]) - ref_recordx, ref_first_sheetx, ref_last_sheetx = info - self._externsheet_info.append(info) - pos += 6 - if blah2: - fprintf( - self.logfile, - "EXTERNSHEET(b8): k = %2d, record = %2d, first_sheet = %5d, last sheet = %5d\n", - k, ref_recordx, ref_first_sheetx, ref_last_sheetx, - ) - else: - nc, ty = unpack("<BB", data[:2]) - if blah2: - print "EXTERNSHEET(b7-):" - hex_char_dump(data, 0, len(data)) - msg = { - 1: "Encoded URL", - 2: "Current sheet!!", - 3: "Specific sheet in own doc't", - 4: "Nonspecific sheet in own doc't!!", - }.get(ty, "Not encoded") - print " %3d chars, type is %d (%s)" % (nc, ty, msg) - if ty == 3: - sheet_name = unicode(data[2:nc+2], self.encoding) - self._extnsht_name_from_num[self._extnsht_count] = sheet_name - if blah2: print self._extnsht_name_from_num - if not (1 <= ty <= 4): - ty = 0 - self._externsheet_type_b57.append(ty) - - def handle_filepass(self, data): - if self.verbosity >= 2: - logf = self.logfile - fprintf(logf, "FILEPASS:\n") - hex_char_dump(data, 0, len(data), base=0, fout=logf) - if self.biff_version >= 80: - kind1, = unpack('<H', data[:2]) - if kind1 == 0: # weak XOR encryption - key, hash_value = unpack('<HH', data[2:]) - fprintf(logf, - 'weak XOR: key=0x%04x hash=0x%04x\n', - key, hash_value) - elif kind1 == 1: - kind2, = unpack('<H', data[4:6]) - if kind2 == 1: # BIFF8 standard encryption - caption = "BIFF8 std" - elif kind2 == 2: - caption = "BIFF8 strong" - else: - caption = "** UNKNOWN ENCRYPTION METHOD **" - fprintf(logf, "%s\n", caption) - raise XLRDError("Workbook is encrypted") - - def handle_name(self, data): - blah = DEBUG or self.verbosity >= 2 - bv = self.biff_version - if bv < 50: - return - self.derive_encoding() - # print - # hex_char_dump(data, 0, len(data)) - ( - option_flags, kb_shortcut, name_len, fmla_len, extsht_index, sheet_index, - menu_text_len, description_text_len, help_topic_text_len, status_bar_text_len, - ) = unpack("<HBBHHH4B", data[0:14]) - nobj = Name() - nobj.book = self ### CIRCULAR ### - name_index = len(self.name_obj_list) - nobj.name_index = name_index - self.name_obj_list.append(nobj) - nobj.option_flags = option_flags - for attr, mask, nshift in ( - ('hidden', 1, 0), - ('func', 2, 1), - ('vbasic', 4, 2), - ('macro', 8, 3), - ('complex', 0x10, 4), - ('builtin', 0x20, 5), - ('funcgroup', 0xFC0, 6), - ('binary', 0x1000, 12), - ): - setattr(nobj, attr, (option_flags & mask) >> nshift) - - macro_flag = " M"[nobj.macro] - if bv < 80: - internal_name, pos = unpack_string_update_pos(data, 14, self.encoding, known_len=name_len) - else: - internal_name, pos = unpack_unicode_update_pos(data, 14, known_len=name_len) - nobj.extn_sheet_num = extsht_index - nobj.excel_sheet_index = sheet_index - nobj.scope = None # patched up in the names_epilogue() method - if blah: - print "NAME[%d]:%s oflags=%d, name_len=%d, fmla_len=%d, extsht_index=%d, sheet_index=%d, name=%r" \ - % (name_index, macro_flag, option_flags, name_len, - fmla_len, extsht_index, sheet_index, internal_name) - name = internal_name - if nobj.builtin: - name = builtin_name_from_code.get(name, "??Unknown??") - if blah: print " builtin: %s" % name - nobj.name = name - nobj.raw_formula = data[pos:] - nobj.basic_formula_len = fmla_len - nobj.evaluated = 0 - if blah: - nobj.dump( - self.logfile, - header="--- handle_name: name[%d] ---" % name_index, - footer="-------------------", - ) - - def names_epilogue(self): - blah = self.verbosity >= 2 - f = self.logfile - if blah: - print >> f, "+++++ names_epilogue +++++" - print >> f, "_all_sheets_map", self._all_sheets_map - print >> f, "_extnsht_name_from_num", self._extnsht_name_from_num - print >> f, "_sheet_num_from_name", self._sheet_num_from_name - num_names = len(self.name_obj_list) - for namex in range(num_names): - nobj = self.name_obj_list[namex] - # Convert from excel_sheet_index to scope. - # This is done here because in BIFF7 and earlier, the - # BOUNDSHEET records (from which _all_sheets_map is derived) - # come after the NAME records. - if self.biff_version >= 80: - sheet_index = nobj.excel_sheet_index - if sheet_index == 0: - intl_sheet_index = -1 # global - elif 1 <= sheet_index <= len(self._all_sheets_map): - intl_sheet_index = self._all_sheets_map[sheet_index-1] - if intl_sheet_index == -1: # maps to a macro or VBA sheet - intl_sheet_index = -2 # valid sheet reference but not useful - else: - # huh? - intl_sheet_index = -3 # invalid - elif 50 <= self.biff_version <= 70: - sheet_index = nobj.extn_sheet_num - if sheet_index == 0: - intl_sheet_index = -1 # global - else: - sheet_name = self._extnsht_name_from_num[sheet_index] - intl_sheet_index = self._sheet_num_from_name.get(sheet_name, -2) - nobj.scope = intl_sheet_index - - for namex in range(num_names): - nobj = self.name_obj_list[namex] - # Parse the formula ... - if nobj.macro or nobj.binary: continue - if nobj.evaluated: continue - evaluate_name_formula(self, nobj, namex, blah=blah) - - if self.verbosity >= 2: - print >> f, "---------- name object dump ----------" - for namex in range(num_names): - nobj = self.name_obj_list[namex] - nobj.dump(f, header="--- name[%d] ---" % namex) - print >> f, "--------------------------------------" - # - # Build some dicts for access to the name objects - # - name_and_scope_map = {} # (name.lower(), scope): Name_object - name_map = {} # name.lower() : list of Name_objects (sorted in scope order) - for namex in range(num_names): - nobj = self.name_obj_list[namex] - name_lcase = nobj.name.lower() - key = (name_lcase, nobj.scope) - if name_and_scope_map.has_key(key): - msg = 'Duplicate entry %r in name_and_scope_map' % (key, ) - if 0: - raise XLRDError(msg) - else: - if self.verbosity: - print >> f, msg - name_and_scope_map[key] = nobj - if name_map.has_key(name_lcase): - name_map[name_lcase].append((nobj.scope, nobj)) - else: - name_map[name_lcase] = [(nobj.scope, nobj)] - for key in name_map.keys(): - alist = name_map[key] - alist.sort() - name_map[key] = [x[1] for x in alist] - self.name_and_scope_map = name_and_scope_map - self.name_map = name_map - - def handle_obj(self, data): - # Not doing much handling at all. - # Worrying about embedded (BOF ... EOF) substreams is done elsewhere. - # DEBUG = 1 - obj_type, obj_id = unpack('<HI', data[4:10]) - # if DEBUG: print "---> handle_obj type=%d id=0x%08x" % (obj_type, obj_id) - - def handle_supbook(self, data): - self._supbook_types.append(None) - blah = DEBUG or self.verbosity >= 2 - if 0: - print "SUPBOOK:" - hex_char_dump(data, 0, len(data)) - num_sheets = unpack("<H", data[0:2])[0] - sbn = self._supbook_count - self._supbook_count += 1 - if data[2:4] == "\x01\x04": - self._supbook_types[-1] = SUPBOOK_INTERNAL - self._supbook_locals_inx = self._supbook_count - 1 - if blah: - print "SUPBOOK[%d]: internal 3D refs; %d sheets" % (sbn, num_sheets) - print " _all_sheets_map", self._all_sheets_map - return - if data[0:4] == "\x01\x00\x01\x3A": - self._supbook_types[-1] = SUPBOOK_ADDIN - self._supbook_addins_inx = self._supbook_count - 1 - if blah: print "SUPBOOK[%d]: add-in functions" % sbn - return - url, pos = unpack_unicode_update_pos(data, 2, lenlen=2) - if num_sheets == 0: - self._supbook_types[-1] = SUPBOOK_DDEOLE - if blah: print "SUPBOOK[%d]: DDE/OLE document = %r" % (sbn, url) - return - self._supbook_types[-1] = SUPBOOK_EXTERNAL - if blah: print "SUPBOOK[%d]: url = %r" % (sbn, url) - sheet_names = [] - for x in range(num_sheets): - shname, pos = unpack_unicode_update_pos(data, pos, lenlen=2) - sheet_names.append(shname) - if blah: print " sheet %d: %r" % (x, shname) - - def handle_sheethdr(self, data): - # This a BIFF 4W special. - # The SHEETHDR record is followed by a (BOF ... EOF) substream containing - # a worksheet. - # DEBUG = 1 - self.derive_encoding() - sheet_len = unpack('<i', data[:4])[0] - sheet_name = unpack_string(data, 4, self.encoding, lenlen=1) - sheetno = self._sheethdr_count - assert sheet_name == self._sheet_names[sheetno] - self._sheethdr_count += 1 - BOF_posn = self._position - posn = BOF_posn - 4 - len(data) - if DEBUG: print >> self.logfile, 'SHEETHDR %d at posn %d: len=%d name=%r' % (sheetno, posn, sheet_len, sheet_name) - self.initialise_format_info() - if DEBUG: print >> self.logfile, 'SHEETHDR: xf epilogue flag is %d' % self._xf_epilogue_done - self._sheet_list.append(None) # get_sheet updates _sheet_list but needs a None beforehand - self.get_sheet(sheetno, update_pos=False) - if DEBUG: print >> self.logfile, 'SHEETHDR: posn after get_sheet() =', self._position - self._position = BOF_posn + sheet_len - - def handle_sheetsoffset(self, data): - # DEBUG = 0 - posn = unpack('<i', data)[0] - if DEBUG: print >> self.logfile, 'SHEETSOFFSET:', posn - self._sheetsoffset = posn - - def handle_sst(self, data): - # DEBUG = 1 - if DEBUG: - print >> self.logfile, "SST Processing" - t0 = time.time() - nbt = len(data) - strlist = [data] - uniquestrings = unpack('<i', data[4:8])[0] - if DEBUG or self.verbosity >= 2: - fprintf(self.logfile, "SST: unique strings: %d\n", uniquestrings) - while 1: - code, nb, data = self.get_record_parts_conditional(XL_CONTINUE) - if code is None: - break - nbt += nb - if DEBUG >= 2: - fprintf(self.logfile, "CONTINUE: adding %d bytes to SST -> %d\n", nb, nbt) - strlist.append(data) - self._sharedstrings = unpack_SST_table(strlist, uniquestrings) - if DEBUG: - t1 = time.time() - print >> self.logfile, "SST processing took %.2f seconds" % (t1 - t0, ) - - def handle_writeaccess(self, data): - # DEBUG = 0 - if self.biff_version < 80: - if not self.encoding: - self.raw_user_name = True - self.user_name = data - return - strg = unpack_string(data, 0, self.encoding, lenlen=1) - else: - strg = unpack_unicode(data, 0, lenlen=2) - if DEBUG: print >> self.logfile, "WRITEACCESS: %d bytes; raw=%d %r" % (len(data), self.raw_user_name, strg) - strg = strg.rstrip() - self.user_name = strg - - def parse_globals(self): - # DEBUG = 0 - # no need to position, just start reading (after the BOF) - formatting.initialise_book(self) - while 1: - rc, length, data = self.get_record_parts() - if DEBUG: print "parse_globals: record code is 0x%04x" % rc - if rc == XL_SST: - self.handle_sst(data) - elif rc == XL_FONT or rc == XL_FONT_B3B4: - self.handle_font(data) - elif rc == XL_FORMAT: # XL_FORMAT2 is BIFF <= 3.0, can't appear in globals - self.handle_format(data) - elif rc == XL_XF: - self.handle_xf(data) - elif rc == XL_BOUNDSHEET: - self.handle_boundsheet(data) - elif rc == XL_DATEMODE: - self.handle_datemode(data) - elif rc == XL_CODEPAGE: - self.handle_codepage(data) - elif rc == XL_COUNTRY: - self.handle_country(data) - elif rc == XL_EXTERNNAME: - self.handle_externname(data) - elif rc == XL_EXTERNSHEET: - self.handle_externsheet(data) - elif rc == XL_FILEPASS: - self.handle_filepass(data) - elif rc == XL_WRITEACCESS: - self.handle_writeaccess(data) - elif rc == XL_SHEETSOFFSET: - self.handle_sheetsoffset(data) - elif rc == XL_SHEETHDR: - self.handle_sheethdr(data) - elif rc == XL_SUPBOOK: - self.handle_supbook(data) - elif rc == XL_NAME: - self.handle_name(data) - elif rc == XL_PALETTE: - self.handle_palette(data) - elif rc == XL_STYLE: - self.handle_style(data) - elif rc & 0xff == 9: - print >> self.logfile, "*** Unexpected BOF at posn %d: 0x%04x len=%d data=%r" \ - % (self._position - length - 4, rc, length, data) - elif rc == XL_EOF: - self.xf_epilogue() - self.names_epilogue() - self.palette_epilogue() - if not self.encoding: - self.derive_encoding() - if self.biff_version == 45: - # DEBUG = 0 - if DEBUG: print "global EOF: position", self._position - # if DEBUG: - # pos = self._position - 4 - # print repr(self.mem[pos:pos+40]) - return - else: - # if DEBUG: - # print "parse_globals: ignoring record code 0x%04x" % rc - pass - - def read(self, pos, length): - data = self.mem[pos:pos+length] - self._position = pos + len(data) - return data - - def getbof(self, rqd_stream): - # DEBUG = 1 - # if DEBUG: print >> self.logfile, "getbof(): position", self._position - if DEBUG: print >> self.logfile, "reqd: 0x%04x" % rqd_stream - def bof_error(msg): - raise XLRDError('Unsupported format, or corrupt file: ' + msg) - savpos = self._position - opcode = self.get2bytes() - if opcode == MY_EOF: - bof_error('Expected BOF record; met end of file') - if opcode not in bofcodes: - bof_error('Expected BOF record; found %r' % self.mem[savpos:savpos+8]) - length = self.get2bytes() - if length == MY_EOF: - bof_error('Incomplete BOF record[1]; met end of file') - if length < boflen[opcode] or length > 20: - bof_error( - 'Invalid length (%d) for BOF record type 0x%04x' - % (length, opcode)) - data = self.read(self._position, length); - if DEBUG: print >> self.logfile, "\ngetbof(): data=%r" % data - if len(data) < length: - bof_error('Incomplete BOF record[2]; met end of file') - version1 = opcode >> 8 - version2, streamtype = unpack('<HH', data[0:4]) - if DEBUG: - print >> self.logfile, "getbof(): op=0x%04x version2=0x%04x streamtype=0x%04x" \ - % (opcode, version2, streamtype) - bof_offset = self._position - 4 - length - if DEBUG: - print >> self.logfile, "getbof(): BOF found at offset %d; savpos=%d" \ - % (bof_offset, savpos) - version = build = year = 0 - if version1 == 0x08: - build, year = unpack('<HH', data[4:8]) - if version2 == 0x0600: - version = 80 - elif version2 == 0x0500: - if year < 1994 or build in (2412, 3218, 3321): - version = 50 - else: - version = 70 - else: - # dodgy one, created by a 3rd-party tool - version = { - 0x0000: 21, - 0x0007: 21, - 0x0200: 21, - 0x0300: 30, - 0x0400: 40, - }.get(version2, 0) - elif version1 in (0x04, 0x02, 0x00): - version = {0x04: 40, 0x02: 30, 0x00: 21}[version1] - - if version == 40 and streamtype == XL_WORKBOOK_GLOBALS_4W: - version = 45 # i.e. 4W - - if DEBUG or self.verbosity >= 2: - print >> self.logfile, \ - "BOF: op=0x%04x vers=0x%04x stream=0x%04x buildid=%d buildyr=%d -> BIFF%d" \ - % (opcode, version2, streamtype, build, year, version) - got_globals = streamtype == XL_WORKBOOK_GLOBALS or ( - version == 45 and streamtype == XL_WORKBOOK_GLOBALS_4W) - if (rqd_stream == XL_WORKBOOK_GLOBALS and got_globals) or streamtype == rqd_stream: - return version - if version < 50 and streamtype == XL_WORKSHEET: - return version - if version >= 50 and streamtype == 0x0100: - bof_error("Workspace file -- no spreadsheet data") - bof_error( - 'BOF not workbook/worksheet: op=0x%04x vers=0x%04x strm=0x%04x build=%d year=%d -> BIFF%d' \ - % (opcode, version2, streamtype, build, year, version) - ) - -# === helper functions - -def expand_cell_address(inrow, incol): - # Ref : OOo docs, "4.3.4 Cell Addresses in BIFF8" - outrow = inrow - if incol & 0x8000: - if outrow >= 32768: - outrow -= 65536 - relrow = 1 - else: - relrow = 0 - outcol = incol & 0xFF - if incol & 0x4000: - if outcol >= 128: - outcol -= 256 - relcol = 1 - else: - relcol = 0 - return outrow, outcol, relrow, relcol - -def colname(colx, _A2Z="ABCDEFGHIJKLMNOPQRSTUVWXYZ"): - assert colx >= 0 - name = '' - while 1: - quot, rem = divmod(colx, 26) - name = _A2Z[rem] + name - if not quot: - return name - colx = quot - 1 - -def display_cell_address(rowx, colx, relrow, relcol): - if relrow: - rowpart = "(*%s%d)" % ("+-"[rowx < 0], abs(rowx)) - else: - rowpart = "$%d" % (rowx+1,) - if relcol: - colpart = "(*%s%d)" % ("+-"[colx < 0], abs(colx)) - else: - colpart = "$" + colname(colx) - return colpart + rowpart - -def unpack_SST_table(datatab, nstrings): - "Return list of strings" - datainx = 0 - ndatas = len(datatab) - data = datatab[0] - datalen = len(data) - pos = 8 - strings = [] - strappend = strings.append - local_unpack = unpack - local_min = min - local_ord = ord - latin_1 = "latin_1" - for _unused_i in xrange(nstrings): - nchars = local_unpack('<H', data[pos:pos+2])[0] - pos += 2 - options = local_ord(data[pos]) - pos += 1 - rtsz = 0 - if options & 0x08: # richtext - rtsz = 4 * local_unpack('<H', data[pos:pos+2])[0] - pos += 2 - if options & 0x04: # phonetic - rtsz += local_unpack('<i', data[pos:pos+4])[0] - pos += 4 - accstrg = u'' - charsgot = 0 - while 1: - charsneed = nchars - charsgot - if options & 0x01: - # Uncompressed UTF-16 - charsavail = local_min((datalen - pos) >> 1, charsneed) - rawstrg = data[pos:pos+2*charsavail] - # if DEBUG: print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - try: - accstrg += unicode(rawstrg, "utf_16_le") - except: - # print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - # Probable cause: dodgy data e.g. unfinished surrogate pair. - # E.g. file unicode2.xls in pyExcelerator's examples has cells containing - # unichr(i) for i in range(0x100000) - # so this will include 0xD800 etc - raise - pos += 2*charsavail - else: - # Note: this is COMPRESSED (not ASCII!) encoding!!! - charsavail = local_min(datalen - pos, charsneed) - rawstrg = data[pos:pos+charsavail] - # if DEBUG: print "SST CMPRSD: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - accstrg += unicode(rawstrg, latin_1) - pos += charsavail - charsgot += charsavail - if charsgot == nchars: - break - datainx += 1 - data = datatab[datainx] - datalen = len(data) - options = local_ord(data[0]) - pos = 1 - pos += rtsz # size of richtext & phonetic stuff to skip - # also allow for the rich text etc being split ... - if pos >= datalen: - # adjust to correct position in next record - pos = pos - datalen - datainx += 1 - if datainx < ndatas: - data = datatab[datainx] - datalen = len(data) - else: - assert _unused_i == nstrings - 1 - strappend(accstrg) - return strings diff --git a/tablib/packages/xlrd/biffh.py b/tablib/packages/xlrd/biffh.py deleted file mode 100644 index ba3b26c..0000000 --- a/tablib/packages/xlrd/biffh.py +++ /dev/null @@ -1,639 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Support module for the xlrd package. -# -# <p>Portions copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p> -## - -# 2008-02-10 SJM BIFF2 BLANK record -# 2008-02-08 SJM Preparation for Excel 2.0 support -# 2008-02-02 SJM Added suffixes (_B2, _B2_ONLY, etc) on record names for biff_dump & biff_count -# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -# 2007-09-08 SJM Avoid crash when zero-length Unicode string missing options byte. -# 2007-04-22 SJM Remove experimental "trimming" facility. - -DEBUG = 0 - -from struct import unpack -import sys -from timemachine import * - -class XLRDError(Exception): - pass - -## -# Parent of almost all other classes in the package. Defines a common "dump" method -# for debugging. - -class BaseObject(object): - - _repr_these = [] - - ## - # @param f open file object, to which the dump is written - # @param header text to write before the dump - # @param footer text to write after the dump - # @param indent number of leading spaces (for recursive calls) - - def dump(self, f=None, header=None, footer=None, indent=0): - if f is None: - f = sys.stderr - alist = self.__dict__.items() - alist.sort() - pad = " " * indent - if header is not None: print >> f, header - list_type = type([]) - dict_type = type({}) - for attr, value in alist: - if getattr(value, 'dump', None) and attr != 'book': - value.dump(f, - header="%s%s (%s object):" % (pad, attr, value.__class__.__name__), - indent=indent+4) - elif attr not in self._repr_these and ( - isinstance(value, list_type) or isinstance(value, dict_type) - ): - print >> f, "%s%s: %s, len = %d" % (pad, attr, type(value), len(value)) - else: - print >> f, "%s%s: %r" % (pad, attr, value) - if footer is not None: print >> f, footer - -FUN, FDT, FNU, FGE, FTX = range(5) # unknown, date, number, general, text -DATEFORMAT = FDT -NUMBERFORMAT = FNU - -( - XL_CELL_EMPTY, - XL_CELL_TEXT, - XL_CELL_NUMBER, - XL_CELL_DATE, - XL_CELL_BOOLEAN, - XL_CELL_ERROR, - XL_CELL_BLANK, # for use in debugging, gathering stats, etc -) = range(7) - -biff_text_from_num = { - 0: "(not BIFF)", - 20: "2.0", - 21: "2.1", - 30: "3", - 40: "4S", - 45: "4W", - 50: "5", - 70: "7", - 80: "8", - 85: "8X", - } - -## -# <p>This dictionary can be used to produce a text version of the internal codes -# that Excel uses for error cells. Here are its contents: -# <pre> -# 0x00: '#NULL!', # Intersection of two cell ranges is empty -# 0x07: '#DIV/0!', # Division by zero -# 0x0F: '#VALUE!', # Wrong type of operand -# 0x17: '#REF!', # Illegal or deleted cell reference -# 0x1D: '#NAME?', # Wrong function or range name -# 0x24: '#NUM!', # Value range overflow -# 0x2A: '#N/A!', # Argument or function not available -# </pre></p> - -error_text_from_code = { - 0x00: '#NULL!', # Intersection of two cell ranges is empty - 0x07: '#DIV/0!', # Division by zero - 0x0F: '#VALUE!', # Wrong type of operand - 0x17: '#REF!', # Illegal or deleted cell reference - 0x1D: '#NAME?', # Wrong function or range name - 0x24: '#NUM!', # Value range overflow - 0x2A: '#N/A!', # Argument or function not available -} - -BIFF_FIRST_UNICODE = 80 - -XL_WORKBOOK_GLOBALS = WBKBLOBAL = 0x5 -XL_WORKBOOK_GLOBALS_4W = 0x100 -XL_WORKSHEET = WRKSHEET = 0x10 - -XL_BOUNDSHEET_WORKSHEET = 0x00 -XL_BOUNDSHEET_CHART = 0x02 -XL_BOUNDSHEET_VB_MODULE = 0x06 - -# XL_RK2 = 0x7e -XL_ARRAY = 0x0221 -XL_ARRAY2 = 0x0021 -XL_BLANK = 0x0201 -XL_BLANK_B2 = 0x01 -XL_BOF = 0x809 -XL_BOOLERR = 0x205 -XL_BOOLERR_B2 = 0x5 -XL_BOUNDSHEET = 0x85 -XL_BUILTINFMTCOUNT = 0x56 -XL_CF = 0x01B1 -XL_CODEPAGE = 0x42 -XL_COLINFO = 0x7D -XL_COLUMNDEFAULT = 0x20 # BIFF2 only -XL_COLWIDTH = 0x24 # BIFF2 only -XL_CONDFMT = 0x01B0 -XL_CONTINUE = 0x3c -XL_COUNTRY = 0x8C -XL_DATEMODE = 0x22 -XL_DEFAULTROWHEIGHT = 0x0225 -XL_DEFCOLWIDTH = 0x55 -XL_DIMENSION = 0x200 -XL_DIMENSION2 = 0x0 -XL_EFONT = 0x45 -XL_EOF = 0x0a -XL_EXTERNNAME = 0x23 -XL_EXTERNSHEET = 0x17 -XL_EXTSST = 0xff -XL_FEAT11 = 0x872 -XL_FILEPASS = 0x2f -XL_FONT = 0x31 -XL_FONT_B3B4 = 0x231 -XL_FORMAT = 0x41e -XL_FORMAT2 = 0x1E # BIFF2, BIFF3 -XL_FORMULA = 0x6 -XL_FORMULA3 = 0x206 -XL_FORMULA4 = 0x406 -XL_GCW = 0xab -XL_INDEX = 0x20b -XL_INTEGER = 0x2 # BIFF2 only -XL_IXFE = 0x44 # BIFF2 only -XL_LABEL = 0x204 -XL_LABEL_B2 = 0x04 -XL_LABELRANGES = 0x15f -XL_LABELSST = 0xfd -XL_MERGEDCELLS = 0xE5 -XL_MSO_DRAWING = 0x00EC -XL_MSO_DRAWING_GROUP = 0x00EB -XL_MSO_DRAWING_SELECTION = 0x00ED -XL_MULRK = 0xbd -XL_MULBLANK = 0xbe -XL_NAME = 0x18 -XL_NOTE = 0x1c -XL_NUMBER = 0x203 -XL_NUMBER_B2 = 0x3 -XL_OBJ = 0x5D -XL_PALETTE = 0x92 -XL_RK = 0x27e -XL_ROW = 0x208 -XL_ROW_B2 = 0x08 -XL_RSTRING = 0xd6 -XL_SHEETHDR = 0x8F # BIFF4W only -XL_SHEETSOFFSET = 0x8E # BIFF4W only -XL_SHRFMLA = 0x04bc -XL_SST = 0xfc -XL_STANDARDWIDTH = 0x99 -XL_STRING = 0x207 -XL_STRING_B2 = 0x7 -XL_STYLE = 0x293 -XL_SUPBOOK = 0x1AE -XL_TABLEOP = 0x236 -XL_TABLEOP2 = 0x37 -XL_TABLEOP_B2 = 0x36 -XL_TXO = 0x1b6 -XL_UNCALCED = 0x5e -XL_UNKNOWN = 0xffff -XL_WINDOW2 = 0x023E -XL_WRITEACCESS = 0x5C -XL_XF = 0xe0 -XL_XF2 = 0x0043 # BIFF2 version of XF record -XL_XF3 = 0x0243 # BIFF3 version of XF record -XL_XF4 = 0x0443 # BIFF4 version of XF record - -boflen = {0x0809: 8, 0x0409: 6, 0x0209: 6, 0x0009: 4} -bofcodes = (0x0809, 0x0409, 0x0209, 0x0009) - -XL_FORMULA_OPCODES = (0x0006, 0x0406, 0x0206) - -_cell_opcode_list = [ - XL_BOOLERR, - XL_FORMULA, - XL_FORMULA3, - XL_FORMULA4, - XL_LABEL, - XL_LABELSST, - XL_MULRK, - XL_NUMBER, - XL_RK, - XL_RSTRING, - ] -_cell_opcode_dict = {} -for _cell_opcode in _cell_opcode_list: - _cell_opcode_dict[_cell_opcode] = 1 -is_cell_opcode = _cell_opcode_dict.has_key - -# def fprintf(f, fmt, *vargs): f.write(fmt % vargs) - -def fprintf(f, fmt, *vargs): - if fmt.endswith('\n'): - print >> f, fmt[:-1] % vargs - else: - print >> f, fmt % vargs, - -def upkbits(tgt_obj, src, manifest, local_setattr=setattr): - for n, mask, attr in manifest: - local_setattr(tgt_obj, attr, (src & mask) >> n) - -def upkbitsL(tgt_obj, src, manifest, local_setattr=setattr, local_int=int): - for n, mask, attr in manifest: - local_setattr(tgt_obj, attr, local_int((src & mask) >> n)) - -def unpack_string(data, pos, encoding, lenlen=1): - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - pos += lenlen - return unicode(data[pos:pos+nchars], encoding) - -def unpack_string_update_pos(data, pos, encoding, lenlen=1, known_len=None): - if known_len is not None: - # On a NAME record, the length byte is detached from the front of the string. - nchars = known_len - else: - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - pos += lenlen - newpos = pos + nchars - return (unicode(data[pos:newpos], encoding), newpos) - -def unpack_unicode(data, pos, lenlen=2): - "Return unicode_strg" - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - if not nchars: - # Ambiguous whether 0-length string should have an "options" byte. - # Avoid crash if missing. - return u"" - pos += lenlen - options = ord(data[pos]) - pos += 1 - # phonetic = options & 0x04 - # richtext = options & 0x08 - if options & 0x08: - # rt = unpack('<H', data[pos:pos+2])[0] # unused - pos += 2 - if options & 0x04: - # sz = unpack('<i', data[pos:pos+4])[0] # unused - pos += 4 - if options & 0x01: - # Uncompressed UTF-16-LE - rawstrg = data[pos:pos+2*nchars] - # if DEBUG: print "nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg) - strg = unicode(rawstrg, 'utf_16_le') - # pos += 2*nchars - else: - # Note: this is COMPRESSED (not ASCII!) encoding!!! - # Merely returning the raw bytes would work OK 99.99% of the time - # if the local codepage was cp1252 -- however this would rapidly go pear-shaped - # for other codepages so we grit our Anglocentric teeth and return Unicode :-) - - strg = unicode(data[pos:pos+nchars], "latin_1") - # pos += nchars - # if richtext: - # pos += 4 * rt - # if phonetic: - # pos += sz - # return (strg, pos) - return strg - -def unpack_unicode_update_pos(data, pos, lenlen=2, known_len=None): - "Return (unicode_strg, updated value of pos)" - if known_len is not None: - # On a NAME record, the length byte is detached from the front of the string. - nchars = known_len - else: - nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0] - pos += lenlen - if not nchars and not data[pos:]: - # Zero-length string with no options byte - return (u"", pos) - options = ord(data[pos]) - pos += 1 - phonetic = options & 0x04 - richtext = options & 0x08 - if richtext: - rt = unpack('<H', data[pos:pos+2])[0] - pos += 2 - if phonetic: - sz = unpack('<i', data[pos:pos+4])[0] - pos += 4 - if options & 0x01: - # Uncompressed UTF-16-LE - strg = unicode(data[pos:pos+2*nchars], 'utf_16_le') - pos += 2*nchars - else: - # Note: this is COMPRESSED (not ASCII!) encoding!!! - strg = unicode(data[pos:pos+nchars], "latin_1") - pos += nchars - if richtext: - pos += 4 * rt - if phonetic: - pos += sz - return (strg, pos) - -def unpack_cell_range_address_list_update_pos( - output_list, data, pos, biff_version, addr_size=6): - # output_list is updated in situ - if biff_version < 80: - assert addr_size == 6 - else: - assert addr_size in (6, 8) - n, = unpack("<H", data[pos:pos+2]) - pos += 2 - if n: - if addr_size == 6: - fmt = "<HHBB" - else: - fmt = "<HHHH" - for _unused in xrange(n): - ra, rb, ca, cb = unpack(fmt, data[pos:pos+addr_size]) - output_list.append((ra, rb+1, ca, cb+1)) - pos += addr_size - return pos - -_brecstrg = """\ -0000 DIMENSIONS_B2 -0001 BLANK_B2 -0002 INTEGER_B2_ONLY -0003 NUMBER_B2 -0004 LABEL_B2 -0005 BOOLERR_B2 -0006 FORMULA -0007 STRING_B2 -0008 ROW_B2 -0009 BOF_B2 -000A EOF -000B INDEX_B2_ONLY -000C CALCCOUNT -000D CALCMODE -000E PRECISION -000F REFMODE -0010 DELTA -0011 ITERATION -0012 PROTECT -0013 PASSWORD -0014 HEADER -0015 FOOTER -0016 EXTERNCOUNT -0017 EXTERNSHEET -0018 NAME_B2,5+ -0019 WINDOWPROTECT -001A VERTICALPAGEBREAKS -001B HORIZONTALPAGEBREAKS -001C NOTE -001D SELECTION -001E FORMAT_B2-3 -001F BUILTINFMTCOUNT_B2 -0020 COLUMNDEFAULT_B2_ONLY -0021 ARRAY_B2_ONLY -0022 DATEMODE -0023 EXTERNNAME -0024 COLWIDTH_B2_ONLY -0025 DEFAULTROWHEIGHT_B2_ONLY -0026 LEFTMARGIN -0027 RIGHTMARGIN -0028 TOPMARGIN -0029 BOTTOMMARGIN -002A PRINTHEADERS -002B PRINTGRIDLINES -002F FILEPASS -0031 FONT -0032 FONT2_B2_ONLY -0036 TABLEOP_B2 -0037 TABLEOP2_B2 -003C CONTINUE -003D WINDOW1 -003E WINDOW2_B2 -0040 BACKUP -0041 PANE -0042 CODEPAGE -0043 XF_B2 -0044 IXFE_B2_ONLY -0045 EFONT_B2_ONLY -004D PLS -0051 DCONREF -0055 DEFCOLWIDTH -0056 BUILTINFMTCOUNT_B3-4 -0059 XCT -005A CRN -005B FILESHARING -005C WRITEACCESS -005D OBJECT -005E UNCALCED -005F SAVERECALC -0063 OBJECTPROTECT -007D COLINFO -007E RK2_mythical_? -0080 GUTS -0081 WSBOOL -0082 GRIDSET -0083 HCENTER -0084 VCENTER -0085 BOUNDSHEET -0086 WRITEPROT -008C COUNTRY -008D HIDEOBJ -008E SHEETSOFFSET -008F SHEETHDR -0090 SORT -0092 PALETTE -0099 STANDARDWIDTH -009B FILTERMODE -009C FNGROUPCOUNT -009D AUTOFILTERINFO -009E AUTOFILTER -00A0 SCL -00A1 SETUP -00AB GCW -00BD MULRK -00BE MULBLANK -00C1 MMS -00D6 RSTRING -00D7 DBCELL -00DA BOOKBOOL -00DD SCENPROTECT -00E0 XF -00E1 INTERFACEHDR -00E2 INTERFACEEND -00E5 MERGEDCELLS -00E9 BITMAP -00EB MSO_DRAWING_GROUP -00EC MSO_DRAWING -00ED MSO_DRAWING_SELECTION -00EF PHONETIC -00FC SST -00FD LABELSST -00FF EXTSST -013D TABID -015F LABELRANGES -0160 USESELFS -0161 DSF -01AE SUPBOOK -01AF PROTECTIONREV4 -01B0 CONDFMT -01B1 CF -01B2 DVAL -01B6 TXO -01B7 REFRESHALL -01B8 HLINK -01BC PASSWORDREV4 -01BE DV -01C0 XL9FILE -01C1 RECALCID -0200 DIMENSIONS -0201 BLANK -0203 NUMBER -0204 LABEL -0205 BOOLERR -0206 FORMULA_B3 -0207 STRING -0208 ROW -0209 BOF -020B INDEX_B3+ -0218 NAME -0221 ARRAY -0223 EXTERNNAME_B3-4 -0225 DEFAULTROWHEIGHT -0231 FONT_B3B4 -0236 TABLEOP -023E WINDOW2 -0243 XF_B3 -027E RK -0293 STYLE -0406 FORMULA_B4 -0409 BOF -041E FORMAT -0443 XF_B4 -04BC SHRFMLA -0800 QUICKTIP -0809 BOF -0862 SHEETLAYOUT -0867 SHEETPROTECTION -0868 RANGEPROTECTION -""" - -biff_rec_name_dict = {} -for _buff in _brecstrg.splitlines(): - _numh, _name = _buff.split() - biff_rec_name_dict[int(_numh, 16)] = _name -del _buff, _name, _brecstrg - -def hex_char_dump(strg, ofs, dlen, base=0, fout=sys.stdout, unnumbered=False): - endpos = min(ofs + dlen, len(strg)) - pos = ofs - numbered = not unnumbered - num_prefix = '' - while pos < endpos: - endsub = min(pos + 16, endpos) - substrg = strg[pos:endsub] - lensub = endsub - pos - if lensub <= 0 or lensub != len(substrg): - fprintf( - sys.stdout, - '??? hex_char_dump: ofs=%d dlen=%d base=%d -> endpos=%d pos=%d endsub=%d substrg=%r\n', - ofs, dlen, base, endpos, pos, endsub, substrg) - break - hexd = ''.join(["%02x " % ord(c) for c in substrg]) - chard = '' - for c in substrg: - if c == '\0': - c = '~' - elif not (' ' <= c <= '~'): - c = '?' - chard += c - if numbered: - num_prefix = "%5d: " % (base+pos-ofs) - fprintf(fout, "%s %-48s %s\n", num_prefix, hexd, chard) - pos = endsub - -def biff_dump(mem, stream_offset, stream_len, base=0, fout=sys.stdout, unnumbered=False): - pos = stream_offset - stream_end = stream_offset + stream_len - adj = base - stream_offset - dummies = 0 - numbered = not unnumbered - num_prefix = '' - while stream_end - pos >= 4: - rc, length = unpack('<HH', mem[pos:pos+4]) - if rc == 0 and length == 0: - if mem[pos:] == '\0' * (stream_end - pos): - dummies = stream_end - pos - savpos = pos - pos = stream_end - break - if dummies: - dummies += 4 - else: - savpos = pos - dummies = 4 - pos += 4 - else: - if dummies: - if numbered: - num_prefix = "%5d: " % (adj + savpos) - fprintf(fout, "%s---- %d zero bytes skipped ----\n", num_prefix, dummies) - dummies = 0 - recname = biff_rec_name_dict.get(rc, '<UNKNOWN>') - if numbered: - num_prefix = "%5d: " % (adj + pos) - fprintf(fout, "%s%04x %s len = %04x (%d)\n", num_prefix, rc, recname, length, length) - pos += 4 - hex_char_dump(mem, pos, length, adj+pos, fout, unnumbered) - pos += length - if dummies: - if numbered: - num_prefix = "%5d: " % (adj + savpos) - fprintf(fout, "%s---- %d zero bytes skipped ----\n", num_prefix, dummies) - if pos < stream_end: - if numbered: - num_prefix = "%5d: " % (adj + pos) - fprintf(fout, "%s---- Misc bytes at end ----\n", num_prefix) - hex_char_dump(mem, pos, stream_end-pos, adj + pos, fout, unnumbered) - elif pos > stream_end: - fprintf(fout, "Last dumped record has length (%d) that is too large\n", length) - -def biff_count_records(mem, stream_offset, stream_len, fout=sys.stdout): - pos = stream_offset - stream_end = stream_offset + stream_len - tally = {} - while stream_end - pos >= 4: - rc, length = unpack('<HH', mem[pos:pos+4]) - if rc == 0 and length == 0: - if mem[pos:] == '\0' * (stream_end - pos): - break - recname = "<Dummy (zero)>" - else: - recname = biff_rec_name_dict.get(rc, None) - if recname is None: - recname = "Unknown_0x%04X" % rc - if tally.has_key(recname): - tally[recname] += 1 - else: - tally[recname] = 1 - pos += length + 4 - slist = tally.items() - slist.sort() - for recname, count in slist: - print >> fout, "%8d %s" % (count, recname) - -encoding_from_codepage = { - 1200 : 'utf_16_le', - 10000: 'mac_roman', - 10006: 'mac_greek', # guess - 10007: 'mac_cyrillic', # guess - 10029: 'mac_latin2', # guess - 10079: 'mac_iceland', # guess - 10081: 'mac_turkish', # guess - 32768: 'mac_roman', - 32769: 'cp1252', - } -# some more guessing, for Indic scripts -# codepage 57000 range: -# 2 Devanagari [0] -# 3 Bengali [1] -# 4 Tamil [5] -# 5 Telegu [6] -# 6 Assamese [1] c.f. Bengali -# 7 Oriya [4] -# 8 Kannada [7] -# 9 Malayalam [8] -# 10 Gujarati [3] -# 11 Gurmukhi [2] diff --git a/tablib/packages/xlrd/compdoc.py b/tablib/packages/xlrd/compdoc.py deleted file mode 100644 index 3abb7a6..0000000 --- a/tablib/packages/xlrd/compdoc.py +++ /dev/null @@ -1,358 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Implements the minimal functionality required -# to extract a "Workbook" or "Book" stream (as one big string) -# from an OLE2 Compound Document file. -# <p>Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p> -## - -# No part of the content of this file was derived from the works of David Giffin. - -# 2008-11-04 SJM Avoid assertion error when -1 used instead of -2 for first_SID of empty SCSS [Frank Hoffsuemmer] -# 2007-09-08 SJM Warning message if sector sizes are extremely large. -# 2007-05-07 SJM Meaningful exception instead of IndexError if a SAT (sector allocation table) is corrupted. -# 2007-04-22 SJM Missing "<" in a struct.unpack call => can't open files on bigendian platforms. - - -import sys -from struct import unpack -from timemachine import * - -## -# Magic cookie that should appear in the first 8 bytes of the file. -SIGNATURE = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" - -EOCSID = -2 -FREESID = -1 -SATSID = -3 -MSATSID = -4 - -class CompDocError(Exception): - pass - -class DirNode(object): - - def __init__(self, DID, dent, DEBUG=0): - # dent is the 128-byte directory entry - self.DID = DID - # (cbufsize, self.etype, self.colour, self.left_DID, self.right_DID, - # self.root_DID, - # self.first_SID, - # self.tot_size) = \ - # unpack('<HBBiii16x4x8x8xii4x', dent[64:128]) - (cbufsize, self.etype, self.colour, self.left_DID, self.right_DID, - self.root_DID) = \ - unpack('<HBBiii', dent[64:80]) - (self.first_SID, self.tot_size) = \ - unpack('<ii', dent[116:124]) - if cbufsize == 0: - self.name = u'' - else: - self.name = unicode(dent[0:cbufsize-2], 'utf_16_le') # omit the trailing U+0000 - self.children = [] # filled in later - self.parent = -1 # indicates orphan; fixed up later - self.tsinfo = unpack('<IIII', dent[100:116]) - if DEBUG: - self.dump(DEBUG) - - def dump(self, DEBUG=1): - print "DID=%d name=%r etype=%d DIDs(left=%d right=%d root=%d parent=%d kids=%r) first_SID=%d tot_size=%d" \ - % (self.DID, self.name, self.etype, self.left_DID, - self.right_DID, self.root_DID, self.parent, self.children, self.first_SID, self.tot_size) - if DEBUG == 2: - # cre_lo, cre_hi, mod_lo, mod_hi = tsinfo - print "timestamp info", self.tsinfo - -def _build_family_tree(dirlist, parent_DID, child_DID): - if child_DID < 0: return - _build_family_tree(dirlist, parent_DID, dirlist[child_DID].left_DID) - dirlist[parent_DID].children.append(child_DID) - dirlist[child_DID].parent = parent_DID - _build_family_tree(dirlist, parent_DID, dirlist[child_DID].right_DID) - if dirlist[child_DID].etype == 1: # storage - _build_family_tree(dirlist, child_DID, dirlist[child_DID].root_DID) - -## -# Compound document handler. -# @param mem The raw contents of the file, as a string, or as an mmap.mmap() object. The -# only operation it needs to support is slicing. - -class CompDoc(object): - - def __init__(self, mem, logfile=sys.stdout, DEBUG=0): - self.logfile = logfile - if mem[0:8] != SIGNATURE: - raise CompDocError('Not an OLE2 compound document') - if mem[28:30] != '\xFE\xFF': - raise CompDocError('Expected "little-endian" marker, found %r' % mem[28:30]) - revision, version = unpack('<HH', mem[24:28]) - if DEBUG: - print >> logfile, "\nCompDoc format: version=0x%04x revision=0x%04x" % (version, revision) - self.mem = mem - ssz, sssz = unpack('<HH', mem[30:34]) - if ssz > 20: # allows for 2**20 bytes i.e. 1MB - print >> logfile, \ - "WARNING: sector size (2**%d) is preposterous; assuming 512 and continuing ..." \ - % ssz - ssz = 9 - if sssz > ssz: - print >> logfile, \ - "WARNING: short stream sector size (2**%d) is preposterous; assuming 64 and continuing ..." \ - % sssz - sssz = 6 - self.sec_size = sec_size = 1 << ssz - self.short_sec_size = 1 << sssz - ( - SAT_tot_secs, self.dir_first_sec_sid, _unused, self.min_size_std_stream, - SSAT_first_sec_sid, SSAT_tot_secs, - MSAT_first_sec_sid, MSAT_tot_secs, - # ) = unpack('<ii4xiiiii', mem[44:76]) - ) = unpack('<iiiiiiii', mem[44:76]) - mem_data_len = len(mem) - 512 - mem_data_secs, left_over = divmod(mem_data_len, sec_size) - if left_over: - #### raise CompDocError("Not a whole number of sectors") - print >> logfile, \ - "WARNING *** file size (%d) not 512 + multiple of sector size (%d)" \ - % (len(mem), sec_size) - if DEBUG: - print >> logfile, 'sec sizes', ssz, sssz, sec_size, self.short_sec_size - print >> logfile, "mem data: %d bytes == %d sectors" % (mem_data_len, mem_data_secs) - print >> logfile, "SAT_tot_secs=%d, dir_first_sec_sid=%d, min_size_std_stream=%d" \ - % (SAT_tot_secs, self.dir_first_sec_sid, self.min_size_std_stream,) - print >> logfile, "SSAT_first_sec_sid=%d, SSAT_tot_secs=%d" % (SSAT_first_sec_sid, SSAT_tot_secs,) - print >> logfile, "MSAT_first_sec_sid=%d, MSAT_tot_secs=%d" % (MSAT_first_sec_sid, MSAT_tot_secs,) - nent = int_floor_div(sec_size, 4) # number of SID entries in a sector - fmt = "<%di" % nent - trunc_warned = 0 - # - # === build the MSAT === - # - MSAT = list(unpack('<109i', mem[76:512])) - sid = MSAT_first_sec_sid - while sid >= 0: - if sid >= mem_data_secs: - raise CompDocError( - "MSAT extension: accessing sector %d but only %d in file" % (sid, mem_data_secs) - ) - offset = 512 + sec_size * sid - news = list(unpack(fmt, mem[offset:offset+sec_size])) - sid = news.pop() - MSAT.extend(news) - if DEBUG: - print >> logfile, "MSAT: len =", len(MSAT) - print >> logfile, MSAT - # - # === build the SAT === - # - self.SAT = [] - for msid in MSAT: - if msid == FREESID: continue - if msid >= mem_data_secs: - if not trunc_warned: - print >> logfile, "WARNING *** File is truncated, or OLE2 MSAT is corrupt!!" - print >> logfile, \ - "INFO: Trying to access sector %d but only %d available" \ - % (msid, mem_data_secs) - trunc_warned = 1 - continue - offset = 512 + sec_size * msid - news = list(unpack(fmt, mem[offset:offset+sec_size])) - self.SAT.extend(news) - if DEBUG: - print >> logfile, "SAT: len =", len(self.SAT) - print >> logfile, self.SAT - # print >> logfile, "SAT ", - # for i, s in enumerate(self.SAT): - # print >> logfile, "entry: %4d offset: %6d, next entry: %4d" % (i, 512 + sec_size * i, s) - # print >> logfile, "%d:%d " % (i, s), - print - - # === build the directory === - # - dbytes = self._get_stream( - self.mem, 512, self.SAT, self.sec_size, self.dir_first_sec_sid, - name="directory") - dirlist = [] - did = -1 - for pos in xrange(0, len(dbytes), 128): - did += 1 - dirlist.append(DirNode(did, dbytes[pos:pos+128], 0)) - self.dirlist = dirlist - _build_family_tree(dirlist, 0, dirlist[0].root_DID) # and stand well back ... - if DEBUG: - for d in dirlist: - d.dump(DEBUG) - # - # === get the SSCS === - # - sscs_dir = self.dirlist[0] - assert sscs_dir.etype == 5 # root entry - if sscs_dir.first_SID < 0 and sscs_dir.tot_size == 0: - # Problem reported by Frank Hoffsuemmer: some software was - # writing -1 instead of -2 (EOCSID) for the first_SID - # when the SCCS was empty. Not having EOCSID caused assertion - # failure in _get_stream. - # Solution: avoid calling _get_stream in any case when the - # SCSS appears to be empty. - self.SSCS = "" - else: - self.SSCS = self._get_stream( - self.mem, 512, self.SAT, sec_size, sscs_dir.first_SID, - sscs_dir.tot_size, name="SSCS") - # if DEBUG: print >> logfile, "SSCS", repr(self.SSCS) - # - # === build the SSAT === - # - self.SSAT = [] - if SSAT_tot_secs > 0 and sscs_dir.tot_size == 0: - print >> logfile, \ - "WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero" - if sscs_dir.tot_size > 0: - sid = SSAT_first_sec_sid - nsecs = SSAT_tot_secs - while sid >= 0 and nsecs > 0: - nsecs -= 1 - start_pos = 512 + sid * sec_size - news = list(unpack(fmt, mem[start_pos:start_pos+sec_size])) - self.SSAT.extend(news) - sid = self.SAT[sid] - # assert SSAT_tot_secs == 0 or sid == EOCSID - if DEBUG: print >> logfile, "SSAT last sid %d; remaining sectors %d" % (sid, nsecs) - assert nsecs == 0 and sid == EOCSID - if DEBUG: print >> logfile, "SSAT", self.SSAT - - def _get_stream(self, mem, base, sat, sec_size, start_sid, size=None, name=''): - # print >> self.logfile, "_get_stream", base, sec_size, start_sid, size - sectors = [] - s = start_sid - if size is None: - # nothing to check against - while s >= 0: - start_pos = base + s * sec_size - sectors.append(mem[start_pos:start_pos+sec_size]) - try: - s = sat[s] - except IndexError: - raise CompDocError( - "OLE2 stream %r: sector allocation table invalid entry (%d)" % - (name, s) - ) - assert s == EOCSID - else: - todo = size - while s >= 0: - start_pos = base + s * sec_size - grab = sec_size - if grab > todo: - grab = todo - todo -= grab - sectors.append(mem[start_pos:start_pos+grab]) - try: - s = sat[s] - except IndexError: - raise CompDocError( - "OLE2 stream %r: sector allocation table invalid entry (%d)" % - (name, s) - ) - assert s == EOCSID - if todo != 0: - print >> self.logfile, \ - "WARNING *** OLE2 stream %r: expected size %d, actual size %d" \ - % (name, size, size - todo) - return ''.join(sectors) - - def _dir_search(self, path, storage_DID=0): - # Return matching DirNode instance, or None - head = path[0] - tail = path[1:] - dl = self.dirlist - for child in dl[storage_DID].children: - if dl[child].name.lower() == head.lower(): - et = dl[child].etype - if et == 2: - return dl[child] - if et == 1: - if not tail: - raise CompDocError("Requested component is a 'storage'") - return self._dir_search(tail, child) - dl[child].dump(1) - raise CompDocError("Requested stream is not a 'user stream'") - return None - - ## - # Interrogate the compound document's directory; return the stream as a string if found, otherwise - # return None. - # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto. - - def get_named_stream(self, qname): - d = self._dir_search(qname.split("/")) - if d is None: - return None - if d.tot_size >= self.min_size_std_stream: - return self._get_stream( - self.mem, 512, self.SAT, self.sec_size, d.first_SID, - d.tot_size, name=qname) - else: - return self._get_stream( - self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID, - d.tot_size, name=qname + " (from SSCS)") - - ## - # Interrogate the compound document's directory. - # If the named stream is not found, (None, 0, 0) will be returned. - # If the named stream is found and is contiguous within the original byte sequence ("mem") - # used when the document was opened, - # then (mem, offset_to_start_of_stream, length_of_stream) is returned. - # Otherwise a new string is built from the fragments and (new_string, 0, length_of_stream) is returned. - # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto. - - def locate_named_stream(self, qname): - d = self._dir_search(qname.split("/")) - if d is None: - return (None, 0, 0) - if d.tot_size >= self.min_size_std_stream: - return self._locate_stream(self.mem, 512, self.SAT, self.sec_size, d.first_SID, d.tot_size) - else: - return ( - self._get_stream( - self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID, - d.tot_size, qname + " (from SSCS)"), - 0, - d.tot_size - ) - return (None, 0, 0) # not found - - def _locate_stream(self, mem, base, sat, sec_size, start_sid, size): - # print >> self.logfile, "_locate_stream", base, sec_size, start_sid, size - s = start_sid - if s < 0: - raise CompDocError("_locate_stream: start_sid (%d) is -ve" % start_sid) - p = -99 # dummy previous SID - start_pos = -9999 - end_pos = -8888 - slices = [] - while s >= 0: - if s == p+1: - # contiguous sectors - end_pos += sec_size - else: - # start new slice - if p >= 0: - # not first time - slices.append((start_pos, end_pos)) - start_pos = base + s * sec_size - end_pos = start_pos + sec_size - p = s - s = sat[s] - assert s == EOCSID - # print >> self.logfile, len(slices) + 1, "slices" - if not slices: - # The stream is contiguous ... just what we like! - return (mem, start_pos, size) - slices.append((start_pos, end_pos)) - return (''.join([mem[start_pos:end_pos] for start_pos, end_pos in slices]), 0, size) - -# ========================================================================================== diff --git a/tablib/packages/xlrd/doc/compdoc.html b/tablib/packages/xlrd/doc/compdoc.html deleted file mode 100644 index c55a194..0000000 --- a/tablib/packages/xlrd/doc/compdoc.html +++ /dev/null @@ -1,69 +0,0 @@ -<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
-<html>
-<head>
-<meta http-equiv='Content-Type' content='text/html; charset=us-ascii' />
-<title>The compdoc Module</title>
-</head>
-<body>
-<h1>The compdoc Module</h1>
-<p>Implements the minimal functionality required
-to extract a "Workbook" or "Book" stream (as one big string)
-from an OLE2 Compound Document file.
-</p><p>Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd</p>
-<p>This module is part of the xlrd package, which is released under a BSD-style licence.</p>
-<h2>Module Contents</h2>
-<dl>
-<dt><b>CompDoc(mem, logfile=sys.stdout, DEBUG=0)</b> (class) [<a href='#compdoc.CompDoc-class'>#</a>]</dt>
-<dd>
-<p>Compound document handler.</p>
-<dl>
-<dt><i>mem</i></dt>
-<dd>
-The raw contents of the file, as a string, or as an mmap.mmap() object. The
-only operation it needs to support is slicing.</dd>
-</dl><br />
-<p>For more information about this class, see <a href='#compdoc.CompDoc-class'><i>The CompDoc Class</i></a>.</p>
-</dd>
-<dt><a id='compdoc.SIGNATURE-variable' name='compdoc.SIGNATURE-variable'><b>SIGNATURE</b></a> (variable) [<a href='#compdoc.SIGNATURE-variable'>#</a>]</dt>
-<dd>
-<p>Magic cookie that should appear in the first 8 bytes of the file.</p>
-</dd>
-</dl>
-<h2><a id='compdoc.CompDoc-class' name='compdoc.CompDoc-class'>The CompDoc Class</a></h2>
-<dl>
-<dt><b>CompDoc(mem, logfile=sys.stdout, DEBUG=0)</b> (class) [<a href='#compdoc.CompDoc-class'>#</a>]</dt>
-<dd>
-<p>Compound document handler.</p>
-<dl>
-<dt><i>mem</i></dt>
-<dd>
-The raw contents of the file, as a string, or as an mmap.mmap() object. The
-only operation it needs to support is slicing.</dd>
-</dl><br />
-</dd>
-<dt><a id='compdoc.CompDoc.get_named_stream-method' name='compdoc.CompDoc.get_named_stream-method'><b>get_named_stream(qname)</b></a> [<a href='#compdoc.CompDoc.get_named_stream-method'>#</a>]</dt>
-<dd>
-<p>Interrogate the compound document's directory; return the stream as a string if found, otherwise
-return None.</p>
-<dl>
-<dt><i>qname</i></dt>
-<dd>
-Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto.</dd>
-</dl><br />
-</dd>
-<dt><a id='compdoc.CompDoc.locate_named_stream-method' name='compdoc.CompDoc.locate_named_stream-method'><b>locate_named_stream(qname)</b></a> [<a href='#compdoc.CompDoc.locate_named_stream-method'>#</a>]</dt>
-<dd>
-<p>Interrogate the compound document's directory.
-If the named stream is not found, (None, 0, 0) will be returned.
-If the named stream is found and is contiguous within the original byte sequence ("mem")
-used when the document was opened,
-then (mem, offset_to_start_of_stream, length_of_stream) is returned.
-Otherwise a new string is built from the fragments and (new_string, 0, length_of_stream) is returned.</p>
-<dl>
-<dt><i>qname</i></dt>
-<dd>
-Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto.</dd>
-</dl><br />
-</dd>
-</dl>
-</body></html>
diff --git a/tablib/packages/xlrd/doc/xlrd.html b/tablib/packages/xlrd/doc/xlrd.html deleted file mode 100644 index f982e0e..0000000 --- a/tablib/packages/xlrd/doc/xlrd.html +++ /dev/null @@ -1,1845 +0,0 @@ -<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
-<html>
-<head>
-<meta http-equiv='Content-Type' content='text/html; charset=us-ascii' />
-<title>The xlrd Module</title>
-</head>
-<body>
-<h1>The xlrd Module</h1>
-<p /><p><b>A Python module for extracting data from MS Excel ™ spreadsheet files.
-<br /><br />
-Version 0.7.1 -- 2009-05-31
-</b></p>
-
-<h2>General information</h2>
-
-<h3>Acknowledgements</h3>
-
-<p>
-Development of this module would not have been possible without the document
-"OpenOffice.org's Documentation of the Microsoft Excel File Format"
-("OOo docs" for short).
-The latest version is available from OpenOffice.org in
-<a href="http://sc.openoffice.org/excelfileformat.pdf"> PDF format</a>
-and
-<a href="http://sc.openoffice.org/excelfileformat.odt"> ODT format.</a>
-Small portions of the OOo docs are reproduced in this
-document. A study of the OOo docs is recommended for those who wish a
-deeper understanding of the Excel file layout than the xlrd docs can provide.
-</p>
-
-<p>Backporting to Python 2.1 was partially funded by
- <a href="http://journyx.com/">
- Journyx - provider of timesheet and project accounting solutions.
- </a>
-</p>
-
-<p>Provision of formatting information in version 0.6.1 was funded by
- <a href="http://www.simplistix.co.uk">
- Simplistix Ltd.
- </a>
-</p>
-
-<h3>Unicode</h3>
-
-<p>This module presents all text strings as Python unicode objects.
-From Excel 97 onwards, text in Excel spreadsheets has been stored as Unicode.
-Older files (Excel 95 and earlier) don't keep strings in Unicode;
-a CODEPAGE record provides a codepage number (for example, 1252) which is
-used by xlrd to derive the encoding (for same example: "cp1252") which is
-used to translate to Unicode.</p>
-<small>
-<p>If the CODEPAGE record is missing (possible if the file was created
-by third-party software), xlrd will assume that the encoding is ascii, and keep going.
-If the actual encoding is not ascii, a UnicodeDecodeError exception will be raised and
-you will need to determine the encoding yourself, and tell xlrd:
-<pre>
- book = xlrd.open_workbook(..., encoding_override="cp1252")
-</pre></p>
-<p>If the CODEPAGE record exists but is wrong (for example, the codepage
-number is 1251, but the strings are actually encoded in koi8_r),
-it can be overridden using the same mechanism.
-The supplied runxlrd.py has a corresponding command-line argument, which
-may be used for experimentation:
-<pre>
- runxlrd.py -e koi8_r 3rows myfile.xls
-</pre></p>
-<p>The first place to look for an encoding ("codec name") is
-<a href="http://docs.python.org/lib/standard-encodings.html">
-the Python documentation</a>.
-</p>
-</small>
-
-<h3>Dates in Excel spreadsheets</h3>
-
-<p>In reality, there are no such things. What you have are floating point
-numbers and pious hope.
-There are several problems with Excel dates:</p>
-
-<p>(1) Dates are not stored as a separate data type; they are stored as
-floating point numbers and you have to rely on
-(a) the "number format" applied to them in Excel and/or
-(b) knowing which cells are supposed to have dates in them.
-This module helps with (a) by inspecting the
-format that has been applied to each number cell;
-if it appears to be a date format, the cell
-is classified as a date rather than a number. Feedback on this feature,
-especially from non-English-speaking locales, would be appreciated.</p>
-
-<p>(2) Excel for Windows stores dates by default as the number of
-days (or fraction thereof) since 1899-12-31T00:00:00. Excel for
-Macintosh uses a default start date of 1904-01-01T00:00:00. The date
-system can be changed in Excel on a per-workbook basis (for example:
-Tools -> Options -> Calculation, tick the "1904 date system" box).
-This is of course a bad idea if there are already dates in the
-workbook. There is no good reason to change it even if there are no
-dates in the workbook. Which date system is in use is recorded in the
-workbook. A workbook transported from Windows to Macintosh (or vice
-versa) will work correctly with the host Excel. When using this
-module's xldate_as_tuple function to convert numbers from a workbook,
-you must use the datemode attribute of the Book object. If you guess,
-or make a judgement depending on where you believe the workbook was
-created, you run the risk of being 1462 days out of kilter.</p>
-
-<p>Reference:
-http://support.microsoft.com/default.aspx?scid=KB;EN-US;q180162</p>
-
-
-<p>(3) The Excel implementation of the Windows-default 1900-based date system works on the
-incorrect premise that 1900 was a leap year. It interprets the number 60 as meaning 1900-02-29,
-which is not a valid date. Consequently any number less than 61 is ambiguous. Example: is 59 the
-result of 1900-02-28 entered directly, or is it 1900-03-01 minus 2 days? The OpenOffice.org Calc
-program "corrects" the Microsoft problem; entering 1900-02-27 causes the number 59 to be stored.
-Save as an XLS file, then open the file with Excel -- you'll see 1900-02-28 displayed.</p>
-
-<p>Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;214326</p>
-
-<p>(4) The Macintosh-default 1904-based date system counts 1904-01-02 as day 1 and 1904-01-01 as day zero.
-Thus any number such that (0.0 <= number < 1.0) is ambiguous. Is 0.625 a time of day (15:00:00),
-independent of the calendar,
-or should it be interpreted as an instant on a particular day (1904-01-01T15:00:00)?
-The xldate_* functions in this module
-take the view that such a number is a calendar-independent time of day (like Python's datetime.time type) for both
-date systems. This is consistent with more recent Microsoft documentation
-(for example, the help file for Excel 2002 which says that the first day
-in the 1904 date system is 1904-01-02).
-
-</p><p>(5) Usage of the Excel DATE() function may leave strange dates in a spreadsheet. Quoting the help file,
-in respect of the 1900 date system: "If year is between 0 (zero) and 1899 (inclusive),
-Excel adds that value to 1900 to calculate the year. For example, DATE(108,1,2) returns January 2, 2008 (1900+108)."
-This gimmick, semi-defensible only for arguments up to 99 and only in the pre-Y2K-awareness era,
-means that DATE(1899, 12, 31) is interpreted as 3799-12-31.</p>
-
-<p>For further information, please refer to the documentation for the xldate_* functions.</p>
-
-<h3> Named references, constants, formulas, and macros</h3>
-
-<p>
-A name is used to refer to a cell, a group of cells, a constant
-value, a formula, or a macro. Usually the scope of a name is global
-across the whole workbook. However it can be local to a worksheet.
-For example, if the sales figures are in different cells in
-different sheets, the user may define the name "Sales" in each
-sheet. There are built-in names, like "Print_Area" and
-"Print_Titles"; these two are naturally local to a sheet.
-</p><p>
-To inspect the names with a user interface like MS Excel, OOo Calc,
-or Gnumeric, click on Insert/Names/Define. This will show the global
-names, plus those local to the currently selected sheet.
-</p><p>
-A Book object provides two dictionaries (name_map and
-name_and_scope_map) and a list (name_obj_list) which allow various
-ways of accessing the Name objects. There is one Name object for
-each NAME record found in the workbook. Name objects have many
-attributes, several of which are relevant only when obj.macro is 1.
-</p><p>
-In the examples directory you will find namesdemo.xls which
-showcases the many different ways that names can be used, and
-xlrdnamesAPIdemo.py which offers 3 different queries for inspecting
-the names in your files, and shows how to extract whatever a name is
-referring to. There is currently one "convenience method",
-Name.cell(), which extracts the value in the case where the name
-refers to a single cell. More convenience methods are planned. The
-source code for Name.cell (in __init__.py) is an extra source of
-information on how the Name attributes hang together.
-</p>
-
-<p><i>Name information is <b>not</b> extracted from files older than
-Excel 5.0 (Book.biff_version < 50)</i></p>
-
-<h3>Formatting</h3>
-
-<h4>Introduction</h4>
-
-<p>This collection of features, new in xlrd version 0.6.1, is intended
-to provide the information needed to (1) display/render spreadsheet contents
-(say) on a screen or in a PDF file, and (2) copy spreadsheet data to another
-file without losing the ability to display/render it.</p>
-
-<h4>The Palette; Colour Indexes</h4>
-
-<p>A colour is represented in Excel as a (red, green, blue) ("RGB") tuple
-with each component in range(256). However it is not possible to access an
-unlimited number of colours; each spreadsheet is limited to a palette of 64 different
-colours (24 in Excel 3.0 and 4.0, 8 in Excel 2.0). Colours are referenced by an index
-("colour index") into this palette.
-
-Colour indexes 0 to 7 represent 8 fixed built-in colours: black, white, red, green, blue,
-yellow, magenta, and cyan.</p><p>
-
-The remaining colours in the palette (8 to 63 in Excel 5.0 and later)
-can be changed by the user. In the Excel 2003 UI, Tools/Options/Color presents a palette
-of 7 rows of 8 colours. The last two rows are reserved for use in charts.<br />
-The correspondence between this grid and the assigned
-colour indexes is NOT left-to-right top-to-bottom.<br />
-Indexes 8 to 15 correspond to changeable
-parallels of the 8 fixed colours -- for example, index 7 is forever cyan;
-index 15 starts off being cyan but can be changed by the user.<br />
-
-The default colour for each index depends on the file version; tables of the defaults
-are available in the source code. If the user changes one or more colours,
-a PALETTE record appears in the XLS file -- it gives the RGB values for *all* changeable
-indexes.<br />
-Note that colours can be used in "number formats": "[CYAN]...." and "[COLOR8]...." refer
-to colour index 7; "[COLOR16]...." will produce cyan
-unless the user changes colour index 15 to something else.<br />
-
-</p><p>In addition, there are several "magic" colour indexes used by Excel:<br />
-0x18 (BIFF3-BIFF4), 0x40 (BIFF5-BIFF8): System window text colour for border lines
-(used in XF, CF, and WINDOW2 records)<br />
-0x19 (BIFF3-BIFF4), 0x41 (BIFF5-BIFF8): System window background colour for pattern background
-(used in XF and CF records )<br />
-0x43: System face colour (dialogue background colour)<br />
-0x4D: System window text colour for chart border lines<br />
-0x4E: System window background colour for chart areas<br />
-0x4F: Automatic colour for chart border lines (seems to be always Black)<br />
-0x50: System ToolTip background colour (used in note objects)<br />
-0x51: System ToolTip text colour (used in note objects)<br />
-0x7FFF: System window text colour for fonts (used in FONT and CF records)<br />
-Note 0x7FFF appears to be the *default* colour index. It appears quite often in FONT
-records.<br />
-
-<h4>Default Formatting</h4>
-
-Default formatting is applied to all empty cells (those not described by a cell record).
-Firstly row default information (ROW record, Rowinfo class) is used if available.
-Failing that, column default information (COLINFO record, Colinfo class) is used if available.
-As a last resort the worksheet/workbook default cell format will be used; this
-should always be present in an Excel file,
-described by the XF record with the fixed index 15 (0-based). By default, it uses the
-worksheet/workbook default cell style, described by the very first XF record (index 0).
-
-<h4> Formatting features not included in xlrd version 0.6.1</h4>
-<ul>
- <li>Rich text i.e. strings containing partial <b>bold</b> <i>italic</i>
- and <u>underlined</u> text, change of font inside a string, etc.
- See OOo docs s3.4 and s3.2</li>
- <li>Asian phonetic text (known as "ruby"), used for Japanese furigana. See OOo docs
- s3.4.2 (p15)</li>
- <li>Conditional formatting. See OOo docs
- s5.12, s6.21 (CONDFMT record), s6.16 (CF record)</li>
- <li>Miscellaneous sheet-level and book-level items e.g. printing layout, screen panes. </li>
- <li>Modern Excel file versions don't keep most of the built-in
- "number formats" in the file; Excel loads formats according to the
- user's locale. Currently xlrd's emulation of this is limited to
- a hard-wired table that applies to the US English locale. This may mean
- that currency symbols, date order, thousands separator, decimals separator, etc
- are inappropriate. Note that this does not affect users who are copying XLS
- files, only those who are visually rendering cells.</li>
-</ul>
-
-<h3>Loading worksheets on demand</h3>
-
-</p><p>This feature, new in version 0.7.1, is governed by the on_demand argument
-to the open_workbook() function and allows saving memory and time by loading
-only those sheets that the caller is interested in, and releasing sheets
-when no longer required.</p>
-
-<p>on_demand=False (default): No change. open_workbook() loads global data
-and all sheets, releases resources no longer required (principally the
-str or mmap object containing the Workbook stream), and returns.</p>
-
-<p>on_demand=True and BIFF version < 5.0: A warning message is emitted,
-on_demand is recorded as False, and the old process is followed.</p>
-
-<p>on_demand=True and BIFF version >= 5.0: open_workbook() loads global
-data and returns without releasing resources. At this stage, the only
-information available about sheets is Book.nsheets and Book.sheet_names().</p>
-
-<p>Book.sheet_by_name() and Book.sheet_by_index() will load the requested
-sheet if it is not already loaded.</p>
-
-<p>Book.sheets() will load all/any unloaded sheets.</p>
-
-<p>The caller may save memory by calling
-Book.unload_sheet(sheet_name_or_index) when finished with the sheet.
-This applies irrespective of the state of on_demand.</p>
-
-<p>The caller may re-load an unloaded sheet by calling Book.sheet_by_xxxx()
- -- except if those required resources have been released (which will
-have happened automatically when on_demand is false). This is the only
-case where an exception will be raised.</p>
-
-<p>The caller may query the state of a sheet:
-Book.sheet_loaded(sheet_name_or_index) -> a bool</p>
-
-<h2>Module Contents</h2>
-<dl>
-<dt><b>BaseObject</b> (class) [<a href='#biffh.BaseObject-class'>#</a>]</dt>
-<dd>
-<p>Parent of almost all other classes in the package.</p>
-<p>For more information about this class, see <a href='#biffh.BaseObject-class'><i>The BaseObject Class</i></a>.</p>
-</dd>
-<dt><b>Book()</b> (class) [<a href='#__init__.Book-class'>#</a>]</dt>
-<dd>
-<p>Contents of a "workbook".</p>
-<p>For more information about this class, see <a href='#__init__.Book-class'><i>The Book Class</i></a>.</p>
-</dd>
-<dt><b>Cell(ctype, value, xf_index=None)</b> (class) [<a href='#sheet.Cell-class'>#</a>]</dt>
-<dd>
-<p>Contains the data for one cell.</p>
-<p>For more information about this class, see <a href='#sheet.Cell-class'><i>The Cell Class</i></a>.</p>
-</dd>
-<dt><a id='formula.cellname-function' name='formula.cellname-function'><b>cellname(rowx, colx)</b></a> [<a href='#formula.cellname-function'>#</a>]</dt>
-<dd>
-<p>Utility function: (5, 7) => 'H6'</p>
-</dd>
-<dt><a id='formula.cellnameabs-function' name='formula.cellnameabs-function'><b>cellnameabs(rowx, colx)</b></a> [<a href='#formula.cellnameabs-function'>#</a>]</dt>
-<dd>
-<p>Utility function: (5, 7) => '$H$6'</p>
-</dd>
-<dt><b>Colinfo</b> (class) [<a href='#sheet.Colinfo-class'>#</a>]</dt>
-<dd>
-<p>Width and default formatting information that applies to one or
-more columns in a sheet.</p>
-<p>For more information about this class, see <a href='#sheet.Colinfo-class'><i>The Colinfo Class</i></a>.</p>
-</dd>
-<dt><a id='formula.colname-function' name='formula.colname-function'><b>colname(colx)</b></a> [<a href='#formula.colname-function'>#</a>]</dt>
-<dd>
-<p>Utility function: 7 => 'H', 27 => 'AB'</p>
-</dd>
-<dt><a id='__init__.count_records-function' name='__init__.count_records-function'><b>count_records(filename, outfile=sys.stdout)</b></a> [<a href='#__init__.count_records-function'>#</a>]</dt>
-<dd>
-<p>For debugging and analysis: summarise the file's BIFF records.
-I.e. produce a sorted file of (record_name, count).</p>
-<dl>
-<dt><i>filename</i></dt>
-<dd>
-The path to the file to be summarised.</dd>
-<dt><i>outfile</i></dt>
-<dd>
-An open file, to which the summary is written.</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.dump-function' name='__init__.dump-function'><b>dump(filename, outfile=sys.stdout, unnumbered=False)</b></a> [<a href='#__init__.dump-function'>#</a>]</dt>
-<dd>
-<p>For debugging: dump the file's BIFF records in char & hex.
-</p><dl>
-<dt><i>filename</i></dt>
-<dd>
-The path to the file to be dumped.</dd>
-<dt><i>outfile</i></dt>
-<dd>
-An open file, to which the dump is written.</dd>
-<dt><i>unnumbered</i></dt>
-<dd>
-If true, omit offsets (for meaningful diffs).</dd>
-</dl><br />
-</dd>
-<dt><a id='sheet.empty_cell-variable' name='sheet.empty_cell-variable'><b>empty_cell</b></a> (variable) [<a href='#sheet.empty_cell-variable'>#</a>]</dt>
-<dd>
-<p>There is one and only one instance of an empty cell -- it's a singleton. This is it.
-You may use a test like "acell is empty_cell".</p>
-</dd>
-<dt><b>EqNeAttrs</b> (class) [<a href='#formatting.EqNeAttrs-class'>#</a>]</dt>
-<dd>
-<p>This mixin class exists solely so that Format, Font, and XF....</p>
-<p>For more information about this class, see <a href='#formatting.EqNeAttrs-class'><i>The EqNeAttrs Class</i></a>.</p>
-</dd>
-<dt><a id='biffh.error_text_from_code-variable' name='biffh.error_text_from_code-variable'><b>error_text_from_code</b></a> (variable) [<a href='#biffh.error_text_from_code-variable'>#</a>]</dt>
-<dd>
-<p /><p>This dictionary can be used to produce a text version of the internal codes
-that Excel uses for error cells. Here are its contents:
-<pre>
-0x00: '#NULL!', # Intersection of two cell ranges is empty
-0x07: '#DIV/0!', # Division by zero
-0x0F: '#VALUE!', # Wrong type of operand
-0x17: '#REF!', # Illegal or deleted cell reference
-0x1D: '#NAME?', # Wrong function or range name
-0x24: '#NUM!', # Value range overflow
-0x2A: '#N/A!', # Argument or function not available
-</pre></p>
-</dd>
-<dt><b>Font</b> (class) [<a href='#formatting.Font-class'>#</a>]</dt>
-<dd>
-<p>An Excel "font" contains the details of not only what is normally
-considered a font, but also several other display attributes.</p>
-<p>For more information about this class, see <a href='#formatting.Font-class'><i>The Font Class</i></a>.</p>
-</dd>
-<dt><b>Format(format_key, ty, format_str)</b> (class) [<a href='#formatting.Format-class'>#</a>]</dt>
-<dd>
-<p>"Number format" information from a FORMAT record.</p>
-<p>For more information about this class, see <a href='#formatting.Format-class'><i>The Format Class</i></a>.</p>
-</dd>
-<dt><b>Name</b> (class) [<a href='#__init__.Name-class'>#</a>]</dt>
-<dd>
-<p>Information relating to a named reference, formula, macro, etc.</p>
-<p>For more information about this class, see <a href='#__init__.Name-class'><i>The Name Class</i></a>.</p>
-</dd>
-<dt><a id='__init__.open_workbook-function' name='__init__.open_workbook-function'><b>open_workbook(filename=None,
-logfile=sys.stdout, verbosity=0, pickleable=True, use_mmap=USE_MMAP,
-file_contents=None,
-encoding_override=None,
-formatting_info=False, on_demand=False,
-)</b></a> [<a href='#__init__.open_workbook-function'>#</a>]</dt>
-<dd>
-<p>Open a spreadsheet file for data extraction.</p>
-<dl>
-<dt><i>filename</i></dt>
-<dd>
-The path to the spreadsheet file to be opened.</dd>
-<dt><i>logfile</i></dt>
-<dd>
-An open file to which messages and diagnostics are written.</dd>
-<dt><i>verbosity</i></dt>
-<dd>
-Increases the volume of trace material written to the logfile.</dd>
-<dt><i>pickleable</i></dt>
-<dd>
-Default is true. In Python 2.4 or earlier, setting to false
-will cause use of array.array objects which save some memory but can't be pickled.
-In Python 2.5, array.arrays are used unconditionally. Note: if you have large files that
-you need to read multiple times, it can be much faster to cPickle.dump() the xlrd.Book object
-once, and use cPickle.load() multiple times.</dd>
-<dt><i>use_mmap</i></dt>
-<dd>
-Whether to use the mmap module is determined heuristically.
-Use this arg to override the result. Current heuristic: mmap is used if it exists.</dd>
-<dt><i>file_contents</i></dt>
-<dd>
-... as a string or an mmap.mmap object or some other behave-alike object.
-If file_contents is supplied, filename will not be used, except (possibly) in messages.</dd>
-<dt><i>encoding_override</i></dt>
-<dd>
-Used to overcome missing or bad codepage information
-in older-version files. Refer to discussion in the <b>Unicode</b> section above.
-<br /> -- New in version 0.6.0
-
-</dd>
-<dt><i>formatting_info</i></dt>
-<dd>
-Governs provision of a reference to an XF (eXtended Format) object
-for each cell in the worksheet.
-<br /> Default is <i>False</i>. This is backwards compatible and saves memory.
-"Blank" cells (those with their own formatting information but no data) are treated as empty
-(by ignoring the file's BLANK and MULBLANK records).
-It cuts off any bottom "margin" of rows of empty (and blank) cells and
-any right "margin" of columns of empty (and blank) cells.
-Only cell_value and cell_type are available.
-<br /> <i>True</i> provides all cells, including empty and blank cells.
-XF information is available for each cell.
-<br /> -- New in version 0.6.1
-
-</dd>
-<dt><i>on_demand</i></dt>
-<dd>
-Governs whether sheets are all loaded initially or when demanded
-by the caller. Please refer back to the section "Loading worksheets on demand" for details.
--- New in version 0.7.1</dd>
-<dt>Returns:</dt>
-<dd>
-An instance of the Book class.</dd>
-</dl><br />
-</dd>
-<dt><b>Operand(akind=None, avalue=None, arank=0, atext='?')</b> (class) [<a href='#formula.Operand-class'>#</a>]</dt>
-<dd>
-<p>Used in evaluating formulas.</p>
-<p>For more information about this class, see <a href='#formula.Operand-class'><i>The Operand Class</i></a>.</p>
-</dd>
-<dt><a id='formula.rangename3d-function' name='formula.rangename3d-function'><b>rangename3d(book, ref3d)</b></a> [<a href='#formula.rangename3d-function'>#</a>]</dt>
-<dd>
-<p>Utility function:
-<br /> Ref3D((1, 4, 5, 20, 7, 10)) => 'Sheet2:Sheet3!$H$6:$J$20'
-</p></dd>
-<dt><a id='formula.rangename3drel-function' name='formula.rangename3drel-function'><b>rangename3drel(book, ref3d)</b></a> [<a href='#formula.rangename3drel-function'>#</a>]</dt>
-<dd>
-<p>Utility function:
-<br /> Ref3D(coords=(0, 1, -32, -22, -13, 13), relflags=(0, 0, 1, 1, 1, 1))
-=> 'Sheet1![@-13,#-32]:[@+12,#-23]'
-where '@' refers to the current or base column and '#'
-refers to the current or base row.
-</p></dd>
-<dt><b>Ref3D(atuple)</b> (class) [<a href='#formula.Ref3D-class'>#</a>]</dt>
-<dd>
-<p>Represents an absolute or relative 3-dimensional reference to a box
-of one or more cells.</p>
-<p>For more information about this class, see <a href='#formula.Ref3D-class'><i>The Ref3D Class</i></a>.</p>
-</dd>
-<dt><b>Rowinfo</b> (class) [<a href='#sheet.Rowinfo-class'>#</a>]</dt>
-<dd>
-<p>Height and default formatting information that applies to a row in a sheet.</p>
-<p>For more information about this class, see <a href='#sheet.Rowinfo-class'><i>The Rowinfo Class</i></a>.</p>
-</dd>
-<dt><b>Sheet(book, position, name, number)</b> (class) [<a href='#sheet.Sheet-class'>#</a>]</dt>
-<dd>
-<p>Contains the data for one worksheet.</p>
-<p>For more information about this class, see <a href='#sheet.Sheet-class'><i>The Sheet Class</i></a>.</p>
-</dd>
-<dt><b>XF</b> (class) [<a href='#formatting.XF-class'>#</a>]</dt>
-<dd>
-<p>eXtended Formatting information for cells, rows, columns and styles.</p>
-<p>For more information about this class, see <a href='#formatting.XF-class'><i>The XF Class</i></a>.</p>
-</dd>
-<dt><b>XFAlignment</b> (class) [<a href='#formatting.XFAlignment-class'>#</a>]</dt>
-<dd>
-<p>A collection of the alignment and similar attributes of an XF record.</p>
-<p>For more information about this class, see <a href='#formatting.XFAlignment-class'><i>The XFAlignment Class</i></a>.</p>
-</dd>
-<dt><b>XFBackground</b> (class) [<a href='#formatting.XFBackground-class'>#</a>]</dt>
-<dd>
-<p>A collection of the background-related attributes of an XF record.</p>
-<p>For more information about this class, see <a href='#formatting.XFBackground-class'><i>The XFBackground Class</i></a>.</p>
-</dd>
-<dt><b>XFBorder</b> (class) [<a href='#formatting.XFBorder-class'>#</a>]</dt>
-<dd>
-<p>A collection of the border-related attributes of an XF record.</p>
-<p>For more information about this class, see <a href='#formatting.XFBorder-class'><i>The XFBorder Class</i></a>.</p>
-</dd>
-<dt><b>XFProtection</b> (class) [<a href='#formatting.XFProtection-class'>#</a>]</dt>
-<dd>
-<p>A collection of the protection-related attributes of an XF record.</p>
-<p>For more information about this class, see <a href='#formatting.XFProtection-class'><i>The XFProtection Class</i></a>.</p>
-</dd>
-<dt><a id='xldate.xldate_as_tuple-function' name='xldate.xldate_as_tuple-function'><b>xldate_as_tuple(xldate, datemode)</b></a> [<a href='#xldate.xldate_as_tuple-function'>#</a>]</dt>
-<dd>
-<p>Convert an Excel number (presumed to represent a date, a datetime or a time) into
-a tuple suitable for feeding to datetime or mx.DateTime constructors.</p>
-<dl>
-<dt><i>xldate</i></dt>
-<dd>
-The Excel number</dd>
-<dt><i>datemode</i></dt>
-<dd>
-0: 1900-based, 1: 1904-based.
-<br />WARNING: when using this function to
-interpret the contents of a workbook, you should pass in the Book.datemode
-attribute of that workbook. Whether
-the workbook has ever been anywhere near a Macintosh is irrelevant.
-</dd>
-<dt>Returns:</dt>
-<dd>
-Gregorian (year, month, day, hour, minute, nearest_second).
-<br />Special case: if 0.0 <= xldate < 1.0, it is assumed to represent a time;
-(0, 0, 0, hour, minute, second) will be returned.
-<br />Note: 1904-01-01 is not regarded as a valid date in the datemode 1 system; its "serial number"
-is zero.
-</dd>
-<dt>Raises <b>XLDateNegative</b>:</dt><dd>
-xldate < 0.00
-</dd>
-<dt>Raises <b>XLDateAmbiguous</b>:</dt><dd>
-The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0)
-</dd>
-<dt>Raises <b>XLDateTooLarge</b>:</dt><dd>
-Gregorian year 10000 or later</dd>
-<dt>Raises <b>XLDateBadDatemode</b>:</dt><dd>
-datemode arg is neither 0 nor 1</dd>
-<dt>Raises <b>XLDateError</b>:</dt><dd>
-Covers the 4 specific errors</dd>
-</dl><br />
-</dd>
-<dt><a id='xldate.xldate_from_date_tuple-function' name='xldate.xldate_from_date_tuple-function'><b>xldate_from_date_tuple((year, month, day), datemode)</b></a> [<a href='#xldate.xldate_from_date_tuple-function'>#</a>]</dt>
-<dd>
-<p>Convert a date tuple (year, month, day) to an Excel date.</p>
-<dl>
-<dt><i>year</i></dt>
-<dd>
-Gregorian year.</dd>
-<dt><i>month</i></dt>
-<dd>
-1 <= month <= 12
-</dd>
-<dt><i>day</i></dt>
-<dd>
-1 <= day <= last day of that (year, month)
-</dd>
-<dt><i>datemode</i></dt>
-<dd>
-0: 1900-based, 1: 1904-based.</dd>
-<dt>Raises <b>XLDateAmbiguous</b>:</dt><dd>
-The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0)
-</dd>
-<dt>Raises <b>XLDateBadDatemode</b>:</dt><dd>
-datemode arg is neither 0 nor 1</dd>
-<dt>Raises <b>XLDateBadTuple</b>:</dt><dd>
-(year, month, day) is too early/late or has invalid component(s)</dd>
-<dt>Raises <b>XLDateError</b>:</dt><dd>
-Covers the specific errors</dd>
-</dl><br />
-</dd>
-<dt><a id='xldate.xldate_from_datetime_tuple-function' name='xldate.xldate_from_datetime_tuple-function'><b>xldate_from_datetime_tuple(datetime_tuple, datemode)</b></a> [<a href='#xldate.xldate_from_datetime_tuple-function'>#</a>]</dt>
-<dd>
-<p>Convert a datetime tuple (year, month, day, hour, minute, second) to an Excel date value.
-For more details, refer to other xldate_from_*_tuple functions.</p>
-<dl>
-<dt><i>datetime_tuple</i></dt>
-<dd>
-(year, month, day, hour, minute, second)</dd>
-<dt><i>datemode</i></dt>
-<dd>
-0: 1900-based, 1: 1904-based.</dd>
-</dl><br />
-</dd>
-<dt><a id='xldate.xldate_from_time_tuple-function' name='xldate.xldate_from_time_tuple-function'><b>xldate_from_time_tuple((hour, minute, second))</b></a> [<a href='#xldate.xldate_from_time_tuple-function'>#</a>]</dt>
-<dd>
-<p>Convert a time tuple (hour, minute, second) to an Excel "date" value (fraction of a day).</p>
-<dl>
-<dt><i>hour</i></dt>
-<dd>
-0 <= hour < 24
-</dd>
-<dt><i>minute</i></dt>
-<dd>
-0 <= minute < 60
-</dd>
-<dt><i>second</i></dt>
-<dd>
-0 <= second < 60
-</dd>
-<dt>Raises <b>XLDateBadTuple</b>:</dt><dd>
-Out-of-range hour, minute, or second</dd>
-</dl><br />
-</dd>
-</dl>
-<h2><a id='biffh.BaseObject-class' name='biffh.BaseObject-class'>The BaseObject Class</a></h2>
-<dl>
-<dt><b>BaseObject</b> (class) [<a href='#biffh.BaseObject-class'>#</a>]</dt>
-<dd>
-<p>Parent of almost all other classes in the package. Defines a common "dump" method
-for debugging.</p>
-</dd>
-<dt><a id='biffh.BaseObject.dump-method' name='biffh.BaseObject.dump-method'><b>dump(f=None, header=None, footer=None, indent=0)</b></a> [<a href='#biffh.BaseObject.dump-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt><i>f</i></dt>
-<dd>
-open file object, to which the dump is written</dd>
-<dt><i>header</i></dt>
-<dd>
-text to write before the dump</dd>
-<dt><i>footer</i></dt>
-<dd>
-text to write after the dump</dd>
-<dt><i>indent</i></dt>
-<dd>
-number of leading spaces (for recursive calls)</dd>
-</dl><br />
-</dd>
-</dl>
-<h2><a id='__init__.Book-class' name='__init__.Book-class'>The Book Class</a></h2>
-<dl>
-<dt><b>Book()</b> (class) [<a href='#__init__.Book-class'>#</a>]</dt>
-<dd>
-<p>Contents of a "workbook".
-</p><p>WARNING: You don't call this class yourself. You use the Book object that
-was returned when you called xlrd.open_workbook("myfile.xls").</p>
-</dd>
-<dt><a id='__init__.Book.biff_version-attribute' name='__init__.Book.biff_version-attribute'><b>biff_version</b></a> [<a href='#__init__.Book.biff_version-attribute'>#</a>]</dt>
-<dd>
-<p>Version of BIFF (Binary Interchange File Format) used to create the file.
-Latest is 8.0 (represented here as 80), introduced with Excel 97.
-Earliest supported by this module: 2.0 (represented as 20).</p>
-</dd>
-<dt><a id='__init__.Book.codepage-attribute' name='__init__.Book.codepage-attribute'><b>codepage</b></a> [<a href='#__init__.Book.codepage-attribute'>#</a>]</dt>
-<dd>
-<p>An integer denoting the character set used for strings in this file.
-For BIFF 8 and later, this will be 1200, meaning Unicode; more precisely, UTF_16_LE.
-For earlier versions, this is used to derive the appropriate Python encoding
-to be used to convert to Unicode.
-Examples: 1252 -> 'cp1252', 10000 -> 'mac_roman'</p>
-</dd>
-<dt><a id='__init__.Book.colour_map-attribute' name='__init__.Book.colour_map-attribute'><b>colour_map</b></a> [<a href='#__init__.Book.colour_map-attribute'>#</a>]</dt>
-<dd>
-<p>This provides definitions for colour indexes. Please refer to the
-above section "The Palette; Colour Indexes" for an explanation
-of how colours are represented in Excel.<br />
-Colour indexes into the palette map into (red, green, blue) tuples.
-"Magic" indexes e.g. 0x7FFF map to None.
-<i>colour_map</i> is what you need if you want to render cells on screen or in a PDF
-file. If you are writing an output XLS file, use <i>palette_record</i>.
-<br /> -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True)
-</p></dd>
-<dt><a id='__init__.Book.countries-attribute' name='__init__.Book.countries-attribute'><b>countries</b></a> [<a href='#__init__.Book.countries-attribute'>#</a>]</dt>
-<dd>
-<p>A tuple containing the (telephone system) country code for:<br />
- [0]: the user-interface setting when the file was created.<br />
- [1]: the regional settings.<br />
-Example: (1, 61) meaning (USA, Australia).
-This information may give a clue to the correct encoding for an unknown codepage.
-For a long list of observed values, refer to the OpenOffice.org documentation for
-the COUNTRY record.
-</p></dd>
-<dt><a id='__init__.Book.datemode-attribute' name='__init__.Book.datemode-attribute'><b>datemode</b></a> [<a href='#__init__.Book.datemode-attribute'>#</a>]</dt>
-<dd>
-<p>Which date system was in force when this file was last saved.<br />
- 0 => 1900 system (the Excel for Windows default).<br />
- 1 => 1904 system (the Excel for Macintosh default).<br />
-</p></dd>
-<dt><a id='__init__.Book.encoding-attribute' name='__init__.Book.encoding-attribute'><b>encoding</b></a> [<a href='#__init__.Book.encoding-attribute'>#</a>]</dt>
-<dd>
-<p>The encoding that was derived from the codepage.</p>
-</dd>
-<dt><a id='__init__.Book.font_list-attribute' name='__init__.Book.font_list-attribute'><b>font_list</b></a> [<a href='#__init__.Book.font_list-attribute'>#</a>]</dt>
-<dd>
-<p>A list of Font class instances, each corresponding to a FONT record.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='__init__.Book.format_list-attribute' name='__init__.Book.format_list-attribute'><b>format_list</b></a> [<a href='#__init__.Book.format_list-attribute'>#</a>]</dt>
-<dd>
-<p>A list of Format objects, each corresponding to a FORMAT record, in
-the order that they appear in the input file.
-It does <i>not</i> contain builtin formats.
-If you are creating an output file using (for example) pyExcelerator,
-use this list.
-The collection to be used for all visual rendering purposes is format_map.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='__init__.Book.format_map-attribute' name='__init__.Book.format_map-attribute'><b>format_map</b></a> [<a href='#__init__.Book.format_map-attribute'>#</a>]</dt>
-<dd>
-<p>The mapping from XF.format_key to Format object.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='__init__.Book.load_time_stage_1-attribute' name='__init__.Book.load_time_stage_1-attribute'><b>load_time_stage_1</b></a> [<a href='#__init__.Book.load_time_stage_1-attribute'>#</a>]</dt>
-<dd>
-<p>Time in seconds to extract the XLS image as a contiguous string (or mmap equivalent).</p>
-</dd>
-<dt><a id='__init__.Book.load_time_stage_2-attribute' name='__init__.Book.load_time_stage_2-attribute'><b>load_time_stage_2</b></a> [<a href='#__init__.Book.load_time_stage_2-attribute'>#</a>]</dt>
-<dd>
-<p>Time in seconds to parse the data from the contiguous string (or mmap equivalent).</p>
-</dd>
-<dt><a id='__init__.Book.name_and_scope_map-attribute' name='__init__.Book.name_and_scope_map-attribute'><b>name_and_scope_map</b></a> [<a href='#__init__.Book.name_and_scope_map-attribute'>#</a>]</dt>
-<dd>
-<p>A mapping from (lower_case_name, scope) to a single Name object.
-<br /> -- New in version 0.6.0
-</p></dd>
-<dt><a id='__init__.Book.name_map-attribute' name='__init__.Book.name_map-attribute'><b>name_map</b></a> [<a href='#__init__.Book.name_map-attribute'>#</a>]</dt>
-<dd>
-<p>A mapping from lower_case_name to a list of Name objects. The list is
-sorted in scope order. Typically there will be one item (of global scope)
-in the list.
-<br /> -- New in version 0.6.0
-</p></dd>
-<dt><a id='__init__.Book.name_obj_list-attribute' name='__init__.Book.name_obj_list-attribute'><b>name_obj_list</b></a> [<a href='#__init__.Book.name_obj_list-attribute'>#</a>]</dt>
-<dd>
-<p>List containing a Name object for each NAME record in the workbook.
-<br /> -- New in version 0.6.0
-</p></dd>
-<dt><a id='__init__.Book.nsheets-attribute' name='__init__.Book.nsheets-attribute'><b>nsheets</b></a> [<a href='#__init__.Book.nsheets-attribute'>#</a>]</dt>
-<dd>
-<p>The number of worksheets present in the workbook file.
-This information is available even when no sheets have yet been loaded.</p>
-</dd>
-<dt><a id='__init__.Book.palette_record-attribute' name='__init__.Book.palette_record-attribute'><b>palette_record</b></a> [<a href='#__init__.Book.palette_record-attribute'>#</a>]</dt>
-<dd>
-<p>If the user has changed any of the colours in the standard palette, the XLS
-file will contain a PALETTE record with 56 (16 for Excel 4.0 and earlier)
-RGB values in it, and this list will be e.g. [(r0, b0, g0), ..., (r55, b55, g55)].
-Otherwise this list will be empty. This is what you need if you are
-writing an output XLS file. If you want to render cells on screen or in a PDF
-file, use colour_map.
-<br /> -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True)
-</p></dd>
-<dt><a id='__init__.Book.sheet_by_index-method' name='__init__.Book.sheet_by_index-method'><b>sheet_by_index(sheetx)</b></a> [<a href='#__init__.Book.sheet_by_index-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt><i>sheetx</i></dt>
-<dd>
-Sheet index in range(nsheets)</dd>
-<dt>Returns:</dt>
-<dd>
-An object of the Sheet class</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Book.sheet_by_name-method' name='__init__.Book.sheet_by_name-method'><b>sheet_by_name(sheet_name)</b></a> [<a href='#__init__.Book.sheet_by_name-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt><i>sheet_name</i></dt>
-<dd>
-Name of sheet required</dd>
-<dt>Returns:</dt>
-<dd>
-An object of the Sheet class</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Book.sheet_loaded-method' name='__init__.Book.sheet_loaded-method'><b>sheet_loaded(sheet_name_or_index)</b></a> [<a href='#__init__.Book.sheet_loaded-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt><i>sheet_name_or_index</i></dt>
-<dd>
-Name or index of sheet enquired upon</dd>
-<dt>Returns:</dt>
-<dd>
-true if sheet is loaded, false otherwise
-<br /> -- New in version 0.7.1
-</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Book.sheet_names-method' name='__init__.Book.sheet_names-method'><b>sheet_names()</b></a> [<a href='#__init__.Book.sheet_names-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt>Returns:</dt>
-<dd>
-A list of the names of all the worksheets in the workbook file.
-This information is available even when no sheets have yet been loaded.</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Book.sheets-method' name='__init__.Book.sheets-method'><b>sheets()</b></a> [<a href='#__init__.Book.sheets-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt>Returns:</dt>
-<dd>
-A list of all sheets in the book.
-All sheets not already loaded will be loaded.</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Book.style_name_map-attribute' name='__init__.Book.style_name_map-attribute'><b>style_name_map</b></a> [<a href='#__init__.Book.style_name_map-attribute'>#</a>]</dt>
-<dd>
-<p>This provides access via name to the extended format information for
-both built-in styles and user-defined styles.<br />
-It maps <i>name</i> to (<i>built_in</i>, <i>xf_index</i>), where:<br />
-<i>name</i> is either the name of a user-defined style,
-or the name of one of the built-in styles. Known built-in names are
-Normal, RowLevel_1 to RowLevel_7,
-ColLevel_1 to ColLevel_7, Comma, Currency, Percent, "Comma [0]",
-"Currency [0]", Hyperlink, and "Followed Hyperlink".<br />
-<i>built_in</i> 1 = built-in style, 0 = user-defined<br />
-<i>xf_index</i> is an index into Book.xf_list.<br />
-References: OOo docs s6.99 (STYLE record); Excel UI Format/Style
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='__init__.Book.unload_sheet-method' name='__init__.Book.unload_sheet-method'><b>unload_sheet(sheet_name_or_index)</b></a> [<a href='#__init__.Book.unload_sheet-method'>#</a>]</dt>
-<dd>
-<dl>
-<dt><i>sheet_name_or_index</i></dt>
-<dd>
-Name or index of sheet to be unloaded.
-<br /> -- New in version 0.7.1
-</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Book.user_name-attribute' name='__init__.Book.user_name-attribute'><b>user_name</b></a> [<a href='#__init__.Book.user_name-attribute'>#</a>]</dt>
-<dd>
-<p>What (if anything) is recorded as the name of the last user to save the file.</p>
-</dd>
-<dt><a id='__init__.Book.xf_list-attribute' name='__init__.Book.xf_list-attribute'><b>xf_list</b></a> [<a href='#__init__.Book.xf_list-attribute'>#</a>]</dt>
-<dd>
-<p>A list of XF class instances, each corresponding to an XF record.
-<br /> -- New in version 0.6.1
-</p></dd>
-</dl>
-<h2><a id='sheet.Cell-class' name='sheet.Cell-class'>The Cell Class</a></h2>
-<dl>
-<dt><b>Cell(ctype, value, xf_index=None)</b> (class) [<a href='#sheet.Cell-class'>#</a>]</dt>
-<dd>
-<p /><p>Contains the data for one cell.</p>
-
-<p>WARNING: You don't call this class yourself. You access Cell objects
-via methods of the Sheet object(s) that you found in the Book object that
-was returned when you called xlrd.open_workbook("myfile.xls").</p>
-<p> Cell objects have three attributes: <i>ctype</i> is an int, <i>value</i>
-(which depends on <i>ctype</i>) and <i>xf_index</i>.
-If "formatting_info" is not enabled when the workbook is opened, xf_index will be None.
-The following table describes the types of cells and how their values
-are represented in Python.</p>
-
-<table border="1" cellpadding="7">
-<tr>
-<th>Type symbol</th>
-<th>Type number</th>
-<th>Python value</th>
-</tr>
-<tr>
-<td>XL_CELL_EMPTY</td>
-<td align="center">0</td>
-<td>empty string u''</td>
-</tr>
-<tr>
-<td>XL_CELL_TEXT</td>
-<td align="center">1</td>
-<td>a Unicode string</td>
-</tr>
-<tr>
-<td>XL_CELL_NUMBER</td>
-<td align="center">2</td>
-<td>float</td>
-</tr>
-<tr>
-<td>XL_CELL_DATE</td>
-<td align="center">3</td>
-<td>float</td>
-</tr>
-<tr>
-<td>XL_CELL_BOOLEAN</td>
-<td align="center">4</td>
-<td>int; 1 means TRUE, 0 means FALSE</td>
-</tr>
-<tr>
-<td>XL_CELL_ERROR</td>
-<td align="center">5</td>
-<td>int representing internal Excel codes; for a text representation,
-refer to the supplied dictionary error_text_from_code</td>
-</tr>
-<tr>
-<td>XL_CELL_BLANK</td>
-<td align="center">6</td>
-<td>empty string u''. Note: this type will appear only when
-open_workbook(..., formatting_info=True) is used.</td>
-</tr>
-</table>
-<p />
-</dd>
-</dl>
-<h2><a id='sheet.Colinfo-class' name='sheet.Colinfo-class'>The Colinfo Class</a></h2>
-<dl>
-<dt><b>Colinfo</b> (class) [<a href='#sheet.Colinfo-class'>#</a>]</dt>
-<dd>
-<p>Width and default formatting information that applies to one or
-more columns in a sheet. Derived from COLINFO records.
-
-</p><p> Here is the default hierarchy for width, according to the OOo docs:
-
-<br />"""In BIFF3, if a COLINFO record is missing for a column,
-the width specified in the record DEFCOLWIDTH is used instead.
-
-<br />In BIFF4-BIFF7, the width set in this [COLINFO] record is only used,
-if the corresponding bit for this column is cleared in the GCW
-record, otherwise the column width set in the DEFCOLWIDTH record
-is used (the STANDARDWIDTH record is always ignored in this case [see footnote!]).
-
-<br />In BIFF8, if a COLINFO record is missing for a column,
-the width specified in the record STANDARDWIDTH is used.
-If this [STANDARDWIDTH] record is also missing,
-the column width of the record DEFCOLWIDTH is used instead."""
-<br />
-
-Footnote: The docs on the GCW record say this:
-"""<br />
-If a bit is set, the corresponding column uses the width set in the STANDARDWIDTH
-record. If a bit is cleared, the corresponding column uses the width set in the
-COLINFO record for this column.
-<br />If a bit is set, and the worksheet does not contain the STANDARDWIDTH record, or if
-the bit is cleared, and the worksheet does not contain the COLINFO record, the DEFCOLWIDTH
-record of the worksheet will be used instead.
-<br />"""<br />
-At the moment (2007-01-17) xlrd is going with the GCW version of the story.
-Reference to the source may be useful: see the computed_column_width(colx) method
-of the Sheet class.
-<br />-- New in version 0.6.1
-</p>
-</dd>
-<dt><a id='sheet.Colinfo.bit1_flag-attribute' name='sheet.Colinfo.bit1_flag-attribute'><b>bit1_flag</b></a> [<a href='#sheet.Colinfo.bit1_flag-attribute'>#</a>]</dt>
-<dd>
-<p>Value of a 1-bit flag whose purpose is unknown
-but is often seen set to 1</p>
-</dd>
-<dt><a id='sheet.Colinfo.collapsed-attribute' name='sheet.Colinfo.collapsed-attribute'><b>collapsed</b></a> [<a href='#sheet.Colinfo.collapsed-attribute'>#</a>]</dt>
-<dd>
-<p>1 = column is collapsed</p>
-</dd>
-<dt><a id='sheet.Colinfo.hidden-attribute' name='sheet.Colinfo.hidden-attribute'><b>hidden</b></a> [<a href='#sheet.Colinfo.hidden-attribute'>#</a>]</dt>
-<dd>
-<p>1 = column is hidden</p>
-</dd>
-<dt><a id='sheet.Colinfo.outline_level-attribute' name='sheet.Colinfo.outline_level-attribute'><b>outline_level</b></a> [<a href='#sheet.Colinfo.outline_level-attribute'>#</a>]</dt>
-<dd>
-<p>Outline level of the column, in range(7).
-(0 = no outline)</p>
-</dd>
-<dt><a id='sheet.Colinfo.width-attribute' name='sheet.Colinfo.width-attribute'><b>width</b></a> [<a href='#sheet.Colinfo.width-attribute'>#</a>]</dt>
-<dd>
-<p>Width of the column in 1/256 of the width of the zero character,
-using default font (first FONT record in the file).</p>
-</dd>
-<dt><a id='sheet.Colinfo.xf_index-attribute' name='sheet.Colinfo.xf_index-attribute'><b>xf_index</b></a> [<a href='#sheet.Colinfo.xf_index-attribute'>#</a>]</dt>
-<dd>
-<p>XF index to be used for formatting empty cells.</p>
-</dd>
-</dl>
-<h2><a id='formatting.EqNeAttrs-class' name='formatting.EqNeAttrs-class'>The EqNeAttrs Class</a></h2>
-<dl>
-<dt><b>EqNeAttrs</b> (class) [<a href='#formatting.EqNeAttrs-class'>#</a>]</dt>
-<dd>
-<p>This mixin class exists solely so that Format, Font, and XF.... objects
-can be compared by value of their attributes.</p>
-</dd>
-</dl>
-<h2><a id='formatting.Font-class' name='formatting.Font-class'>The Font Class</a></h2>
-<dl>
-<dt><b>Font</b> (class) [<a href='#formatting.Font-class'>#</a>]</dt>
-<dd>
-<p>An Excel "font" contains the details of not only what is normally
-considered a font, but also several other display attributes.
-Items correspond to those in the Excel UI's Format/Cells/Font tab.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='formatting.Font.bold-attribute' name='formatting.Font.bold-attribute'><b>bold</b></a> [<a href='#formatting.Font.bold-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Characters are bold. Redundant; see "weight" attribute.</p>
-</dd>
-<dt><a id='formatting.Font.character_set-attribute' name='formatting.Font.character_set-attribute'><b>character_set</b></a> [<a href='#formatting.Font.character_set-attribute'>#</a>]</dt>
-<dd>
-<p>Values: 0 = ANSI Latin, 1 = System default, 2 = Symbol,
-77 = Apple Roman,
-128 = ANSI Japanese Shift-JIS,
-129 = ANSI Korean (Hangul),
-130 = ANSI Korean (Johab),
-134 = ANSI Chinese Simplified GBK,
-136 = ANSI Chinese Traditional BIG5,
-161 = ANSI Greek,
-162 = ANSI Turkish,
-163 = ANSI Vietnamese,
-177 = ANSI Hebrew,
-178 = ANSI Arabic,
-186 = ANSI Baltic,
-204 = ANSI Cyrillic,
-222 = ANSI Thai,
-238 = ANSI Latin II (Central European),
-255 = OEM Latin I</p>
-</dd>
-<dt><a id='formatting.Font.colour_index-attribute' name='formatting.Font.colour_index-attribute'><b>colour_index</b></a> [<a href='#formatting.Font.colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>An explanation of "colour index" is given in the Formatting
-section at the start of this document.</p>
-</dd>
-<dt><a id='formatting.Font.escapement-attribute' name='formatting.Font.escapement-attribute'><b>escapement</b></a> [<a href='#formatting.Font.escapement-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Superscript, 2 = Subscript.</p>
-</dd>
-<dt><a id='formatting.Font.family-attribute' name='formatting.Font.family-attribute'><b>family</b></a> [<a href='#formatting.Font.family-attribute'>#</a>]</dt>
-<dd>
-<p>0 = None (unknown or don't care)<br />
-1 = Roman (variable width, serifed)<br />
-2 = Swiss (variable width, sans-serifed)<br />
-3 = Modern (fixed width, serifed or sans-serifed)<br />
-4 = Script (cursive)<br />
-5 = Decorative (specialised, for example Old English, Fraktur)
-</p></dd>
-<dt><a id='formatting.Font.font_index-attribute' name='formatting.Font.font_index-attribute'><b>font_index</b></a> [<a href='#formatting.Font.font_index-attribute'>#</a>]</dt>
-<dd>
-<p>The 0-based index used to refer to this Font() instance.
-Note that index 4 is never used; xlrd supplies a dummy place-holder.</p>
-</dd>
-<dt><a id='formatting.Font.height-attribute' name='formatting.Font.height-attribute'><b>height</b></a> [<a href='#formatting.Font.height-attribute'>#</a>]</dt>
-<dd>
-<p>Height of the font (in twips). A twip = 1/20 of a point.</p>
-</dd>
-<dt><a id='formatting.Font.italic-attribute' name='formatting.Font.italic-attribute'><b>italic</b></a> [<a href='#formatting.Font.italic-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Characters are italic.</p>
-</dd>
-<dt><a id='formatting.Font.name-attribute' name='formatting.Font.name-attribute'><b>name</b></a> [<a href='#formatting.Font.name-attribute'>#</a>]</dt>
-<dd>
-<p>The name of the font. Example: u"Arial"</p>
-</dd>
-<dt><a id='formatting.Font.outline-attribute' name='formatting.Font.outline-attribute'><b>outline</b></a> [<a href='#formatting.Font.outline-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Font is outline style (Macintosh only)</p>
-</dd>
-<dt><a id='formatting.Font.shadow-attribute' name='formatting.Font.shadow-attribute'><b>shadow</b></a> [<a href='#formatting.Font.shadow-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Font is shadow style (Macintosh only)</p>
-</dd>
-<dt><a id='formatting.Font.struck_out-attribute' name='formatting.Font.struck_out-attribute'><b>struck_out</b></a> [<a href='#formatting.Font.struck_out-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Characters are struck out.</p>
-</dd>
-<dt><a id='formatting.Font.underline_type-attribute' name='formatting.Font.underline_type-attribute'><b>underline_type</b></a> [<a href='#formatting.Font.underline_type-attribute'>#</a>]</dt>
-<dd>
-<p>0 = None<br />
-1 = Single; 0x21 (33) = Single accounting<br />
-2 = Double; 0x22 (34) = Double accounting
-</p></dd>
-<dt><a id='formatting.Font.underlined-attribute' name='formatting.Font.underlined-attribute'><b>underlined</b></a> [<a href='#formatting.Font.underlined-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Characters are underlined. Redundant; see "underline_type" attribute.</p>
-</dd>
-<dt><a id='formatting.Font.weight-attribute' name='formatting.Font.weight-attribute'><b>weight</b></a> [<a href='#formatting.Font.weight-attribute'>#</a>]</dt>
-<dd>
-<p>Font weight (100-1000). Standard values are 400 for normal text
-and 700 for bold text.</p>
-</dd>
-</dl>
-<h2><a id='formatting.Format-class' name='formatting.Format-class'>The Format Class</a></h2>
-<dl>
-<dt><b>Format(format_key, ty, format_str)</b> (class) [<a href='#formatting.Format-class'>#</a>]</dt>
-<dd>
-<p>"Number format" information from a FORMAT record.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='formatting.Format.format_key-attribute' name='formatting.Format.format_key-attribute'><b>format_key</b></a> [<a href='#formatting.Format.format_key-attribute'>#</a>]</dt>
-<dd>
-<p>The key into Book.format_map</p>
-</dd>
-<dt><a id='formatting.Format.format_str-attribute' name='formatting.Format.format_str-attribute'><b>format_str</b></a> [<a href='#formatting.Format.format_str-attribute'>#</a>]</dt>
-<dd>
-<p>The format string</p>
-</dd>
-<dt><a id='formatting.Format.type-attribute' name='formatting.Format.type-attribute'><b>type</b></a> [<a href='#formatting.Format.type-attribute'>#</a>]</dt>
-<dd>
-<p>A classification that has been inferred from the format string.
-Currently, this is used only to distinguish between numbers and dates.
-<br />Values:
-<br />FUN = 0 # unknown
-<br />FDT = 1 # date
-<br />FNU = 2 # number
-<br />FGE = 3 # general
-<br />FTX = 4 # text
-</p></dd>
-</dl>
-<h2><a id='__init__.Name-class' name='__init__.Name-class'>The Name Class</a></h2>
-<dl>
-<dt><b>Name</b> (class) [<a href='#__init__.Name-class'>#</a>]</dt>
-<dd>
-<p>Information relating to a named reference, formula, macro, etc.
-<br /> -- New in version 0.6.0
-<br /> -- <i>Name information is <b>not</b> extracted from files older than
-Excel 5.0 (Book.biff_version < 50)</i>
-</p></dd>
-<dt><a id='__init__.Name.area2d-method' name='__init__.Name.area2d-method'><b>area2d(clipped=True)</b></a> [<a href='#__init__.Name.area2d-method'>#</a>]</dt>
-<dd>
-<p>This is a convenience method for the use case where the name
-refers to one rectangular area in one worksheet.</p>
-<dl>
-<dt><i>clipped</i></dt>
-<dd>
-If true (the default), the returned rectangle is clipped
-to fit in (0, sheet.nrows, 0, sheet.ncols) -- it is guaranteed that
-0 <= rowxlo <= rowxhi <= sheet.nrows and that the number of usable rows
-in the area (which may be zero) is rowxhi - rowxlo; likewise for columns.
-</dd>
-<dt>Returns:</dt>
-<dd>
-a tuple (sheet_object, rowxlo, rowxhi, colxlo, colxhi).</dd>
-<dt>Raises <b>XLRDError</b>:</dt><dd>
-The name is not a constant absolute reference
-to a single area in a single sheet.</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Name.binary-attribute' name='__init__.Name.binary-attribute'><b>binary</b></a> [<a href='#__init__.Name.binary-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Formula definition; 1 = Binary data<br /> <i>No examples have been sighted.</i>
-</p></dd>
-<dt><a id='__init__.Name.builtin-attribute' name='__init__.Name.builtin-attribute'><b>builtin</b></a> [<a href='#__init__.Name.builtin-attribute'>#</a>]</dt>
-<dd>
-<p>0 = User-defined name; 1 = Built-in name
-(common examples: Print_Area, Print_Titles; see OOo docs for full list)</p>
-</dd>
-<dt><a id='__init__.Name.cell-method' name='__init__.Name.cell-method'><b>cell()</b></a> [<a href='#__init__.Name.cell-method'>#</a>]</dt>
-<dd>
-<p>This is a convenience method for the frequent use case where the name
-refers to a single cell.</p>
-<dl>
-<dt>Returns:</dt>
-<dd>
-An instance of the Cell class.</dd>
-<dt>Raises <b>XLRDError</b>:</dt><dd>
-The name is not a constant absolute reference
-to a single cell.</dd>
-</dl><br />
-</dd>
-<dt><a id='__init__.Name.complex-attribute' name='__init__.Name.complex-attribute'><b>complex</b></a> [<a href='#__init__.Name.complex-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Simple formula; 1 = Complex formula (array formula or user defined)<br />
-<i>No examples have been sighted.</i>
-</p></dd>
-<dt><a id='__init__.Name.func-attribute' name='__init__.Name.func-attribute'><b>func</b></a> [<a href='#__init__.Name.func-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Command macro; 1 = Function macro. Relevant only if macro == 1</p>
-</dd>
-<dt><a id='__init__.Name.funcgroup-attribute' name='__init__.Name.funcgroup-attribute'><b>funcgroup</b></a> [<a href='#__init__.Name.funcgroup-attribute'>#</a>]</dt>
-<dd>
-<p>Function group. Relevant only if macro == 1; see OOo docs for values.</p>
-</dd>
-<dt><a id='__init__.Name.hidden-attribute' name='__init__.Name.hidden-attribute'><b>hidden</b></a> [<a href='#__init__.Name.hidden-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Visible; 1 = Hidden</p>
-</dd>
-<dt><a id='__init__.Name.macro-attribute' name='__init__.Name.macro-attribute'><b>macro</b></a> [<a href='#__init__.Name.macro-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Standard name; 1 = Macro name</p>
-</dd>
-<dt><a id='__init__.Name.name-attribute' name='__init__.Name.name-attribute'><b>name</b></a> [<a href='#__init__.Name.name-attribute'>#</a>]</dt>
-<dd>
-<p>A Unicode string. If builtin, decoded as per OOo docs.</p>
-</dd>
-<dt><a id='__init__.Name.name_index-attribute' name='__init__.Name.name_index-attribute'><b>name_index</b></a> [<a href='#__init__.Name.name_index-attribute'>#</a>]</dt>
-<dd>
-<p>The index of this object in book.name_obj_list</p>
-</dd>
-<dt><a id='__init__.Name.raw_formula-attribute' name='__init__.Name.raw_formula-attribute'><b>raw_formula</b></a> [<a href='#__init__.Name.raw_formula-attribute'>#</a>]</dt>
-<dd>
-<p>An 8-bit string.</p>
-</dd>
-<dt><a id='__init__.Name.result-attribute' name='__init__.Name.result-attribute'><b>result</b></a> [<a href='#__init__.Name.result-attribute'>#</a>]</dt>
-<dd>
-<p>The result of evaluating the formula, if any.
-If no formula, or evaluation of the formula encountered problems,
-the result is None. Otherwise the result is a single instance of the
-Operand class.</p>
-</dd>
-<dt><a id='__init__.Name.scope-attribute' name='__init__.Name.scope-attribute'><b>scope</b></a> [<a href='#__init__.Name.scope-attribute'>#</a>]</dt>
-<dd>
-<p>-1: The name is global (visible in all calculation sheets).<br />
--2: The name belongs to a macro sheet or VBA sheet.<br />
--3: The name is invalid.<br />
-0 <= scope < book.nsheets: The name is local to the sheet whose index is scope.
-</p></dd>
-<dt><a id='__init__.Name.vbasic-attribute' name='__init__.Name.vbasic-attribute'><b>vbasic</b></a> [<a href='#__init__.Name.vbasic-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Sheet macro; 1 = VisualBasic macro. Relevant only if macro == 1</p>
-</dd>
-</dl>
-<h2><a id='formula.Operand-class' name='formula.Operand-class'>The Operand Class</a></h2>
-<dl>
-<dt><b>Operand(akind=None, avalue=None, arank=0, atext='?')</b> (class) [<a href='#formula.Operand-class'>#</a>]</dt>
-<dd>
-<p>Used in evaluating formulas.
-The following table describes the kinds and how their values
-are represented.</p>
-
-<table border="1" cellpadding="7">
-<tr>
-<th>Kind symbol</th>
-<th>Kind number</th>
-<th>Value representation</th>
-</tr>
-<tr>
-<td>oBOOL</td>
-<td align="center">3</td>
-<td>integer: 0 => False; 1 => True</td>
-</tr>
-<tr>
-<td>oERR</td>
-<td align="center">4</td>
-<td>None, or an int error code (same as XL_CELL_ERROR in the Cell class).
-</td>
-</tr>
-<tr>
-<td>oMSNG</td>
-<td align="center">5</td>
-<td>Used by Excel as a placeholder for a missing (not supplied) function
-argument. Should *not* appear as a final formula result. Value is None.</td>
-</tr>
-<tr>
-<td>oNUM</td>
-<td align="center">2</td>
-<td>A float. Note that there is no way of distinguishing dates.</td>
-</tr>
-<tr>
-<td>oREF</td>
-<td align="center">-1</td>
-<td>The value is either None or a non-empty list of
-absolute Ref3D instances.<br />
-</td>
-</tr>
-<tr>
-<td>oREL</td>
-<td align="center">-2</td>
-<td>The value is None or a non-empty list of
-fully or partially relative Ref3D instances.
-</td>
-</tr>
-<tr>
-<td>oSTRG</td>
-<td align="center">1</td>
-<td>A Unicode string.</td>
-</tr>
-<tr>
-<td>oUNK</td>
-<td align="center">0</td>
-<td>The kind is unknown or ambiguous. The value is None</td>
-</tr>
-</table>
-<p />
-</dd>
-<dt><a id='formula.Operand.kind-attribute' name='formula.Operand.kind-attribute'><b>kind</b></a> [<a href='#formula.Operand.kind-attribute'>#</a>]</dt>
-<dd>
-<p>oUNK means that the kind of operand is not known unambiguously.</p>
-</dd>
-<dt><a id='formula.Operand.text-attribute' name='formula.Operand.text-attribute'><b>text</b></a> [<a href='#formula.Operand.text-attribute'>#</a>]</dt>
-<dd>
-<p>The reconstituted text of the original formula. Function names will be
-in English irrespective of the original language, which doesn't seem
-to be recorded anywhere. The separator is ",", not ";" or whatever else
-might be more appropriate for the end-user's locale; patches welcome.</p>
-</dd>
-<dt><a id='formula.Operand.value-attribute' name='formula.Operand.value-attribute'><b>value</b></a> [<a href='#formula.Operand.value-attribute'>#</a>]</dt>
-<dd>
-<p>None means that the actual value of the operand is a variable
-(depends on cell data), not a constant.</p>
-</dd>
-</dl>
-<h2><a id='formula.Ref3D-class' name='formula.Ref3D-class'>The Ref3D Class</a></h2>
-<dl>
-<dt><b>Ref3D(atuple)</b> (class) [<a href='#formula.Ref3D-class'>#</a>]</dt>
-<dd>
-<p /><p>Represents an absolute or relative 3-dimensional reference to a box
-of one or more cells.<br />
--- New in version 0.6.0
-</p>
-
-<p>The <i>coords</i> attribute is a tuple of the form:<br />
-(shtxlo, shtxhi, rowxlo, rowxhi, colxlo, colxhi)<br />
-where 0 <= thingxlo <= thingx < thingxhi.<br />
-Note that it is quite possible to have thingx > nthings; for example
-Print_Titles could have colxhi == 256 and/or rowxhi == 65536
-irrespective of how many columns/rows are actually used in the worksheet.
-The caller will need to decide how to handle this situation.
-Keyword: IndexError :-)
-</p>
-
-<p>The components of the coords attribute are also available as individual
-attributes: shtxlo, shtxhi, rowxlo, rowxhi, colxlo, and colxhi.</p>
-
-<p>The <i>relflags</i> attribute is a 6-tuple of flags which indicate whether
-the corresponding (sheet|row|col)(lo|hi) is relative (1) or absolute (0).<br />
-Note that there is necessarily no information available as to what cell(s)
-the reference could possibly be relative to. The caller must decide what if
-any use to make of oREL operands. Note also that a partially relative
-reference may well be a typo.
-For example, define name A1Z10 as $a$1:$z10 (missing $ after z)
-while the cursor is on cell Sheet3!A27.<br />
-The resulting Ref3D instance will have coords = (2, 3, 0, -16, 0, 26)
-and relflags = (0, 0, 0, 1, 0, 0).<br />
-So far, only one possibility of a sheet-relative component in
-a reference has been noticed: a 2D reference located in the "current sheet".
-<br /> This will appear as coords = (0, 1, ...) and relflags = (1, 1, ...).
-</p></dd>
-</dl>
-<h2><a id='sheet.Rowinfo-class' name='sheet.Rowinfo-class'>The Rowinfo Class</a></h2>
-<dl>
-<dt><b>Rowinfo</b> (class) [<a href='#sheet.Rowinfo-class'>#</a>]</dt>
-<dd>
-<p>Height and default formatting information that applies to a row in a sheet.
-Derived from ROW records.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='sheet.Rowinfo.additional_space_above-attribute' name='sheet.Rowinfo.additional_space_above-attribute'><b>additional_space_above</b></a> [<a href='#sheet.Rowinfo.additional_space_above-attribute'>#</a>]</dt>
-<dd>
-<p>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.</p>
-</dd>
-<dt><a id='sheet.Rowinfo.additional_space_below-attribute' name='sheet.Rowinfo.additional_space_below-attribute'><b>additional_space_below</b></a> [<a href='#sheet.Rowinfo.additional_space_below-attribute'>#</a>]</dt>
-<dd>
-<p>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.</p>
-</dd>
-<dt><a id='sheet.Rowinfo.has_default_height-attribute' name='sheet.Rowinfo.has_default_height-attribute'><b>has_default_height</b></a> [<a href='#sheet.Rowinfo.has_default_height-attribute'>#</a>]</dt>
-<dd>
-<p>0 = Row has custom height; 1 = Row has default height</p>
-</dd>
-<dt><a id='sheet.Rowinfo.has_default_xf_index-attribute' name='sheet.Rowinfo.has_default_xf_index-attribute'><b>has_default_xf_index</b></a> [<a href='#sheet.Rowinfo.has_default_xf_index-attribute'>#</a>]</dt>
-<dd>
-<p>1 = the xf_index attribute is usable; 0 = ignore it</p>
-</dd>
-<dt><a id='sheet.Rowinfo.height-attribute' name='sheet.Rowinfo.height-attribute'><b>height</b></a> [<a href='#sheet.Rowinfo.height-attribute'>#</a>]</dt>
-<dd>
-<p>Height of the row, in twips. One twip == 1/20 of a point</p>
-</dd>
-<dt><a id='sheet.Rowinfo.height_mismatch-attribute' name='sheet.Rowinfo.height_mismatch-attribute'><b>height_mismatch</b></a> [<a href='#sheet.Rowinfo.height_mismatch-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Row height and default font height do not match</p>
-</dd>
-<dt><a id='sheet.Rowinfo.hidden-attribute' name='sheet.Rowinfo.hidden-attribute'><b>hidden</b></a> [<a href='#sheet.Rowinfo.hidden-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Row is hidden (manually, or by a filter or outline group)</p>
-</dd>
-<dt><a id='sheet.Rowinfo.outline_group_starts_ends-attribute' name='sheet.Rowinfo.outline_group_starts_ends-attribute'><b>outline_group_starts_ends</b></a> [<a href='#sheet.Rowinfo.outline_group_starts_ends-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Outline group starts or ends here (depending on where the
-outline buttons are located, see WSBOOL record [TODO ??]),
-<i>and</i> is collapsed
-</p></dd>
-<dt><a id='sheet.Rowinfo.outline_level-attribute' name='sheet.Rowinfo.outline_level-attribute'><b>outline_level</b></a> [<a href='#sheet.Rowinfo.outline_level-attribute'>#</a>]</dt>
-<dd>
-<p>Outline level of the row</p>
-</dd>
-<dt><a id='sheet.Rowinfo.xf_index-attribute' name='sheet.Rowinfo.xf_index-attribute'><b>xf_index</b></a> [<a href='#sheet.Rowinfo.xf_index-attribute'>#</a>]</dt>
-<dd>
-<p>Index to default XF record for empty cells in this row.
-Don't use this if has_default_xf_index == 0.</p>
-</dd>
-</dl>
-<h2><a id='sheet.Sheet-class' name='sheet.Sheet-class'>The Sheet Class</a></h2>
-<dl>
-<dt><b>Sheet(book, position, name, number)</b> (class) [<a href='#sheet.Sheet-class'>#</a>]</dt>
-<dd>
-<p /><p>Contains the data for one worksheet.</p>
-
-<p>In the cell access functions, "rowx" is a row index, counting from zero, and "colx" is a
-column index, counting from zero.
-Negative values for row/column indexes and slice positions are supported in the expected fashion.</p>
-
-<p>For information about cell types and cell values, refer to the documentation of the Cell class.</p>
-
-<p>WARNING: You don't call this class yourself. You access Sheet objects via the Book object that
-was returned when you called xlrd.open_workbook("myfile.xls").</p>
-</dd>
-<dt><a id='sheet.Sheet.cell-method' name='sheet.Sheet.cell-method'><b>cell(rowx, colx)</b></a> [<a href='#sheet.Sheet.cell-method'>#</a>]</dt>
-<dd>
-<p>Cell object in the given row and column.</p>
-</dd>
-<dt><a id='sheet.Sheet.cell_type-method' name='sheet.Sheet.cell_type-method'><b>cell_type(rowx, colx)</b></a> [<a href='#sheet.Sheet.cell_type-method'>#</a>]</dt>
-<dd>
-<p>Type of the cell in the given row and column.
-Refer to the documentation of the Cell class.</p>
-</dd>
-<dt><a id='sheet.Sheet.cell_value-method' name='sheet.Sheet.cell_value-method'><b>cell_value(rowx, colx)</b></a> [<a href='#sheet.Sheet.cell_value-method'>#</a>]</dt>
-<dd>
-<p>Value of the cell in the given row and column.</p>
-</dd>
-<dt><a id='sheet.Sheet.cell_xf_index-method' name='sheet.Sheet.cell_xf_index-method'><b>cell_xf_index(rowx, colx)</b></a> [<a href='#sheet.Sheet.cell_xf_index-method'>#</a>]</dt>
-<dd>
-<p>XF index of the cell in the given row and column.
-This is an index into Book.xf_list.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='sheet.Sheet.col-method' name='sheet.Sheet.col-method'><b>col(colx)</b></a> [<a href='#sheet.Sheet.col-method'>#</a>]</dt>
-<dd>
-<p>Returns a sequence of the Cell objects in the given column.</p>
-</dd>
-<dt><a id='sheet.Sheet.col_label_ranges-attribute' name='sheet.Sheet.col_label_ranges-attribute'><b>col_label_ranges</b></a> [<a href='#sheet.Sheet.col_label_ranges-attribute'>#</a>]</dt>
-<dd>
-<p>List of address ranges of cells containing column labels.
-These are set up in Excel by Insert > Name > Labels > Columns.
-<br /> -- New in version 0.6.0
-<br />How to deconstruct the list:
-<pre>
-for crange in thesheet.col_label_ranges:
- rlo, rhi, clo, chi = crange
- for rx in xrange(rlo, rhi):
- for cx in xrange(clo, chi):
- print "Column label at (rowx=%d, colx=%d) is %r" \
- (rx, cx, thesheet.cell_value(rx, cx))
-</pre>
-</p></dd>
-<dt><a id='sheet.Sheet.col_slice-method' name='sheet.Sheet.col_slice-method'><b>col_slice(colx, start_rowx=0, end_rowx=None)</b></a> [<a href='#sheet.Sheet.col_slice-method'>#</a>]</dt>
-<dd>
-<p>Returns a slice of the Cell objects in the given column.</p>
-</dd>
-<dt><a id='sheet.Sheet.col_types-method' name='sheet.Sheet.col_types-method'><b>col_types(colx, start_rowx=0, end_rowx=None)</b></a> [<a href='#sheet.Sheet.col_types-method'>#</a>]</dt>
-<dd>
-<p>Returns a slice of the types of the cells in the given column.</p>
-</dd>
-<dt><a id='sheet.Sheet.col_values-method' name='sheet.Sheet.col_values-method'><b>col_values(colx, start_rowx=0, end_rowx=None)</b></a> [<a href='#sheet.Sheet.col_values-method'>#</a>]</dt>
-<dd>
-<p>Returns a slice of the values of the cells in the given column.</p>
-</dd>
-<dt><a id='sheet.Sheet.colinfo_map-attribute' name='sheet.Sheet.colinfo_map-attribute'><b>colinfo_map</b></a> [<a href='#sheet.Sheet.colinfo_map-attribute'>#</a>]</dt>
-<dd>
-<p>The map from a column index to a Colinfo object. Often there is an entry
-in COLINFO records for all column indexes in range(257).
-Note that xlrd ignores the entry for the non-existent
-257th column. On the other hand, there may be no entry for unused columns.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='sheet.Sheet.computed_column_width-method' name='sheet.Sheet.computed_column_width-method'><b>computed_column_width(colx)</b></a> [<a href='#sheet.Sheet.computed_column_width-method'>#</a>]</dt>
-<dd>
-<p>Determine column display width.
-<br /> -- New in version 0.6.1
-<br />
-</p><dl>
-<dt><i>colx</i></dt>
-<dd>
-Index of the queried column, range 0 to 255.
-Note that it is possible to find out the width that will be used to display
-columns with no cell information e.g. column IV (colx=255).</dd>
-<dt>Returns:</dt>
-<dd>
-The column width that will be used for displaying
-the given column by Excel, in units of 1/256th of the width of a
-standard character (the digit zero in the first font).</dd>
-</dl><br />
-</dd>
-<dt><a id='sheet.Sheet.default_additional_space_above-attribute' name='sheet.Sheet.default_additional_space_above-attribute'><b>default_additional_space_above</b></a> [<a href='#sheet.Sheet.default_additional_space_above-attribute'>#</a>]</dt>
-<dd>
-<p>Default value to be used for a row if there is
-no ROW record for that row.
-From the <i>optional</i> DEFAULTROWHEIGHT record.
-</p></dd>
-<dt><a id='sheet.Sheet.default_additional_space_below-attribute' name='sheet.Sheet.default_additional_space_below-attribute'><b>default_additional_space_below</b></a> [<a href='#sheet.Sheet.default_additional_space_below-attribute'>#</a>]</dt>
-<dd>
-<p>Default value to be used for a row if there is
-no ROW record for that row.
-From the <i>optional</i> DEFAULTROWHEIGHT record.
-</p></dd>
-<dt><a id='sheet.Sheet.default_row_height-attribute' name='sheet.Sheet.default_row_height-attribute'><b>default_row_height</b></a> [<a href='#sheet.Sheet.default_row_height-attribute'>#</a>]</dt>
-<dd>
-<p>Default value to be used for a row if there is
-no ROW record for that row.
-From the <i>optional</i> DEFAULTROWHEIGHT record.
-</p></dd>
-<dt><a id='sheet.Sheet.default_row_height_mismatch-attribute' name='sheet.Sheet.default_row_height_mismatch-attribute'><b>default_row_height_mismatch</b></a> [<a href='#sheet.Sheet.default_row_height_mismatch-attribute'>#</a>]</dt>
-<dd>
-<p>Default value to be used for a row if there is
-no ROW record for that row.
-From the <i>optional</i> DEFAULTROWHEIGHT record.
-</p></dd>
-<dt><a id='sheet.Sheet.default_row_hidden-attribute' name='sheet.Sheet.default_row_hidden-attribute'><b>default_row_hidden</b></a> [<a href='#sheet.Sheet.default_row_hidden-attribute'>#</a>]</dt>
-<dd>
-<p>Default value to be used for a row if there is
-no ROW record for that row.
-From the <i>optional</i> DEFAULTROWHEIGHT record.
-</p></dd>
-<dt><a id='sheet.Sheet.defcolwidth-attribute' name='sheet.Sheet.defcolwidth-attribute'><b>defcolwidth</b></a> [<a href='#sheet.Sheet.defcolwidth-attribute'>#</a>]</dt>
-<dd>
-<p>Default column width from DEFCOLWIDTH record, else None.
-From the OOo docs:<br />
-"""Column width in characters, using the width of the zero character
-from default font (first FONT record in the file). Excel adds some
-extra space to the default width, depending on the default font and
-default font size. The algorithm how to exactly calculate the resulting
-column width is not known.<br />
-Example: The default width of 8 set in this record results in a column
-width of 8.43 using Arial font with a size of 10 points."""<br />
-For the default hierarchy, refer to the Colinfo class above.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='sheet.Sheet.gcw-attribute' name='sheet.Sheet.gcw-attribute'><b>gcw</b></a> [<a href='#sheet.Sheet.gcw-attribute'>#</a>]</dt>
-<dd>
-<p>A 256-element tuple corresponding to the contents of the GCW record for this sheet.
-If no such record, treat as all bits zero.
-Applies to BIFF4-7 only. See docs of Colinfo class for discussion.</p>
-</dd>
-<dt><a id='sheet.Sheet.merged_cells-attribute' name='sheet.Sheet.merged_cells-attribute'><b>merged_cells</b></a> [<a href='#sheet.Sheet.merged_cells-attribute'>#</a>]</dt>
-<dd>
-<p>List of address ranges of cells which have been merged.
-These are set up in Excel by Format > Cells > Alignment, then ticking
-the "Merge cells" box.
-<br /> -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True)
-<br />How to deconstruct the list:
-<pre>
-for crange in thesheet.merged_cells:
- rlo, rhi, clo, chi = crange
- for rowx in xrange(rlo, rhi):
- for colx in xrange(clo, chi):
- # cell (rlo, clo) (the top left one) will carry the data
- # and formatting info; the remainder will be recorded as
- # blank cells, but a renderer will apply the formatting info
- # for the top left cell (e.g. border, pattern) to all cells in
- # the range.
-</pre>
-</p></dd>
-<dt><a id='sheet.Sheet.name-attribute' name='sheet.Sheet.name-attribute'><b>name</b></a> [<a href='#sheet.Sheet.name-attribute'>#</a>]</dt>
-<dd>
-<p>Name of sheet.</p>
-</dd>
-<dt><a id='sheet.Sheet.ncols-attribute' name='sheet.Sheet.ncols-attribute'><b>ncols</b></a> [<a href='#sheet.Sheet.ncols-attribute'>#</a>]</dt>
-<dd>
-<p>Number of columns in sheet. A column index is in range(thesheet.ncols).</p>
-</dd>
-<dt><a id='sheet.Sheet.nrows-attribute' name='sheet.Sheet.nrows-attribute'><b>nrows</b></a> [<a href='#sheet.Sheet.nrows-attribute'>#</a>]</dt>
-<dd>
-<p>Number of rows in sheet. A row index is in range(thesheet.nrows).</p>
-</dd>
-<dt><a id='sheet.Sheet.row-method' name='sheet.Sheet.row-method'><b>row(rowx)</b></a> [<a href='#sheet.Sheet.row-method'>#</a>]</dt>
-<dd>
-<p>Returns a sequence of the Cell objects in the given row.</p>
-</dd>
-<dt><a id='sheet.Sheet.row_label_ranges-attribute' name='sheet.Sheet.row_label_ranges-attribute'><b>row_label_ranges</b></a> [<a href='#sheet.Sheet.row_label_ranges-attribute'>#</a>]</dt>
-<dd>
-<p>List of address ranges of cells containing row labels.
-For more details, see <i>col_label_ranges</i> above.
-<br /> -- New in version 0.6.0
-</p></dd>
-<dt><a id='sheet.Sheet.row_slice-method' name='sheet.Sheet.row_slice-method'><b>row_slice(rowx, start_colx=0, end_colx=None)</b></a> [<a href='#sheet.Sheet.row_slice-method'>#</a>]</dt>
-<dd>
-<p>Returns a slice of the Cell objects in the given row.</p>
-</dd>
-<dt><a id='sheet.Sheet.row_types-method' name='sheet.Sheet.row_types-method'><b>row_types(rowx, start_colx=0, end_colx=None)</b></a> [<a href='#sheet.Sheet.row_types-method'>#</a>]</dt>
-<dd>
-<p>Returns a slice of the types
-of the cells in the given row.</p>
-</dd>
-<dt><a id='sheet.Sheet.row_values-method' name='sheet.Sheet.row_values-method'><b>row_values(rowx, start_colx=0, end_colx=None)</b></a> [<a href='#sheet.Sheet.row_values-method'>#</a>]</dt>
-<dd>
-<p>Returns a slice of the values
-of the cells in the given row.</p>
-</dd>
-<dt><a id='sheet.Sheet.rowinfo_map-attribute' name='sheet.Sheet.rowinfo_map-attribute'><b>rowinfo_map</b></a> [<a href='#sheet.Sheet.rowinfo_map-attribute'>#</a>]</dt>
-<dd>
-<p>The map from a row index to a Rowinfo object. Note that it is possible
-to have missing entries -- at least one source of XLS files doesn't
-bother writing ROW records.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='sheet.Sheet.standardwidth-attribute' name='sheet.Sheet.standardwidth-attribute'><b>standardwidth</b></a> [<a href='#sheet.Sheet.standardwidth-attribute'>#</a>]</dt>
-<dd>
-<p>Default column width from STANDARDWIDTH record, else None.
-From the OOo docs:<br />
-"""Default width of the columns in 1/256 of the width of the zero
-character, using default font (first FONT record in the file)."""<br />
-For the default hierarchy, refer to the Colinfo class above.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='sheet.Sheet.visibility-attribute' name='sheet.Sheet.visibility-attribute'><b>visibility</b></a> [<a href='#sheet.Sheet.visibility-attribute'>#</a>]</dt>
-<dd>
-<p>Visibility of the sheet. 0 = visible, 1 = hidden (can be unhidden
-by user -- Format/Sheet/Unhide), 2 = "very hidden" (can be unhidden
-only by VBA macro).</p>
-</dd>
-</dl>
-<h2><a id='formatting.XF-class' name='formatting.XF-class'>The XF Class</a></h2>
-<dl>
-<dt><b>XF</b> (class) [<a href='#formatting.XF-class'>#</a>]</dt>
-<dd>
-<p>eXtended Formatting information for cells, rows, columns and styles.
-<br /> -- New in version 0.6.1
-
-</p><p>Each of the 6 flags below describes the validity of
-a specific group of attributes.
-<br />
-In cell XFs, flag==0 means the attributes of the parent style XF are used,
-(but only if the attributes are valid there); flag==1 means the attributes
-of this XF are used.<br />
-In style XFs, flag==0 means the attribute setting is valid; flag==1 means
-the attribute should be ignored.<br />
-Note that the API
-provides both "raw" XFs and "computed" XFs -- in the latter case, cell XFs
-have had the above inheritance mechanism applied.
-</p>
-</dd>
-<dt><a id='formatting.XF._alignment_flag-attribute' name='formatting.XF._alignment_flag-attribute'><b>_alignment_flag</b></a> [<a href='#formatting.XF._alignment_flag-attribute'>#</a>]</dt>
-<dd>
-</dd>
-<dt><a id='formatting.XF._background_flag-attribute' name='formatting.XF._background_flag-attribute'><b>_background_flag</b></a> [<a href='#formatting.XF._background_flag-attribute'>#</a>]</dt>
-<dd>
-</dd>
-<dt><a id='formatting.XF._border_flag-attribute' name='formatting.XF._border_flag-attribute'><b>_border_flag</b></a> [<a href='#formatting.XF._border_flag-attribute'>#</a>]</dt>
-<dd>
-</dd>
-<dt><a id='formatting.XF._font_flag-attribute' name='formatting.XF._font_flag-attribute'><b>_font_flag</b></a> [<a href='#formatting.XF._font_flag-attribute'>#</a>]</dt>
-<dd>
-</dd>
-<dt><a id='formatting.XF._format_flag-attribute' name='formatting.XF._format_flag-attribute'><b>_format_flag</b></a> [<a href='#formatting.XF._format_flag-attribute'>#</a>]</dt>
-<dd>
-</dd>
-<dt><a id='formatting.XF._protection_flag-attribute' name='formatting.XF._protection_flag-attribute'><b>_protection_flag</b></a> [<a href='#formatting.XF._protection_flag-attribute'>#</a>]</dt>
-<dd>
-<p> 
-</p></dd>
-<dt><a id='formatting.XF.alignment-attribute' name='formatting.XF.alignment-attribute'><b>alignment</b></a> [<a href='#formatting.XF.alignment-attribute'>#</a>]</dt>
-<dd>
-<p>An instance of an XFAlignment object.</p>
-</dd>
-<dt><a id='formatting.XF.background-attribute' name='formatting.XF.background-attribute'><b>background</b></a> [<a href='#formatting.XF.background-attribute'>#</a>]</dt>
-<dd>
-<p>An instance of an XFBackground object.</p>
-</dd>
-<dt><a id='formatting.XF.border-attribute' name='formatting.XF.border-attribute'><b>border</b></a> [<a href='#formatting.XF.border-attribute'>#</a>]</dt>
-<dd>
-<p>An instance of an XFBorder object.</p>
-</dd>
-<dt><a id='formatting.XF.font_index-attribute' name='formatting.XF.font_index-attribute'><b>font_index</b></a> [<a href='#formatting.XF.font_index-attribute'>#</a>]</dt>
-<dd>
-<p>Index into Book.font_list</p>
-</dd>
-<dt><a id='formatting.XF.format_key-attribute' name='formatting.XF.format_key-attribute'><b>format_key</b></a> [<a href='#formatting.XF.format_key-attribute'>#</a>]</dt>
-<dd>
-<p>Key into Book.format_map
-</p><p>
-Warning: OOo docs on the XF record call this "Index to FORMAT record".
-It is not an index in the Python sense. It is a key to a map.
-It is true <i>only</i> for Excel 4.0 and earlier files
-that the key into format_map from an XF instance
-is the same as the index into format_list, and <i>only</i>
-if the index is less than 164.
-</p>
-</dd>
-<dt><a id='formatting.XF.is_style-attribute' name='formatting.XF.is_style-attribute'><b>is_style</b></a> [<a href='#formatting.XF.is_style-attribute'>#</a>]</dt>
-<dd>
-<p>0 = cell XF, 1 = style XF</p>
-</dd>
-<dt><a id='formatting.XF.parent_style_index-attribute' name='formatting.XF.parent_style_index-attribute'><b>parent_style_index</b></a> [<a href='#formatting.XF.parent_style_index-attribute'>#</a>]</dt>
-<dd>
-<p>cell XF: Index into Book.xf_list
-of this XF's style XF<br />
-style XF: 0xFFF
-</p></dd>
-<dt><a id='formatting.XF.protection-attribute' name='formatting.XF.protection-attribute'><b>protection</b></a> [<a href='#formatting.XF.protection-attribute'>#</a>]</dt>
-<dd>
-<p>An instance of an XFProtection object.</p>
-</dd>
-<dt><a id='formatting.XF.xf_index-attribute' name='formatting.XF.xf_index-attribute'><b>xf_index</b></a> [<a href='#formatting.XF.xf_index-attribute'>#</a>]</dt>
-<dd>
-<p>Index into Book.xf_list</p>
-</dd>
-</dl>
-<h2><a id='formatting.XFAlignment-class' name='formatting.XFAlignment-class'>The XFAlignment Class</a></h2>
-<dl>
-<dt><b>XFAlignment</b> (class) [<a href='#formatting.XFAlignment-class'>#</a>]</dt>
-<dd>
-<p>A collection of the alignment and similar attributes of an XF record.
-Items correspond to those in the Excel UI's Format/Cells/Alignment tab.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='formatting.XFAlignment.hor_align-attribute' name='formatting.XFAlignment.hor_align-attribute'><b>hor_align</b></a> [<a href='#formatting.XFAlignment.hor_align-attribute'>#</a>]</dt>
-<dd>
-<p>Values: section 6.115 (p 214) of OOo docs</p>
-</dd>
-<dt><a id='formatting.XFAlignment.indent_level-attribute' name='formatting.XFAlignment.indent_level-attribute'><b>indent_level</b></a> [<a href='#formatting.XFAlignment.indent_level-attribute'>#</a>]</dt>
-<dd>
-<p>A number in range(15).</p>
-</dd>
-<dt><a id='formatting.XFAlignment.rotation-attribute' name='formatting.XFAlignment.rotation-attribute'><b>rotation</b></a> [<a href='#formatting.XFAlignment.rotation-attribute'>#</a>]</dt>
-<dd>
-<p>Values: section 6.115 (p 215) of OOo docs.<br />
-Note: file versions BIFF7 and earlier use the documented
-"orientation" attribute; this will be mapped (without loss)
-into "rotation".
-</p></dd>
-<dt><a id='formatting.XFAlignment.shrink_to_fit-attribute' name='formatting.XFAlignment.shrink_to_fit-attribute'><b>shrink_to_fit</b></a> [<a href='#formatting.XFAlignment.shrink_to_fit-attribute'>#</a>]</dt>
-<dd>
-<p>1 = shrink font size to fit text into cell.</p>
-</dd>
-<dt><a id='formatting.XFAlignment.text_direction-attribute' name='formatting.XFAlignment.text_direction-attribute'><b>text_direction</b></a> [<a href='#formatting.XFAlignment.text_direction-attribute'>#</a>]</dt>
-<dd>
-<p>0 = according to context; 1 = left-to-right; 2 = right-to-left</p>
-</dd>
-<dt><a id='formatting.XFAlignment.text_wrapped-attribute' name='formatting.XFAlignment.text_wrapped-attribute'><b>text_wrapped</b></a> [<a href='#formatting.XFAlignment.text_wrapped-attribute'>#</a>]</dt>
-<dd>
-<p>1 = text is wrapped at right margin</p>
-</dd>
-<dt><a id='formatting.XFAlignment.vert_align-attribute' name='formatting.XFAlignment.vert_align-attribute'><b>vert_align</b></a> [<a href='#formatting.XFAlignment.vert_align-attribute'>#</a>]</dt>
-<dd>
-<p>Values: section 6.115 (p 215) of OOo docs</p>
-</dd>
-</dl>
-<h2><a id='formatting.XFBackground-class' name='formatting.XFBackground-class'>The XFBackground Class</a></h2>
-<dl>
-<dt><b>XFBackground</b> (class) [<a href='#formatting.XFBackground-class'>#</a>]</dt>
-<dd>
-<p>A collection of the background-related attributes of an XF record.
-Items correspond to those in the Excel UI's Format/Cells/Patterns tab.
-An explanation of "colour index" is given in the Formatting
-section at the start of this document.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='formatting.XFBackground.background_colour_index-attribute' name='formatting.XFBackground.background_colour_index-attribute'><b>background_colour_index</b></a> [<a href='#formatting.XFBackground.background_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>See section 3.11 of the OOo docs.</p>
-</dd>
-<dt><a id='formatting.XFBackground.fill_pattern-attribute' name='formatting.XFBackground.fill_pattern-attribute'><b>fill_pattern</b></a> [<a href='#formatting.XFBackground.fill_pattern-attribute'>#</a>]</dt>
-<dd>
-<p>See section 3.11 of the OOo docs.</p>
-</dd>
-<dt><a id='formatting.XFBackground.pattern_colour_index-attribute' name='formatting.XFBackground.pattern_colour_index-attribute'><b>pattern_colour_index</b></a> [<a href='#formatting.XFBackground.pattern_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>See section 3.11 of the OOo docs.</p>
-</dd>
-</dl>
-<h2><a id='formatting.XFBorder-class' name='formatting.XFBorder-class'>The XFBorder Class</a></h2>
-<dl>
-<dt><b>XFBorder</b> (class) [<a href='#formatting.XFBorder-class'>#</a>]</dt>
-<dd>
-<p /><p>A collection of the border-related attributes of an XF record.
-Items correspond to those in the Excel UI's Format/Cells/Border tab.</p>
-<p> An explanations of "colour index" is given in the Formatting
-section at the start of this document.
-There are five line style attributes; possible values and the
-associated meanings are:
-0 = No line,
-1 = Thin,
-2 = Medium,
-3 = Dashed,
-4 = Dotted,
-5 = Thick,
-6 = Double,
-7 = Hair,
-8 = Medium dashed,
-9 = Thin dash-dotted,
-10 = Medium dash-dotted,
-11 = Thin dash-dot-dotted,
-12 = Medium dash-dot-dotted,
-13 = Slanted medium dash-dotted.
-The line styles 8 to 13 appear in BIFF8 files (Excel 97 and later) only.
-For pictures of the line styles, refer to OOo docs s3.10 (p22)
-"Line Styles for Cell Borders (BIFF3-BIFF8)".</p>
-<br /> -- New in version 0.6.1
-</dd>
-<dt><a id='formatting.XFBorder.bottom_colour_index-attribute' name='formatting.XFBorder.bottom_colour_index-attribute'><b>bottom_colour_index</b></a> [<a href='#formatting.XFBorder.bottom_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>The colour index for the cell's bottom line</p>
-</dd>
-<dt><a id='formatting.XFBorder.bottom_line_style-attribute' name='formatting.XFBorder.bottom_line_style-attribute'><b>bottom_line_style</b></a> [<a href='#formatting.XFBorder.bottom_line_style-attribute'>#</a>]</dt>
-<dd>
-<p>The line style for the cell's bottom line</p>
-</dd>
-<dt><a id='formatting.XFBorder.diag_colour_index-attribute' name='formatting.XFBorder.diag_colour_index-attribute'><b>diag_colour_index</b></a> [<a href='#formatting.XFBorder.diag_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>The colour index for the cell's diagonal lines, if any</p>
-</dd>
-<dt><a id='formatting.XFBorder.diag_down-attribute' name='formatting.XFBorder.diag_down-attribute'><b>diag_down</b></a> [<a href='#formatting.XFBorder.diag_down-attribute'>#</a>]</dt>
-<dd>
-<p>1 = draw a diagonal from top left to bottom right</p>
-</dd>
-<dt><a id='formatting.XFBorder.diag_line_style-attribute' name='formatting.XFBorder.diag_line_style-attribute'><b>diag_line_style</b></a> [<a href='#formatting.XFBorder.diag_line_style-attribute'>#</a>]</dt>
-<dd>
-<p>The line style for the cell's diagonal lines, if any</p>
-</dd>
-<dt><a id='formatting.XFBorder.diag_up-attribute' name='formatting.XFBorder.diag_up-attribute'><b>diag_up</b></a> [<a href='#formatting.XFBorder.diag_up-attribute'>#</a>]</dt>
-<dd>
-<p>1 = draw a diagonal from bottom left to top right</p>
-</dd>
-<dt><a id='formatting.XFBorder.left_colour_index-attribute' name='formatting.XFBorder.left_colour_index-attribute'><b>left_colour_index</b></a> [<a href='#formatting.XFBorder.left_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>The colour index for the cell's left line</p>
-</dd>
-<dt><a id='formatting.XFBorder.left_line_style-attribute' name='formatting.XFBorder.left_line_style-attribute'><b>left_line_style</b></a> [<a href='#formatting.XFBorder.left_line_style-attribute'>#</a>]</dt>
-<dd>
-<p>The line style for the cell's left line</p>
-</dd>
-<dt><a id='formatting.XFBorder.right_colour_index-attribute' name='formatting.XFBorder.right_colour_index-attribute'><b>right_colour_index</b></a> [<a href='#formatting.XFBorder.right_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>The colour index for the cell's right line</p>
-</dd>
-<dt><a id='formatting.XFBorder.right_line_style-attribute' name='formatting.XFBorder.right_line_style-attribute'><b>right_line_style</b></a> [<a href='#formatting.XFBorder.right_line_style-attribute'>#</a>]</dt>
-<dd>
-<p>The line style for the cell's right line</p>
-</dd>
-<dt><a id='formatting.XFBorder.top_colour_index-attribute' name='formatting.XFBorder.top_colour_index-attribute'><b>top_colour_index</b></a> [<a href='#formatting.XFBorder.top_colour_index-attribute'>#</a>]</dt>
-<dd>
-<p>The colour index for the cell's top line</p>
-</dd>
-<dt><a id='formatting.XFBorder.top_line_style-attribute' name='formatting.XFBorder.top_line_style-attribute'><b>top_line_style</b></a> [<a href='#formatting.XFBorder.top_line_style-attribute'>#</a>]</dt>
-<dd>
-<p>The line style for the cell's top line</p>
-</dd>
-</dl>
-<h2><a id='formatting.XFProtection-class' name='formatting.XFProtection-class'>The XFProtection Class</a></h2>
-<dl>
-<dt><b>XFProtection</b> (class) [<a href='#formatting.XFProtection-class'>#</a>]</dt>
-<dd>
-<p>A collection of the protection-related attributes of an XF record.
-Items correspond to those in the Excel UI's Format/Cells/Protection tab.
-Note the OOo docs include the "cell or style" bit
-in this bundle of attributes.
-This is incorrect; the bit is used in determining which bundles to use.
-<br /> -- New in version 0.6.1
-</p></dd>
-<dt><a id='formatting.XFProtection.cell_locked-attribute' name='formatting.XFProtection.cell_locked-attribute'><b>cell_locked</b></a> [<a href='#formatting.XFProtection.cell_locked-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Cell is prevented from being changed, moved, resized, or deleted
-(only if the sheet is protected).</p>
-</dd>
-<dt><a id='formatting.XFProtection.formula_hidden-attribute' name='formatting.XFProtection.formula_hidden-attribute'><b>formula_hidden</b></a> [<a href='#formatting.XFProtection.formula_hidden-attribute'>#</a>]</dt>
-<dd>
-<p>1 = Hide formula so that it doesn't appear in the formula bar when
-the cell is selected (only if the sheet is protected).</p>
-</dd>
-</dl>
-</body></html>
diff --git a/tablib/packages/xlrd/examples/namesdemo.xls b/tablib/packages/xlrd/examples/namesdemo.xls Binary files differdeleted file mode 100644 index 8a16865..0000000 --- a/tablib/packages/xlrd/examples/namesdemo.xls +++ /dev/null diff --git a/tablib/packages/xlrd/examples/xlrdnameAPIdemo.py b/tablib/packages/xlrd/examples/xlrdnameAPIdemo.py deleted file mode 100644 index 6cd60df..0000000 --- a/tablib/packages/xlrd/examples/xlrdnameAPIdemo.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Module/script example of the xlrd API for extracting information -# about named references, named constants, etc. -# -# <p>Copyright © 2006 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p> -## - -import xlrd -import sys -import glob - -def scope_as_string(book, scope): - if 0 <= scope < book.nsheets: - return "sheet #%d (%r)" % (scope, book.sheet_names()[scope]) - if scope == -1: - return "Global" - if scope == -2: - return "Macro/VBA" - return "Unknown scope value (%r)" % scope - -def do_scope_query(book, scope_strg, show_contents=0, f=sys.stdout): - try: - qscope = int(scope_strg) - except ValueError: - if scope_strg == "*": - qscope = None # means "all' - else: - # so assume it's a sheet name ... - qscope = book.sheet_names().index(scope_strg) - print >> f, "%r => %d" % (scope_strg, qscope) - for nobj in book.name_obj_list: - if qscope is None or nobj.scope == qscope: - show_name_object(book, nobj, show_contents, f) - -def show_name_details(book, name, show_contents=0, f=sys.stdout): - """ - book -- Book object obtained from xlrd.open_workbook(). - name -- The name that's being investigated. - show_contents -- 0: Don't; 1: Non-empty cells only; 2: All cells - f -- Open output file handle. - """ - name_lcase = name.lower() # Excel names are case-insensitive. - nobj_list = book.name_map.get(name_lcase) - if not nobj_list: - print >> f, "%r: unknown name" % name - return - for nobj in nobj_list: - show_name_object(book, nobj, show_contents, f) - -def show_name_details_in_scope( - book, name, scope_strg, show_contents=0, f=sys.stdout, - ): - try: - scope = int(scope_strg) - except ValueError: - # so assume it's a sheet name ... - scope = book.sheet_names().index(scope_strg) - print >> f, "%r => %d" % (scope_strg, scope) - name_lcase = name.lower() # Excel names are case-insensitive. - while 1: - nobj = book.name_and_scope_map.get((name_lcase, scope)) - if nobj: - break - print >> f, "Name %r not found in scope %d" % (name, scope) - if scope == -1: - return - scope = -1 # Try again with global scope - print >> f, "Name %r found in scope %d" % (name, scope) - show_name_object(book, nobj, show_contents, f) - -def showable_cell_value(celltype, cellvalue, datemode): - if celltype == xlrd.XL_CELL_DATE: - try: - showval = xlrd.xldate_as_tuple(cellvalue, datemode) - except xlrd.XLDateError: - e1, e2 = sys.exc_info()[:2] - showval = "%s:%s" % (e1.__name__, e2) - elif celltype == xlrd.XL_CELL_ERROR: - showval = xlrd.error_text_from_code.get( - cellvalue, '<Unknown error code 0x%02x>' % cellvalue) - else: - showval = cellvalue - return showval - -def show_name_object(book, nobj, show_contents=0, f=sys.stdout): - print >> f, "\nName: %r, scope: %r (%s)" \ - % (nobj.name, nobj.scope, scope_as_string(book, nobj.scope)) - res = nobj.result - print >> f, "Formula eval result: %r" % res - if res is None: - return - # result should be an instance of the Operand class - kind = res.kind - value = res.value - if kind >= 0: - # A scalar, or unknown ... you've seen all there is to see. - pass - elif kind == xlrd.oREL: - # A list of Ref3D objects representing *relative* ranges - for i in xrange(len(value)): - ref3d = value[i] - print >> f, "Range %d: %r ==> %s"% (i, ref3d.coords, xlrd.rangename3drel(book, ref3d)) - elif kind == xlrd.oREF: - # A list of Ref3D objects - for i in xrange(len(value)): - ref3d = value[i] - print >> f, "Range %d: %r ==> %s"% (i, ref3d.coords, xlrd.rangename3d(book, ref3d)) - if not show_contents: - continue - datemode = book.datemode - for shx in xrange(ref3d.shtxlo, ref3d.shtxhi): - sh = book.sheet_by_index(shx) - print >> f, " Sheet #%d (%s)" % (shx, sh.name) - rowlim = min(ref3d.rowxhi, sh.nrows) - collim = min(ref3d.colxhi, sh.ncols) - for rowx in xrange(ref3d.rowxlo, rowlim): - for colx in xrange(ref3d.colxlo, collim): - cty = sh.cell_type(rowx, colx) - if cty == xlrd.XL_CELL_EMPTY and show_contents == 1: - continue - cval = sh.cell_value(rowx, colx) - sval = showable_cell_value(cty, cval, datemode) - print >> f, " (%3d,%3d) %-5s: %r" \ - % (rowx, colx, xlrd.cellname(rowx, colx), sval) - -if __name__ == "__main__": - def usage(): - text = """ -usage: xlrdnameAIPdemo.py glob_pattern name scope show_contents - -where: - "glob_pattern" designates a set of files - "name" is a name or '*' (all names) - "scope" is -1 (global) or a sheet number - or a sheet name or * (all scopes) - "show_contents" is one of 0 (no show), - 1 (only non-empty cells), or 2 (all cells) - -Examples (script name and glob_pattern arg omitted for brevity) - [Searching through book.name_obj_list] - * * 0 lists all names - * * 1 lists all names, showing referenced non-empty cells - * 1 0 lists all names local to the 2nd sheet - * Northern 0 lists all names local to the 'Northern' sheet - * -1 0 lists all names with global scope - [Initial direct access through book.name_map] - Sales * 0 lists all occurrences of "Sales" in any scope - [Direct access through book.name_and_scope_map] - Revenue -1 0 checks if "Revenue" exists in global scope - -""" - sys.stdout.write(text) - - if len(sys.argv) != 5: - usage() - sys.exit(0) - arg_pattern = sys.argv[1] # glob pattern e.g. "foo*.xls" - arg_name = sys.argv[2] # see below - arg_scope = sys.argv[3] # see below - arg_show_contents = int(sys.argv[4]) # 0: no show, 1: only non-empty cells, - # 2: all cells - for fname in glob.glob(arg_pattern): - book = xlrd.open_workbook(fname) - if arg_name == "*": - # Examine book.name_obj_list to find all names - # in a given scope ("*" => all scopes) - do_scope_query(book, arg_scope, arg_show_contents) - elif arg_scope == "*": - # Using book.name_map to find all usage of a name. - show_name_details(book, arg_name, arg_show_contents) - else: - # Using book.name_and_scope_map to find which if any instances - # of a name are visible in the given scope, which can be supplied - # as -1 (global) or a sheet number or a sheet name. - show_name_details_in_scope(book, arg_name, arg_scope, arg_show_contents) diff --git a/tablib/packages/xlrd/formatting.py b/tablib/packages/xlrd/formatting.py deleted file mode 100644 index 302764b..0000000 --- a/tablib/packages/xlrd/formatting.py +++ /dev/null @@ -1,1256 +0,0 @@ -# -*- coding:cp1252 -*- - -## -# Module for formatting information. -# -# <p>Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>Copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under -# a BSD-style licence.</p> -## - -# No part of the content of this file was derived from the works of David Giffin. - -# 2009-05-31 SJM Fixed problem with non-zero reserved bits in some STYLE records in Mac Excel files -# 2008-08-03 SJM Ignore PALETTE record when Book.formatting_info is false -# 2008-08-03 SJM Tolerate up to 4 bytes trailing junk on PALETTE record -# 2008-05-10 SJM Do some XF checks only when Book.formatting_info is true -# 2008-02-08 SJM Preparation for Excel 2.0 support -# 2008-02-03 SJM Another tweak to is_date_format_string() -# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -# 2007-10-13 SJM Warning: style XF whose parent XF index != 0xFFF -# 2007-09-08 SJM Work around corrupt STYLE record -# 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file - -DEBUG = 0 -import copy, re -from timemachine import * -from biffh import BaseObject, unpack_unicode, unpack_string, \ - upkbits, upkbitsL, fprintf, \ - FUN, FDT, FNU, FGE, FTX, XL_CELL_NUMBER, XL_CELL_DATE, \ - XL_FORMAT, XL_FORMAT2, \ - XLRDError -from struct import unpack - -excel_default_palette_b5 = ( - ( 0, 0, 0), (255, 255, 255), (255, 0, 0), ( 0, 255, 0), - ( 0, 0, 255), (255, 255, 0), (255, 0, 255), ( 0, 255, 255), - (128, 0, 0), ( 0, 128, 0), ( 0, 0, 128), (128, 128, 0), - (128, 0, 128), ( 0, 128, 128), (192, 192, 192), (128, 128, 128), - (153, 153, 255), (153, 51, 102), (255, 255, 204), (204, 255, 255), - (102, 0, 102), (255, 128, 128), ( 0, 102, 204), (204, 204, 255), - ( 0, 0, 128), (255, 0, 255), (255, 255, 0), ( 0, 255, 255), - (128, 0, 128), (128, 0, 0), ( 0, 128, 128), ( 0, 0, 255), - ( 0, 204, 255), (204, 255, 255), (204, 255, 204), (255, 255, 153), - (153, 204, 255), (255, 153, 204), (204, 153, 255), (227, 227, 227), - ( 51, 102, 255), ( 51, 204, 204), (153, 204, 0), (255, 204, 0), - (255, 153, 0), (255, 102, 0), (102, 102, 153), (150, 150, 150), - ( 0, 51, 102), ( 51, 153, 102), ( 0, 51, 0), ( 51, 51, 0), - (153, 51, 0), (153, 51, 102), ( 51, 51, 153), ( 51, 51, 51), - ) - -excel_default_palette_b2 = excel_default_palette_b5[:16] - -# Following two tables borrowed from Gnumeric 1.4 source. -excel_default_palette_b5_gnumeric_14 = ( - #### dodgy; didn't match Excel results - ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0), - ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255), - (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0), - (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128), - (128,128,255), (128, 32, 96), (255,255,192), (160,224,224), - ( 96, 0,128), (255,128,128), ( 0,128,192), (192,192,255), - ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255), - (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255), - ( 0,204,255), (105,255,255), (204,255,204), (255,255,153), - (166,202,240), (204,156,204), (204,153,255), (227,227,227), - ( 51,102,255), ( 51,204,204), ( 51,153, 51), (153,153, 51), - (153,102, 51), (153,102,102), (102,102,153), (150,150,150), - ( 51, 51,204), ( 51,102,102), ( 0, 51, 0), ( 51, 51, 0), - (102, 51, 0), (153, 51,102), ( 51, 51,153), ( 66, 66, 66), - ) -excel_default_palette_b8 = ( # (red, green, blue) - ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0), - ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255), - (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0), - (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128), - (153,153,255), (153, 51,102), (255,255,204), (204,255,255), - (102, 0,102), (255,128,128), ( 0,102,204), (204,204,255), - ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255), - (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255), - ( 0,204,255), (204,255,255), (204,255,204), (255,255,153), - (153,204,255), (255,153,204), (204,153,255), (255,204,153), - ( 51,102,255), ( 51,204,204), (153,204, 0), (255,204, 0), - (255,153, 0), (255,102, 0), (102,102,153), (150,150,150), - ( 0, 51,102), ( 51,153,102), ( 0, 51, 0), ( 51, 51, 0), - (153, 51, 0), (153, 51,102), ( 51, 51,153), ( 51, 51, 51), - ) - -default_palette = { - 80: excel_default_palette_b8, - 70: excel_default_palette_b5, - 50: excel_default_palette_b5, - 45: excel_default_palette_b2, - 40: excel_default_palette_b2, - 30: excel_default_palette_b2, - 21: excel_default_palette_b2, - 20: excel_default_palette_b2, - } - -""" -00H = Normal -01H = RowLevel_lv (see next field) -02H = ColLevel_lv (see next field) -03H = Comma -04H = Currency -05H = Percent -06H = Comma [0] (BIFF4-BIFF8) -07H = Currency [0] (BIFF4-BIFF8) -08H = Hyperlink (BIFF8) -09H = Followed Hyperlink (BIFF8) -""" -built_in_style_names = [ - "Normal", - "RowLevel_", - "ColLevel_", - "Comma", - "Currency", - "Percent", - "Comma [0]", - "Currency [0]", - "Hyperlink", - "Followed Hyperlink", - ] - -def initialise_colour_map(book): - book.colour_map = {} - book.colour_indexes_used = {} - if not book.formatting_info: - return - # Add the 8 invariant colours - for i in xrange(8): - book.colour_map[i] = excel_default_palette_b8[i] - # Add the default palette depending on the version - dpal = default_palette[book.biff_version] - ndpal = len(dpal) - for i in xrange(ndpal): - book.colour_map[i+8] = dpal[i] - # Add the specials -- None means the RGB value is not known - # System window text colour for border lines - book.colour_map[ndpal+8] = None - # System window background colour for pattern background - book.colour_map[ndpal+8+1] = None # - for ci in ( - 0x51, # System ToolTip text colour (used in note objects) - 0x7FFF, # 32767, system window text colour for fonts - ): - book.colour_map[ci] = None - -def nearest_colour_index(colour_map, rgb, debug=0): - # General purpose function. Uses Euclidean distance. - # So far used only for pre-BIFF8 WINDOW2 record. - # Doesn't have to be fast. - # Doesn't have to be fancy. - best_metric = 3 * 256 * 256 - best_colourx = 0 - for colourx, cand_rgb in colour_map.items(): - if cand_rgb is None: - continue - metric = 0 - for v1, v2 in zip(rgb, cand_rgb): - metric += (v1 - v2) * (v1 - v2) - if metric < best_metric: - best_metric = metric - best_colourx = colourx - if metric == 0: - break - if debug: - print "nearest_colour_index for %r is %r -> %r; best_metric is %d" \ - % (rgb, best_colourx, colour_map[best_colourx], best_metric) - return best_colourx - -## -# This mixin class exists solely so that Format, Font, and XF.... objects -# can be compared by value of their attributes. -class EqNeAttrs(object): - - def __eq__(self, other): - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return self.__dict__ != other.__dict__ - -## -# An Excel "font" contains the details of not only what is normally -# considered a font, but also several other display attributes. -# Items correspond to those in the Excel UI's Format/Cells/Font tab. -# <br /> -- New in version 0.6.1 -class Font(BaseObject, EqNeAttrs): - ## - # 1 = Characters are bold. Redundant; see "weight" attribute. - bold = 0 - ## - # Values: 0 = ANSI Latin, 1 = System default, 2 = Symbol, - # 77 = Apple Roman, - # 128 = ANSI Japanese Shift-JIS, - # 129 = ANSI Korean (Hangul), - # 130 = ANSI Korean (Johab), - # 134 = ANSI Chinese Simplified GBK, - # 136 = ANSI Chinese Traditional BIG5, - # 161 = ANSI Greek, - # 162 = ANSI Turkish, - # 163 = ANSI Vietnamese, - # 177 = ANSI Hebrew, - # 178 = ANSI Arabic, - # 186 = ANSI Baltic, - # 204 = ANSI Cyrillic, - # 222 = ANSI Thai, - # 238 = ANSI Latin II (Central European), - # 255 = OEM Latin I - character_set = 0 - ## - # An explanation of "colour index" is given in the Formatting - # section at the start of this document. - colour_index = 0 - ## - # 1 = Superscript, 2 = Subscript. - escapement = 0 - ## - # 0 = None (unknown or don't care)<br /> - # 1 = Roman (variable width, serifed)<br /> - # 2 = Swiss (variable width, sans-serifed)<br /> - # 3 = Modern (fixed width, serifed or sans-serifed)<br /> - # 4 = Script (cursive)<br /> - # 5 = Decorative (specialised, for example Old English, Fraktur) - family = 0 - ## - # The 0-based index used to refer to this Font() instance. - # Note that index 4 is never used; xlrd supplies a dummy place-holder. - font_index = 0 - ## - # Height of the font (in twips). A twip = 1/20 of a point. - height = 0 - ## - # 1 = Characters are italic. - italic = 0 - ## - # The name of the font. Example: u"Arial" - name = u"" - ## - # 1 = Characters are struck out. - struck_out = 0 - ## - # 0 = None<br /> - # 1 = Single; 0x21 (33) = Single accounting<br /> - # 2 = Double; 0x22 (34) = Double accounting - underline_type = 0 - ## - # 1 = Characters are underlined. Redundant; see "underline_type" attribute. - underlined = 0 - ## - # Font weight (100-1000). Standard values are 400 for normal text - # and 700 for bold text. - weight = 400 - ## - # 1 = Font is outline style (Macintosh only) - outline = 0 - ## - # 1 = Font is shadow style (Macintosh only) - shadow = 0 - - # No methods ... - -def handle_efont(book, data): # BIFF2 only - if not book.formatting_info: - return - book.font_list[-1].colour_index = unpack('<H', data)[0] - -def handle_font(book, data): - if not book.formatting_info: - return - if not book.encoding: - book.derive_encoding() - blah = DEBUG or book.verbosity >= 2 - bv = book.biff_version - k = len(book.font_list) - if k == 4: - f = Font() - f.name = u'Dummy Font' - f.font_index = k - book.font_list.append(f) - k += 1 - f = Font() - f.font_index = k - book.font_list.append(f) - if bv >= 50: - ( - f.height, option_flags, f.colour_index, f.weight, - f.escapement_type, f.underline_type, f.family, - f.character_set, - ) = unpack('<HHHHHBBB', data[0:13]) - f.bold = option_flags & 1 - f.italic = (option_flags & 2) >> 1 - f.underlined = (option_flags & 4) >> 2 - f.struck_out = (option_flags & 8) >> 3 - f.outline = (option_flags & 16) >> 4 - f.shadow = (option_flags & 32) >> 5 - if bv >= 80: - f.name = unpack_unicode(data, 14, lenlen=1) - else: - f.name = unpack_string(data, 14, book.encoding, lenlen=1) - elif bv >= 30: - f.height, option_flags, f.colour_index = unpack('<HHH', data[0:6]) - f.bold = option_flags & 1 - f.italic = (option_flags & 2) >> 1 - f.underlined = (option_flags & 4) >> 2 - f.struck_out = (option_flags & 8) >> 3 - f.outline = (option_flags & 16) >> 4 - f.shadow = (option_flags & 32) >> 5 - f.name = unpack_string(data, 6, book.encoding, lenlen=1) - # Now cook up the remaining attributes ... - f.weight = [400, 700][f.bold] - f.escapement_type = 0 # None - f.underline_type = f.underlined # None or Single - f.family = 0 # Unknown / don't care - f.character_set = 1 # System default (0 means "ANSI Latin") - else: # BIFF2 - f.height, option_flags = unpack('<HH', data[0:4]) - f.colour_index = 0x7FFF # "system window text colour" - f.bold = option_flags & 1 - f.italic = (option_flags & 2) >> 1 - f.underlined = (option_flags & 4) >> 2 - f.struck_out = (option_flags & 8) >> 3 - f.outline = 0 - f.shadow = 0 - f.name = unpack_string(data, 4, book.encoding, lenlen=1) - # Now cook up the remaining attributes ... - f.weight = [400, 700][f.bold] - f.escapement_type = 0 # None - f.underline_type = f.underlined # None or Single - f.family = 0 # Unknown / don't care - f.character_set = 1 # System default (0 means "ANSI Latin") - if blah: - f.dump( - book.logfile, - header="--- handle_font: font[%d] ---" % f.font_index, - footer="-------------------", - ) - -# === "Number formats" === - -## -# "Number format" information from a FORMAT record. -# <br /> -- New in version 0.6.1 -class Format(BaseObject, EqNeAttrs): - ## - # The key into Book.format_map - format_key = 0 - ## - # A classification that has been inferred from the format string. - # Currently, this is used only to distinguish between numbers and dates. - # <br />Values: - # <br />FUN = 0 # unknown - # <br />FDT = 1 # date - # <br />FNU = 2 # number - # <br />FGE = 3 # general - # <br />FTX = 4 # text - type = FUN - ## - # The format string - format_str = u'' - - def __init__(self, format_key, ty, format_str): - self.format_key = format_key - self.type = ty - self.format_str = format_str - -std_format_strings = { - # "std" == "standard for US English locale" - # #### TODO ... a lot of work to tailor these to the user's locale. - # See e.g. gnumeric-1.x.y/src/formats.c - 0x00: "General", - 0x01: "0", - 0x02: "0.00", - 0x03: "#,##0", - 0x04: "#,##0.00", - 0x05: "$#,##0_);($#,##0)", - 0x06: "$#,##0_);[Red]($#,##0)", - 0x07: "$#,##0.00_);($#,##0.00)", - 0x08: "$#,##0.00_);[Red]($#,##0.00)", - 0x09: "0%", - 0x0a: "0.00%", - 0x0b: "0.00E+00", - 0x0c: "# ?/?", - 0x0d: "# ??/??", - 0x0e: "m/d/yy", - 0x0f: "d-mmm-yy", - 0x10: "d-mmm", - 0x11: "mmm-yy", - 0x12: "h:mm AM/PM", - 0x13: "h:mm:ss AM/PM", - 0x14: "h:mm", - 0x15: "h:mm:ss", - 0x16: "m/d/yy h:mm", - 0x25: "#,##0_);(#,##0)", - 0x26: "#,##0_);[Red](#,##0)", - 0x27: "#,##0.00_);(#,##0.00)", - 0x28: "#,##0.00_);[Red](#,##0.00)", - 0x29: "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)", - 0x2a: "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)", - 0x2b: "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)", - 0x2c: "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)", - 0x2d: "mm:ss", - 0x2e: "[h]:mm:ss", - 0x2f: "mm:ss.0", - 0x30: "##0.0E+0", - 0x31: "@", - } - -fmt_code_ranges = [ # both-inclusive ranges of "standard" format codes - # Source: the openoffice.org doc't - ( 0, 0, FGE), - ( 1, 13, FNU), - (14, 22, FDT), - #### (27, 36, FDT), # Japanese dates -- not sure of reliability of this - (37, 44, FNU), - (45, 47, FDT), - (48, 48, FNU), - (49, 49, FTX), - ####(50, 58, FDT), # Japanese dates -- but Gnumeric assumes - # built-in formats finish at 49, not at 163 - ] - -std_format_code_types = {} -for lo, hi, ty in fmt_code_ranges: - for x in xrange(lo, hi+1): - std_format_code_types[x] = ty -del lo, hi, ty, x - -date_chars = u'ymdhs' # year, month/minute, day, hour, second -date_char_dict = {} -for _c in date_chars + date_chars.upper(): - date_char_dict[_c] = 5 -del _c, date_chars - -skip_char_dict = {} -for _c in u'$-+/(): ': - skip_char_dict[_c] = 1 - -num_char_dict = { - u'0': 5, - u'#': 5, - u'?': 5, - } - -non_date_formats = { - u'0.00E+00':1, - u'##0.0E+0':1, - u'General' :1, - u'GENERAL' :1, # OOo Calc 1.1.4 does this. - u'general' :1, # pyExcelerator 0.6.3 does this. - u'@' :1, - } - -fmt_bracketed_sub = re.compile(r'\[[^]]*\]').sub - -# Boolean format strings (actual cases) -# u'"Yes";"Yes";"No"' -# u'"True";"True";"False"' -# u'"On";"On";"Off"' - -def is_date_format_string(book, fmt): - # Heuristics: - # Ignore "text" and [stuff in square brackets (aarrgghh -- see below)]. - # Handle backslashed-escaped chars properly. - # E.g. hh\hmm\mss\s should produce a display like 23h59m59s - # Date formats have one or more of ymdhs (caseless) in them. - # Numeric formats have # and 0. - # N.B. u'General"."' hence get rid of "text" first. - # TODO: Find where formats are interpreted in Gnumeric - # TODO: u'[h]\\ \\h\\o\\u\\r\\s' ([h] means don't care about hours > 23) - state = 0 - s = '' - ignorable = skip_char_dict.has_key - for c in fmt: - if state == 0: - if c == u'"': - state = 1 - elif c in ur"\_*": - state = 2 - elif ignorable(c): - pass - else: - s += c - elif state == 1: - if c == u'"': - state = 0 - elif state == 2: - # Ignore char after backslash, underscore or asterisk - state = 0 - assert 0 <= state <= 2 - if book.verbosity >= 4: - print "is_date_format_string: reduced format is %r" % s - s = fmt_bracketed_sub('', s) - if non_date_formats.has_key(s): - return False - state = 0 - separator = ";" - got_sep = 0 - date_count = num_count = 0 - for c in s: - if date_char_dict.has_key(c): - date_count += date_char_dict[c] - elif num_char_dict.has_key(c): - num_count += num_char_dict[c] - elif c == separator: - got_sep = 1 - # print num_count, date_count, repr(fmt) - if date_count and not num_count: - return True - if num_count and not date_count: - return False - if date_count: - fprintf(book.logfile, - 'WARNING *** is_date_format: ambiguous d=%d n=%d fmt=%r\n', - date_count, num_count, fmt) - elif not got_sep: - fprintf(book.logfile, - "WARNING *** format %r produces constant result\n", - fmt) - return date_count > num_count - -def handle_format(self, data, rectype=XL_FORMAT): - DEBUG = 0 - bv = self.biff_version - if rectype == XL_FORMAT2: - bv = min(bv, 30) - if not self.encoding: - self.derive_encoding() - strpos = 2 - if bv >= 50: - fmtkey = unpack('<H', data[0:2])[0] - else: - fmtkey = self.actualfmtcount - if bv <= 30: - strpos = 0 - self.actualfmtcount += 1 - if bv >= 80: - unistrg = unpack_unicode(data, 2) - else: - unistrg = unpack_string(data, strpos, self.encoding, lenlen=1) - blah = DEBUG or self.verbosity >= 3 - if blah: - fprintf(self.logfile, - "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n", - self.actualfmtcount, fmtkey, fmtkey, unistrg) - is_date_s = self.is_date_format_string(unistrg) - ty = [FGE, FDT][is_date_s] - if not(fmtkey > 163 or bv < 50): - # user_defined if fmtkey > 163 - # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-( - # if earlier than BIFF 5, standard info is useless - std_ty = std_format_code_types.get(fmtkey, FUN) - # print "std ty", std_ty - is_date_c = std_ty == FDT - if 0 < fmtkey < 50 and (is_date_c ^ is_date_s): - DEBUG = 2 - fprintf(self.logfile, - "WARNING *** Conflict between " - "std format key %d and its format string %r\n", - fmtkey, unistrg) - if DEBUG == 2: - fprintf(self.logfile, - "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r", - ty, is_date_c, is_date_s, unistrg) - fmtobj = Format(fmtkey, ty, unistrg) - if blah: - fmtobj.dump(self.logfile, - header="--- handle_format [%d] ---" % (self.actualfmtcount-1, )) - self.format_map[fmtkey] = fmtobj - self.format_list.append(fmtobj) - -# ============================================================================= - -def handle_palette(book, data): - if not book.formatting_info: - return - blah = DEBUG or book.verbosity >= 2 - n_colours, = unpack('<H', data[:2]) - expected_n_colours = (16, 56)[book.biff_version >= 50] - if ((DEBUG or book.verbosity >= 1) - and n_colours != expected_n_colours): - fprintf(book.logfile, - "NOTE *** Expected %d colours in PALETTE record, found %d\n", - expected_n_colours, n_colours) - elif blah: - fprintf(book.logfile, - "PALETTE record with %d colours\n", n_colours) - fmt = '<xx%di' % n_colours # use i to avoid long integers - expected_size = 4 * n_colours + 2 - actual_size = len(data) - tolerance = 4 - if not expected_size <= actual_size <= expected_size + tolerance: - raise XLRDError('PALETTE record: expected size %d, actual size %d' % (expected_size, actual_size)) - colours = unpack(fmt, data[:expected_size]) - assert book.palette_record == [] # There should be only 1 PALETTE record - # a colour will be 0xbbggrr - # IOW, red is at the little end - for i in xrange(n_colours): - c = colours[i] - red = c & 0xff - green = (c >> 8) & 0xff - blue = (c >> 16) & 0xff - old_rgb = book.colour_map[8+i] - new_rgb = (red, green, blue) - book.palette_record.append(new_rgb) - book.colour_map[8+i] = new_rgb - if blah: - if new_rgb != old_rgb: - print >> book.logfile, "%2d: %r -> %r" % (i, old_rgb, new_rgb) - -def palette_epilogue(book): - # Check colour indexes in fonts etc. - # This must be done here as FONT records - # come *before* the PALETTE record :-( - for font in book.font_list: - if font.font_index == 4: # the missing font record - continue - cx = font.colour_index - if cx == 0x7fff: # system window text colour - continue - if book.colour_map.has_key(cx): - book.colour_indexes_used[cx] = 1 - else: - print "Size of colour table:", len(book.colour_map) - print >> book.logfile, \ - "*** Font #%d (%r): colour index 0x%04x is unknown" \ - % (font.font_index, font.name, cx) - if book.verbosity >= 1: - used = book.colour_indexes_used.keys() - used.sort() - print >> book.logfile, "\nColour indexes used:\n%r\n" % used - -def handle_style(book, data): - blah = DEBUG or book.verbosity >= 2 - bv = book.biff_version - flag_and_xfx, built_in_id, level = unpack('<HBB', data[:4]) - xf_index = flag_and_xfx & 0x0fff - if (data == "\0\0\0\0" - and "Normal" not in book.style_name_map): - # Erroneous record (doesn't have built-in bit set). - # Example file supplied by Jeff Bell. - built_in = 1 - built_in_id = 0 - xf_index = 0 - name = "Normal" - level = 255 - elif flag_and_xfx & 0x8000: - # built-in style - built_in = 1 - name = built_in_style_names[built_in_id] - if 1 <= built_in_id <= 2: - name += str(level + 1) - else: - # user-defined style - if bv >= 80: - name = unpack_unicode(data, 2, lenlen=2) - else: - name = unpack_string(data, 2, book.encoding, lenlen=1) - if blah and not name: - print >> book.logfile, \ - "WARNING *** A user-defined style has a zero-length name" - built_in = 0 - built_in_id = 0 - level = 0 - book.style_name_map[name] = (built_in, xf_index) - if blah: - print >> book.logfile, \ - "STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d name=%r" \ - % (built_in, xf_index, built_in_id, level, name) - -def check_colour_indexes_in_obj(book, obj, orig_index): - alist = obj.__dict__.items() - alist.sort() - for attr, nobj in alist: - if hasattr(nobj, 'dump'): - check_colour_indexes_in_obj(book, nobj, orig_index) - elif attr.find('colour_index') >= 0: - if book.colour_map.has_key(nobj): - book.colour_indexes_used[nobj] = 1 - continue - oname = obj.__class__.__name__ - print >> book.logfile, \ - "*** xf #%d : %s.%s = 0x%04x (unknown)" \ - % (orig_index, oname, attr, nobj) - -def handle_xf(self, data): - ### self is a Book instance - # DEBUG = 0 - blah = DEBUG or self.verbosity >= 3 - bv = self.biff_version - xf = XF() - xf.alignment = XFAlignment() - xf.alignment.indent_level = 0 - xf.alignment.shrink_to_fit = 0 - xf.alignment.text_direction = 0 - xf.border = XFBorder() - xf.border.diag_up = 0 - xf.border.diag_down = 0 - xf.border.diag_colour_index = 0 - xf.border.diag_line_style = 0 # no line - xf.background = XFBackground() - xf.protection = XFProtection() - # fill in the known standard formats - if bv >= 50 and not self.xfcount: - # i.e. do this once before we process the first XF record - for x in std_format_code_types.keys(): - if not self.format_map.has_key(x): - ty = std_format_code_types[x] - fmt_str = std_format_strings[x] - fmtobj = Format(x, ty, fmt_str) - self.format_map[x] = fmtobj - if bv >= 80: - unpack_fmt = '<HHHBBBBIiH' - (xf.font_index, xf.format_key, pkd_type_par, - pkd_align1, xf.alignment.rotation, pkd_align2, - pkd_used, pkd_brdbkg1, pkd_brdbkg2, pkd_brdbkg3, - ) = unpack(unpack_fmt, data[0:20]) - upkbits(xf.protection, pkd_type_par, ( - (0, 0x01, 'cell_locked'), - (1, 0x02, 'formula_hidden'), - )) - upkbits(xf, pkd_type_par, ( - (2, 0x0004, 'is_style'), - # Following is not in OOo docs, but is mentioned - # in Gnumeric source and also in (deep breath) - # org.apache.poi.hssf.record.ExtendedFormatRecord.java - (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. - (4, 0xFFF0, 'parent_style_index'), - )) - upkbits(xf.alignment, pkd_align1, ( - (0, 0x07, 'hor_align'), - (3, 0x08, 'text_wrapped'), - (4, 0x70, 'vert_align'), - )) - upkbits(xf.alignment, pkd_align2, ( - (0, 0x0f, 'indent_level'), - (4, 0x10, 'shrink_to_fit'), - (6, 0xC0, 'text_direction'), - )) - reg = pkd_used >> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbitsL(xf.border, pkd_brdbkg1, ( - (0, 0x0000000f, 'left_line_style'), - (4, 0x000000f0, 'right_line_style'), - (8, 0x00000f00, 'top_line_style'), - (12, 0x0000f000, 'bottom_line_style'), - (16, 0x007f0000, 'left_colour_index'), - (23, 0x3f800000, 'right_colour_index'), - (30, 0x40000000, 'diag_down'), - (31, 0x80000000L, 'diag_up'), - )) - upkbits(xf.border, pkd_brdbkg2, ( - (0, 0x0000007F, 'top_colour_index'), - (7, 0x00003F80, 'bottom_colour_index'), - (14, 0x001FC000, 'diag_colour_index'), - (21, 0x01E00000, 'diag_line_style'), - )) - upkbitsL(xf.background, pkd_brdbkg2, ( - (26, 0xFC000000L, 'fill_pattern'), - )) - upkbits(xf.background, pkd_brdbkg3, ( - (0, 0x007F, 'pattern_colour_index'), - (7, 0x3F80, 'background_colour_index'), - )) - elif bv >= 50: - unpack_fmt = '<HHHBBIi' - (xf.font_index, xf.format_key, pkd_type_par, - pkd_align1, pkd_orient_used, - pkd_brdbkg1, pkd_brdbkg2, - ) = unpack(unpack_fmt, data[0:16]) - upkbits(xf.protection, pkd_type_par, ( - (0, 0x01, 'cell_locked'), - (1, 0x02, 'formula_hidden'), - )) - upkbits(xf, pkd_type_par, ( - (2, 0x0004, 'is_style'), - (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. - (4, 0xFFF0, 'parent_style_index'), - )) - upkbits(xf.alignment, pkd_align1, ( - (0, 0x07, 'hor_align'), - (3, 0x08, 'text_wrapped'), - (4, 0x70, 'vert_align'), - )) - orientation = pkd_orient_used & 0x03 - xf.alignment.rotation = [0, 255, 90, 180][orientation] - reg = pkd_orient_used >> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbitsL(xf.background, pkd_brdbkg1, ( - ( 0, 0x0000007F, 'pattern_colour_index'), - ( 7, 0x00003F80, 'background_colour_index'), - (16, 0x003F0000, 'fill_pattern'), - )) - upkbitsL(xf.border, pkd_brdbkg1, ( - (22, 0x01C00000, 'bottom_line_style'), - (25, 0xFE000000L, 'bottom_colour_index'), - )) - upkbits(xf.border, pkd_brdbkg2, ( - ( 0, 0x00000007, 'top_line_style'), - ( 3, 0x00000038, 'left_line_style'), - ( 6, 0x000001C0, 'right_line_style'), - ( 9, 0x0000FE00, 'top_colour_index'), - (16, 0x007F0000, 'left_colour_index'), - (23, 0x3F800000, 'right_colour_index'), - )) - elif bv >= 40: - unpack_fmt = '<BBHBBHI' - (xf.font_index, xf.format_key, pkd_type_par, - pkd_align_orient, pkd_used, - pkd_bkg_34, pkd_brd_34, - ) = unpack(unpack_fmt, data[0:12]) - upkbits(xf.protection, pkd_type_par, ( - (0, 0x01, 'cell_locked'), - (1, 0x02, 'formula_hidden'), - )) - upkbits(xf, pkd_type_par, ( - (2, 0x0004, 'is_style'), - (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. - (4, 0xFFF0, 'parent_style_index'), - )) - upkbits(xf.alignment, pkd_align_orient, ( - (0, 0x07, 'hor_align'), - (3, 0x08, 'text_wrapped'), - (4, 0x30, 'vert_align'), - )) - orientation = (pkd_align_orient & 0xC0) >> 6 - xf.alignment.rotation = [0, 255, 90, 180][orientation] - reg = pkd_used >> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbits(xf.background, pkd_bkg_34, ( - ( 0, 0x003F, 'fill_pattern'), - ( 6, 0x07C0, 'pattern_colour_index'), - (11, 0xF800, 'background_colour_index'), - )) - upkbitsL(xf.border, pkd_brd_34, ( - ( 0, 0x00000007, 'top_line_style'), - ( 3, 0x000000F8, 'top_colour_index'), - ( 8, 0x00000700, 'left_line_style'), - (11, 0x0000F800, 'left_colour_index'), - (16, 0x00070000, 'bottom_line_style'), - (19, 0x00F80000, 'bottom_colour_index'), - (24, 0x07000000, 'right_line_style'), - (27, 0xF8000000L, 'right_colour_index'), - )) - elif bv == 30: - unpack_fmt = '<BBBBHHI' - (xf.font_index, xf.format_key, pkd_type_prot, - pkd_used, pkd_align_par, - pkd_bkg_34, pkd_brd_34, - ) = unpack(unpack_fmt, data[0:12]) - upkbits(xf.protection, pkd_type_prot, ( - (0, 0x01, 'cell_locked'), - (1, 0x02, 'formula_hidden'), - )) - upkbits(xf, pkd_type_prot, ( - (2, 0x0004, 'is_style'), - (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known. - )) - upkbits(xf.alignment, pkd_align_par, ( - (0, 0x07, 'hor_align'), - (3, 0x08, 'text_wrapped'), - )) - upkbits(xf, pkd_align_par, ( - (4, 0xFFF0, 'parent_style_index'), - )) - reg = pkd_used >> 2 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, reg & 1) - reg >>= 1 - upkbits(xf.background, pkd_bkg_34, ( - ( 0, 0x003F, 'fill_pattern'), - ( 6, 0x07C0, 'pattern_colour_index'), - (11, 0xF800, 'background_colour_index'), - )) - upkbitsL(xf.border, pkd_brd_34, ( - ( 0, 0x00000007, 'top_line_style'), - ( 3, 0x000000F8, 'top_colour_index'), - ( 8, 0x00000700, 'left_line_style'), - (11, 0x0000F800, 'left_colour_index'), - (16, 0x00070000, 'bottom_line_style'), - (19, 0x00F80000, 'bottom_colour_index'), - (24, 0x07000000, 'right_line_style'), - (27, 0xF8000000L, 'right_colour_index'), - )) - xf.alignment.vert_align = 2 # bottom - xf.alignment.rotation = 0 - elif bv == 21: - #### Warning: incomplete treatment; formatting_info not fully supported. - #### Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16], - #### and create XF[0:16] like the standard ones in BIFF8 - #### *AND* add 16 to all XF references in cell records :-( - (xf.font_index, format_etc, halign_etc) = unpack('<BxBB', data) - xf.format_key = format_etc & 0x3F - upkbits(xf.protection, format_etc, ( - (6, 0x40, 'cell_locked'), - (7, 0x80, 'formula_hidden'), - )) - upkbits(xf.alignment, halign_etc, ( - (0, 0x07, 'hor_align'), - )) - for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')): - if halign_etc & mask: - colour_index, line_style = 8, 1 # black, thin - else: - colour_index, line_style = 0, 0 # none, none - setattr(xf.border, side + '_colour_index', colour_index) - setattr(xf.border, side + '_line_style', line_style) - bg = xf.background - if halign_etc & 0x80: - bg.fill_pattern = 17 - else: - bg.fill_pattern = 0 - bg.background_colour_index = 9 # white - bg.pattern_colour_index = 8 # black - xf.parent_style_index = 0 # ??????????? - xf.alignment.vert_align = 2 # bottom - xf.alignment.rotation = 0 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, 1) - else: - raise XLRDError('programmer stuff-up: bv=%d' % bv) - - xf.xf_index = len(self.xf_list) - self.xf_list.append(xf) - self.xfcount += 1 - if blah: - xf.dump( - self.logfile, - header="--- handle_xf: xf[%d] ---" % xf.xf_index, - footer=" ", - ) - # Now for some assertions ... - if self.formatting_info: - if xf.is_style and xf.parent_style_index != 0x0FFF: - msg = "WARNING *** XF[%d] is a style XF but parent_style_index is 0x%04x, not 0x0fff\n" - fprintf(self.logfile, msg, xf.xf_index, xf.parent_style_index) - check_colour_indexes_in_obj(self, xf, xf.xf_index) - if not self.format_map.has_key(xf.format_key): - msg = "WARNING *** XF[%d] unknown (raw) format key (%d, 0x%04x)\n" - fprintf(self.logfile, msg, - xf.xf_index, xf.format_key, xf.format_key) - xf.format_key = 0 - -def xf_epilogue(self): - # self is a Book instance. - self._xf_epilogue_done = 1 - num_xfs = len(self.xf_list) - blah = DEBUG or self.verbosity >= 3 - blah1 = DEBUG or self.verbosity >= 1 - if blah: - fprintf(self.logfile, "xf_epilogue called ...\n") - - def check_same(book_arg, xf_arg, parent_arg, attr): - # the _arg caper is to avoid a Warning msg from Python 2.1 :-( - if getattr(xf_arg, attr) != getattr(parent_arg, attr): - fprintf(book_arg.logfile, - "NOTE !!! XF[%d] parent[%d] %s different\n", - xf_arg.xf_index, parent_arg.xf_index, attr) - - for xfx in xrange(num_xfs): - xf = self.xf_list[xfx] - if not self.format_map.has_key(xf.format_key): - msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" - fprintf(self.logfile, msg, - xf.xf_index, xf.format_key, xf.format_key) - xf.format_key = 0 - cellty_from_fmtty = { - FNU: XL_CELL_NUMBER, - FUN: XL_CELL_NUMBER, - FGE: XL_CELL_NUMBER, - FDT: XL_CELL_DATE, - FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. - } - fmt = self.format_map[xf.format_key] - cellty = cellty_from_fmtty[fmt.type] - self._xf_index_to_xl_type_map[xf.xf_index] = cellty - # Now for some assertions etc - if not self.formatting_info: - continue - if xf.is_style: - continue - if not(0 <= xf.parent_style_index < num_xfs): - fprintf(self.logfile, - "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n", - xf.xf_index, xf.is_style, xf.parent_style_index) - # make it conform - xf.parent_style_index = 0 - if self.biff_version >= 30: - assert xf.parent_style_index != xf.xf_index - assert self.xf_list[xf.parent_style_index].is_style - if blah1 and xf.parent_style_index > xf.xf_index: - fprintf(self.logfile, - "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n", - xf.xf_index, xf.parent_style_index) - parent = self.xf_list[xf.parent_style_index] - if not xf._alignment_flag and not parent._alignment_flag: - if blah1: check_same(self, xf, parent, 'alignment') - if not xf._background_flag and not parent._background_flag: - if blah1: check_same(self, xf, parent, 'background') - if not xf._border_flag and not parent._border_flag: - if blah1: check_same(self, xf, parent, 'border') - if not xf._protection_flag and not parent._protection_flag: - if blah1: check_same(self, xf, parent, 'protection') - if not xf._format_flag and not parent._format_flag: - if blah1 and xf.format_key != parent.format_key: - fprintf(self.logfile, - "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n", - xf.xf_index, xf.format_key, parent.xf_index, parent.format_key, - self.format_map[xf.format_key].format_str, - self.format_map[parent.format_key].format_str) - if not xf._font_flag and not parent._font_flag: - if blah1 and xf.font_index != parent.font_index: - fprintf(self.logfile, - "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n", - xf.xf_index, xf.font_index, parent.xf_index, parent.font_index) - -def initialise_book(book): - initialise_colour_map(book) - book._xf_epilogue_done = 0 - methods = ( - handle_font, - handle_efont, - handle_format, - is_date_format_string, - handle_palette, - palette_epilogue, - handle_style, - handle_xf, - xf_epilogue, - ) - for method in methods: - setattr(book.__class__, method.__name__, method) - -## -# <p>A collection of the border-related attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Border tab.</p> -# <p> An explanations of "colour index" is given in the Formatting -# section at the start of this document. -# There are five line style attributes; possible values and the -# associated meanings are: -# 0 = No line, -# 1 = Thin, -# 2 = Medium, -# 3 = Dashed, -# 4 = Dotted, -# 5 = Thick, -# 6 = Double, -# 7 = Hair, -# 8 = Medium dashed, -# 9 = Thin dash-dotted, -# 10 = Medium dash-dotted, -# 11 = Thin dash-dot-dotted, -# 12 = Medium dash-dot-dotted, -# 13 = Slanted medium dash-dotted. -# The line styles 8 to 13 appear in BIFF8 files (Excel 97 and later) only. -# For pictures of the line styles, refer to OOo docs s3.10 (p22) -# "Line Styles for Cell Borders (BIFF3-BIFF8)".</p> -# <br /> -- New in version 0.6.1 -class XFBorder(BaseObject, EqNeAttrs): - - ## - # The colour index for the cell's top line - top_colour_index = 0 - ## - # The colour index for the cell's bottom line - bottom_colour_index = 0 - ## - # The colour index for the cell's left line - left_colour_index = 0 - ## - # The colour index for the cell's right line - right_colour_index = 0 - ## - # The colour index for the cell's diagonal lines, if any - diag_colour_index = 0 - ## - # The line style for the cell's top line - top_line_style = 0 - ## - # The line style for the cell's bottom line - bottom_line_style = 0 - ## - # The line style for the cell's left line - left_line_style = 0 - ## - # The line style for the cell's right line - right_line_style = 0 - ## - # The line style for the cell's diagonal lines, if any - diag_line_style = 0 - ## - # 1 = draw a diagonal from top left to bottom right - diag_down = 0 - ## - # 1 = draw a diagonal from bottom left to top right - diag_up = 0 - -## -# A collection of the background-related attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Patterns tab. -# An explanation of "colour index" is given in the Formatting -# section at the start of this document. -# <br /> -- New in version 0.6.1 -class XFBackground(BaseObject, EqNeAttrs): - - ## - # See section 3.11 of the OOo docs. - fill_pattern = 0 - ## - # See section 3.11 of the OOo docs. - background_colour_index = 0 - ## - # See section 3.11 of the OOo docs. - pattern_colour_index = 0 - -## -# A collection of the alignment and similar attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Alignment tab. -# <br /> -- New in version 0.6.1 - -class XFAlignment(BaseObject, EqNeAttrs): - - ## - # Values: section 6.115 (p 214) of OOo docs - hor_align = 0 - ## - # Values: section 6.115 (p 215) of OOo docs - vert_align = 0 - ## - # Values: section 6.115 (p 215) of OOo docs.<br /> - # Note: file versions BIFF7 and earlier use the documented - # "orientation" attribute; this will be mapped (without loss) - # into "rotation". - rotation = 0 - ## - # 1 = text is wrapped at right margin - text_wrapped = 0 - ## - # A number in range(15). - indent_level = 0 - ## - # 1 = shrink font size to fit text into cell. - shrink_to_fit = 0 - ## - # 0 = according to context; 1 = left-to-right; 2 = right-to-left - text_direction = 0 - -## -# A collection of the protection-related attributes of an XF record. -# Items correspond to those in the Excel UI's Format/Cells/Protection tab. -# Note the OOo docs include the "cell or style" bit -# in this bundle of attributes. -# This is incorrect; the bit is used in determining which bundles to use. -# <br /> -- New in version 0.6.1 - -class XFProtection(BaseObject, EqNeAttrs): - - ## - # 1 = Cell is prevented from being changed, moved, resized, or deleted - # (only if the sheet is protected). - cell_locked = 0 - ## - # 1 = Hide formula so that it doesn't appear in the formula bar when - # the cell is selected (only if the sheet is protected). - formula_hidden = 0 - -## -# eXtended Formatting information for cells, rows, columns and styles. -# <br /> -- New in version 0.6.1 -# -# <p>Each of the 6 flags below describes the validity of -# a specific group of attributes. -# <br /> -# In cell XFs, flag==0 means the attributes of the parent style XF are used, -# (but only if the attributes are valid there); flag==1 means the attributes -# of this XF are used.<br /> -# In style XFs, flag==0 means the attribute setting is valid; flag==1 means -# the attribute should be ignored.<br /> -# Note that the API -# provides both "raw" XFs and "computed" XFs -- in the latter case, cell XFs -# have had the above inheritance mechanism applied. -# </p> - -class XF(BaseObject): - - ## - # 0 = cell XF, 1 = style XF - is_style = 0 - ## - # cell XF: Index into Book.xf_list - # of this XF's style XF<br /> - # style XF: 0xFFF - parent_style_index = 0 - ## - # - _format_flag = 0 - ## - # - _font_flag = 0 - ## - # - _alignment_flag = 0 - ## - # - _border_flag = 0 - ## - # - _background_flag = 0 - ## - # - _protection_flag = 0 - ## - # Index into Book.xf_list - xf_index = 0 - ## - # Index into Book.font_list - font_index = 0 - ## - # Key into Book.format_map - # <p> - # Warning: OOo docs on the XF record call this "Index to FORMAT record". - # It is not an index in the Python sense. It is a key to a map. - # It is true <i>only</i> for Excel 4.0 and earlier files - # that the key into format_map from an XF instance - # is the same as the index into format_list, and <i>only</i> - # if the index is less than 164. - # </p> - format_key = 0 - ## - # An instance of an XFProtection object. - protection = None - ## - # An instance of an XFBackground object. - background = None - ## - # An instance of an XFAlignment object. - alignment = None - ## - # An instance of an XFBorder object. - border = None diff --git a/tablib/packages/xlrd/formula.py b/tablib/packages/xlrd/formula.py deleted file mode 100644 index 4edbc29..0000000 --- a/tablib/packages/xlrd/formula.py +++ /dev/null @@ -1,2092 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# Module for parsing/evaluating Microsoft Excel formulas. -# -# <p>Copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under -# a BSD-style licence.</p> -## - -# No part of the content of this file was derived from the works of David Giffin. - -import copy -from struct import unpack -from timemachine import * -from biffh import unpack_unicode_update_pos, unpack_string_update_pos, \ - XLRDError, hex_char_dump, error_text_from_code, BaseObject - -__all__ = [ - 'oBOOL', 'oERR', 'oNUM', 'oREF', 'oREL', 'oSTRG', 'oUNK', - 'decompile_formula', - 'dump_formula', - 'evaluate_name_formula', - 'okind_dict', - 'rangename3d', 'rangename3drel', 'cellname', 'cellnameabs', 'colname', - ] - -# sztabN[opcode] -> the number of bytes to consume. -# -1 means variable -# -2 means this opcode not implemented in this version. -# Which N to use? Depends on biff_version; see szdict. -sztab0 = [-2, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 8, 4, 2, 2, 3, 9, 8, 2, 3, 8, 4, 7, 5, 5, 5, 2, 4, 7, 4, 7, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2] -sztab1 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 2, 3, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2] -sztab2 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 3, 4, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2] -sztab3 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 15, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 25, 18, 21, 18, 21, -2, -2] -sztab4 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 5, 5, 9, 7, 7, 7, 3, 5, 9, 5, 9, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 7, 7, 11, 7, 11, -2, -2] - -szdict = { - 20 : sztab0, - 30 : sztab1, - 40 : sztab2, - 45 : sztab2, - 50 : sztab3, - 70 : sztab3, - 80 : sztab4, - } - -# For debugging purposes ... the name for each opcode -# (without the prefix "t" used on OOo docs) -onames = ['Unk00', 'Exp', 'Tbl', 'Add', 'Sub', 'Mul', 'Div', 'Power', 'Concat', 'LT', 'LE', 'EQ', 'GE', 'GT', 'NE', 'Isect', 'List', 'Range', 'Uplus', 'Uminus', 'Percent', 'Paren', 'MissArg', 'Str', 'Extended', 'Attr', 'Sheet', 'EndSheet', 'Err', 'Bool', 'Int', 'Num', 'Array', 'Func', 'FuncVar', 'Name', 'Ref', 'Area', 'MemArea', 'MemErr', 'MemNoMem', 'MemFunc', 'RefErr', 'AreaErr', 'RefN', 'AreaN', 'MemAreaN', 'MemNoMemN', '', '', '', '', '', '', '', '', 'FuncCE', 'NameX', 'Ref3d', 'Area3d', 'RefErr3d', 'AreaErr3d', '', ''] - -func_defs = { - # index: (name, min#args, max#args, flags, #known_args, return_type, kargs) - 0 : ('COUNT', 0, 30, 0x04, 1, 'V', 'R'), - 1 : ('IF', 2, 3, 0x04, 3, 'V', 'VRR'), - 2 : ('ISNA', 1, 1, 0x02, 1, 'V', 'V'), - 3 : ('ISERROR', 1, 1, 0x02, 1, 'V', 'V'), - 4 : ('SUM', 0, 30, 0x04, 1, 'V', 'R'), - 5 : ('AVERAGE', 1, 30, 0x04, 1, 'V', 'R'), - 6 : ('MIN', 1, 30, 0x04, 1, 'V', 'R'), - 7 : ('MAX', 1, 30, 0x04, 1, 'V', 'R'), - 8 : ('ROW', 0, 1, 0x04, 1, 'V', 'R'), - 9 : ('COLUMN', 0, 1, 0x04, 1, 'V', 'R'), - 10 : ('NA', 0, 0, 0x02, 0, 'V', ''), - 11 : ('NPV', 2, 30, 0x04, 2, 'V', 'VR'), - 12 : ('STDEV', 1, 30, 0x04, 1, 'V', 'R'), - 13 : ('DOLLAR', 1, 2, 0x04, 1, 'V', 'V'), - 14 : ('FIXED', 2, 3, 0x04, 3, 'V', 'VVV'), - 15 : ('SIN', 1, 1, 0x02, 1, 'V', 'V'), - 16 : ('COS', 1, 1, 0x02, 1, 'V', 'V'), - 17 : ('TAN', 1, 1, 0x02, 1, 'V', 'V'), - 18 : ('ATAN', 1, 1, 0x02, 1, 'V', 'V'), - 19 : ('PI', 0, 0, 0x02, 0, 'V', ''), - 20 : ('SQRT', 1, 1, 0x02, 1, 'V', 'V'), - 21 : ('EXP', 1, 1, 0x02, 1, 'V', 'V'), - 22 : ('LN', 1, 1, 0x02, 1, 'V', 'V'), - 23 : ('LOG10', 1, 1, 0x02, 1, 'V', 'V'), - 24 : ('ABS', 1, 1, 0x02, 1, 'V', 'V'), - 25 : ('INT', 1, 1, 0x02, 1, 'V', 'V'), - 26 : ('SIGN', 1, 1, 0x02, 1, 'V', 'V'), - 27 : ('ROUND', 2, 2, 0x02, 2, 'V', 'VV'), - 28 : ('LOOKUP', 2, 3, 0x04, 2, 'V', 'VR'), - 29 : ('INDEX', 2, 4, 0x0c, 4, 'R', 'RVVV'), - 30 : ('REPT', 2, 2, 0x02, 2, 'V', 'VV'), - 31 : ('MID', 3, 3, 0x02, 3, 'V', 'VVV'), - 32 : ('LEN', 1, 1, 0x02, 1, 'V', 'V'), - 33 : ('VALUE', 1, 1, 0x02, 1, 'V', 'V'), - 34 : ('TRUE', 0, 0, 0x02, 0, 'V', ''), - 35 : ('FALSE', 0, 0, 0x02, 0, 'V', ''), - 36 : ('AND', 1, 30, 0x04, 1, 'V', 'R'), - 37 : ('OR', 1, 30, 0x04, 1, 'V', 'R'), - 38 : ('NOT', 1, 1, 0x02, 1, 'V', 'V'), - 39 : ('MOD', 2, 2, 0x02, 2, 'V', 'VV'), - 40 : ('DCOUNT', 3, 3, 0x02, 3, 'V', 'RRR'), - 41 : ('DSUM', 3, 3, 0x02, 3, 'V', 'RRR'), - 42 : ('DAVERAGE', 3, 3, 0x02, 3, 'V', 'RRR'), - 43 : ('DMIN', 3, 3, 0x02, 3, 'V', 'RRR'), - 44 : ('DMAX', 3, 3, 0x02, 3, 'V', 'RRR'), - 45 : ('DSTDEV', 3, 3, 0x02, 3, 'V', 'RRR'), - 46 : ('VAR', 1, 30, 0x04, 1, 'V', 'R'), - 47 : ('DVAR', 3, 3, 0x02, 3, 'V', 'RRR'), - 48 : ('TEXT', 2, 2, 0x02, 2, 'V', 'VV'), - 49 : ('LINEST', 1, 4, 0x04, 4, 'A', 'RRVV'), - 50 : ('TREND', 1, 4, 0x04, 4, 'A', 'RRRV'), - 51 : ('LOGEST', 1, 4, 0x04, 4, 'A', 'RRVV'), - 52 : ('GROWTH', 1, 4, 0x04, 4, 'A', 'RRRV'), - 56 : ('PV', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 57 : ('FV', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 58 : ('NPER', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 59 : ('PMT', 3, 5, 0x04, 5, 'V', 'VVVVV'), - 60 : ('RATE', 3, 6, 0x04, 6, 'V', 'VVVVVV'), - 61 : ('MIRR', 3, 3, 0x02, 3, 'V', 'RVV'), - 62 : ('IRR', 1, 2, 0x04, 2, 'V', 'RV'), - 63 : ('RAND', 0, 0, 0x0a, 0, 'V', ''), - 64 : ('MATCH', 2, 3, 0x04, 3, 'V', 'VRR'), - 65 : ('DATE', 3, 3, 0x02, 3, 'V', 'VVV'), - 66 : ('TIME', 3, 3, 0x02, 3, 'V', 'VVV'), - 67 : ('DAY', 1, 1, 0x02, 1, 'V', 'V'), - 68 : ('MONTH', 1, 1, 0x02, 1, 'V', 'V'), - 69 : ('YEAR', 1, 1, 0x02, 1, 'V', 'V'), - 70 : ('WEEKDAY', 1, 2, 0x04, 2, 'V', 'VV'), - 71 : ('HOUR', 1, 1, 0x02, 1, 'V', 'V'), - 72 : ('MINUTE', 1, 1, 0x02, 1, 'V', 'V'), - 73 : ('SECOND', 1, 1, 0x02, 1, 'V', 'V'), - 74 : ('NOW', 0, 0, 0x0a, 0, 'V', ''), - 75 : ('AREAS', 1, 1, 0x02, 1, 'V', 'R'), - 76 : ('ROWS', 1, 1, 0x02, 1, 'V', 'R'), - 77 : ('COLUMNS', 1, 1, 0x02, 1, 'V', 'R'), - 78 : ('OFFSET', 3, 5, 0x04, 5, 'R', 'RVVVV'), - 82 : ('SEARCH', 2, 3, 0x04, 3, 'V', 'VVV'), - 83 : ('TRANSPOSE', 1, 1, 0x02, 1, 'A', 'A'), - 86 : ('TYPE', 1, 1, 0x02, 1, 'V', 'V'), - 92 : ('SERIESSUM', 4, 4, 0x02, 4, 'V', 'VVVA'), - 97 : ('ATAN2', 2, 2, 0x02, 2, 'V', 'VV'), - 98 : ('ASIN', 1, 1, 0x02, 1, 'V', 'V'), - 99 : ('ACOS', 1, 1, 0x02, 1, 'V', 'V'), - 100: ('CHOOSE', 2, 30, 0x04, 2, 'V', 'VR'), - 101: ('HLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'), - 102: ('VLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'), - 105: ('ISREF', 1, 1, 0x02, 1, 'V', 'R'), - 109: ('LOG', 1, 2, 0x04, 2, 'V', 'VV'), - 111: ('CHAR', 1, 1, 0x02, 1, 'V', 'V'), - 112: ('LOWER', 1, 1, 0x02, 1, 'V', 'V'), - 113: ('UPPER', 1, 1, 0x02, 1, 'V', 'V'), - 114: ('PROPER', 1, 1, 0x02, 1, 'V', 'V'), - 115: ('LEFT', 1, 2, 0x04, 2, 'V', 'VV'), - 116: ('RIGHT', 1, 2, 0x04, 2, 'V', 'VV'), - 117: ('EXACT', 2, 2, 0x02, 2, 'V', 'VV'), - 118: ('TRIM', 1, 1, 0x02, 1, 'V', 'V'), - 119: ('REPLACE', 4, 4, 0x02, 4, 'V', 'VVVV'), - 120: ('SUBSTITUTE', 3, 4, 0x04, 4, 'V', 'VVVV'), - 121: ('CODE', 1, 1, 0x02, 1, 'V', 'V'), - 124: ('FIND', 2, 3, 0x04, 3, 'V', 'VVV'), - 125: ('CELL', 1, 2, 0x0c, 2, 'V', 'VR'), - 126: ('ISERR', 1, 1, 0x02, 1, 'V', 'V'), - 127: ('ISTEXT', 1, 1, 0x02, 1, 'V', 'V'), - 128: ('ISNUMBER', 1, 1, 0x02, 1, 'V', 'V'), - 129: ('ISBLANK', 1, 1, 0x02, 1, 'V', 'V'), - 130: ('T', 1, 1, 0x02, 1, 'V', 'R'), - 131: ('N', 1, 1, 0x02, 1, 'V', 'R'), - 140: ('DATEVALUE', 1, 1, 0x02, 1, 'V', 'V'), - 141: ('TIMEVALUE', 1, 1, 0x02, 1, 'V', 'V'), - 142: ('SLN', 3, 3, 0x02, 3, 'V', 'VVV'), - 143: ('SYD', 4, 4, 0x02, 4, 'V', 'VVVV'), - 144: ('DDB', 4, 5, 0x04, 5, 'V', 'VVVVV'), - 148: ('INDIRECT', 1, 2, 0x0c, 2, 'R', 'VV'), - 162: ('CLEAN', 1, 1, 0x02, 1, 'V', 'V'), - 163: ('MDETERM', 1, 1, 0x02, 1, 'V', 'A'), - 164: ('MINVERSE', 1, 1, 0x02, 1, 'A', 'A'), - 165: ('MMULT', 2, 2, 0x02, 2, 'A', 'AA'), - 167: ('IPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'), - 168: ('PPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'), - 169: ('COUNTA', 0, 30, 0x04, 1, 'V', 'R'), - 183: ('PRODUCT', 0, 30, 0x04, 1, 'V', 'R'), - 184: ('FACT', 1, 1, 0x02, 1, 'V', 'V'), - 189: ('DPRODUCT', 3, 3, 0x02, 3, 'V', 'RRR'), - 190: ('ISNONTEXT', 1, 1, 0x02, 1, 'V', 'V'), - 193: ('STDEVP', 1, 30, 0x04, 1, 'V', 'R'), - 194: ('VARP', 1, 30, 0x04, 1, 'V', 'R'), - 195: ('DSTDEVP', 3, 3, 0x02, 3, 'V', 'RRR'), - 196: ('DVARP', 3, 3, 0x02, 3, 'V', 'RRR'), - 197: ('TRUNC', 1, 2, 0x04, 2, 'V', 'VV'), - 198: ('ISLOGICAL', 1, 1, 0x02, 1, 'V', 'V'), - 199: ('DCOUNTA', 3, 3, 0x02, 3, 'V', 'RRR'), - 204: ('USDOLLAR', 1, 2, 0x04, 2, 'V', 'VV'), - 205: ('FINDB', 2, 3, 0x04, 3, 'V', 'VVV'), - 206: ('SEARCHB', 2, 3, 0x04, 3, 'V', 'VVV'), - 207: ('REPLACEB', 4, 4, 0x02, 4, 'V', 'VVVV'), - 208: ('LEFTB', 1, 2, 0x04, 2, 'V', 'VV'), - 209: ('RIGHTB', 1, 2, 0x04, 2, 'V', 'VV'), - 210: ('MIDB', 3, 3, 0x02, 3, 'V', 'VVV'), - 211: ('LENB', 1, 1, 0x02, 1, 'V', 'V'), - 212: ('ROUNDUP', 2, 2, 0x02, 2, 'V', 'VV'), - 213: ('ROUNDDOWN', 2, 2, 0x02, 2, 'V', 'VV'), - 214: ('ASC', 1, 1, 0x02, 1, 'V', 'V'), - 215: ('DBCS', 1, 1, 0x02, 1, 'V', 'V'), - 216: ('RANK', 2, 3, 0x04, 3, 'V', 'VRV'), - 219: ('ADDRESS', 2, 5, 0x04, 5, 'V', 'VVVVV'), - 220: ('DAYS360', 2, 3, 0x04, 3, 'V', 'VVV'), - 221: ('TODAY', 0, 0, 0x0a, 0, 'V', ''), - 222: ('VDB', 5, 7, 0x04, 7, 'V', 'VVVVVVV'), - 227: ('MEDIAN', 1, 30, 0x04, 1, 'V', 'R'), - 228: ('SUMPRODUCT', 1, 30, 0x04, 1, 'V', 'A'), - 229: ('SINH', 1, 1, 0x02, 1, 'V', 'V'), - 230: ('COSH', 1, 1, 0x02, 1, 'V', 'V'), - 231: ('TANH', 1, 1, 0x02, 1, 'V', 'V'), - 232: ('ASINH', 1, 1, 0x02, 1, 'V', 'V'), - 233: ('ACOSH', 1, 1, 0x02, 1, 'V', 'V'), - 234: ('ATANH', 1, 1, 0x02, 1, 'V', 'V'), - 235: ('DGET', 3, 3, 0x02, 3, 'V', 'RRR'), - 244: ('INFO', 1, 1, 0x02, 1, 'V', 'V'), - 247: ('DB', 4, 5, 0x04, 5, 'V', 'VVVVV'), - 252: ('FREQUENCY', 2, 2, 0x02, 2, 'A', 'RR'), - 261: ('ERROR.TYPE', 1, 1, 0x02, 1, 'V', 'V'), - 269: ('AVEDEV', 1, 30, 0x04, 1, 'V', 'R'), - 270: ('BETADIST', 3, 5, 0x04, 1, 'V', 'V'), - 271: ('GAMMALN', 1, 1, 0x02, 1, 'V', 'V'), - 272: ('BETAINV', 3, 5, 0x04, 1, 'V', 'V'), - 273: ('BINOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 274: ('CHIDIST', 2, 2, 0x02, 2, 'V', 'VV'), - 275: ('CHIINV', 2, 2, 0x02, 2, 'V', 'VV'), - 276: ('COMBIN', 2, 2, 0x02, 2, 'V', 'VV'), - 277: ('CONFIDENCE', 3, 3, 0x02, 3, 'V', 'VVV'), - 278: ('CRITBINOM', 3, 3, 0x02, 3, 'V', 'VVV'), - 279: ('EVEN', 1, 1, 0x02, 1, 'V', 'V'), - 280: ('EXPONDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 281: ('FDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 282: ('FINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 283: ('FISHER', 1, 1, 0x02, 1, 'V', 'V'), - 284: ('FISHERINV', 1, 1, 0x02, 1, 'V', 'V'), - 285: ('FLOOR', 2, 2, 0x02, 2, 'V', 'VV'), - 286: ('GAMMADIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 287: ('GAMMAINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 288: ('CEILING', 2, 2, 0x02, 2, 'V', 'VV'), - 289: ('HYPGEOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 290: ('LOGNORMDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 291: ('LOGINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 292: ('NEGBINOMDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 293: ('NORMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'), - 294: ('NORMSDIST', 1, 1, 0x02, 1, 'V', 'V'), - 295: ('NORMINV', 3, 3, 0x02, 3, 'V', 'VVV'), - 296: ('NORMSINV', 1, 1, 0x02, 1, 'V', 'V'), - 297: ('STANDARDIZE', 3, 3, 0x02, 3, 'V', 'VVV'), - 298: ('ODD', 1, 1, 0x02, 1, 'V', 'V'), - 299: ('PERMUT', 2, 2, 0x02, 2, 'V', 'VV'), - 300: ('POISSON', 3, 3, 0x02, 3, 'V', 'VVV'), - 301: ('TDIST', 3, 3, 0x02, 3, 'V', 'VVV'), - 302: ('WEIBULL', 4, 4, 0x02, 4, 'V', 'VVVV'), - 303: ('SUMXMY2', 2, 2, 0x02, 2, 'V', 'AA'), - 304: ('SUMX2MY2', 2, 2, 0x02, 2, 'V', 'AA'), - 305: ('SUMX2PY2', 2, 2, 0x02, 2, 'V', 'AA'), - 306: ('CHITEST', 2, 2, 0x02, 2, 'V', 'AA'), - 307: ('CORREL', 2, 2, 0x02, 2, 'V', 'AA'), - 308: ('COVAR', 2, 2, 0x02, 2, 'V', 'AA'), - 309: ('FORECAST', 3, 3, 0x02, 3, 'V', 'VAA'), - 310: ('FTEST', 2, 2, 0x02, 2, 'V', 'AA'), - 311: ('INTERCEPT', 2, 2, 0x02, 2, 'V', 'AA'), - 312: ('PEARSON', 2, 2, 0x02, 2, 'V', 'AA'), - 313: ('RSQ', 2, 2, 0x02, 2, 'V', 'AA'), - 314: ('STEYX', 2, 2, 0x02, 2, 'V', 'AA'), - 315: ('SLOPE', 2, 2, 0x02, 2, 'V', 'AA'), - 316: ('TTEST', 4, 4, 0x02, 4, 'V', 'AAVV'), - 317: ('PROB', 3, 4, 0x04, 3, 'V', 'AAV'), - 318: ('DEVSQ', 1, 30, 0x04, 1, 'V', 'R'), - 319: ('GEOMEAN', 1, 30, 0x04, 1, 'V', 'R'), - 320: ('HARMEAN', 1, 30, 0x04, 1, 'V', 'R'), - 321: ('SUMSQ', 0, 30, 0x04, 1, 'V', 'R'), - 322: ('KURT', 1, 30, 0x04, 1, 'V', 'R'), - 323: ('SKEW', 1, 30, 0x04, 1, 'V', 'R'), - 324: ('ZTEST', 2, 3, 0x04, 2, 'V', 'RV'), - 325: ('LARGE', 2, 2, 0x02, 2, 'V', 'RV'), - 326: ('SMALL', 2, 2, 0x02, 2, 'V', 'RV'), - 327: ('QUARTILE', 2, 2, 0x02, 2, 'V', 'RV'), - 328: ('PERCENTILE', 2, 2, 0x02, 2, 'V', 'RV'), - 329: ('PERCENTRANK', 2, 3, 0x04, 2, 'V', 'RV'), - 330: ('MODE', 1, 30, 0x04, 1, 'V', 'A'), - 331: ('TRIMMEAN', 2, 2, 0x02, 2, 'V', 'RV'), - 332: ('TINV', 2, 2, 0x02, 2, 'V', 'VV'), - 336: ('CONCATENATE', 0, 30, 0x04, 1, 'V', 'V'), - 337: ('POWER', 2, 2, 0x02, 2, 'V', 'VV'), - 342: ('RADIANS', 1, 1, 0x02, 1, 'V', 'V'), - 343: ('DEGREES', 1, 1, 0x02, 1, 'V', 'V'), - 344: ('SUBTOTAL', 2, 30, 0x04, 2, 'V', 'VR'), - 345: ('SUMIF', 2, 3, 0x04, 3, 'V', 'RVR'), - 346: ('COUNTIF', 2, 2, 0x02, 2, 'V', 'RV'), - 347: ('COUNTBLANK', 1, 1, 0x02, 1, 'V', 'R'), - 350: ('ISPMT', 4, 4, 0x02, 4, 'V', 'VVVV'), - 351: ('DATEDIF', 3, 3, 0x02, 3, 'V', 'VVV'), - 352: ('DATESTRING', 1, 1, 0x02, 1, 'V', 'V'), - 353: ('NUMBERSTRING', 2, 2, 0x02, 2, 'V', 'VV'), - 354: ('ROMAN', 1, 2, 0x04, 2, 'V', 'VV'), - 358: ('GETPIVOTDATA', 2, 2, 0x02, 2, 'V', 'RV'), - 359: ('HYPERLINK', 1, 2, 0x04, 2, 'V', 'VV'), - 360: ('PHONETIC', 1, 1, 0x02, 1, 'V', 'V'), - 361: ('AVERAGEA', 1, 30, 0x04, 1, 'V', 'R'), - 362: ('MAXA', 1, 30, 0x04, 1, 'V', 'R'), - 363: ('MINA', 1, 30, 0x04, 1, 'V', 'R'), - 364: ('STDEVPA', 1, 30, 0x04, 1, 'V', 'R'), - 365: ('VARPA', 1, 30, 0x04, 1, 'V', 'R'), - 366: ('STDEVA', 1, 30, 0x04, 1, 'V', 'R'), - 367: ('VARA', 1, 30, 0x04, 1, 'V', 'R'), - 368: ('BAHTTEXT', 1, 1, 0x02, 1, 'V', 'V'), - 369: ('THAIDAYOFWEEK', 1, 1, 0x02, 1, 'V', 'V'), - 370: ('THAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'), - 371: ('THAIMONTHOFYEAR', 1, 1, 0x02, 1, 'V', 'V'), - 372: ('THAINUMSOUND', 1, 1, 0x02, 1, 'V', 'V'), - 373: ('THAINUMSTRING', 1, 1, 0x02, 1, 'V', 'V'), - 374: ('THAISTRINGLENGTH', 1, 1, 0x02, 1, 'V', 'V'), - 375: ('ISTHAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'), - 376: ('ROUNDBAHTDOWN', 1, 1, 0x02, 1, 'V', 'V'), - 377: ('ROUNDBAHTUP', 1, 1, 0x02, 1, 'V', 'V'), - 378: ('THAIYEAR', 1, 1, 0x02, 1, 'V', 'V'), - 379: ('RTD', 2, 5, 0x04, 1, 'V', 'V'), - } - -tAttrNames = { - 0x00: "Skip??", # seen in SAMPLES.XLS which shipped with Excel 5.0 - 0x01: "Volatile", - 0x02: "If", - 0x04: "Choose", - 0x08: "Skip", - 0x10: "Sum", - 0x20: "Assign", - 0x40: "Space", - 0x41: "SpaceVolatile", - } - -_error_opcodes = {} -for _x in [0x07, 0x08, 0x0A, 0x0B, 0x1C, 0x1D, 0x2F]: - _error_opcodes[_x] = 1 -is_error_opcode = _error_opcodes.has_key - -tRangeFuncs = (min, max, min, max, min, max) -tIsectFuncs = (max, min, max, min, max, min) - -def do_box_funcs(box_funcs, boxa, boxb): - return tuple([ - func(numa, numb) - for func, numa, numb in zip(box_funcs, boxa.coords, boxb.coords) - ]) - -def adjust_cell_addr_biff8(rowval, colval, reldelta, browx=None, bcolx=None): - row_rel = (colval >> 15) & 1 - col_rel = (colval >> 14) & 1 - rowx = rowval - colx = colval & 0xff - if reldelta: - if row_rel and rowx >= 32768: - rowx -= 65536 - if col_rel and colx >= 128: - colx -= 256 - else: - if row_rel: - rowx -= browx - if col_rel: - colx -= bcolx - return rowx, colx, row_rel, col_rel - -def adjust_cell_addr_biff_le7( - rowval, colval, reldelta, browx=None, bcolx=None): - row_rel = (rowval >> 15) & 1 - col_rel = (rowval >> 14) & 1 - rowx = rowval & 0x3fff - colx = colval - if reldelta: - if row_rel and rowx >= 8192: - rowx -= 16384 - if col_rel and colx >= 128: - colx -= 256 - else: - if row_rel: - rowx -= browx - if col_rel: - colx -= bcolx - return rowx, colx, row_rel, col_rel - -def get_cell_addr(data, pos, bv, reldelta, browx=None, bcolx=None): - if bv >= 80: - rowval, colval = unpack("<HH", data[pos:pos+4]) - # print " rv=%04xh cv=%04xh" % (rowval, colval) - return adjust_cell_addr_biff8(rowval, colval, reldelta, browx, bcolx) - else: - rowval, colval = unpack("<HB", data[pos:pos+3]) - # print " rv=%04xh cv=%04xh" % (rowval, colval) - return adjust_cell_addr_biff_le7( - rowval, colval, reldelta, browx, bcolx) - -def get_cell_range_addr(data, pos, bv, reldelta, browx=None, bcolx=None): - if bv >= 80: - row1val, row2val, col1val, col2val = unpack("<HHHH", data[pos:pos+8]) - # print " rv=%04xh cv=%04xh" % (row1val, col1val) - # print " rv=%04xh cv=%04xh" % (row2val, col2val) - res1 = adjust_cell_addr_biff8(row1val, col1val, reldelta, browx, bcolx) - res2 = adjust_cell_addr_biff8(row2val, col2val, reldelta, browx, bcolx) - return res1, res2 - else: - row1val, row2val, col1val, col2val = unpack("<HHBB", data[pos:pos+6]) - # print " rv=%04xh cv=%04xh" % (row1val, col1val) - # print " rv=%04xh cv=%04xh" % (row2val, col2val) - res1 = adjust_cell_addr_biff_le7( - row1val, col1val, reldelta, browx, bcolx) - res2 = adjust_cell_addr_biff_le7( - row2val, col2val, reldelta, browx, bcolx) - return res1, res2 - -def get_externsheet_local_range(bk, refx, blah=0): - try: - info = bk._externsheet_info[refx] - except IndexError: - print "!!! get_externsheet_local_range: refx=%d, not in range(%d)" \ - % (refx, len(bk._externsheet_info)) - return (-101, -101) - ref_recordx, ref_first_sheetx, ref_last_sheetx = info - if ref_recordx == bk._supbook_addins_inx: - if blah: - print "/// get_externsheet_local_range(refx=%d) -> addins %r" % (refx, info) - assert ref_first_sheetx == 0xFFFE == ref_last_sheetx - return (-5, -5) - if ref_recordx != bk._supbook_locals_inx: - if blah: - print "/// get_externsheet_local_range(refx=%d) -> external %r" % (refx, info) - return (-4, -4) # external reference - if ref_first_sheetx == 0xFFFE == ref_last_sheetx: - if blah: - print "/// get_externsheet_local_range(refx=%d) -> unspecified sheet %r" % (refx, info) - return (-1, -1) # internal reference, any sheet - if ref_first_sheetx == 0xFFFF == ref_last_sheetx: - if blah: - print "/// get_externsheet_local_range(refx=%d) -> deleted sheet(s)" % (refx, ) - return (-2, -2) # internal reference, deleted sheet(s) - nsheets = len(bk._all_sheets_map) - if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets): - if blah: - print "/// get_externsheet_local_range(refx=%d) -> %r" % (refx, info) - print "--- first/last sheet not in range(%d)" % nsheets - return (-102, -102) # stuffed up somewhere :-( - xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx] - xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx] - if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2): - return (-3, -3) # internal reference, but to a macro sheet - return xlrd_sheetx1, xlrd_sheetx2 - -def get_externsheet_local_range_b57( - bk, raw_extshtx, ref_first_sheetx, ref_last_sheetx, blah=0): - if raw_extshtx > 0: - if blah: - print "/// get_externsheet_local_range_b57(raw_extshtx=%d) -> external" % raw_extshtx - return (-4, -4) # external reference - if ref_first_sheetx == -1 and ref_last_sheetx == -1: - return (-2, -2) # internal reference, deleted sheet(s) - nsheets = len(bk._all_sheets_map) - if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets): - if blah: - print "/// get_externsheet_local_range_b57(%d, %d, %d) -> ???" \ - % (raw_extshtx, ref_first_sheetx, ref_last_sheetx) - print "--- first/last sheet not in range(%d)" % nsheets - return (-103, -103) # stuffed up somewhere :-( - xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx] - xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx] - if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2): - return (-3, -3) # internal reference, but to a macro sheet - return xlrd_sheetx1, xlrd_sheetx2 - -class FormulaError(Exception): - pass - -oBOOL = 3 -oERR = 4 -oMSNG = 5 # tMissArg -oNUM = 2 -oREF = -1 -oREL = -2 -oSTRG = 1 -oUNK = 0 - -okind_dict = { - -2: "oREL", - -1: "oREF", - 0 : "oUNK", - 1 : "oSTRG", - 2 : "oNUM", - 3 : "oBOOL", - 4 : "oERR", - 5 : "oMSNG", - } - -listsep = ',' #### probably should depend on locale - -## -# Used in evaluating formulas. -# The following table describes the kinds and how their values -# are represented.</p> -# -# <table border="1" cellpadding="7"> -# <tr> -# <th>Kind symbol</th> -# <th>Kind number</th> -# <th>Value representation</th> -# </tr> -# <tr> -# <td>oBOOL</td> -# <td align="center">3</td> -# <td>integer: 0 => False; 1 => True</td> -# </tr> -# <tr> -# <td>oERR</td> -# <td align="center">4</td> -# <td>None, or an int error code (same as XL_CELL_ERROR in the Cell class). -# </td> -# </tr> -# <tr> -# <td>oMSNG</td> -# <td align="center">5</td> -# <td>Used by Excel as a placeholder for a missing (not supplied) function -# argument. Should *not* appear as a final formula result. Value is None.</td> -# </tr> -# <tr> -# <td>oNUM</td> -# <td align="center">2</td> -# <td>A float. Note that there is no way of distinguishing dates.</td> -# </tr> -# <tr> -# <td>oREF</td> -# <td align="center">-1</td> -# <td>The value is either None or a non-empty list of -# absolute Ref3D instances.<br> -# </td> -# </tr> -# <tr> -# <td>oREL</td> -# <td align="center">-2</td> -# <td>The value is None or a non-empty list of -# fully or partially relative Ref3D instances. -# </td> -# </tr> -# <tr> -# <td>oSTRG</td> -# <td align="center">1</td> -# <td>A Unicode string.</td> -# </tr> -# <tr> -# <td>oUNK</td> -# <td align="center">0</td> -# <td>The kind is unknown or ambiguous. The value is None</td> -# </tr> -# </table> -#<p></p> - -class Operand(object): - - ## - # None means that the actual value of the operand is a variable - # (depends on cell data), not a constant. - value = None - ## - # oUNK means that the kind of operand is not known unambiguously. - kind = oUNK - ## - # The reconstituted text of the original formula. Function names will be - # in English irrespective of the original language, which doesn't seem - # to be recorded anywhere. The separator is ",", not ";" or whatever else - # might be more appropriate for the end-user's locale; patches welcome. - text = '?' - - def __init__(self, akind=None, avalue=None, arank=0, atext='?'): - if akind is not None: - self.kind = akind - if avalue is not None: - self.value = avalue - self.rank = arank - # rank is an internal gizmo (operator precedence); - # it's used in reconstructing formula text. - self.text = atext - - def __repr__(self): - kind_text = okind_dict.get(self.kind, "?Unknown kind?") - return "Operand(kind=%s, value=%r, text=%r)" \ - % (kind_text, self.value, self.text) - -if CAN_SUBCLASS_BUILTIN: - _ref3d_base = tuple -else: - _ref3d_base = object - -## -# <p>Represents an absolute or relative 3-dimensional reference to a box -# of one or more cells.<br /> -# -- New in version 0.6.0 -# </p> -# -# <p>The <i>coords</i> attribute is a tuple of the form:<br /> -# (shtxlo, shtxhi, rowxlo, rowxhi, colxlo, colxhi)<br /> -# where 0 <= thingxlo <= thingx < thingxhi.<br /> -# Note that it is quite possible to have thingx > nthings; for example -# Print_Titles could have colxhi == 256 and/or rowxhi == 65536 -# irrespective of how many columns/rows are actually used in the worksheet. -# The caller will need to decide how to handle this situation. -# Keyword: IndexError :-) -# </p> -# -# <p>The components of the coords attribute are also available as individual -# attributes: shtxlo, shtxhi, rowxlo, rowxhi, colxlo, and colxhi.</p> -# -# <p>The <i>relflags</i> attribute is a 6-tuple of flags which indicate whether -# the corresponding (sheet|row|col)(lo|hi) is relative (1) or absolute (0).<br> -# Note that there is necessarily no information available as to what cell(s) -# the reference could possibly be relative to. The caller must decide what if -# any use to make of oREL operands. Note also that a partially relative -# reference may well be a typo. -# For example, define name A1Z10 as $a$1:$z10 (missing $ after z) -# while the cursor is on cell Sheet3!A27.<br> -# The resulting Ref3D instance will have coords = (2, 3, 0, -16, 0, 26) -# and relflags = (0, 0, 0, 1, 0, 0).<br> -# So far, only one possibility of a sheet-relative component in -# a reference has been noticed: a 2D reference located in the "current sheet". -# <br /> This will appear as coords = (0, 1, ...) and relflags = (1, 1, ...). - -class Ref3D(_ref3d_base): - - def __init__(self, atuple): - self.coords = atuple[0:6] - self.relflags = atuple[6:12] - if not self.relflags: - self.relflags = (0, 0, 0, 0, 0, 0) - (self.shtxlo, self.shtxhi, - self.rowxlo, self.rowxhi, - self.colxlo, self.colxhi) = self.coords - - def __repr__(self): - if not self.relflags or self.relflags == (0, 0, 0, 0, 0, 0): - return "Ref3D(coords=%r)" % (self.coords, ) - else: - return "Ref3D(coords=%r, relflags=%r)" \ - % (self.coords, self.relflags) - -tAdd = 0x03 -tSub = 0x04 -tMul = 0x05 -tDiv = 0x06 -tPower = 0x07 -tConcat = 0x08 -tLT, tLE, tEQ, tGE, tGT, tNE = range(0x09, 0x0F) - -import operator as opr - -def nop(x): - return x - -def _opr_pow(x, y): return x ** y - -def _opr_lt(x, y): return x < y -def _opr_le(x, y): return x <= y -def _opr_eq(x, y): return x == y -def _opr_ge(x, y): return x >= y -def _opr_gt(x, y): return x > y -def _opr_ne(x, y): return x != y - -def num2strg(num): - """Attempt to emulate Excel's default conversion - from number to string. - """ - s = str(num) - if s.endswith(".0"): - s = s[:-2] - return s - -_arith_argdict = {oNUM: nop, oSTRG: float} -_cmp_argdict = {oNUM: nop, oSTRG: nop} -# Seems no conversions done on relops; in Excel, "1" > 9 produces TRUE. -_strg_argdict = {oNUM:num2strg, oSTRG:nop} -binop_rules = { - tAdd: (_arith_argdict, oNUM, opr.add, 30, '+'), - tSub: (_arith_argdict, oNUM, opr.sub, 30, '-'), - tMul: (_arith_argdict, oNUM, opr.mul, 40, '*'), - tDiv: (_arith_argdict, oNUM, opr.div, 40, '/'), - tPower: (_arith_argdict, oNUM, _opr_pow, 50, '^',), - tConcat:(_strg_argdict, oSTRG, opr.add, 20, '&'), - tLT: (_cmp_argdict, oBOOL, _opr_lt, 10, '<'), - tLE: (_cmp_argdict, oBOOL, _opr_le, 10, '<='), - tEQ: (_cmp_argdict, oBOOL, _opr_eq, 10, '='), - tGE: (_cmp_argdict, oBOOL, _opr_ge, 10, '>='), - tGT: (_cmp_argdict, oBOOL, _opr_gt, 10, '>'), - tNE: (_cmp_argdict, oBOOL, _opr_ne, 10, '<>'), - } - -unop_rules = { - 0x13: (lambda x: -x, 70, '-', ''), # unary minus - 0x12: (lambda x: x, 70, '+', ''), # unary plus - 0x14: (lambda x: x / 100.0, 60, '', '%'),# percent - } - -LEAF_RANK = 90 -FUNC_RANK = 90 - -STACK_ALARM_LEVEL = 5 -STACK_PANIC_LEVEL = 10 - -def evaluate_name_formula(bk, nobj, namex, blah=0, level=0): - if level > STACK_ALARM_LEVEL: - blah = 1 - data = nobj.raw_formula - fmlalen = nobj.basic_formula_len - bv = bk.biff_version - reldelta = 1 # All defined name formulas use "Method B" [OOo docs] - if blah: - print "::: evaluate_name_formula %r %r %d %d %r level=%d" \ - % (namex, nobj.name, fmlalen, bv, data, level) - hex_char_dump(data, 0, fmlalen) - if level > STACK_PANIC_LEVEL: - raise XLRDError("Excessive indirect references in NAME formula") - sztab = szdict[bv] - pos = 0 - stack = [] - any_rel = 0 - any_err = 0 - any_external = 0 - unk_opnd = Operand(oUNK, None) - error_opnd = Operand(oERR, None) - spush = stack.append - - def do_binop(opcd, stk): - assert len(stk) >= 2 - bop = stk.pop() - aop = stk.pop() - argdict, result_kind, func, rank, sym = binop_rules[opcd] - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - resop = Operand(result_kind, None, rank, otext) - try: - bconv = argdict[bop.kind] - aconv = argdict[aop.kind] - except KeyError: - stk.append(resop) - return - if bop.value is None or aop.value is None: - stk.append(resop) - return - bval = bconv(bop.value) - aval = aconv(aop.value) - result = func(aval, bval) - if result_kind == oBOOL: - result = intbool(result) # -> 1 or 0 - resop.value = result - stk.append(resop) - - def do_unaryop(opcode, arglist, result_kind, stk): - assert len(stk) >= 1 - aop = stk.pop() - assert aop.kind in arglist - val = aop.value - func, rank, sym1, sym2 = unop_rules[opcode] - otext = ''.join([ - sym1, - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym2, - ]) - if val is not None: - val = func(val) - stk.append(Operand(result_kind, val, rank, otext)) - - def not_in_name_formula(op_arg, oname_arg): - msg = "ERROR *** Token 0x%02x (%s) found in NAME formula" \ - % (op_arg, oname_arg) - raise FormulaError(msg) - - if fmlalen == 0: - stack = [unk_opnd] - - while 0 <= pos < fmlalen: - op = ord(data[pos]) - opcode = op & 0x1f - optype = (op & 0x60) >> 5 - if optype: - opx = opcode + 32 - else: - opx = opcode - oname = onames[opx] # + [" RVA"][optype] - sz = sztab[opx] - if blah: - print "Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \ - % (pos, op, oname, sz, opcode, optype) - print "Stack =", stack - if sz == -2: - msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \ - % (op, oname, bv) - raise FormulaError(msg) - if not optype: - if 0x00 <= opcode <= 0x02: # unk_opnd, tExp, tTbl - not_in_name_formula(op, oname) - elif 0x03 <= opcode <= 0x0E: - # Add, Sub, Mul, Div, Power - # tConcat - # tLT, ..., tNE - do_binop(opcode, stack) - elif opcode == 0x0F: # tIsect - if blah: print >> bk.logfile, "tIsect pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ' ' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF) - res.text = otext - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind == oUNK or aop.kind == oUNK: - # This can happen with undefined - # (go search in the current sheet) labels. - # For example =Bob Sales - # Each label gets a NAME record with an empty formula (!) - # Evaluation of the tName token classifies it as oUNK - # res.kind = oREF - pass - elif bop.kind == oREF == aop.kind: - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tIsectFuncs, aop.value[0], bop.value[0]) - res.value = [Ref3D(coords)] - elif bop.kind == oREL == aop.kind: - res.kind = oREL - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tIsectFuncs, aop.value[0], bop.value[0]) - relfa = aop.value[0].relflags - relfb = bop.value[0].relflags - if relfa == relfb: - res.value = [Ref3D(coords + relfa)] - else: - pass - spush(res) - if blah: print >> bk.logfile, "tIsect post", stack - elif opcode == 0x10: # tList - if blah: print >> bk.logfile, "tList pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ',' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL): - res.kind = oREF - if aop.kind == oREL or bop.kind == oREL: - res.kind = oREL - if aop.value is not None and bop.value is not None: - assert len(aop.value) >= 1 - assert len(bop.value) == 1 - res.value = aop.value + bop.value - else: - pass - spush(res) - if blah: print >> bk.logfile, "tList post", stack - elif opcode == 0x11: # tRange - if blah: print >> bk.logfile, "tRange pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ':' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res = oERR - elif bop.kind == oREF == aop.kind: - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tRangeFuncs, aop.value[0], bop.value[0]) - res.value = [Ref3D(coords)] - elif bop.kind == oREL == aop.kind: - res.kind = oREL - if aop.value is not None and bop.value is not None: - assert len(aop.value) == 1 - assert len(bop.value) == 1 - coords = do_box_funcs( - tRangeFuncs, aop.value[0], bop.value[0]) - relfa = aop.value[0].relflags - relfb = bop.value[0].relflags - if relfa == relfb: - res.value = [Ref3D(coords + relfa)] - else: - pass - spush(res) - if blah: print >> bk.logfile, "tRange post", stack - elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent - do_unaryop(opcode, (oUNK, oNUM,), oNUM, stack) - elif opcode == 0x15: # tParen - # source cosmetics - pass - elif opcode == 0x16: # tMissArg - spush(Operand(oMSNG, None, LEAF_RANK, '')) - elif opcode == 0x17: # tStr - if bv <= 70: - strg, newpos = unpack_string_update_pos( - data, pos+1, bk.encoding, lenlen=1) - else: - strg, newpos = unpack_unicode_update_pos( - data, pos+1, lenlen=1) - sz = newpos - pos - if blah: print >> bk.logfile, " sz=%d strg=%r" % (sz, strg) - text = '"' + strg.replace('"', '""') + '"' - spush(Operand(oSTRG, strg, LEAF_RANK, text)) - elif opcode == 0x18: # tExtended - # new with BIFF 8 - assert bv >= 80 - # not in OOo docs - raise FormulaError("tExtended token not implemented") - elif opcode == 0x19: # tAttr - subop, nc = unpack("<BH", data[pos+1:pos+4]) - subname = tAttrNames.get(subop, "??Unknown??") - if subop == 0x04: # Choose - sz = nc * 2 + 6 - elif subop == 0x10: # Sum (single arg) - sz = 4 - if blah: print >> bk.logfile, "tAttrSum", stack - assert len(stack) >= 1 - aop = stack[-1] - otext = 'SUM(%s)' % aop.text - stack[-1] = Operand(oNUM, None, FUNC_RANK, otext) - else: - sz = 4 - if blah: - print " subop=%02xh subname=t%s sz=%d nc=%02xh" \ - % (subop, subname, sz, nc) - elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet - assert bv < 50 - raise FormulaError("tSheet & tEndsheet tokens not implemented") - elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum - inx = opcode - 0x1C - nb = [1, 1, 2, 8][inx] - kind = [oERR, oBOOL, oNUM, oNUM][inx] - value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb]) - if inx == 2: # tInt - value = float(value) - text = str(value) - elif inx == 3: # tNum - text = str(value) - elif inx == 1: # tBool - text = ('FALSE', 'TRUE')[value] - else: - text = '"' +error_text_from_code[value] + '"' - spush(Operand(kind, value, LEAF_RANK, text)) - else: - raise FormulaError("Unhandled opcode: 0x%02x" % opcode) - if sz <= 0: - raise FormulaError("Size not set for opcode 0x%02x" % opcode) - pos += sz - continue - if opcode == 0x00: # tArray - spush(unk_opnd) - elif opcode == 0x01: # tFunc - nb = 1 + int(bv >= 40) - funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0] - func_attrs = func_defs.get(funcx, None) - if not func_attrs: - print >> bk.logfile, "*** formula/tFunc unknown FuncID:%d" \ - % funcx - spush(unk_opnd) - else: - func_name, nargs = func_attrs[:2] - if blah: - print " FuncID=%d name=%s nargs=%d" \ - % (funcx, func_name, nargs) - assert len(stack) >= nargs - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - del stack[-nargs:] - res = Operand(oUNK, None, FUNC_RANK, otext) - spush(res) - elif opcode == 0x02: #tFuncVar - nb = 1 + int(bv >= 40) - nargs, funcx = unpack("<B" + " BH"[nb], data[pos+1:pos+2+nb]) - prompt, nargs = divmod(nargs, 128) - macro, funcx = divmod(funcx, 32768) - if blah: - print " FuncID=%d nargs=%d macro=%d prompt=%d" \ - % (funcx, nargs, macro, prompt) - func_attrs = func_defs.get(funcx, None) - if not func_attrs: - print >> bk.logfile, "*** formula/tFuncVar unknown FuncID:%d" \ - % funcx - spush(unk_opnd) - else: - func_name, minargs, maxargs = func_attrs[:3] - if blah: - print " name: %r, min~max args: %d~%d" \ - % (func_name, minargs, maxargs) - assert minargs <= nargs <= maxargs - assert len(stack) >= nargs - assert len(stack) >= nargs - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - res = Operand(oUNK, None, FUNC_RANK, otext) - if funcx == 1: # IF - testarg = stack[-nargs] - if testarg.kind not in (oNUM, oBOOL): - if blah and testarg.kind != oUNK: - print "IF testarg kind?" - elif testarg.value not in (0, 1): - if blah and testarg.value is not None: - print "IF testarg value?" - else: - if nargs == 2 and not testarg.value: - # IF(FALSE, tv) => FALSE - res.kind, res.value = oBOOL, 0 - else: - respos = -nargs + 2 - int(testarg.value) - chosen = stack[respos] - if chosen.kind == oMSNG: - res.kind, res.value = oNUM, 0 - else: - res.kind, res.value = chosen.kind, chosen.value - if blah: - print "$$$$$$ IF => constant" - elif funcx == 100: # CHOOSE - testarg = stack[-nargs] - if testarg.kind == oNUM: - if 1 <= testarg.value < nargs: - chosen = stack[-nargs + int(testarg.value)] - if chosen.kind == oMSNG: - res.kind, res.value = oNUM, 0 - else: - res.kind, res.value = chosen.kind, chosen.value - del stack[-nargs:] - spush(res) - elif opcode == 0x03: #tName - tgtnamex = unpack("<H", data[pos+1:pos+3])[0] - 1 - # Only change with BIFF version is number of trailing UNUSED bytes! - if blah: print >> bk.logfile, " tgtnamex=%d" % tgtnamex - tgtobj = bk.name_obj_list[tgtnamex] - if not tgtobj.evaluated: - ### recursive ### - evaluate_name_formula(bk, tgtobj, tgtnamex, blah, level+1) - if tgtobj.macro or tgtobj.binary \ - or tgtobj.any_err: - if blah: - tgtobj.dump( - bk.logfile, - header="!!! tgtobj has problems!!!", - footer="----------- --------", - ) - res = Operand(oUNK, None) - any_err = any_err or tgtobj.macro or tgtobj.binary or tgtobj.any_err - any_rel = any_rel or tgtobj.any_rel - else: - assert len(tgtobj.stack) == 1 - res = copy.deepcopy(tgtobj.stack[0]) - res.rank = LEAF_RANK - if tgtobj.scope == -1: - res.text = tgtobj.name - else: - res.text = "%s!%s" \ - % (bk._sheet_names[tgtobj.scope], tgtobj.name) - if blah: - print >> bk.logfile, " tName: setting text to", repr(res.text) - spush(res) - elif opcode == 0x04: # tRef - # not_in_name_formula(op, oname) - res = get_cell_addr(data, pos+1, bv, reldelta) - if blah: print >> bk.logfile, " ", res - rowx, colx, row_rel, col_rel = res - shx1 = shx2 = 0 ####### N.B. relative to the CURRENT SHEET - any_rel = 1 - coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1) - if blah: print >> bk.logfile, " ", coords - res = Operand(oUNK, None) - if optype == 1: - relflags = (1, 1, row_rel, row_rel, col_rel, col_rel) - res = Operand(oREL, [Ref3D(coords + relflags)]) - spush(res) - elif opcode == 0x05: # tArea - # not_in_name_formula(op, oname) - res1, res2 = get_cell_range_addr(data, pos+1, bv, reldelta) - if blah: print >> bk.logfile, " ", res1, res2 - rowx1, colx1, row_rel1, col_rel1 = res1 - rowx2, colx2, row_rel2, col_rel2 = res2 - shx1 = shx2 = 0 ####### N.B. relative to the CURRENT SHEET - any_rel = 1 - coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1) - if blah: print >> bk.logfile, " ", coords - res = Operand(oUNK, None) - if optype == 1: - relflags = (1, 1, row_rel1, row_rel2, col_rel1, col_rel2) - res = Operand(oREL, [Ref3D(coords + relflags)]) - spush(res) - elif opcode == 0x06: # tMemArea - not_in_name_formula(op, oname) - elif opcode == 0x09: # tMemFunc - nb = unpack("<H", data[pos+1:pos+3])[0] - if blah: print >> bk.logfile, " %d bytes of cell ref formula" % nb - # no effect on stack - elif opcode == 0x0C: #tRefN - not_in_name_formula(op, oname) - # res = get_cell_addr(data, pos+1, bv, reldelta=1) - # # note *ALL* tRefN usage has signed offset for relative addresses - # any_rel = 1 - # if blah: print >> bk.logfile, " ", res - # spush(res) - elif opcode == 0x0D: #tAreaN - not_in_name_formula(op, oname) - # res = get_cell_range_addr(data, pos+1, bv, reldelta=1) - # # note *ALL* tAreaN usage has signed offset for relative addresses - # any_rel = 1 - # if blah: print >> bk.logfile, " ", res - elif opcode == 0x1A: # tRef3d - if bv >= 80: - res = get_cell_addr(data, pos+3, bv, reldelta) - refx = unpack("<H", data[pos+1:pos+3])[0] - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - else: - res = get_cell_addr(data, pos+15, bv, reldelta) - raw_extshtx, raw_shx1, raw_shx2 = \ - unpack("<hxxxxxxxxhh", data[pos+1:pos+15]) - if blah: - print >> bk.logfile, "tRef3d", raw_extshtx, raw_shx1, raw_shx2 - shx1, shx2 = get_externsheet_local_range_b57( - bk, raw_extshtx, raw_shx1, raw_shx2, blah) - rowx, colx, row_rel, col_rel = res - is_rel = row_rel or col_rel - any_rel = any_rel or is_rel - coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1) - any_err |= shx1 < -1 - if blah: print >> bk.logfile, " ", coords - res = Operand(oUNK, None) - if is_rel: - relflags = (0, 0, row_rel, row_rel, col_rel, col_rel) - ref3d = Ref3D(coords + relflags) - res.kind = oREL - res.text = rangename3drel(bk, ref3d) - else: - ref3d = Ref3D(coords) - res.kind = oREF - res.text = rangename3d(bk, ref3d) - res.rank = LEAF_RANK - if optype == 1: - res.value = [ref3d] - spush(res) - elif opcode == 0x1B: # tArea3d - if bv >= 80: - res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) - refx = unpack("<H", data[pos+1:pos+3])[0] - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - else: - res1, res2 = get_cell_range_addr(data, pos+15, bv, reldelta) - raw_extshtx, raw_shx1, raw_shx2 = \ - unpack("<hxxxxxxxxhh", data[pos+1:pos+15]) - if blah: - print >> bk.logfile, "tArea3d", raw_extshtx, raw_shx1, raw_shx2 - shx1, shx2 = get_externsheet_local_range_b57( - bk, raw_extshtx, raw_shx1, raw_shx2, blah) - any_err |= shx1 < -1 - rowx1, colx1, row_rel1, col_rel1 = res1 - rowx2, colx2, row_rel2, col_rel2 = res2 - is_rel = row_rel1 or col_rel1 or row_rel2 or col_rel2 - any_rel = any_rel or is_rel - coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1) - if blah: print >> bk.logfile, " ", coords - res = Operand(oUNK, None) - if is_rel: - relflags = (0, 0, row_rel1, row_rel2, col_rel1, col_rel2) - ref3d = Ref3D(coords + relflags) - res.kind = oREL - res.text = rangename3drel(bk, ref3d) - else: - ref3d = Ref3D(coords) - res.kind = oREF - res.text = rangename3d(bk, ref3d) - res.rank = LEAF_RANK - if optype == 1: - res.value = [ref3d] - - spush(res) - elif opcode == 0x19: # tNameX - dodgy = 0 - res = Operand(oUNK, None) - if bv >= 80: - refx, tgtnamex = unpack("<HH", data[pos+1:pos+5]) - tgtnamex -= 1 - origrefx = refx - else: - refx, tgtnamex = unpack("<hxxxxxxxxH", data[pos+1:pos+13]) - tgtnamex -= 1 - origrefx = refx - if refx > 0: - refx -= 1 - elif refx < 0: - refx = -refx - 1 - else: - dodgy = 1 - if blah: - print >> bk.logfile, \ - " origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \ - % (origrefx, refx, tgtnamex, dodgy) - if tgtnamex == namex: - if blah: print >> bk.logfile, "!!!! Self-referential !!!!" - dodgy = any_err = 1 - if not dodgy: - if bv >= 80: - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - elif origrefx > 0: - shx1, shx2 = (-4, -4) # external ref - else: - exty = bk._externsheet_type_b57[refx] - if exty == 4: # non-specific sheet in own doc't - shx1, shx2 = (-1, -1) # internal, any sheet - else: - shx1, shx2 = (-666, -666) - if dodgy or shx1 < -1: - otext = "<<Name #%d in external(?) file #%d>>" \ - % (tgtnamex, origrefx) - res = Operand(oUNK, None, LEAF_RANK, otext) - else: - tgtobj = bk.name_obj_list[tgtnamex] - if not tgtobj.evaluated: - ### recursive ### - evaluate_name_formula(bk, tgtobj, tgtnamex, blah, level+1) - if tgtobj.macro or tgtobj.binary \ - or tgtobj.any_err: - if blah: - tgtobj.dump( - bk.logfile, - header="!!! bad tgtobj !!!", - footer="------------------", - ) - res = Operand(oUNK, None) - any_err = any_err or tgtobj.macro or tgtobj.binary or tgtobj.any_err - any_rel = any_rel or tgtobj.any_rel - else: - assert len(tgtobj.stack) == 1 - res = copy.deepcopy(tgtobj.stack[0]) - res.rank = LEAF_RANK - if tgtobj.scope == -1: - res.text = tgtobj.name - else: - res.text = "%s!%s" \ - % (bk._sheet_names[tgtobj.scope], tgtobj.name) - if blah: - print >> bk.logfile, " tNameX: setting text to", repr(res.text) - spush(res) - elif is_error_opcode(opcode): - any_err = 1 - spush(error_opnd) - else: - if blah: - print >> bk.logfile, "FORMULA: /// Not handled yet: t" + oname - any_err = 1 - if sz <= 0: - raise FormulaError("Fatal: token size is not positive") - pos += sz - any_rel = not not any_rel - if blah: - print "End of formula. level=%d any_rel=%d any_err=%d stack=%r" % \ - (level, not not any_rel, any_err, stack) - if len(stack) >= 2: - print "*** Stack has unprocessed args" - print - nobj.stack = stack - if len(stack) != 1: - nobj.result = None - else: - nobj.result = stack[0] - nobj.any_rel = any_rel - nobj.any_err = any_err - nobj.any_external = any_external - nobj.evaluated = 1 - -#### under construction #### -def decompile_formula(bk, fmla, fmlalen, - reldelta, browx=None, bcolx=None, - # browx & bcolx are required when reldelta == 0 - blah=0, level=0): - if level > STACK_ALARM_LEVEL: - blah = 1 - data = fmla - bv = bk.biff_version - if blah: - print "::: decompile_formula len=%d reldelta=%d %r level=%d" \ - % (fmlalen, reldelta, data, level) - hex_char_dump(data, 0, fmlalen) - if level > STACK_PANIC_LEVEL: - raise XLRDError("Excessive indirect references in formula") - sztab = szdict[bv] - pos = 0 - stack = [] - any_rel = 0 - any_err = 0 - any_external = 0 - unk_opnd = Operand(oUNK, None) - error_opnd = Operand(oERR, None) - spush = stack.append - - def do_binop(opcd, stk): - assert len(stk) >= 2 - bop = stk.pop() - aop = stk.pop() - argdict, result_kind, func, rank, sym = binop_rules[opcd] - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - resop = Operand(result_kind, None, rank, otext) - stk.append(resop) - - def do_unaryop(opcode, arglist, result_kind, stk): - assert len(stk) >= 1 - aop = stk.pop() - assert aop.kind in arglist - func, rank, sym1, sym2 = unop_rules[opcode] - otext = ''.join([ - sym1, - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym2, - ]) - stk.append(Operand(result_kind, None, rank, otext)) - - def not_in_name_formula(op_arg, oname_arg): - msg = "ERROR *** Unexpected token 0x%02x (%s) found in formula" \ - % (op_arg, oname_arg) - # print msg - raise FormulaError(msg) - - if fmlalen == 0: - stack = [unk_opnd] - - while 0 <= pos < fmlalen: - op = ord(data[pos]) - opcode = op & 0x1f - optype = (op & 0x60) >> 5 - if optype: - opx = opcode + 32 - else: - opx = opcode - oname = onames[opx] # + [" RVA"][optype] - sz = sztab[opx] - if blah: - print "Pos:%d Op:0x%02x opname:t%s Sz:%d opcode:%02xh optype:%02xh" \ - % (pos, op, oname, sz, opcode, optype) - print "Stack =", stack - if sz == -2: - msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \ - % (op, oname, bv) - raise FormulaError(msg) - if not optype: - if 0x00 <= opcode <= 0x02: # unk_opnd, tExp, tTbl - not_in_name_formula(op, oname) - elif 0x03 <= opcode <= 0x0E: - # Add, Sub, Mul, Div, Power - # tConcat - # tLT, ..., tNE - do_binop(opcode, stack) - elif opcode == 0x0F: # tIsect - if blah: print >> bk.logfile, "tIsect pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ' ' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF) - res.text = otext - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind == oUNK or aop.kind == oUNK: - # This can happen with undefined - # (go search in the current sheet) labels. - # For example =Bob Sales - # Each label gets a NAME record with an empty formula (!) - # Evaluation of the tName token classifies it as oUNK - # res.kind = oREF - pass - elif bop.kind == oREF == aop.kind: - pass - elif bop.kind == oREL == aop.kind: - res.kind = oREL - else: - pass - spush(res) - if blah: print >> bk.logfile, "tIsect post", stack - elif opcode == 0x10: # tList - if blah: print >> bk.logfile, "tList pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ',' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res.kind = oERR - elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL): - res.kind = oREF - if aop.kind == oREL or bop.kind == oREL: - res.kind = oREL - else: - pass - spush(res) - if blah: print >> bk.logfile, "tList post", stack - elif opcode == 0x11: # tRange - if blah: print >> bk.logfile, "tRange pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - sym = ':' - rank = 80 ########## check ####### - otext = ''.join([ - '('[:aop.rank < rank], - aop.text, - ')'[:aop.rank < rank], - sym, - '('[:bop.rank < rank], - bop.text, - ')'[:bop.rank < rank], - ]) - res = Operand(oREF, None, rank, otext) - if bop.kind == oERR or aop.kind == oERR: - res = oERR - elif bop.kind == oREF == aop.kind: - pass - else: - pass - spush(res) - if blah: print >> bk.logfile, "tRange post", stack - elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent - do_unaryop(opcode, (oUNK, oNUM,), oNUM, stack) - elif opcode == 0x15: # tParen - # source cosmetics - pass - elif opcode == 0x16: # tMissArg - spush(Operand(oMSNG, None, LEAF_RANK, '')) - elif opcode == 0x17: # tStr - if bv <= 70: - strg, newpos = unpack_string_update_pos( - data, pos+1, bk.encoding, lenlen=1) - else: - strg, newpos = unpack_unicode_update_pos( - data, pos+1, lenlen=1) - sz = newpos - pos - if blah: print >> bk.logfile, " sz=%d strg=%r" % (sz, strg) - text = '"' + strg.replace('"', '""') + '"' - spush(Operand(oSTRG, None, LEAF_RANK, text)) - elif opcode == 0x18: # tExtended - # new with BIFF 8 - assert bv >= 80 - # not in OOo docs - raise FormulaError("tExtended token not implemented") - elif opcode == 0x19: # tAttr - subop, nc = unpack("<BH", data[pos+1:pos+4]) - subname = tAttrNames.get(subop, "??Unknown??") - if subop == 0x04: # Choose - sz = nc * 2 + 6 - elif subop == 0x10: # Sum (single arg) - sz = 4 - if blah: print >> bk.logfile, "tAttrSum", stack - assert len(stack) >= 1 - aop = stack[-1] - otext = 'SUM(%s)' % aop.text - stack[-1] = Operand(oNUM, None, FUNC_RANK, otext) - else: - sz = 4 - if blah: - print " subop=%02xh subname=t%s sz=%d nc=%02xh" \ - % (subop, subname, sz, nc) - elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet - assert bv < 50 - raise FormulaError("tSheet & tEndsheet tokens not implemented") - elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum - inx = opcode - 0x1C - nb = [1, 1, 2, 8][inx] - kind = [oERR, oBOOL, oNUM, oNUM][inx] - value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb]) - if inx == 2: # tInt - value = float(value) - text = str(value) - elif inx == 3: # tNum - text = str(value) - elif inx == 1: # tBool - text = ('FALSE', 'TRUE')[value] - else: - text = '"' +error_text_from_code[value] + '"' - spush(Operand(kind, None, LEAF_RANK, text)) - else: - raise FormulaError("Unhandled opcode: 0x%02x" % opcode) - if sz <= 0: - raise FormulaError("Size not set for opcode 0x%02x" % opcode) - pos += sz - continue - if opcode == 0x00: # tArray - spush(unk_opnd) - elif opcode == 0x01: # tFunc - nb = 1 + int(bv >= 40) - funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0] - func_attrs = func_defs.get(funcx, None) - if not func_attrs: - print >> bk.logfile, "*** formula/tFunc unknown FuncID:%d" % funcx - spush(unk_opnd) - else: - func_name, nargs = func_attrs[:2] - if blah: - print " FuncID=%d name=%s nargs=%d" \ - % (funcx, func_name, nargs) - assert len(stack) >= nargs - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - del stack[-nargs:] - res = Operand(oUNK, None, FUNC_RANK, otext) - spush(res) - elif opcode == 0x02: #tFuncVar - nb = 1 + int(bv >= 40) - nargs, funcx = unpack("<B" + " BH"[nb], data[pos+1:pos+2+nb]) - prompt, nargs = divmod(nargs, 128) - macro, funcx = divmod(funcx, 32768) - if blah: - print " FuncID=%d nargs=%d macro=%d prompt=%d" \ - % (funcx, nargs, macro, prompt) - #### TODO #### if funcx == 255: # call add-in function - if funcx == 255: - func_attrs = ("CALL_ADDIN", 1, 30) - else: - func_attrs = func_defs.get(funcx, None) - if not func_attrs: - print >> bk.logfile, "*** formula/tFuncVar unknown FuncID:%d" \ - % funcx - spush(unk_opnd) - else: - func_name, minargs, maxargs = func_attrs[:3] - if blah: - print " name: %r, min~max args: %d~%d" \ - % (func_name, minargs, maxargs) - assert minargs <= nargs <= maxargs - assert len(stack) >= nargs - assert len(stack) >= nargs - argtext = listsep.join([arg.text for arg in stack[-nargs:]]) - otext = "%s(%s)" % (func_name, argtext) - res = Operand(oUNK, None, FUNC_RANK, otext) - del stack[-nargs:] - spush(res) - elif opcode == 0x03: #tName - tgtnamex = unpack("<H", data[pos+1:pos+3])[0] - 1 - # Only change with BIFF version is number of trailing UNUSED bytes! - if blah: print >> bk.logfile, " tgtnamex=%d" % tgtnamex - tgtobj = bk.name_obj_list[tgtnamex] - if tgtobj.scope == -1: - otext = tgtobj.name - else: - otext = "%s!%s" % (bk._sheet_names[tgtobj.scope], tgtobj.name) - if blah: - print >> bk.logfile, " tName: setting text to", repr(otext) - res = Operand(oUNK, None, LEAF_RANK, otext) - spush(res) - elif opcode == 0x04: # tRef - res = get_cell_addr(data, pos+1, bv, reldelta, browx, bcolx) - if blah: print >> bk.logfile, " ", res - rowx, colx, row_rel, col_rel = res - is_rel = row_rel or col_rel - if is_rel: - okind = oREL - else: - okind = oREF - otext = cellnamerel(rowx, colx, row_rel, col_rel) - res = Operand(okind, None, LEAF_RANK, otext) - spush(res) - elif opcode == 0x05: # tArea - res1, res2 = get_cell_range_addr( - data, pos+1, bv, reldelta, browx, bcolx) - if blah: print >> bk.logfile, " ", res1, res2 - rowx1, colx1, row_rel1, col_rel1 = res1 - rowx2, colx2, row_rel2, col_rel2 = res2 - coords = (rowx1, rowx2+1, colx1, colx2+1) - relflags = (row_rel1, row_rel2, col_rel1, col_rel2) - is_rel = intbool(sum(relflags)) - if is_rel: - okind = oREL - else: - okind = oREF - if blah: print >> bk.logfile, " ", coords, relflags - otext = rangename2drel(coords, relflags) - res = Operand(okind, None, LEAF_RANK, otext) - spush(res) - elif opcode == 0x06: # tMemArea - not_in_name_formula(op, oname) - elif opcode == 0x09: # tMemFunc - nb = unpack("<H", data[pos+1:pos+3])[0] - if blah: print >> bk.logfile, " %d bytes of cell ref formula" % nb - # no effect on stack - elif opcode == 0x0C: #tRefN - not_in_name_formula(op, oname) - # res = get_cell_addr(data, pos+1, bv, reldelta=1) - # # note *ALL* tRefN usage has signed offset for relative addresses - # any_rel = 1 - # if blah: print >> bk.logfile, " ", res - # spush(res) - elif opcode == 0x0D: #tAreaN - not_in_name_formula(op, oname) - # res = get_cell_range_addr(data, pos+1, bv, reldelta=1) - # # note *ALL* tAreaN usage has signed offset for relative addresses - # any_rel = 1 - # if blah: print >> bk.logfile, " ", res - elif opcode == 0x1A: # tRef3d - if bv >= 80: - res = get_cell_addr(data, pos+3, bv, reldelta, browx, bcolx) - refx = unpack("<H", data[pos+1:pos+3])[0] - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - else: - res = get_cell_addr(data, pos+15, bv, reldelta, browx, bcolx) - raw_extshtx, raw_shx1, raw_shx2 = \ - unpack("<hxxxxxxxxhh", data[pos+1:pos+15]) - if blah: - print >> bk.logfile, "tRef3d", raw_extshtx, raw_shx1, raw_shx2 - shx1, shx2 = get_externsheet_local_range_b57( - bk, raw_extshtx, raw_shx1, raw_shx2, blah) - rowx, colx, row_rel, col_rel = res - is_rel = row_rel or col_rel - any_rel = any_rel or is_rel - coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1) - any_err |= shx1 < -1 - if blah: print >> bk.logfile, " ", coords - res = Operand(oUNK, None) - if is_rel: - relflags = (0, 0, row_rel, row_rel, col_rel, col_rel) - ref3d = Ref3D(coords + relflags) - res.kind = oREL - res.text = rangename3drel(bk, ref3d) - else: - ref3d = Ref3D(coords) - res.kind = oREF - res.text = rangename3d(bk, ref3d) - res.rank = LEAF_RANK - res.value = None - spush(res) - elif opcode == 0x1B: # tArea3d - if bv >= 80: - res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) - refx = unpack("<H", data[pos+1:pos+3])[0] - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - else: - res1, res2 = get_cell_range_addr(data, pos+15, bv, reldelta) - raw_extshtx, raw_shx1, raw_shx2 = \ - unpack("<hxxxxxxxxhh", data[pos+1:pos+15]) - if blah: - print >> bk.logfile, "tArea3d", raw_extshtx, raw_shx1, raw_shx2 - shx1, shx2 = get_externsheet_local_range_b57( - bk, raw_extshtx, raw_shx1, raw_shx2, blah) - any_err |= shx1 < -1 - rowx1, colx1, row_rel1, col_rel1 = res1 - rowx2, colx2, row_rel2, col_rel2 = res2 - is_rel = row_rel1 or col_rel1 or row_rel2 or col_rel2 - any_rel = any_rel or is_rel - coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1) - if blah: print >> bk.logfile, " ", coords - res = Operand(oUNK, None) - if is_rel: - relflags = (0, 0, row_rel1, row_rel2, col_rel1, col_rel2) - ref3d = Ref3D(coords + relflags) - res.kind = oREL - res.text = rangename3drel(bk, ref3d) - else: - ref3d = Ref3D(coords) - res.kind = oREF - res.text = rangename3d(bk, ref3d) - res.rank = LEAF_RANK - spush(res) - elif opcode == 0x19: # tNameX - dodgy = 0 - res = Operand(oUNK, None) - if bv >= 80: - refx, tgtnamex = unpack("<HH", data[pos+1:pos+5]) - tgtnamex -= 1 - origrefx = refx - else: - refx, tgtnamex = unpack("<hxxxxxxxxH", data[pos+1:pos+13]) - tgtnamex -= 1 - origrefx = refx - if refx > 0: - refx -= 1 - elif refx < 0: - refx = -refx - 1 - else: - dodgy = 1 - if blah: - print >> bk.logfile, \ - " origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \ - % (origrefx, refx, tgtnamex, dodgy) - # if tgtnamex == namex: - # if blah: print >> bk.logfile, "!!!! Self-referential !!!!" - # dodgy = any_err = 1 - if not dodgy: - if bv >= 80: - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - elif origrefx > 0: - shx1, shx2 = (-4, -4) # external ref - else: - exty = bk._externsheet_type_b57[refx] - if exty == 4: # non-specific sheet in own doc't - shx1, shx2 = (-1, -1) # internal, any sheet - else: - shx1, shx2 = (-666, -666) - okind = oUNK - ovalue = None - if shx1 == -5: # addin func name - okind = oSTRG - ovalue = bk.addin_func_names[tgtnamex] - otext = '"' + ovalue.replace('"', '""') + '"' - elif dodgy or shx1 < -1: - otext = "<<Name #%d in external(?) file #%d>>" \ - % (tgtnamex, origrefx) - else: - tgtobj = bk.name_obj_list[tgtnamex] - if tgtobj.scope == -1: - otext = tgtobj.name - else: - otext = "%s!%s" \ - % (bk._sheet_names[tgtobj.scope], tgtobj.name) - if blah: - print >> bk.logfile, " tNameX: setting text to", repr(res.text) - res = Operand(okind, ovalue, LEAF_RANK, otext) - spush(res) - elif is_error_opcode(opcode): - any_err = 1 - spush(error_opnd) - else: - if blah: - print >> bk.logfile, "FORMULA: /// Not handled yet: t" + oname - any_err = 1 - if sz <= 0: - raise FormulaError("Fatal: token size is not positive") - pos += sz - any_rel = not not any_rel - if blah: - print "End of formula. level=%d any_rel=%d any_err=%d stack=%r" % \ - (level, not not any_rel, any_err, stack) - if len(stack) >= 2: - print "*** Stack has unprocessed args" - print - - if len(stack) != 1: - result = None - else: - result = stack[0].text - return result - -#### under deconstruction ### -def dump_formula(bk, data, fmlalen, bv, reldelta, blah=0, isname=0): - if blah: - print "dump_formula", fmlalen, bv, len(data) - hex_char_dump(data, 0, fmlalen) - assert bv >= 80 #### this function needs updating #### - sztab = szdict[bv] - pos = 0 - stack = [] - any_rel = 0 - any_err = 0 - spush = stack.append - while 0 <= pos < fmlalen: - op = ord(data[pos]) - opcode = op & 0x1f - optype = (op & 0x60) >> 5 - if optype: - opx = opcode + 32 - else: - opx = opcode - oname = onames[opx] # + [" RVA"][optype] - - sz = sztab[opx] - if blah: - print "Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \ - % (pos, op, oname, sz, opcode, optype) - if not optype: - if 0x01 <= opcode <= 0x02: # tExp, tTbl - # reference to a shared formula or table record - rowx, colx = unpack("<HH", data[pos+1:pos+5]) - if blah: print >> bk.logfile, " ", (rowx, colx) - elif opcode == 0x10: # tList - if blah: print >> bk.logfile, "tList pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - spush(aop + bop) - if blah: print >> bk.logfile, "tlist post", stack - elif opcode == 0x11: # tRange - if blah: print >> bk.logfile, "tRange pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - assert len(aop) == 1 - assert len(bop) == 1 - result = do_box_funcs(tRangeFuncs, aop[0], bop[0]) - spush(result) - if blah: print >> bk.logfile, "tRange post", stack - elif opcode == 0x0F: # tIsect - if blah: print >> bk.logfile, "tIsect pre", stack - assert len(stack) >= 2 - bop = stack.pop() - aop = stack.pop() - assert len(aop) == 1 - assert len(bop) == 1 - result = do_box_funcs(tIsectFuncs, aop[0], bop[0]) - spush(result) - if blah: print >> bk.logfile, "tIsect post", stack - elif opcode == 0x19: # tAttr - subop, nc = unpack("<BH", data[pos+1:pos+4]) - subname = tAttrNames.get(subop, "??Unknown??") - if subop == 0x04: # Choose - sz = nc * 2 + 6 - else: - sz = 4 - if blah: print >> bk.logfile, " subop=%02xh subname=t%s sz=%d nc=%02xh" % (subop, subname, sz, nc) - elif opcode == 0x17: # tStr - if bv <= 70: - nc = ord(data[pos+1]) - strg = data[pos+2:pos+2+nc] # left in 8-bit encoding - sz = nc + 2 - else: - strg, newpos = unpack_unicode_update_pos(data, pos+1, lenlen=1) - sz = newpos - pos - if blah: print >> bk.logfile, " sz=%d strg=%r" % (sz, strg) - else: - if sz <= 0: - print "**** Dud size; exiting ****" - return - pos += sz - continue - if opcode == 0x00: # tArray - pass - elif opcode == 0x01: # tFunc - nb = 1 + int(bv >= 40) - funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb]) - if blah: print >> bk.logfile, " FuncID=%d" % funcx - elif opcode == 0x02: #tFuncVar - nb = 1 + int(bv >= 40) - nargs, funcx = unpack("<B" + " BH"[nb], data[pos+1:pos+2+nb]) - prompt, nargs = divmod(nargs, 128) - macro, funcx = divmod(funcx, 32768) - if blah: print >> bk.logfile, " FuncID=%d nargs=%d macro=%d prompt=%d" % (funcx, nargs, macro, prompt) - elif opcode == 0x03: #tName - namex = unpack("<H", data[pos+1:pos+3]) - # Only change with BIFF version is the number of trailing UNUSED bytes!!! - if blah: print >> bk.logfile, " namex=%d" % namex - elif opcode == 0x04: # tRef - res = get_cell_addr(data, pos+1, bv, reldelta) - if blah: print >> bk.logfile, " ", res - elif opcode == 0x05: # tArea - res = get_cell_range_addr(data, pos+1, bv, reldelta) - if blah: print >> bk.logfile, " ", res - elif opcode == 0x09: # tMemFunc - nb = unpack("<H", data[pos+1:pos+3])[0] - if blah: print >> bk.logfile, " %d bytes of cell ref formula" % nb - elif opcode == 0x0C: #tRefN - res = get_cell_addr(data, pos+1, bv, reldelta=1) - # note *ALL* tRefN usage has signed offset for relative addresses - any_rel = 1 - if blah: print >> bk.logfile, " ", res - elif opcode == 0x0D: #tAreaN - res = get_cell_range_addr(data, pos+1, bv, reldelta=1) - # note *ALL* tAreaN usage has signed offset for relative addresses - any_rel = 1 - if blah: print >> bk.logfile, " ", res - elif opcode == 0x1A: # tRef3d - refx = unpack("<H", data[pos+1:pos+3])[0] - res = get_cell_addr(data, pos+3, bv, reldelta) - if blah: print >> bk.logfile, " ", refx, res - rowx, colx, row_rel, col_rel = res - any_rel = any_rel or row_rel or col_rel - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - any_err |= shx1 < -1 - coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1) - if blah: print >> bk.logfile, " ", coords - if optype == 1: spush([coords]) - elif opcode == 0x1B: # tArea3d - refx = unpack("<H", data[pos+1:pos+3])[0] - res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta) - if blah: print >> bk.logfile, " ", refx, res1, res2 - rowx1, colx1, row_rel1, col_rel1 = res1 - rowx2, colx2, row_rel2, col_rel2 = res2 - any_rel = any_rel or row_rel1 or col_rel1 or row_rel2 or col_rel2 - shx1, shx2 = get_externsheet_local_range(bk, refx, blah) - any_err |= shx1 < -1 - coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1) - if blah: print >> bk.logfile, " ", coords - if optype == 1: spush([coords]) - elif opcode == 0x19: # tNameX - refx, namex = unpack("<HH", data[pos+1:pos+5]) - if blah: print >> bk.logfile, " refx=%d namex=%d" % (refx, namex) - elif is_error_opcode(opcode): - any_err = 1 - else: - if blah: print >> bk.logfile, "FORMULA: /// Not handled yet: t" + oname - any_err = 1 - if sz <= 0: - print "**** Dud size; exiting ****" - return - pos += sz - if blah: - print >> bk.logfile, "End of formula. any_rel=%d any_err=%d stack=%r" % \ - (not not any_rel, any_err, stack) - if len(stack) >= 2: - print >> bk.logfile, "*** Stack has unprocessed args" - -# === Some helper functions for displaying cell references === - -# Note that a "non-standard" syntax is used in row and column -# components in relative references. -# For example, consider a relative reference: up two rows, right 3 columns. -# On screen, with cursor in cell D10, this would appear as G8. -# On screen, with cursor in cell Z100, this would appear as AC98. -# On screen, with cursor in cell A1, this would appear as D65535. -# These functions will display such a reference as [@+3,#-2]. -# "@" refers to the unknown base column. -# "#" refers to the unknown base row. -# -# I'm aware of only one possibility of a sheet-relative component in -# a reference: a 2D reference located in the "current sheet". -# xlrd stores this internally with bounds of (0, 1, ...) and -# relative flags of (1, 1, ...). These functions display the -# sheet component as empty, just like Excel etc. - -def rownamerel(rowx, rowxrel): - if not rowxrel: - return "$%d" % rowx - if rowx > 0: - return "#+%d" % rowx - if rowx < 0: - return "#-%d" % (-rowx) - return "#" - -def colnamerel(colx, colxrel): - if not colxrel: - return "$" + colname(colx) - if colx > 0: - return "@+%d" % colx - if colx < 0: - return "@-%d" % (-colx) - return "@" -## -# Utility function: (5, 7) => 'H6' -def cellname(rowx, colx): - """ (5, 7) => 'H6' """ - return "%s%d" % (colname(colx), rowx+1) - -## -# Utility function: (5, 7) => '$H$6' -def cellnameabs(rowx, colx): - """ (5, 7) => '$H$6' """ - return "$%s$%d" % (colname(colx), rowx+1) - -def cellnamerel(rowx, colx, rowxrel, colxrel): - if not rowxrel and not colxrel: - return cellnameabs(rowx, colx) - return "[%s,%s]" % ( - colnamerel(colx, colxrel), - rownamerel(rowx, rowxrel)) -## -# Utility function: 7 => 'H', 27 => 'AB' -def colname(colx): - """ 7 => 'H', 27 => 'AB' """ - alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - if colx <= 25: - return alphabet[colx] - else: - xdiv26, xmod26 = divmod(colx, 26) - return alphabet[xdiv26 - 1] + alphabet[xmod26] - -def rangename2d(rlo, rhi, clo, chi): - """ (5, 20, 7, 10) => '$H$6:$J$20' """ - if rhi == rlo+1 and chi == clo+1: - return cellnameabs(rlo, clo) - return "%s:%s" % (cellnameabs(rlo, clo), cellnameabs(rhi-1, chi-1)) - -def rangename2drel((rlo, rhi, clo, chi), (rlorel, rhirel, clorel, chirel)): - return "%s:%s" % ( - cellnamerel(rlo, clo, rlorel, clorel), - cellnamerel(rhi-1, chi-1, rhirel, chirel) - ) -## -# Utility function: -# <br /> Ref3D((1, 4, 5, 20, 7, 10)) => 'Sheet2:Sheet3!$H$6:$J$20' -def rangename3d(book, ref3d): - """ Ref3D(1, 4, 5, 20, 7, 10) => 'Sheet2:Sheet3!$H$6:$J$20' - (assuming Excel's default sheetnames) """ - coords = ref3d.coords - return "%s!%s" % ( - sheetrange(book, *coords[:2]), - rangename2d(*coords[2:6])) - -## -# Utility function: -# <br /> Ref3D(coords=(0, 1, -32, -22, -13, 13), relflags=(0, 0, 1, 1, 1, 1)) -# => 'Sheet1![@-13,#-32]:[@+12,#-23]' -# where '@' refers to the current or base column and '#' -# refers to the current or base row. -def rangename3drel(book, ref3d): - coords = ref3d.coords - relflags = ref3d.relflags - shdesc = sheetrangerel(book, coords[:2], relflags[:2]) - rngdesc = rangename2drel(coords[2:6], relflags[2:6]) - if not shdesc: - return rngdesc - return "%s!%s" % (shdesc, rngdesc) - -def quotedsheetname(shnames, shx): - if shx >= 0: - shname = shnames[shx] - else: - shname = { - -1: "?internal; any sheet?", - -2: "internal; deleted sheet", - -3: "internal; macro sheet", - -4: "<<external>>", - }.get(shx, "?error %d?" % shx) - if "'" in shname: - return "'" + shname.replace("'", "''") + "'" - if " " in shname: - return "'" + shname + "'" - return shname - -def sheetrange(book, slo, shi): - shnames = book.sheet_names() - shdesc = quotedsheetname(shnames, slo) - if slo != shi-1: - shdesc += ":" + quotedsheetname(shnames, shi-1) - return shdesc - -def sheetrangerel(book, (slo, shi), (slorel, shirel)): - if not slorel and not shirel: - return sheetrange(book, slo, shi) - assert (slo == 0 == shi-1) and slorel and shirel - return "" - -# ============================================================== diff --git a/tablib/packages/xlrd/licences.py b/tablib/packages/xlrd/licences.py deleted file mode 100644 index 1e262a9..0000000 --- a/tablib/packages/xlrd/licences.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: cp1252 -*- - -""" -Portions copyright © 2005-2009, Stephen John Machin, Lingfo Pty Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. None of the names of Stephen John Machin, Lingfo Pty Ltd and any -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -THE POSSIBILITY OF SUCH DAMAGE. -""" - -""" -/*- - * Copyright (c) 2001 David Giffin. - * All rights reserved. - * - * Based on the the Java version: Andrew Khan Copyright (c) 2000. - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by - * David Giffin <david@giffin.org>." - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by - * David Giffin <david@giffin.org>." - * - * THIS SOFTWARE IS PROVIDED BY DAVID GIFFIN ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID GIFFIN OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ -""" diff --git a/tablib/packages/xlrd/sheet.py b/tablib/packages/xlrd/sheet.py deleted file mode 100644 index 70f7779..0000000 --- a/tablib/packages/xlrd/sheet.py +++ /dev/null @@ -1,1768 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# <p> Portions copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p> -## - -# 2009-05-31 SJM Fixed problem with no CODEPAGE record on extremely minimal BIFF2.x 3rd-party file -# 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo -# 2008-02-09 SJM Excel 2.0: build XFs on the fly from cell attributes -# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files. -# 2007-10-11 SJM Added missing entry for blank cell type to ctype_text -# 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file -# 2007-04-22 SJM Remove experimental "trimming" facility. - -from biffh import * -from timemachine import * -from struct import unpack -from formula import dump_formula, decompile_formula, rangename2d -from formatting import nearest_colour_index, Format -import time - -DEBUG = 0 -OBJ_MSO_DEBUG = 0 - -_WINDOW2_options = ( - # Attribute names and initial values to use in case - # a WINDOW2 record is not written. - ("show_formulas", 0), - ("show_grid_lines", 1), - ("show_sheet_headers", 1), - ("panes_are_frozen", 0), - ("show_zero_values", 1), - ("automatic_grid_line_colour", 1), - ("columns_from_right_to_left", 0), - ("show_outline_symbols", 1), - ("remove_splits_if_pane_freeze_is_removed", 0), - ("sheet_selected", 0), - # "sheet_visible" appears to be merely a clone of "sheet_selected". - # The real thing is the visibility attribute from the BOUNDSHEET record. - ("sheet_visible", 0), - ("show_in_page_break_preview", 0), - ) - -## -# <p>Contains the data for one worksheet.</p> -# -# <p>In the cell access functions, "rowx" is a row index, counting from zero, and "colx" is a -# column index, counting from zero. -# Negative values for row/column indexes and slice positions are supported in the expected fashion.</p> -# -# <p>For information about cell types and cell values, refer to the documentation of the Cell class.</p> -# -# <p>WARNING: You don't call this class yourself. You access Sheet objects via the Book object that -# was returned when you called xlrd.open_workbook("myfile.xls").</p> - - -class Sheet(BaseObject): - ## - # Name of sheet. - name = '' - - ## - # Number of rows in sheet. A row index is in range(thesheet.nrows). - nrows = 0 - - ## - # Number of columns in sheet. A column index is in range(thesheet.ncols). - ncols = 0 - - ## - # The map from a column index to a Colinfo object. Often there is an entry - # in COLINFO records for all column indexes in range(257). - # Note that xlrd ignores the entry for the non-existent - # 257th column. On the other hand, there may be no entry for unused columns. - # <br /> -- New in version 0.6.1 - colinfo_map = {} - - ## - # The map from a row index to a Rowinfo object. Note that it is possible - # to have missing entries -- at least one source of XLS files doesn't - # bother writing ROW records. - # <br /> -- New in version 0.6.1 - rowinfo_map = {} - - ## - # List of address ranges of cells containing column labels. - # These are set up in Excel by Insert > Name > Labels > Columns. - # <br> -- New in version 0.6.0 - # <br>How to deconstruct the list: - # <pre> - # for crange in thesheet.col_label_ranges: - # rlo, rhi, clo, chi = crange - # for rx in xrange(rlo, rhi): - # for cx in xrange(clo, chi): - # print "Column label at (rowx=%d, colx=%d) is %r" \ - # (rx, cx, thesheet.cell_value(rx, cx)) - # </pre> - col_label_ranges = [] - - ## - # List of address ranges of cells containing row labels. - # For more details, see <i>col_label_ranges</i> above. - # <br> -- New in version 0.6.0 - row_label_ranges = [] - - ## - # List of address ranges of cells which have been merged. - # These are set up in Excel by Format > Cells > Alignment, then ticking - # the "Merge cells" box. - # <br> -- New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True) - # <br>How to deconstruct the list: - # <pre> - # for crange in thesheet.merged_cells: - # rlo, rhi, clo, chi = crange - # for rowx in xrange(rlo, rhi): - # for colx in xrange(clo, chi): - # # cell (rlo, clo) (the top left one) will carry the data - # # and formatting info; the remainder will be recorded as - # # blank cells, but a renderer will apply the formatting info - # # for the top left cell (e.g. border, pattern) to all cells in - # # the range. - # </pre> - merged_cells = [] - - ## - # Default column width from DEFCOLWIDTH record, else None. - # From the OOo docs:<br /> - # """Column width in characters, using the width of the zero character - # from default font (first FONT record in the file). Excel adds some - # extra space to the default width, depending on the default font and - # default font size. The algorithm how to exactly calculate the resulting - # column width is not known.<br /> - # Example: The default width of 8 set in this record results in a column - # width of 8.43 using Arial font with a size of 10 points."""<br /> - # For the default hierarchy, refer to the Colinfo class above. - # <br /> -- New in version 0.6.1 - defcolwidth = None - - ## - # Default column width from STANDARDWIDTH record, else None. - # From the OOo docs:<br /> - # """Default width of the columns in 1/256 of the width of the zero - # character, using default font (first FONT record in the file)."""<br /> - # For the default hierarchy, refer to the Colinfo class above. - # <br /> -- New in version 0.6.1 - standardwidth = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the <i>optional</i> DEFAULTROWHEIGHT record. - default_row_height = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the <i>optional</i> DEFAULTROWHEIGHT record. - default_row_height_mismatch = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the <i>optional</i> DEFAULTROWHEIGHT record. - default_row_hidden = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the <i>optional</i> DEFAULTROWHEIGHT record. - default_additional_space_above = None - - ## - # Default value to be used for a row if there is - # no ROW record for that row. - # From the <i>optional</i> DEFAULTROWHEIGHT record. - default_additional_space_below = None - - ## - # Visibility of the sheet. 0 = visible, 1 = hidden (can be unhidden - # by user -- Format/Sheet/Unhide), 2 = "very hidden" (can be unhidden - # only by VBA macro). - visibility = 0 - - ## - # A 256-element tuple corresponding to the contents of the GCW record for this sheet. - # If no such record, treat as all bits zero. - # Applies to BIFF4-7 only. See docs of Colinfo class for discussion. - gcw = (0, ) * 256 - - def __init__(self, book, position, name, number): - self.book = book - self.biff_version = book.biff_version - self._position = position - self.logfile = book.logfile - self.pickleable = book.pickleable - self.dont_use_array = not(array_array and (CAN_PICKLE_ARRAY or not book.pickleable)) - self.name = name - self.number = number - self.verbosity = book.verbosity - self.formatting_info = book.formatting_info - self._xf_index_to_xl_type_map = book._xf_index_to_xl_type_map - self.nrows = 0 # actual, including possibly empty cells - self.ncols = 0 - self._maxdatarowx = -1 # highest rowx containing a non-empty cell - self._maxdatacolx = -1 # highest colx containing a non-empty cell - self._dimnrows = 0 # as per DIMENSIONS record - self._dimncols = 0 - self._cell_values = [] - self._cell_types = [] - self._cell_xf_indexes = [] - self._need_fix_ragged_rows = 0 - self.defcolwidth = None - self.standardwidth = None - self.default_row_height = None - self.default_row_height_mismatch = 0 - self.default_row_hidden = 0 - self.default_additional_space_above = 0 - self.default_additional_space_below = 0 - self.colinfo_map = {} - self.rowinfo_map = {} - self.col_label_ranges = [] - self.row_label_ranges = [] - self.merged_cells = [] - self._xf_index_stats = [0, 0, 0, 0] - self.visibility = book._sheet_visibility[number] # from BOUNDSHEET record - for attr, defval in _WINDOW2_options: - setattr(self, attr, defval) - self.first_visible_rowx = 0 - self.first_visible_colx = 0 - self.gridline_colour_index = 0x40 - self.gridline_colour_rgb = None # pre-BIFF8 - self.cached_page_break_preview_mag_factor = 0 - self.cached_normal_view_mag_factor = 0 - self._ixfe = None # BIFF2 only - self._cell_attr_to_xfx = {} # BIFF2.0 only - - #### Don't initialise this here, use class attribute initialisation. - #### self.gcw = (0, ) * 256 #### - - if self.biff_version >= 80: - self.utter_max_rows = 65536 - else: - self.utter_max_rows = 16384 - self.utter_max_cols = 256 - - ## - # Cell object in the given row and column. - def cell(self, rowx, colx): - if self.formatting_info: - xfx = self.cell_xf_index(rowx, colx) - else: - xfx = None - return Cell( - self._cell_types[rowx][colx], - self._cell_values[rowx][colx], - xfx, - ) - - ## - # Value of the cell in the given row and column. - def cell_value(self, rowx, colx): - return self._cell_values[rowx][colx] - - ## - # Type of the cell in the given row and column. - # Refer to the documentation of the Cell class. - def cell_type(self, rowx, colx): - return self._cell_types[rowx][colx] - - ## - # XF index of the cell in the given row and column. - # This is an index into Book.xf_list. - # <br /> -- New in version 0.6.1 - def cell_xf_index(self, rowx, colx): - self.req_fmt_info() - xfx = self._cell_xf_indexes[rowx][colx] - if xfx > -1: - self._xf_index_stats[0] += 1 - return xfx - # Check for a row xf_index - try: - xfx = self.rowinfo_map[rowx].xf_index - if xfx > -1: - self._xf_index_stats[1] += 1 - return xfx - except KeyError: - pass - # Check for a column xf_index - try: - xfx = self.colinfo_map[colx].xf_index - assert xfx > -1 - self._xf_index_stats[2] += 1 - return xfx - except KeyError: - # If all else fails, 15 is used as hardwired global default xf_index. - self._xf_index_stats[3] += 1 - return 15 - - ## - # Returns a sequence of the Cell objects in the given row. - def row(self, rowx): - return [ - self.cell(rowx, colx) - for colx in xrange(self.ncols) - ] - - ## - # Returns a slice of the types - # of the cells in the given row. - def row_types(self, rowx, start_colx=0, end_colx=None): - if end_colx is None: - return self._cell_types[rowx][start_colx:] - return self._cell_types[rowx][start_colx:end_colx] - - ## - # Returns a slice of the values - # of the cells in the given row. - def row_values(self, rowx, start_colx=0, end_colx=None): - if end_colx is None: - return self._cell_values[rowx][start_colx:] - return self._cell_values[rowx][start_colx:end_colx] - - ## - # Returns a slice of the Cell objects in the given row. - def row_slice(self, rowx, start_colx=0, end_colx=None): - nc = self.ncols - if start_colx < 0: - start_colx += nc - if start_colx < 0: - start_colx = 0 - if end_colx is None or end_colx > nc: - end_colx = nc - elif end_colx < 0: - end_colx += nc - return [ - self.cell(rowx, colx) - for colx in xrange(start_colx, end_colx) - ] - - ## - # Returns a slice of the Cell objects in the given column. - def col_slice(self, colx, start_rowx=0, end_rowx=None): - nr = self.nrows - if start_rowx < 0: - start_rowx += nr - if start_rowx < 0: - start_rowx = 0 - if end_rowx is None or end_rowx > nr: - end_rowx = nr - elif end_rowx < 0: - end_rowx += nr - return [ - self.cell(rowx, colx) - for rowx in xrange(start_rowx, end_rowx) - ] - - ## - # Returns a slice of the values of the cells in the given column. - def col_values(self, colx, start_rowx=0, end_rowx=None): - nr = self.nrows - if start_rowx < 0: - start_rowx += nr - if start_rowx < 0: - start_rowx = 0 - if end_rowx is None or end_rowx > nr: - end_rowx = nr - elif end_rowx < 0: - end_rowx += nr - return [ - self._cell_values[rowx][colx] - for rowx in xrange(start_rowx, end_rowx) - ] - - ## - # Returns a slice of the types of the cells in the given column. - def col_types(self, colx, start_rowx=0, end_rowx=None): - nr = self.nrows - if start_rowx < 0: - start_rowx += nr - if start_rowx < 0: - start_rowx = 0 - if end_rowx is None or end_rowx > nr: - end_rowx = nr - elif end_rowx < 0: - end_rowx += nr - return [ - self._cell_types[rowx][colx] - for rowx in xrange(start_rowx, end_rowx) - ] - - ## - # Returns a sequence of the Cell objects in the given column. - def col(self, colx): - return self.col_slice(colx) - # Above two lines just for the docs. Here's the real McCoy: - col = col_slice - - # === Following methods are used in building the worksheet. - # === They are not part of the API. - - def extend_cells(self, nr, nc): - # print "extend_cells_2", self.nrows, self.ncols, nr, nc - assert 1 <= nc <= self.utter_max_cols - assert 1 <= nr <= self.utter_max_rows - if nr <= self.nrows: - # New cell is in an existing row, so extend that row (if necessary). - # Note that nr < self.nrows means that the cell data - # is not in ascending row order!! - self._need_fix_ragged_rows = 1 - nrx = nr - 1 - trow = self._cell_types[nrx] - tlen = len(trow) - nextra = max(nc, self.ncols) - tlen - if nextra > 0: - xce = XL_CELL_EMPTY - if self.dont_use_array: - trow.extend([xce] * nextra) - if self.formatting_info: - self._cell_xf_indexes[nrx].extend([-1] * nextra) - else: - aa = array_array - trow.extend(aa('B', [xce]) * nextra) - if self.formatting_info: - self._cell_xf_indexes[nrx].extend(aa('h', [-1]) * nextra) - self._cell_values[nrx].extend([''] * nextra) - if nc > self.ncols: - self.ncols = nc - self._need_fix_ragged_rows = 1 - if nr > self.nrows: - scta = self._cell_types.append - scva = self._cell_values.append - scxa = self._cell_xf_indexes.append - fmt_info = self.formatting_info - xce = XL_CELL_EMPTY - nc = self.ncols - if self.dont_use_array: - for _unused in xrange(self.nrows, nr): - scta([xce] * nc) - scva([''] * nc) - if fmt_info: - scxa([-1] * nc) - else: - aa = array_array - for _unused in xrange(self.nrows, nr): - scta(aa('B', [xce]) * nc) - scva([''] * nc) - if fmt_info: - scxa(aa('h', [-1]) * nc) - self.nrows = nr - - def fix_ragged_rows(self): - t0 = time.time() - ncols = self.ncols - xce = XL_CELL_EMPTY - aa = array_array - s_cell_types = self._cell_types - s_cell_values = self._cell_values - s_cell_xf_indexes = self._cell_xf_indexes - s_dont_use_array = self.dont_use_array - s_fmt_info = self.formatting_info - totrowlen = 0 - for rowx in xrange(self.nrows): - trow = s_cell_types[rowx] - rlen = len(trow) - totrowlen += rlen - nextra = ncols - rlen - if nextra > 0: - s_cell_values[rowx][rlen:] = [''] * nextra - if s_dont_use_array: - trow[rlen:] = [xce] * nextra - if s_fmt_info: - s_cell_xf_indexes[rowx][rlen:] = [-1] * nextra - else: - trow.extend(aa('B', [xce]) * nextra) - if s_fmt_info: - s_cell_xf_indexes[rowx][rlen:] = aa('h', [-1]) * nextra - self._fix_ragged_rows_time = time.time() - t0 - if 0 and self.nrows: - avgrowlen = float(totrowlen) / self.nrows - print >> self.logfile, \ - "sheet %d: avg row len %.1f; max row len %d" \ - % (self.number, avgrowlen, self.ncols) - - def tidy_dimensions(self): - if self.verbosity >= 3: - fprintf(self.logfile, - "tidy_dimensions: nrows=%d ncols=%d _need_fix_ragged_rows=%d\n", - self.nrows, self.ncols, self._need_fix_ragged_rows, - ) - if 1 and self.merged_cells: - nr = nc = 0 - umaxrows = self.utter_max_rows - umaxcols = self.utter_max_cols - for crange in self.merged_cells: - rlo, rhi, clo, chi = crange - if not (0 <= rlo < rhi <= umaxrows) \ - or not (0 <= clo < chi <= umaxcols): - fprintf(self.logfile, - "*** WARNING: sheet #%d (%r), MERGEDCELLS bad range %r\n", - self.number, self.name, crange) - if rhi > nr: nr = rhi - if chi > nc: nc = chi - self.extend_cells(nr, nc) - if self.verbosity >= 1 \ - and (self.nrows != self._dimnrows or self.ncols != self._dimncols): - fprintf(self.logfile, - "NOTE *** sheet %d (%r): DIMENSIONS R,C = %d,%d should be %d,%d\n", - self.number, - self.name, - self._dimnrows, - self._dimncols, - self.nrows, - self.ncols, - ) - if self._need_fix_ragged_rows: - self.fix_ragged_rows() - - def put_cell(self, rowx, colx, ctype, value, xf_index): - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - if self.formatting_info: - self._cell_xf_indexes[rowx][colx] = xf_index - except IndexError: - # print >> self.logfile, "put_cell extending", rowx, colx - self.extend_cells(rowx+1, colx+1) - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - if self.formatting_info: - self._cell_xf_indexes[rowx][colx] = xf_index - except: - print >> self.logfile, "put_cell", rowx, colx - raise - except: - print >> self.logfile, "put_cell", rowx, colx - raise - - def put_blank_cell(self, rowx, colx, xf_index): - # This is used for cells from BLANK and MULBLANK records - ctype = XL_CELL_BLANK - value = '' - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - self._cell_xf_indexes[rowx][colx] = xf_index - except IndexError: - # print >> self.logfile, "put_cell extending", rowx, colx - self.extend_cells(rowx+1, colx+1) - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - self._cell_xf_indexes[rowx][colx] = xf_index - except: - print >> self.logfile, "put_cell", rowx, colx - raise - except: - print >> self.logfile, "put_cell", rowx, colx - raise - - def put_number_cell(self, rowx, colx, value, xf_index): - ctype = self._xf_index_to_xl_type_map[xf_index] - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - if self.formatting_info: - self._cell_xf_indexes[rowx][colx] = xf_index - except IndexError: - # print >> self.logfile, "put_number_cell extending", rowx, colx - self.extend_cells(rowx+1, colx+1) - try: - self._cell_types[rowx][colx] = ctype - self._cell_values[rowx][colx] = value - if self.formatting_info: - self._cell_xf_indexes[rowx][colx] = xf_index - except: - print >> self.logfile, "put_number_cell", rowx, colx - raise - except: - print >> self.logfile, "put_number_cell", rowx, colx - raise - - # === Methods after this line neither know nor care about how cells are stored. - - def read(self, bk): - global rc_stats - DEBUG = 0 - blah = DEBUG or self.verbosity >= 2 - blah_rows = DEBUG or self.verbosity >= 4 - blah_formulas = 1 and blah - oldpos = bk._position - bk._position = self._position - XL_SHRFMLA_ETC_ETC = ( - XL_SHRFMLA, XL_ARRAY, XL_TABLEOP, XL_TABLEOP2, - XL_ARRAY2, XL_TABLEOP_B2, - ) - self_put_number_cell = self.put_number_cell - self_put_cell = self.put_cell - self_put_blank_cell = self.put_blank_cell - local_unpack = unpack - bk_get_record_parts = bk.get_record_parts - bv = self.biff_version - fmt_info = self.formatting_info - eof_found = 0 - while 1: - # if DEBUG: print "SHEET.READ: about to read from position %d" % bk._position - rc, data_len, data = bk_get_record_parts() - # if rc in rc_stats: - # rc_stats[rc] += 1 - # else: - # rc_stats[rc] = 1 - # if DEBUG: print "SHEET.READ: op 0x%04x, %d bytes %r" % (rc, data_len, data) - if rc == XL_NUMBER: - rowx, colx, xf_index, d = local_unpack('<HHHd', data) - # if xf_index == 0: - # fprintf(self.logfile, - # "NUMBER: r=%d c=%d xfx=%d %f\n", rowx, colx, xf_index, d) - self_put_number_cell(rowx, colx, d, xf_index) - elif rc == XL_LABELSST: - rowx, colx, xf_index, sstindex = local_unpack('<HHHi', data) - # print "LABELSST", rowx, colx, sstindex, bk._sharedstrings[sstindex] - self_put_cell(rowx, colx, XL_CELL_TEXT, bk._sharedstrings[sstindex], xf_index) - elif rc == XL_LABEL or rc == XL_RSTRING: - # RSTRING has extra richtext info at the end, but we ignore it. - rowx, colx, xf_index = local_unpack('<HHH', data[0:6]) - if bv < BIFF_FIRST_UNICODE: - strg = unpack_string(data, 6, bk.encoding or bk.derive_encoding, lenlen=2) - else: - strg = unpack_unicode(data, 6, lenlen=2) - self_put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index) - elif rc == XL_RK: - rowx, colx, xf_index = local_unpack('<HHH', data[:6]) - d = unpack_RK(data[6:10]) - self_put_number_cell(rowx, colx, d, xf_index) - elif rc == XL_MULRK: - mulrk_row, mulrk_first = local_unpack('<HH', data[0:4]) - mulrk_last, = local_unpack('<H', data[-2:]) - pos = 4 - for colx in xrange(mulrk_first, mulrk_last+1): - xf_index, = local_unpack('<H', data[pos:pos+2]) - d = unpack_RK(data[pos+2:pos+6]) - pos += 6 - self_put_number_cell(mulrk_row, colx, d, xf_index) - elif rc == XL_ROW: - # Version 0.6.0a3: ROW records are just not worth using (for memory allocation). - # Version 0.6.1: now used for formatting info. - if not fmt_info: continue - rowx, bits1, bits2 = local_unpack('<H4xH4xi', data[0:16]) - if not(0 <= rowx < self.utter_max_rows): - print >> self.logfile, \ - "*** NOTE: ROW record has row index %d; " \ - "should have 0 <= rowx < %d -- record ignored!" \ - % (rowx, self.utter_max_rows) - continue - r = Rowinfo() - # Using upkbits() is far too slow on a file - # with 30 sheets each with 10K rows :-( - # upkbits(r, bits1, ( - # ( 0, 0x7FFF, 'height'), - # (15, 0x8000, 'has_default_height'), - # )) - # upkbits(r, bits2, ( - # ( 0, 0x00000007, 'outline_level'), - # ( 4, 0x00000010, 'outline_group_starts_ends'), - # ( 5, 0x00000020, 'hidden'), - # ( 6, 0x00000040, 'height_mismatch'), - # ( 7, 0x00000080, 'has_default_xf_index'), - # (16, 0x0FFF0000, 'xf_index'), - # (28, 0x10000000, 'additional_space_above'), - # (29, 0x20000000, 'additional_space_below'), - # )) - # So: - r.height = bits1 & 0x7fff - r.has_default_height = (bits1 >> 15) & 1 - r.outline_level = bits2 & 7 - r.outline_group_starts_ends = (bits2 >> 4) & 1 - r.hidden = (bits2 >> 5) & 1 - r.height_mismatch = (bits2 >> 6) & 1 - r.has_default_xf_index = (bits2 >> 7) & 1 - r.xf_index = (bits2 >> 16) & 0xfff - r.additional_space_above = (bits2 >> 28) & 1 - r.additional_space_below = (bits2 >> 29) & 1 - if not r.has_default_xf_index: - r.xf_index = -1 - self.rowinfo_map[rowx] = r - if 0 and r.xf_index > -1: - fprintf(self.logfile, - "**ROW %d %d %d\n", - self.number, rowx, r.xf_index) - if blah_rows: - print >> self.logfile, 'ROW', rowx, bits1, bits2 - r.dump(self.logfile, - header="--- sh #%d, rowx=%d ---" % (self.number, rowx)) - elif rc in XL_FORMULA_OPCODES: # 06, 0206, 0406 - # DEBUG = 1 - # if DEBUG: print "FORMULA: rc: 0x%04x data: %r" % (rc, data) - if bv >= 50: - rowx, colx, xf_index, result_str, flags = local_unpack('<HHH8sH', data[0:16]) - lenlen = 2 - tkarr_offset = 20 - elif bv >= 30: - rowx, colx, xf_index, result_str, flags = local_unpack('<HHH8sH', data[0:16]) - lenlen = 2 - tkarr_offset = 16 - else: # BIFF2 - rowx, colx, cell_attr, result_str, flags = local_unpack('<HH3s8sB', data[0:16]) - xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx, colx) - lenlen = 1 - tkarr_offset = 16 - if blah_formulas: # testing formula dumper - #### XXXX FIXME - fprintf(self.logfile, "FORMULA: rowx=%d colx=%d\n", rowx, colx) - fmlalen = local_unpack("<H", data[20:22])[0] - decompile_formula(bk, data[22:], fmlalen, - reldelta=0, browx=rowx, bcolx=colx, blah=1) - if result_str[6:8] == "\xFF\xFF": - if result_str[0] == '\x00': - # need to read next record (STRING) - gotstring = 0 - # if flags & 8: - if 1: # "flags & 8" applies only to SHRFMLA - # actually there's an optional SHRFMLA or ARRAY etc record to skip over - rc2, data2_len, data2 = bk.get_record_parts() - if rc2 == XL_STRING or rc2 == XL_STRING_B2: - gotstring = 1 - elif rc2 == XL_ARRAY: - row1x, rownx, col1x, colnx, array_flags, tokslen = \ - local_unpack("<HHBBBxxxxxH", data2[:14]) - if blah_formulas: - fprintf(self.logfile, "ARRAY: %d %d %d %d %d\n", - row1x, rownx, col1x, colnx, array_flags) - dump_formula(bk, data2[14:], tokslen, bv, reldelta=0, blah=1) - elif rc2 == XL_SHRFMLA: - row1x, rownx, col1x, colnx, nfmlas, tokslen = \ - local_unpack("<HHBBxBH", data2[:10]) - if blah_formulas: - fprintf(self.logfile, "SHRFMLA (sub): %d %d %d %d %d\n", - row1x, rownx, col1x, colnx, nfmlas) - decompile_formula(bk, data2[10:], tokslen, reldelta=1, blah=1) - elif rc2 not in XL_SHRFMLA_ETC_ETC: - raise XLRDError( - "Expected SHRFMLA, ARRAY, TABLEOP* or STRING record; found 0x%04x" % rc2) - # if DEBUG: print "gotstring:", gotstring - # now for the STRING record - if not gotstring: - rc2, _unused_len, data2 = bk.get_record_parts() - if rc2 not in (XL_STRING, XL_STRING_B2): - raise XLRDError("Expected STRING record; found 0x%04x" % rc2) - # if DEBUG: print "STRING: data=%r BIFF=%d cp=%d" % (data2, self.biff_version, bk.encoding) - if self.biff_version < BIFF_FIRST_UNICODE: - strg = unpack_string(data2, 0, bk.encoding or bk.derive_encoding, lenlen=1 + int(bv > 20)) - else: - strg = unpack_unicode(data2, 0, lenlen=2) - self.put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index) - # if DEBUG: print "FORMULA strg %r" % strg - elif result_str[0] == '\x01': - # boolean formula result - value = ord(result_str[2]) - self.put_cell(rowx, colx, XL_CELL_BOOLEAN, value, xf_index) - elif result_str[0] == '\x02': - # Error in cell - value = ord(result_str[2]) - self.put_cell(rowx, colx, XL_CELL_ERROR, value, xf_index) - elif result_str[0] == '\x03': - # empty ... i.e. empty (zero-length) string, NOT an empty cell. - self.put_cell(rowx, colx, XL_CELL_TEXT, u"", xf_index) - else: - raise XLRDError("unexpected special case (0x%02x) in FORMULA" % ord(result_str[0])) - else: - # it is a number - d = local_unpack('<d', result_str)[0] - self_put_number_cell(rowx, colx, d, xf_index) - elif rc == XL_BOOLERR: - rowx, colx, xf_index, value, is_err = local_unpack('<HHHBB', data[:8]) - # Note OOo Calc 2.0 writes 9-byte BOOLERR records. - # OOo docs say 8. Excel writes 8. - cellty = (XL_CELL_BOOLEAN, XL_CELL_ERROR)[is_err] - # if DEBUG: print "XL_BOOLERR", rowx, colx, xf_index, value, is_err - self.put_cell(rowx, colx, cellty, value, xf_index) - elif rc == XL_COLINFO: - if not fmt_info: continue - c = Colinfo() - first_colx, last_colx, c.width, c.xf_index, flags \ - = local_unpack("<HHHHH", data[:10]) - #### Colinfo.width is denominated in 256ths of a character, - #### *not* in characters. - if not(0 <= first_colx <= last_colx <= 256): - # Note: 256 instead of 255 is a common mistake. - # We silently ignore the non-existing 257th column in that case. - print >> self.logfile, \ - "*** NOTE: COLINFO record has first col index %d, last %d; " \ - "should have 0 <= first <= last <= 255 -- record ignored!" \ - % (first_colx, last_colx) - del c - continue - upkbits(c, flags, ( - ( 0, 0x0001, 'hidden'), - ( 1, 0x0002, 'bit1_flag'), - # *ALL* colinfos created by Excel in "default" cases are 0x0002!! - # Maybe it's "locked" by analogy with XFProtection data. - ( 8, 0x0700, 'outline_level'), - (12, 0x1000, 'collapsed'), - )) - for colx in xrange(first_colx, last_colx+1): - if colx > 255: break # Excel does 0 to 256 inclusive - self.colinfo_map[colx] = c - if 0: - fprintf(self.logfile, - "**COL %d %d %d\n", - self.number, colx, c.xf_index) - if blah: - fprintf( - self.logfile, - "COLINFO sheet #%d cols %d-%d: wid=%d xf_index=%d flags=0x%04x\n", - self.number, first_colx, last_colx, c.width, c.xf_index, flags, - ) - c.dump(self.logfile, header='===') - elif rc == XL_DEFCOLWIDTH: - self.defcolwidth, = local_unpack("<H", data[:2]) - if 0: print >> self.logfile, 'DEFCOLWIDTH', self.defcolwidth - elif rc == XL_STANDARDWIDTH: - if data_len != 2: - print >> self.logfile, '*** ERROR *** STANDARDWIDTH', data_len, repr(data) - self.standardwidth, = local_unpack("<H", data[:2]) - if 0: print >> self.logfile, 'STANDARDWIDTH', self.standardwidth - elif rc == XL_GCW: - if not fmt_info: continue # useless w/o COLINFO - assert data_len == 34 - assert data[0:2] == "\x20\x00" - iguff = unpack("<8i", data[2:34]) - gcw = [] - for bits in iguff: - for j in xrange(32): - gcw.append(bits & 1) - bits >>= 1 - self.gcw = tuple(gcw) - if 0: - showgcw = "".join(map(lambda x: "F "[x], gcw)).rstrip().replace(' ', '.') - print "GCW:", showgcw - elif rc == XL_BLANK: - if not fmt_info: continue - rowx, colx, xf_index = local_unpack('<HHH', data[:6]) - if 0: print >> self.logfile, "BLANK", rowx, colx, xf_index - self_put_blank_cell(rowx, colx, xf_index) - elif rc == XL_MULBLANK: # 00BE - if not fmt_info: continue - mul_row, mul_first = local_unpack('<HH', data[0:4]) - mul_last, = local_unpack('<H', data[-2:]) - if 0: - print >> self.logfile, "MULBLANK", mul_row, mul_first, mul_last - pos = 4 - for colx in xrange(mul_first, mul_last+1): - xf_index, = local_unpack('<H', data[pos:pos+2]) - pos += 2 - self_put_blank_cell(mul_row, colx, xf_index) - elif rc == XL_DIMENSION or rc == XL_DIMENSION2: - # if data_len == 10: - # Was crashing on BIFF 4.0 file w/o the two trailing unused bytes. - # Reported by Ralph Heimburger. - if bv < 80: - dim_tuple = local_unpack('<HxxH', data[2:8]) - else: - dim_tuple = local_unpack('<ixxH', data[4:12]) - self.nrows, self.ncols = 0, 0 - self._dimnrows, self._dimncols = dim_tuple - if not self.book._xf_epilogue_done: - # Needed for bv <= 40 - self.book.xf_epilogue() - if blah: - fprintf(self.logfile, - "sheet %d(%r) DIMENSIONS: ncols=%d nrows=%d\n", - self.number, self.name, self._dimncols, self._dimnrows - ) - elif rc == XL_EOF: - DEBUG = 0 - if DEBUG: print >> self.logfile, "SHEET.READ: EOF" - eof_found = 1 - break - elif rc == XL_OBJ: - # handle SHEET-level objects; note there's a separate Book.handle_obj - self.handle_obj(data) - elif rc == XL_MSO_DRAWING: - self.handle_msodrawingetc(rc, data_len, data) - elif rc == XL_TXO: - self.handle_txo(data) - elif rc == XL_NOTE: - self.handle_note(data) - elif rc == XL_FEAT11: - self.handle_feat11(data) - elif rc in bofcodes: ##### EMBEDDED BOF ##### - version, boftype = local_unpack('<HH', data[0:4]) - if boftype != 0x20: # embedded chart - print >> self.logfile, \ - "*** Unexpected embedded BOF (0x%04x) at offset %d: version=0x%04x type=0x%04x" \ - % (rc, bk._position - data_len - 4, version, boftype) - while 1: - code, data_len, data = bk.get_record_parts() - if code == XL_EOF: - break - if DEBUG: print >> self.logfile, "---> found EOF" - elif rc == XL_COUNTRY: - bk.handle_country(data) - elif rc == XL_LABELRANGES: - pos = 0 - pos = unpack_cell_range_address_list_update_pos( - self.row_label_ranges, data, pos, bv, addr_size=8, - ) - pos = unpack_cell_range_address_list_update_pos( - self.col_label_ranges, data, pos, bv, addr_size=8, - ) - assert pos == data_len - elif rc == XL_ARRAY: - row1x, rownx, col1x, colnx, array_flags, tokslen = \ - local_unpack("<HHBBBxxxxxH", data[:14]) - if blah_formulas: - print "ARRAY:", row1x, rownx, col1x, colnx, array_flags - dump_formula(bk, data[14:], tokslen, bv, reldelta=0, blah=1) - elif rc == XL_SHRFMLA: - row1x, rownx, col1x, colnx, nfmlas, tokslen = \ - local_unpack("<HHBBxBH", data[:10]) - if blah_formulas: - print "SHRFMLA (main):", row1x, rownx, col1x, colnx, nfmlas - decompile_formula(bk, data[10:], tokslen, reldelta=0, blah=1) - elif rc == XL_CONDFMT: - if not fmt_info: continue - assert bv >= 80 - num_CFs, needs_recalc, browx1, browx2, bcolx1, bcolx2 = \ - unpack("<6H", data[0:12]) - if self.verbosity >= 1: - fprintf(self.logfile, - "\n*** WARNING: Ignoring CONDFMT (conditional formatting) record\n" \ - "*** in Sheet %d (%r).\n" \ - "*** %d CF record(s); needs_recalc_or_redraw = %d\n" \ - "*** Bounding box is %s\n", - self.number, self.name, num_CFs, needs_recalc, - rangename2d(browx1, browx2+1, bcolx1, bcolx2+1), - ) - olist = [] # updated by the function - pos = unpack_cell_range_address_list_update_pos( - olist, data, 12, bv, addr_size=8) - # print >> self.logfile, repr(result), len(result) - if self.verbosity >= 1: - fprintf(self.logfile, - "*** %d individual range(s):\n" \ - "*** %s\n", - len(olist), - ", ".join([rangename2d(*coords) for coords in olist]), - ) - elif rc == XL_CF: - if not fmt_info: continue - cf_type, cmp_op, sz1, sz2, flags = unpack("<BBHHi", data[0:10]) - font_block = (flags >> 26) & 1 - bord_block = (flags >> 28) & 1 - patt_block = (flags >> 29) & 1 - if self.verbosity >= 1: - fprintf(self.logfile, - "\n*** WARNING: Ignoring CF (conditional formatting) sub-record.\n" \ - "*** cf_type=%d, cmp_op=%d, sz1=%d, sz2=%d, flags=0x%08x\n" \ - "*** optional data blocks: font=%d, border=%d, pattern=%d\n", - cf_type, cmp_op, sz1, sz2, flags, - font_block, bord_block, patt_block, - ) - # hex_char_dump(data, 0, data_len) - pos = 12 - if font_block: - (font_height, font_options, weight, escapement, underline, - font_colour_index, two_bits, font_esc, font_underl) = \ - unpack("<64x i i H H B 3x i 4x i i i 18x", data[pos:pos+118]) - font_style = (two_bits > 1) & 1 - posture = (font_options > 1) & 1 - font_canc = (two_bits > 7) & 1 - cancellation = (font_options > 7) & 1 - if self.verbosity >= 1: - fprintf(self.logfile, - "*** Font info: height=%d, weight=%d, escapement=%d,\n" \ - "*** underline=%d, colour_index=%d, esc=%d, underl=%d,\n" \ - "*** style=%d, posture=%d, canc=%d, cancellation=%d\n", - font_height, weight, escapement, underline, - font_colour_index, font_esc, font_underl, - font_style, posture, font_canc, cancellation, - ) - pos += 118 - if bord_block: - pos += 8 - if patt_block: - pos += 4 - fmla1 = data[pos:pos+sz1] - pos += sz1 - if blah and sz1: - fprintf(self.logfile, - "*** formula 1:\n", - ) - dump_formula(bk, fmla1, sz1, bv, reldelta=0, blah=1) - fmla2 = data[pos:pos+sz2] - pos += sz2 - assert pos == data_len - if blah and sz2: - fprintf(self.logfile, - "*** formula 2:\n", - ) - dump_formula(bk, fmla2, sz2, bv, reldelta=0, blah=1) - elif rc == XL_DEFAULTROWHEIGHT: - if data_len == 4: - bits, self.default_row_height = unpack("<HH", data[:4]) - elif data_len == 2: - self.default_row_height, = unpack("<H", data) - bits = 0 - fprintf(self.logfile, - "*** WARNING: DEFAULTROWHEIGHT record len is 2, " \ - "should be 4; assuming BIFF2 format\n") - else: - bits = 0 - fprintf(self.logfile, - "*** WARNING: DEFAULTROWHEIGHT record len is %d, " \ - "should be 4; ignoring this record\n", - data_len) - self.default_row_height_mismatch = bits & 1 - self.default_row_hidden = (bits >> 1) & 1 - self.default_additional_space_above = (bits >> 2) & 1 - self.default_additional_space_below = (bits >> 3) & 1 - elif rc == XL_MERGEDCELLS: - if not fmt_info: continue - pos = unpack_cell_range_address_list_update_pos( - self.merged_cells, data, 0, bv, addr_size=8) - if blah: - fprintf(self.logfile, - "MERGEDCELLS: %d ranges\n", int_floor_div(pos - 2, 8)) - assert pos == data_len, \ - "MERGEDCELLS: pos=%d data_len=%d" % (pos, data_len) - elif rc == XL_WINDOW2: - if bv >= 80: - (options, - self.first_visible_rowx, self.first_visible_colx, - self.gridline_colour_index, - self.cached_page_break_preview_mag_factor, - self.cached_normal_view_mag_factor - ) = unpack("<HHHHxxHH", data[:14]) - else: # BIFF3-7 - (options, - self.first_visible_rowx, self.first_visible_colx, - ) = unpack("<HHH", data[:6]) - self.gridline_colour_rgb = unpack("<BBB", data[6:9]) - self.gridline_colour_index = \ - nearest_colour_index( - self.book.colour_map, - self.gridline_colour_rgb, - debug=0) - self.cached_page_break_preview_mag_factor = 0 # default (60%) - self.cached_normal_view_mag_factor = 0 # default (100%) - # options -- Bit, Mask, Contents: - # 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 (6.71) describes unfrozen or frozen panes. - for attr, _unused_defval in _WINDOW2_options: - setattr(self, attr, options & 1) - options >>= 1 - # print "WINDOW2: visible=%d selected=%d" \ - # % (self.sheet_visible, self.sheet_selected) - #### all of the following are for BIFF <= 4W - elif bv <= 45: - if rc == XL_FORMAT or rc == XL_FORMAT2: - bk.handle_format(data, rc) - elif rc == XL_FONT or rc == XL_FONT_B3B4: - bk.handle_font(data) - elif rc == XL_STYLE: - if not self.book._xf_epilogue_done: - self.book.xf_epilogue() - bk.handle_style(data) - elif rc == XL_PALETTE: - bk.handle_palette(data) - elif rc == XL_BUILTINFMTCOUNT: - bk.handle_builtinfmtcount(data) - elif rc == XL_XF4 or rc == XL_XF3 or rc == XL_XF2: #### N.B. not XL_XF - bk.handle_xf(data) - elif rc == XL_DATEMODE: - bk.handle_datemode(data) - elif rc == XL_CODEPAGE: - bk.handle_codepage(data) - elif rc == XL_FILEPASS: - bk.handle_filepass(data) - elif rc == XL_WRITEACCESS: - bk.handle_writeaccess(data) - elif rc == XL_IXFE: - self._ixfe = local_unpack('<H', data)[0] - elif rc == XL_NUMBER_B2: - rowx, colx, cell_attr, d = local_unpack('<HH3sd', data) - self_put_number_cell(rowx, colx, d, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)) - elif rc == XL_INTEGER: - rowx, colx, cell_attr, d = local_unpack('<HH3sH', data) - self_put_number_cell(rowx, colx, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)) - elif rc == XL_LABEL_B2: - rowx, colx, cell_attr = local_unpack('<HH3s', data[0:7]) - strg = unpack_string(data, 7, bk.encoding or bk.derive_encoding(), lenlen=1) - self_put_cell(rowx, colx, XL_CELL_TEXT, strg, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)) - elif rc == XL_BOOLERR_B2: - rowx, colx, cell_attr, value, is_err = local_unpack('<HH3sBB', data) - cellty = (XL_CELL_BOOLEAN, XL_CELL_ERROR)[is_err] - # if DEBUG: print "XL_BOOLERR_B2", rowx, colx, cell_attr, value, is_err - self.put_cell(rowx, colx, cellty, value, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)) - elif rc == XL_BLANK_B2: - if not fmt_info: continue - rowx, colx, cell_attr = local_unpack('<HH3s', data[:7]) - self_put_blank_cell(rowx, colx, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)) - elif rc == XL_EFONT: - bk.handle_efont(data) - elif rc == XL_ROW_B2: - if not fmt_info: continue - rowx, bits1, has_defaults = local_unpack('<H4xH2xB', data[0:11]) - if not(0 <= rowx < self.utter_max_rows): - print >> self.logfile, \ - "*** NOTE: ROW_B2 record has row index %d; " \ - "should have 0 <= rowx < %d -- record ignored!" \ - % (rowx, self.utter_max_rows) - continue - r = Rowinfo() - r.height = bits1 & 0x7fff - r.has_default_height = (bits1 >> 15) & 1 - r.outline_level = 0 - r.outline_group_starts_ends = 0 - r.hidden = 0 - r.height_mismatch = 0 - r.has_default_xf_index = has_defaults & 1 - r.additional_space_above = 0 - r.additional_space_below = 0 - if not r.has_default_xf_index: - r.xf_index = -1 - elif data_len == 18: - # Seems the XF index in the cell_attr is dodgy - xfx = local_unpack('<H', data[16:18])[0] - r.xf_index = self.fixed_BIFF2_xfindex(cell_attr=None, rowx=rowx, colx=-1, true_xfx=xfx) - else: - cell_attr = data[13:16] - r.xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx, colx=-1) - self.rowinfo_map[rowx] = r - if 0 and r.xf_index > -1: - fprintf(self.logfile, - "**ROW %d %d %d\n", - self.number, rowx, r.xf_index) - if blah_rows: - print >> self.logfile, 'ROW_B2', rowx, bits1, has_defaults - r.dump(self.logfile, - header="--- sh #%d, rowx=%d ---" % (self.number, rowx)) - elif rc == XL_COLWIDTH: # BIFF2 only - if not fmt_info: continue - first_colx, last_colx, width\ - = local_unpack("<BBH", data[:4]) - if not(first_colx <= last_colx): - print >> self.logfile, \ - "*** NOTE: COLWIDTH record has first col index %d, last %d; " \ - "should have first <= last -- record ignored!" \ - % (first_colx, last_colx) - continue - for colx in xrange(first_colx, last_colx+1): - if self.colinfo_map.has_key(colx): - c = self.colinfo_map[colx] - else: - c = Colinfo() - self.colinfo_map[colx] = c - c.width = width - if blah: - fprintf( - self.logfile, - "COLWIDTH sheet #%d cols %d-%d: wid=%d\n", - self.number, first_colx, last_colx, width - ) - elif rc == XL_COLUMNDEFAULT: # BIFF2 only - if not fmt_info: continue - first_colx, last_colx = local_unpack("<HH", data[:4]) - #### Warning OOo docs wrong; first_colx <= colx < last_colx - if blah: - fprintf( - self.logfile, - "COLUMNDEFAULT sheet #%d cols in range(%d, %d)\n", - self.number, first_colx, last_colx - ) - if not(0 <= first_colx < last_colx <= 256): - print >> self.logfile, \ - "*** NOTE: COLUMNDEFAULT record has first col index %d, last %d; " \ - "should have 0 <= first < last <= 256" \ - % (first_colx, last_colx) - last_colx = min(last_colx, 256) - for colx in xrange(first_colx, last_colx): - offset = 4 + 3 * (colx - first_colx) - cell_attr = data[offset:offset+3] - xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx=-1, colx=colx) - if self.colinfo_map.has_key(colx): - c = self.colinfo_map[colx] - else: - c = Colinfo() - self.colinfo_map[colx] = c - c.xf_index = xf_index - else: - # if DEBUG: print "SHEET.READ: Unhandled record type %02x %d bytes %r" % (rc, data_len, data) - pass - if not eof_found: - raise XLRDError("Sheet %d (%r) missing EOF record" \ - % (self.number, self.name)) - self.tidy_dimensions() - bk._position = oldpos - return 1 - - def fixed_BIFF2_xfindex(self, cell_attr, rowx, colx, true_xfx=None): - DEBUG = 0 - blah = DEBUG or self.verbosity >= 2 - if self.biff_version == 21: - if self._xf_index_to_xl_type_map: - if true_xfx is not None: - xfx = true_xfx - else: - xfx = ord(cell_attr[0]) & 0x3F - if xfx == 0x3F: - if self._ixfe is None: - raise XLRDError("BIFF2 cell record has XF index 63 but no preceding IXFE record.") - xfx = self._ixfe - # OOo docs are capable of interpretation that each - # cell record is preceded immediately by its own IXFE record. - # Empirical evidence is that (sensibly) an IXFE record applies to all - # following cell records until another IXFE comes along. - return xfx - # Have either Excel 2.0, or broken 2.1 w/o XF records -- same effect. - self.biff_version = self.book.biff_version = 20 - #### check that XF slot in cell_attr is zero - xfx_slot = ord(cell_attr[0]) & 0x3F - assert xfx_slot == 0 - xfx = self._cell_attr_to_xfx.get(cell_attr) - if xfx is not None: - return xfx - if blah: - fprintf(self.logfile, "New cell_attr %r at (%r, %r)\n", cell_attr, rowx, colx) - book = self.book - xf = self.fake_XF_from_BIFF20_cell_attr(cell_attr) - xfx = len(book.xf_list) - xf.xf_index = xfx - book.xf_list.append(xf) - if blah: - xf.dump(self.logfile, header="=== Faked XF %d ===" % xfx, footer="======") - if not book.format_map.has_key(xf.format_key): - msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n" - fprintf(self.logfile, msg, - xf.xf_index, xf.format_key, xf.format_key) - fmt = Format(xf.format_key, FUN, u"General") - book.format_map[xf.format_key] = fmt - while len(book.format_list) <= xf.format_key: - book.format_list.append(fmt) - cellty_from_fmtty = { - FNU: XL_CELL_NUMBER, - FUN: XL_CELL_NUMBER, - FGE: XL_CELL_NUMBER, - FDT: XL_CELL_DATE, - FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. - } - fmt = book.format_map[xf.format_key] - cellty = cellty_from_fmtty[fmt.type] - self._xf_index_to_xl_type_map[xf.xf_index] = cellty - self._cell_attr_to_xfx[cell_attr] = xfx - return xfx - - def fake_XF_from_BIFF20_cell_attr(self, cell_attr): - from formatting import XF, XFAlignment, XFBorder, XFBackground, XFProtection - xf = XF() - xf.alignment = XFAlignment() - xf.alignment.indent_level = 0 - xf.alignment.shrink_to_fit = 0 - xf.alignment.text_direction = 0 - xf.border = XFBorder() - xf.border.diag_up = 0 - xf.border.diag_down = 0 - xf.border.diag_colour_index = 0 - xf.border.diag_line_style = 0 # no line - xf.background = XFBackground() - xf.protection = XFProtection() - (prot_bits, font_and_format, halign_etc) = unpack('<BBB', cell_attr) - xf.format_key = font_and_format & 0x3F - xf.font_index = (font_and_format & 0xC0) >> 6 - upkbits(xf.protection, prot_bits, ( - (6, 0x40, 'cell_locked'), - (7, 0x80, 'formula_hidden'), - )) - xf.alignment.hor_align = halign_etc & 0x07 - for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')): - if halign_etc & mask: - colour_index, line_style = 8, 1 # black, thin - else: - colour_index, line_style = 0, 0 # none, none - setattr(xf.border, side + '_colour_index', colour_index) - setattr(xf.border, side + '_line_style', line_style) - bg = xf.background - if halign_etc & 0x80: - bg.fill_pattern = 17 - else: - bg.fill_pattern = 0 - bg.background_colour_index = 9 # white - bg.pattern_colour_index = 8 # black - xf.parent_style_index = 0 # ??????????? - xf.alignment.vert_align = 2 # bottom - xf.alignment.rotation = 0 - for attr_stem in \ - "format font alignment border background protection".split(): - attr = "_" + attr_stem + "_flag" - setattr(xf, attr, 1) - return xf - - def req_fmt_info(self): - if not self.formatting_info: - raise XLRDError("Feature requires open_workbook(..., formatting_info=True)") - - ## - # Determine column display width. - # <br /> -- New in version 0.6.1 - # <br /> - # @param colx Index of the queried column, range 0 to 255. - # Note that it is possible to find out the width that will be used to display - # columns with no cell information e.g. column IV (colx=255). - # @return The column width that will be used for displaying - # the given column by Excel, in units of 1/256th of the width of a - # standard character (the digit zero in the first font). - - def computed_column_width(self, colx): - self.req_fmt_info() - if self.biff_version >= 80: - colinfo = self.colinfo_map.get(colx, None) - if colinfo is not None: - return colinfo.width - if self.standardwidth is not None: - return self.standardwidth - elif self.biff_version >= 40: - if self.gcw[colx]: - if self.standardwidth is not None: - return self.standardwidth - else: - colinfo = self.colinfo_map.get(colx, None) - if colinfo is not None: - return colinfo.width - elif self.biff_version == 30: - colinfo = self.colinfo_map.get(colx, None) - if colinfo is not None: - return colinfo.width - # All roads lead to Rome and the DEFCOLWIDTH ... - if self.defcolwidth is not None: - return self.defcolwidth * 256 - return 8 * 256 # 8 is what Excel puts in a DEFCOLWIDTH record - - def handle_msodrawingetc(self, recid, data_len, data): - if not OBJ_MSO_DEBUG: - return - DEBUG = 1 - if self.biff_version < 80: - return - o = MSODrawing() - pos = 0 - while pos < data_len: - tmp, fbt, cb = unpack('<HHI', data[pos:pos+8]) - ver = tmp & 0xF - inst = (tmp >> 4) & 0xFFF - if ver == 0xF: - ndb = 0 # container - else: - ndb = cb - if DEBUG: - hex_char_dump(data, pos, ndb + 8, base=0, fout=self.logfile) - fprintf(self.logfile, - "fbt:0x%04X inst:%d ver:0x%X cb:%d (0x%04X)\n", - fbt, inst, ver, cb, cb) - if fbt == 0xF010: # Client Anchor - assert ndb == 18 - (o.anchor_unk, - o.anchor_colx_lo, o.anchor_rowx_lo, - o.anchor_colx_hi, o.anchor_rowx_hi) = unpack('<Hiiii', data[pos+8:pos+8+ndb]) - elif fbt == 0xF011: # Client Data - # must be followed by an OBJ record - assert cb == 0 - assert pos + 8 == data_len - else: - pass - pos += ndb + 8 - else: - # didn't break out of while loop - assert pos == data_len - if DEBUG: - o.dump(self.logfile, header="=== MSODrawing ===", footer= " ") - - - def handle_obj(self, data): - if not OBJ_MSO_DEBUG: - return - DEBUG = 1 - if self.biff_version < 80: - return - o = MSObj() - data_len = len(data) - pos = 0 - if DEBUG: - fprintf(self.logfile, "... OBJ record ...\n") - while pos < data_len: - ft, cb = unpack('<HH', data[pos:pos+4]) - if DEBUG: - hex_char_dump(data, pos, cb, base=0, fout=self.logfile) - if ft == 0x15: # ftCmo ... s/b first - assert pos == 0 - o.type, o.id, option_flags = unpack('<HHH', data[pos+4:pos+10]) - upkbits(o, option_flags, ( - ( 0, 0x0001, 'locked'), - ( 4, 0x0010, 'printable'), - ( 8, 0x0100, 'autofilter'), # not documented in Excel 97 dev kit - ( 9, 0x0200, 'scrollbar_flag'), # not documented in Excel 97 dev kit - (13, 0x2000, 'autofill'), - (14, 0x4000, 'autoline'), - )) - elif ft == 0x00: - assert cb == 0 - assert pos + 4 == data_len - elif ft == 0x0C: # Scrollbar - values = unpack('<5H', data[pos+8:pos+18]) - for value, tag in zip(values, ('value', 'min', 'max', 'inc', 'page')): - setattr(o, 'scrollbar_' + tag, value) - elif ft == 0x0D: # "Notes structure" [used for cell comments] - pass ############## not documented in Excel 97 dev kit - elif ft == 0x13: # list box data - if o.autofilter: # non standard exit. NOT documented - break - else: - pass - pos += cb + 4 - else: - # didn't break out of while loop - assert pos == data_len - if DEBUG: - o.dump(self.logfile, header="=== MSOBj ===", footer= " ") - - def handle_note(self, data): - if not OBJ_MSO_DEBUG: - return - DEBUG = 1 - if self.biff_version < 80: - return - if DEBUG: - fprintf(self.logfile, '... NOTE record ...\n') - hex_char_dump(data, 0, len(data), base=0, fout=self.logfile) - o = MSNote() - data_len = len(data) - o.rowx, o.colx, option_flags, o.object_id = unpack('<4H', data[:8]) - o.show = (option_flags >> 1) & 1 - # Docs say NULL [sic] bytes padding between string count and string data - # to ensure that string is word-aligned. Appears to be nonsense. - # There also seems to be a random(?) byte after the string (not counted in the - # string length. - o.original_author, endpos = unpack_unicode_update_pos(data, 8, lenlen=2) - assert endpos == data_len - 1 - o.last_byte = data[-1] - if DEBUG: - o.dump(self.logfile, header="=== MSNote ===", footer= " ") - - def handle_txo(self, data): - if not OBJ_MSO_DEBUG: - return - DEBUG = 1 - if self.biff_version < 80: - return - o = MSTxo() - data_len = len(data) - option_flags, o.rot, cchText, cbRuns = unpack('<HH6xHH4x', data) - upkbits(o, option_flags, ( - (3, 0x000E, 'horz_align'), - (6, 0x0070, 'vert_align'), - (9, 0x0200, 'lock_text'), - )) - rc2, data2_len, data2 = self.book.get_record_parts() - assert rc2 == XL_CONTINUE - o.text, endpos = unpack_unicode_update_pos(data2, 0, known_len=cchText) - assert endpos == data2_len - rc3, data3_len, data3 = self.book.get_record_parts() - assert rc3 == XL_CONTINUE - # ignore the formatting runs for the moment - if DEBUG: - o.dump(self.logfile, header="=== MSTxo ===", footer= " ") - - def handle_feat11(self, data): - if not OBJ_MSO_DEBUG: - return - # rt: Record type; this matches the BIFF rt in the first two bytes of the record; =0872h - # grbitFrt: FRT cell reference flag (see table below for details) - # Ref0: Range reference to a worksheet cell region if grbitFrt=1 (bitFrtRef). Otherwise blank. - # isf: Shared feature type index =5 for Table - # fHdr: =0 since this is for feat not feat header - # reserved0: Reserved for future use =0 for Table - # cref: Count of ref ranges this feature is on - # cbFeatData: Count of byte for the current feature data. - # reserved1: =0 currently not used - # Ref1: Repeat of Ref0. UNDOCUMENTED - rt, grbitFrt, Ref0, isf, fHdr, reserved0, cref, cbFeatData, reserved1, Ref1 = unpack('<HH8sHBiHiH8s', data[0:35]) - assert reserved0 == 0 - assert reserved1 == 0 - assert isf == 5 - assert rt == 0x872 - assert fHdr == 0 - assert Ref1 == Ref0 - print "FEAT11: grbitFrt=%d Ref0=%r cref=%d cbFeatData=%d" % (grbitFrt, Ref0, cref, cbFeatData) - # lt: Table data source type: - # =0 for Excel Worksheet Table =1 for read-write SharePoint linked List - # =2 for XML mapper Table =3 for Query Table - # idList: The ID of the Table (unique per worksheet) - # crwHeader: How many header/title rows the Table has at the top - # crwTotals: How many total rows the Table has at the bottom - # idFieldNext: Next id to try when assigning a unique id to a new field - # cbFSData: The size of the Fixed Data portion of the Table data structure. - # rupBuild: the rupBuild that generated the record - # unusedShort: UNUSED short that can be used later. The value is reserved during round-tripping. - # listFlags: Collection of bit flags: (see listFlags' bit setting table below for detail.) - # lPosStmCache: Table data stream position of cached data - # cbStmCache: Count of bytes of cached data - # cchStmCache: Count of characters of uncompressed cached data in the stream - # lem: Table edit mode (see List (Table) Editing Mode (lem) setting table below for details.) - # rgbHashParam: Hash value for SharePoint Table - # cchName: Count of characters in the Table name string rgbName - (lt, idList, crwHeader, crwTotals, idFieldNext, cbFSData, - rupBuild, unusedShort, listFlags, lPosStmCache, cbStmCache, - cchStmCache, lem, rgbHashParam, cchName) = unpack('<iiiiiiHHiiiii16sH', data[35:35+66]) - print "lt=%d idList=%d crwHeader=%d crwTotals=%d idFieldNext=%d cbFSData=%d\n"\ - "rupBuild=%d unusedShort=%d listFlags=%04X lPosStmCache=%d cbStmCache=%d\n"\ - "cchStmCache=%d lem=%d rgbHashParam=%r cchName=%d" % ( - lt, idList, crwHeader, crwTotals, idFieldNext, cbFSData, - rupBuild, unusedShort,listFlags, lPosStmCache, cbStmCache, - cchStmCache, lem, rgbHashParam, cchName) - -class MSODrawing(BaseObject): - pass - -class MSObj(BaseObject): - pass - -class MSTxo(BaseObject): - pass - -class MSNote(BaseObject): - pass - -# === helpers === - -def unpack_RK(rk_str): - flags = ord(rk_str[0]) - if flags & 2: - # There's a SIGNED 30-bit integer in there! - i, = unpack('<i', rk_str) - i >>= 2 # div by 4 to drop the 2 flag bits - if flags & 1: - return i / 100.0 - return float(i) - else: - # It's the most significant 30 bits of an IEEE 754 64-bit FP number - d, = unpack('<d', '\0\0\0\0' + chr(flags & 252) + rk_str[1:4]) - if flags & 1: - return d / 100.0 - return d - -##### =============== Cell ======================================== ##### - -cellty_from_fmtty = { - FNU: XL_CELL_NUMBER, - FUN: XL_CELL_NUMBER, - FGE: XL_CELL_NUMBER, - FDT: XL_CELL_DATE, - FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text. - } - -ctype_text = { - XL_CELL_EMPTY: 'empty', - XL_CELL_TEXT: 'text', - XL_CELL_NUMBER: 'number', - XL_CELL_DATE: 'xldate', - XL_CELL_BOOLEAN: 'bool', - XL_CELL_ERROR: 'error', - XL_CELL_BLANK: 'blank', - } - -## -# <p>Contains the data for one cell.</p> -# -# <p>WARNING: You don't call this class yourself. You access Cell objects -# via methods of the Sheet object(s) that you found in the Book object that -# was returned when you called xlrd.open_workbook("myfile.xls").</p> -# <p> Cell objects have three attributes: <i>ctype</i> is an int, <i>value</i> -# (which depends on <i>ctype</i>) and <i>xf_index</i>. -# If "formatting_info" is not enabled when the workbook is opened, xf_index will be None. -# The following table describes the types of cells and how their values -# are represented in Python.</p> -# -# <table border="1" cellpadding="7"> -# <tr> -# <th>Type symbol</th> -# <th>Type number</th> -# <th>Python value</th> -# </tr> -# <tr> -# <td>XL_CELL_EMPTY</td> -# <td align="center">0</td> -# <td>empty string u''</td> -# </tr> -# <tr> -# <td>XL_CELL_TEXT</td> -# <td align="center">1</td> -# <td>a Unicode string</td> -# </tr> -# <tr> -# <td>XL_CELL_NUMBER</td> -# <td align="center">2</td> -# <td>float</td> -# </tr> -# <tr> -# <td>XL_CELL_DATE</td> -# <td align="center">3</td> -# <td>float</td> -# </tr> -# <tr> -# <td>XL_CELL_BOOLEAN</td> -# <td align="center">4</td> -# <td>int; 1 means TRUE, 0 means FALSE</td> -# </tr> -# <tr> -# <td>XL_CELL_ERROR</td> -# <td align="center">5</td> -# <td>int representing internal Excel codes; for a text representation, -# refer to the supplied dictionary error_text_from_code</td> -# </tr> -# <tr> -# <td>XL_CELL_BLANK</td> -# <td align="center">6</td> -# <td>empty string u''. Note: this type will appear only when -# open_workbook(..., formatting_info=True) is used.</td> -# </tr> -# </table> -#<p></p> - -class Cell(BaseObject): - - __slots__ = ['ctype', 'value', 'xf_index'] - - def __init__(self, ctype, value, xf_index=None): - self.ctype = ctype - self.value = value - self.xf_index = xf_index - - def __repr__(self): - if self.xf_index is None: - return "%s:%r" % (ctype_text[self.ctype], self.value) - else: - return "%s:%r (XF:%r)" % (ctype_text[self.ctype], self.value, self.xf_index) - -## -# There is one and only one instance of an empty cell -- it's a singleton. This is it. -# You may use a test like "acell is empty_cell". -empty_cell = Cell(XL_CELL_EMPTY, '') - -##### =============== Colinfo and Rowinfo ============================== ##### - -## -# Width and default formatting information that applies to one or -# more columns in a sheet. Derived from COLINFO records. -# -# <p> Here is the default hierarchy for width, according to the OOo docs: -# -# <br />"""In BIFF3, if a COLINFO record is missing for a column, -# the width specified in the record DEFCOLWIDTH is used instead. -# -# <br />In BIFF4-BIFF7, the width set in this [COLINFO] record is only used, -# if the corresponding bit for this column is cleared in the GCW -# record, otherwise the column width set in the DEFCOLWIDTH record -# is used (the STANDARDWIDTH record is always ignored in this case [see footnote!]). -# -# <br />In BIFF8, if a COLINFO record is missing for a column, -# the width specified in the record STANDARDWIDTH is used. -# If this [STANDARDWIDTH] record is also missing, -# the column width of the record DEFCOLWIDTH is used instead.""" -# <br /> -# -# Footnote: The docs on the GCW record say this: -# """<br /> -# If a bit is set, the corresponding column uses the width set in the STANDARDWIDTH -# record. If a bit is cleared, the corresponding column uses the width set in the -# COLINFO record for this column. -# <br />If a bit is set, and the worksheet does not contain the STANDARDWIDTH record, or if -# the bit is cleared, and the worksheet does not contain the COLINFO record, the DEFCOLWIDTH -# record of the worksheet will be used instead. -# <br />"""<br /> -# At the moment (2007-01-17) xlrd is going with the GCW version of the story. -# Reference to the source may be useful: see the computed_column_width(colx) method -# of the Sheet class. -# <br />-- New in version 0.6.1 -# </p> - -class Colinfo(BaseObject): - ## - # Width of the column in 1/256 of the width of the zero character, - # using default font (first FONT record in the file). - width = 0 - ## - # XF index to be used for formatting empty cells. - xf_index = -1 - ## - # 1 = column is hidden - hidden = 0 - ## - # Value of a 1-bit flag whose purpose is unknown - # but is often seen set to 1 - bit1_flag = 0 - ## - # Outline level of the column, in range(7). - # (0 = no outline) - outline_level = 0 - ## - # 1 = column is collapsed - collapsed = 0 - -## -# Height and default formatting information that applies to a row in a sheet. -# Derived from ROW records. -# <br /> -- New in version 0.6.1 - -class Rowinfo(BaseObject): - ## - # Height of the row, in twips. One twip == 1/20 of a point - height = 0 - ## - # 0 = Row has custom height; 1 = Row has default height - has_default_height = 0 - ## - # Outline level of the row - outline_level = 0 - ## - # 1 = Outline group starts or ends here (depending on where the - # outline buttons are located, see WSBOOL record [TODO ??]), - # <i>and</i> is collapsed - outline_group_starts_ends = 0 - ## - # 1 = Row is hidden (manually, or by a filter or outline group) - hidden = 0 - ## - # 1 = Row height and default font height do not match - height_mismatch = 0 - ## - # 1 = the xf_index attribute is usable; 0 = ignore it - has_default_xf_index = 0 - ## - # Index to default XF record for empty cells in this row. - # Don't use this if has_default_xf_index == 0. - xf_index = -9999 - ## - # 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. - additional_space_above = 0 - ## - # 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. - additional_space_below = 0 diff --git a/tablib/packages/xlrd/timemachine.py b/tablib/packages/xlrd/timemachine.py deleted file mode 100644 index 1718c03..0000000 --- a/tablib/packages/xlrd/timemachine.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: cp1252 -*- - -## -# <p>Copyright © 2006-2008 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p> -## - -# timemachine.py -- adaptation for earlier Pythons e.g. 2.1 -# usage: from timemachine import * - -# 2008-02-08 SJM Generalised method of detecting IronPython - -import sys - -python_version = sys.version_info[:2] # e.g. version 2.4 -> (2, 4) - -CAN_PICKLE_ARRAY = python_version >= (2, 5) -CAN_SUBCLASS_BUILTIN = python_version >= (2, 2) - -if sys.version.find("IronPython") >= 0: - array_array = None -else: - from array import array as array_array - -if python_version < (2, 2): - class object: - pass - False = 0 - True = 1 - -def int_floor_div(x, y): - return divmod(x, y)[0] - -def intbool(x): - if x: - return 1 - return 0 - -if python_version < (2, 3): - def sum(sequence, start=0): - tot = start - for item in aseq: - tot += item - return tot diff --git a/tablib/packages/xlrd/xldate.py b/tablib/packages/xlrd/xldate.py deleted file mode 100644 index e5f7591..0000000 --- a/tablib/packages/xlrd/xldate.py +++ /dev/null @@ -1,171 +0,0 @@ -# -*- coding: cp1252 -*- - -# No part of the content of this file was derived from the works of David Giffin. - -## -# <p>Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd</p> -# <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p> -# -# <p>Provides function(s) for dealing with Microsoft Excel ™ dates.</p> -## - -# 2008-10-18 SJM Fix bug in xldate_from_date_tuple (affected some years after 2099) - -# The conversion from days to (year, month, day) starts with -# an integral "julian day number" aka JDN. -# FWIW, JDN 0 corresponds to noon on Monday November 24 in Gregorian year -4713. -# More importantly: -# Noon on Gregorian 1900-03-01 (day 61 in the 1900-based system) is JDN 2415080.0 -# Noon on Gregorian 1904-01-02 (day 1 in the 1904-based system) is JDN 2416482.0 - -from timemachine import int_floor_div as ifd - -_JDN_delta = (2415080 - 61, 2416482 - 1) -assert _JDN_delta[1] - _JDN_delta[0] == 1462 - -class XLDateError(ValueError): pass - -class XLDateNegative(XLDateError): pass -class XLDateAmbiguous(XLDateError): pass -class XLDateTooLarge(XLDateError): pass -class XLDateBadDatemode(XLDateError): pass -class XLDateBadTuple(XLDateError): pass - -_XLDAYS_TOO_LARGE = (2958466, 2958466 - 1462) # This is equivalent to 10000-01-01 - -## -# Convert an Excel number (presumed to represent a date, a datetime or a time) into -# a tuple suitable for feeding to datetime or mx.DateTime constructors. -# @param xldate The Excel number -# @param datemode 0: 1900-based, 1: 1904-based. -# <br>WARNING: when using this function to -# interpret the contents of a workbook, you should pass in the Book.datemode -# attribute of that workbook. Whether -# the workbook has ever been anywhere near a Macintosh is irrelevant. -# @return Gregorian (year, month, day, hour, minute, nearest_second). -# <br>Special case: if 0.0 <= xldate < 1.0, it is assumed to represent a time; -# (0, 0, 0, hour, minute, second) will be returned. -# <br>Note: 1904-01-01 is not regarded as a valid date in the datemode 1 system; its "serial number" -# is zero. -# @throws XLDateNegative xldate < 0.00 -# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0) -# @throws XLDateTooLarge Gregorian year 10000 or later -# @throws XLDateBadDatemode datemode arg is neither 0 nor 1 -# @throws XLDateError Covers the 4 specific errors - -def xldate_as_tuple(xldate, datemode): - if datemode not in (0, 1): - raise XLDateBadDatemode(datemode) - if xldate == 0.00: - return (0, 0, 0, 0, 0, 0) - if xldate < 0.00: - raise XLDateNegative(xldate) - xldays = int(xldate) - frac = xldate - xldays - seconds = int(round(frac * 86400.0)) - assert 0 <= seconds <= 86400 - if seconds == 86400: - hour = minute = second = 0 - xldays += 1 - else: - # second = seconds % 60; minutes = seconds // 60 - minutes, second = divmod(seconds, 60) - # minute = minutes % 60; hour = minutes // 60 - hour, minute = divmod(minutes, 60) - if xldays >= _XLDAYS_TOO_LARGE[datemode]: - raise XLDateTooLarge(xldate) - - if xldays == 0: - return (0, 0, 0, hour, minute, second) - - if xldays < 61 and datemode == 0: - raise XLDateAmbiguous(xldate) - - jdn = xldays + _JDN_delta[datemode] - yreg = (ifd(ifd(jdn * 4 + 274277, 146097) * 3, 4) + jdn + 1363) * 4 + 3 - mp = ifd(yreg % 1461, 4) * 535 + 333 - d = ifd(mp % 16384, 535) + 1 - # mp /= 16384 - mp >>= 14 - if mp >= 10: - return (ifd(yreg, 1461) - 4715, mp - 9, d, hour, minute, second) - else: - return (ifd(yreg, 1461) - 4716, mp + 3, d, hour, minute, second) - -# === conversions from date/time to xl numbers - -def _leap(y): - if y % 4: return 0 - if y % 100: return 1 - if y % 400: return 0 - return 1 - -_days_in_month = (None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) - -## -# Convert a date tuple (year, month, day) to an Excel date. -# @param year Gregorian year. -# @param month 1 <= month <= 12 -# @param day 1 <= day <= last day of that (year, month) -# @param datemode 0: 1900-based, 1: 1904-based. -# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0) -# @throws XLDateBadDatemode datemode arg is neither 0 nor 1 -# @throws XLDateBadTuple (year, month, day) is too early/late or has invalid component(s) -# @throws XLDateError Covers the specific errors - -def xldate_from_date_tuple((year, month, day), datemode): - - if datemode not in (0, 1): - raise XLDateBadDatemode(datemode) - - if year == 0 and month == 0 and day == 0: - return 0.00 - - if not (1900 <= year <= 9999): - raise XLDateBadTuple("Invalid year: %r" % ((year, month, day),)) - if not (1 <= month <= 12): - raise XLDateBadTuple("Invalid month: %r" % ((year, month, day),)) - if day < 1 \ - or (day > _days_in_month[month] and not(day == 29 and month == 2 and _leap(year))): - raise XLDateBadTuple("Invalid day: %r" % ((year, month, day),)) - - Yp = year + 4716 - M = month - if M <= 2: - Yp = Yp - 1 - Mp = M + 9 - else: - Mp = M - 3 - jdn = ifd(1461 * Yp, 4) + ifd(979 * Mp + 16, 32) + \ - day - 1364 - ifd(ifd(Yp + 184, 100) * 3, 4) - xldays = jdn - _JDN_delta[datemode] - if xldays <= 0: - raise XLDateBadTuple("Invalid (year, month, day): %r" % ((year, month, day),)) - if xldays < 61 and datemode == 0: - raise XLDateAmbiguous("Before 1900-03-01: %r" % ((year, month, day),)) - return float(xldays) - -## -# Convert a time tuple (hour, minute, second) to an Excel "date" value (fraction of a day). -# @param hour 0 <= hour < 24 -# @param minute 0 <= minute < 60 -# @param second 0 <= second < 60 -# @throws XLDateBadTuple Out-of-range hour, minute, or second - -def xldate_from_time_tuple((hour, minute, second)): - if 0 <= hour < 24 and 0 <= minute < 60 and 0 <= second < 60: - return ((second / 60.0 + minute) / 60.0 + hour) / 24.0 - raise XLDateBadTuple("Invalid (hour, minute, second): %r" % ((hour, minute, second),)) - -## -# Convert a datetime tuple (year, month, day, hour, minute, second) to an Excel date value. -# For more details, refer to other xldate_from_*_tuple functions. -# @param datetime_tuple (year, month, day, hour, minute, second) -# @param datemode 0: 1900-based, 1: 1904-based. - -def xldate_from_datetime_tuple(datetime_tuple, datemode): - return ( - xldate_from_date_tuple(datetime_tuple[:3], datemode) - + - xldate_from_time_tuple(datetime_tuple[3:]) - ) diff --git a/tablib/packages/xlrd3/__init__.py b/tablib/packages/xlrd3/__init__.py deleted file mode 100644 index 98f322b..0000000 --- a/tablib/packages/xlrd3/__init__.py +++ /dev/null @@ -1,1642 +0,0 @@ -# Copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd3 package, which is released under a
-# BSD-style licence.
-#
-# xlrd3, the Python 3 port of xlrd v0.7.1
-#
-# A Python module for extracting data from MS Excel spreadsheet files.
-#
-# General information
-#
-# Acknowledgements
-#
-# Development of this module would not have been possible without the document
-# "OpenOffice.org's Documentation of the Microsoft Excel File Format"
-# ("OOo docs" for short).
-# The latest version is available from OpenOffice.org in
-# http://sc.openoffice.org/excelfileformat.pdf PDF format
-# and
-# http://sc.openoffice.org/excelfileformat.odt ODT format.
-# Small portions of the OOo docs are reproduced in this
-# document. A study of the OOo docs is recommended for those who wish a
-# deeper understanding of the Excel file layout than the xlrd docs can provide.
-#
-# Provision of formatting information in version 0.6.1 was funded by
-# http://www.simplistix.co.uk Simplistix Ltd.
-#
-# Unicode
-#
-# This module presents all text strings as Python unicode objects.
-# From Excel 97 onwards, text in Excel spreadsheets has been stored as Unicode.
-# Older files (Excel 95 and earlier) don't keep strings in Unicode;
-# a CODEPAGE record provides a codepage number (for example, 1252) which is
-# used by xlrd to derive the encoding (for same example: "cp1252") which is
-# used to translate to Unicode.
-#
-# If the CODEPAGE record is missing (possible if the file was created
-# by third-party software), xlrd will assume that the encoding is ascii, and keep going.
-# If the actual encoding is not ascii, a UnicodeDecodeError exception will be raised and
-# you will need to determine the encoding yourself, and tell xlrd::
-#
-# book = xlrd.open_workbook(..., encoding_override="cp1252")
-#
-# If the CODEPAGE record exists but is wrong (for example, the codepage
-# number is 1251, but the strings are actually encoded in koi8_r),
-# it can be overridden using the same mechanism.
-# The supplied runxlrd.py has a corresponding command-line argument, which
-# may be used for experimentation::
-#
-# runxlrd.py -e koi8_r 3rows myfile.xls
-#
-# The first place to look for an encoding ("codec name") is
-# http://docs.python.org/lib/standard-encodings.html
-# the Python documentation.
-#
-# Dates in Excel spreadsheets
-#
-# In reality, there are no such things. What you have are floating point
-# numbers and pious hope.
-# There are several problems with Excel dates:
-#
-# (1) Dates are not stored as a separate data type; they are stored as
-# floating point numbers and you have to rely on
-# (a) the "number format" applied to them in Excel and/or
-# (b) knowing which cells are supposed to have dates in them.
-# This module helps with (a) by inspecting the
-# format that has been applied to each number cell;
-# if it appears to be a date format, the cell
-# is classified as a date rather than a number. Feedback on this feature,
-# especially from non-English-speaking locales, would be appreciated.
-#
-# (2) Excel for Windows stores dates by default as the number of
-# days (or fraction thereof) since 1899-12-31T00:00:00. Excel for
-# Macintosh uses a default start date of 1904-01-01T00:00:00. The date
-# system can be changed in Excel on a per-workbook basis (for example:
-# Tools -> Options -> Calculation, tick the "1904 date system" box).
-# This is of course a bad idea if there are already dates in the
-# workbook. There is no good reason to change it even if there are no
-# dates in the workbook. Which date system is in use is recorded in the
-# workbook. A workbook transported from Windows to Macintosh (or vice
-# versa) will work correctly with the host Excel. When using this
-# module's xldate_as_tuple function to convert numbers from a workbook,
-# you must use the datemode attribute of the Book object. If you guess,
-# or make a judgement depending on where you believe the workbook was
-# created, you run the risk of being 1462 days out of kilter.
-#
-# Reference:
-# http://support.microsoft.com/default.aspx?scid=KB;EN-US;q180162
-#
-# (3) The Excel implementation of the Windows-default 1900-based date system works on the
-# incorrect premise that 1900 was a leap year. It interprets the number 60 as meaning 1900-02-29,
-# which is not a valid date. Consequently any number less than 61 is ambiguous. Example: is 59 the
-# result of 1900-02-28 entered directly, or is it 1900-03-01 minus 2 days? The OpenOffice.org Calc
-# program "corrects" the Microsoft problem; entering 1900-02-27 causes the number 59 to be stored.
-# Save as an XLS file, then open the file with Excel -- you'll see 1900-02-28 displayed.
-#
-# Reference: http://support.microsoft.com/default.aspx?scid=kb;en-us;214326
-#
-# (4) The Macintosh-default 1904-based date system counts 1904-01-02 as day 1 and 1904-01-01 as day zero.
-# Thus any number such that (0.0 <= number < 1.0) is ambiguous. Is 0.625 a time of day (15:00:00),
-# independent of the calendar,
-# or should it be interpreted as an instant on a particular day (1904-01-01T15:00:00)?
-# The xldate_* functions in this module
-# take the view that such a number is a calendar-independent time of day (like Python's datetime.time type) for both
-# date systems. This is consistent with more recent Microsoft documentation
-# (for example, the help file for Excel 2002 which says that the first day
-# in the 1904 date system is 1904-01-02).
-#
-# (5) Usage of the Excel DATE() function may leave strange dates in a spreadsheet. Quoting the help file,
-# in respect of the 1900 date system: "If year is between 0 (zero) and 1899 (inclusive),
-# Excel adds that value to 1900 to calculate the year. For example, DATE(108,1,2) returns January 2, 2008 (1900+108)."
-# This gimmick, semi-defensible only for arguments up to 99 and only in the pre-Y2K-awareness era,
-# means that DATE(1899, 12, 31) is interpreted as 3799-12-31.
-#
-# For further information, please refer to the documentation for the xldate_* functions.
-#
-# Named references, constants, formulas, and macros
-#
-# A name is used to refer to a cell, a group of cells, a constant
-# value, a formula, or a macro. Usually the scope of a name is global
-# across the whole workbook. However it can be local to a worksheet.
-# For example, if the sales figures are in different cells in
-# different sheets, the user may define the name "Sales" in each
-# sheet. There are built-in names, like "Print_Area" and
-# "Print_Titles"; these two are naturally local to a sheet.
-#
-# To inspect the names with a user interface like MS Excel, OOo Calc,
-# or Gnumeric, click on Insert/Names/Define. This will show the global
-# names, plus those local to the currently selected sheet.
-#
-# A Book object provides two dictionaries (name_map and
-# name_and_scope_map) and a list (name_obj_list) which allow various
-# ways of accessing the Name objects. There is one Name object for
-# each NAME record found in the workbook. Name objects have many
-# attributes, several of which are relevant only when obj.macro is 1.
-#
-# In the examples directory you will find namesdemo.xls which
-# showcases the many different ways that names can be used, and
-# xlrdnamesAPIdemo.py which offers 3 different queries for inspecting
-# the names in your files, and shows how to extract whatever a name is
-# referring to. There is currently one "convenience method",
-# Name.cell(), which extracts the value in the case where the name
-# refers to a single cell. More convenience methods are planned. The
-# source code for Name.cell (in __init__.py) is an extra source of
-# information on how the Name attributes hang together.
-#
-# Name information is **not** extracted from files older than
-# Excel 5.0 (Book.biff_version < 50)
-#
-# Formatting
-#
-# Introduction
-#
-# This collection of features, new in xlrd version 0.6.1, is intended
-# to provide the information needed to (1) display/render spreadsheet contents
-# (say) on a screen or in a PDF file, and (2) copy spreadsheet data to another
-# file without losing the ability to display/render it.
-#
-# The Palette; Colour Indexes
-#
-# A colour is represented in Excel as a (red, green, blue) ("RGB") tuple
-# with each component in range(256). However it is not possible to access an
-# unlimited number of colours; each spreadsheet is limited to a palette of 64 different
-# colours (24 in Excel 3.0 and 4.0, 8 in Excel 2.0). Colours are referenced by an index
-# ("colour index") into this palette.
-#
-# Colour indexes 0 to 7 represent 8 fixed built-in colours: black, white, red, green, blue,
-# yellow, magenta, and cyan.
-#
-# The remaining colours in the palette (8 to 63 in Excel 5.0 and later)
-# can be changed by the user. In the Excel 2003 UI, Tools/Options/Color presents a palette
-# of 7 rows of 8 colours. The last two rows are reserved for use in charts.
-# The correspondence between this grid and the assigned
-# colour indexes is NOT left-to-right top-to-bottom.
-# Indexes 8 to 15 correspond to changeable
-# parallels of the 8 fixed colours -- for example, index 7 is forever cyan;
-# index 15 starts off being cyan but can be changed by the user.
-#
-# The default colour for each index depends on the file version; tables of the defaults
-# are available in the source code. If the user changes one or more colours,
-# a PALETTE record appears in the XLS file -- it gives the RGB values for *all* changeable
-# indexes.
-# Note that colours can be used in "number formats": "[CYAN]...." and "[COLOR8]...." refer
-# to colour index 7; "[COLOR16]...." will produce cyan
-# unless the user changes colour index 15 to something else.
-#
-# In addition, there are several "magic" colour indexes used by Excel:
-# 0x18 (BIFF3-BIFF4), 0x40 (BIFF5-BIFF8): System window text colour for border lines
-# (used in XF, CF, and WINDOW2 records)
-# 0x19 (BIFF3-BIFF4), 0x41 (BIFF5-BIFF8): System window background colour for pattern background
-# (used in XF and CF records )
-# 0x43: System face colour (dialogue background colour)
-# 0x4D: System window text colour for chart border lines
-# 0x4E: System window background colour for chart areas
-# 0x4F: Automatic colour for chart border lines (seems to be always Black)
-# 0x50: System ToolTip background colour (used in note objects)
-# 0x51: System ToolTip text colour (used in note objects)
-# 0x7FFF: System window text colour for fonts (used in FONT and CF records)
-# Note 0x7FFF appears to be the *default* colour index. It appears quite often in FONT
-# records.
-#
-# Default Formatting
-#
-# Default formatting is applied to all empty cells (those not described by a cell record).
-# Firstly row default information (ROW record, Rowinfo class) is used if available.
-# Failing that, column default information (COLINFO record, Colinfo class) is used if available.
-# As a last resort the worksheet/workbook default cell format will be used; this
-# should always be present in an Excel file,
-# described by the XF record with the fixed index 15 (0-based). By default, it uses the
-# worksheet/workbook default cell style, described by the very first XF record (index 0).
-#
-# Formatting features not included in xlrd version 0.6.1
-#
-# - Rich text i.e. strings containing partial bold, italic
-# and underlined text, change of font inside a string, etc.
-# See OOo docs s3.4 and s3.2
-# - Asian phonetic text (known as "ruby"), used for Japanese furigana. See OOo docs
-# s3.4.2 (p15)
-# - Conditional formatting. See OOo docs
-# s5.12, s6.21 (CONDFMT record), s6.16 (CF record)
-# - Miscellaneous sheet-level and book-level items e.g. printing layout, screen panes.
-# - Modern Excel file versions don't keep most of the built-in
-# "number formats" in the file; Excel loads formats according to the
-# user's locale. Currently xlrd's emulation of this is limited to
-# a hard-wired table that applies to the US English locale. This may mean
-# that currency symbols, date order, thousands separator, decimals separator, etc
-# are inappropriate. Note that this does not affect users who are copying XLS
-# files, only those who are visually rendering cells.
-#
-# Loading worksheets on demand
-#
-# This feature, new in version 0.7.1, is governed by the on_demand argument
-# to the open_workbook() function and allows saving memory and time by loading
-# only those sheets that the caller is interested in, and releasing sheets
-# when no longer required.
-#
-# on_demand=False (default): No change. open_workbook() loads global data
-# and all sheets, releases resources no longer required (principally the
-# str or mmap object containing the Workbook stream), and returns.
-#
-# on_demand=True and BIFF version < 5.0: A warning message is emitted,
-# on_demand is recorded as False, and the old process is followed.
-#
-# on_demand=True and BIFF version >= 5.0: open_workbook() loads global
-# data and returns without releasing resources. At this stage, the only
-# information available about sheets is Book.nsheets and Book.sheet_names().
-#
-# Book.sheet_by_name() and Book.sheet_by_index() will load the requested
-# sheet if it is not already loaded.
-#
-# Book.sheets() will load all/any unloaded sheets.
-#
-# The caller may save memory by calling
-# Book.unload_sheet(sheet_name_or_index) when finished with the sheet.
-# This applies irrespective of the state of on_demand.
-#
-# The caller may re-load an unloaded sheet by calling Book.sheet_by_xxxx()
-# -- except if those required resources have been released (which will
-# have happened automatically when on_demand is false). This is the only
-# case where an exception will be raised.
-#
-# The caller may query the state of a sheet:
-# Book.sheet_loaded(sheet_name_or_index) -> a bool
-#
-# 2010-12-03 mozman start xlrd3, for changes see NEWS.txt
-#
-# 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo
-# 2008-11-23 SJM Support dumping FILEPASS and EXTERNNAME records; extra info from SUPBOOK records
-# 2008-11-23 SJM colname utility function now supports more than 256 columns
-# 2008-04-24 SJM Recovery code for file with out-of-order/missing/wrong CODEPAGE record needed to be called for EXTERNSHEET/BOUNDSHEET/NAME/SHEETHDR records.
-# 2008-02-08 SJM Preparation for Excel 2.0 support
-# 2008-02-03 SJM Minor tweaks for IronPython support
-# 2008-02-02 SJM Previous change stopped dump() and count_records() ... fixed
-# 2007-12-25 SJM Decouple Book initialisation & loading -- to allow for multiple loaders.
-# 2007-12-20 SJM Better error message for unsupported file format.
-# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files.
-# 2007-11-20 SJM Wasn't handling EXTERNSHEET record that needed CONTINUE record(s)
-# 2007-07-07 SJM Version changed to 0.7.0 (alpha 1)
-# 2007-07-07 SJM Logfile arg wasn't being passed from open_workbook to compdoc.CompDoc
-# 2007-05-21 SJM If no CODEPAGE record in pre-8.0 file, assume ascii and keep going.
-# 2007-04-22 SJM Removed antique undocumented Book.get_name_dict method.
-
-import sys
-import time
-from struct import unpack
-import mmap
-
-from . import sheet
-from . import compdoc
-from . import formatting
-from .biffh import *
-from .xldate import xldate_as_tuple, XLDateError
-from .formula import *
-from .xfcell import XFCell
-
-empty_cell = sheet.empty_cell # for exposure to the world ...
-
-DEBUG = False
-USE_FANCY_CD = 1
-
-MY_EOF = 0xF00BAAA # not a 16-bit number
-
-SUPBOOK_UNK = 0
-SUPBOOK_INTERNAL = 1
-SUPBOOK_EXTERNAL = 2
-SUPBOOK_ADDIN = 3
-SUPBOOK_DDEOLE = 4
-
-SUPPORTED_VERSIONS = (80, 70, 50, 45, 40, 30, 21, 20)
-
-code_from_builtin_name = {
- "Consolidate_Area": "\x00",
- "Auto_Open": "\x01",
- "Auto_Close": "\x02",
- "Extract": "\x03",
- "Database": "\x04",
- "Criteria": "\x05",
- "Print_Area": "\x06",
- "Print_Titles": "\x07",
- "Recorder": "\x08",
- "Data_Form": "\x09",
- "Auto_Activate": "\x0A",
- "Auto_Deactivate": "\x0B",
- "Sheet_Title": "\x0C",
- "_FilterDatabase": "\x0D",
- }
-
-builtin_name_from_code = {}
-for _bin, _bic in code_from_builtin_name.items():
- builtin_name_from_code[_bic] = _bin
-
-#
-# Open a spreadsheet file for data extraction.
-#
-# @param filename The path to the spreadsheet file to be opened.
-#
-# @param logfile An open file to which messages and diagnostics are written.
-#
-# @param verbosity Increases the volume of trace material written to the logfile.
-#
-# @param pickleable Default is true. In Python 2.4 or earlier, setting to false
-# will cause use of array.array objects which save some memory but can't be pickled.
-# In Python 2.5, array.arrays are used unconditionally. Note: if you have large files that
-# you need to read multiple times, it can be much faster to cPickle.dump() the xlrd.Book object
-# once, and use cPickle.load() multiple times.
-# @param use_mmap Whether to use the mmap module is determined heuristically.
-# Use this arg to override the result. Current heuristic: mmap is used if it exists.
-#
-# @param file_contents ... as a string or an mmap.mmap object or some other behave-alike object.
-# If file_contents is supplied, filename will not be used, except (possibly) in messages.
-#
-# @param encoding_override Used to overcome missing or bad codepage information
-# in older-version files. Refer to discussion in the <b>Unicode</b> section above.
-# - New in version 0.6.0
-#
-# @param formatting_info Governs provision of a reference to an XF (eXtended Format) object
-# for each cell in the worksheet.
-# Default is <i>False</i>. This is backwards compatible and saves memory.
-# "Blank" cells (those with their own formatting information but no data) are treated as empty
-# (by ignoring the file's BLANK and MULBLANK records).
-# It cuts off any bottom "margin" of rows of empty (and blank) cells and
-# any right "margin" of columns of empty (and blank) cells.
-# Only cell_value and cell_type are available.
-# `True` provides all cells, including empty and blank cells.
-# XF information is available for each cell.
-# - New in version 0.6.1
-#
-# @param on_demand Governs whether sheets are all loaded initially or when demanded
-# by the caller. Please refer back to the section "Loading worksheets on demand" for details.
-# - New in version 0.7.1
-#
-# @return An instance of the Book class.
-
-def open_workbook(filename=None,
- logfile=sys.stdout,
- verbosity=0,
- pickleable=True,
- use_mmap=True,
- file_contents=None,
- encoding_override=None,
- formatting_info=False,
- on_demand=False):
- t0 = time.clock()
- workbook = Book()
- workbook.biff2_8_load(filename=filename,
- file_contents=file_contents,
- logfile=logfile,
- verbosity=verbosity,
- pickleable=pickleable,
- use_mmap=use_mmap,
- encoding_override=encoding_override,
- formatting_info=formatting_info,
- on_demand=on_demand)
- t1 = time.clock()
- workbook.load_time_stage_1 = t1 - t0
- biff_version = workbook.getbof(XL_WORKBOOK_GLOBALS)
- if not biff_version:
- raise XLRDError("Can't determine file's BIFF version")
-
- if biff_version not in SUPPORTED_VERSIONS:
- raise XLRDError( "BIFF version %s is not supported" % \
- biff_text_from_num[biff_version])
-
- workbook.biff_version = biff_version
-
- if biff_version <= 40:
- # no workbook globals, only 1 worksheet
- if on_demand:
- fprintf(workbook.logfile,
- "*** WARNING: on_demand is not supported for this Excel version.\n" \
- "*** Setting on_demand to False.\n")
- workbook.on_demand = on_demand = False
- workbook.fake_globals_get_sheet()
- elif biff_version == 45:
- # worksheet(s) embedded in global stream
- workbook.parse_globals()
- if on_demand:
- fprintf(workbook.logfile,
- "*** WARNING: on_demand is not supported for this Excel version.\n" \
- "*** Setting on_demand to False.\n")
- workbook.on_demand = on_demand = False
- else:
- workbook.parse_globals()
- workbook._sheet_list = [None for sh in workbook._sheet_names]
- if not on_demand:
- workbook.get_sheets()
-
- workbook.nsheets = len(workbook._sheet_list)
- if biff_version == 45 and workbook.nsheets > 1:
- fprintf(workbook.logfile,
- "*** WARNING: Excel 4.0 workbook (.XLW) file contains %d worksheets.\n" \
- "*** Book-level data will be that of the last worksheet.\n",
- workbook.nsheets)
-
- if not on_demand:
- workbook.release_resources()
- t2 = time.clock()
- workbook.load_time_stage_2 = t2 - t1
- return workbook
-
-# For debugging: dump the file's BIFF records in char & hex.
-# @param filename The path to the file to be dumped.
-# @param outfile An open file, to which the dump is written.
-# @param unnumbered If true, omit offsets (for meaningful diffs).
-
-def dump(filename, outfile=sys.stdout, unnumbered=False):
- workbook = Book()
- workbook.biff2_8_load(filename=filename, logfile=outfile, )
- biff_dump(workbook.mem, workbook.base, workbook.stream_len, 0, outfile, unnumbered)
-
-# For debugging and analysis: summarise the file's BIFF records.
-# I.e. produce a sorted file of (record_name, count).
-# @param filename The path to the file to be summarised.
-# @param outfile An open file, to which the summary is written.
-
-def count_records(filename, outfile=sys.stdout):
- workbook = Book()
- workbook.biff2_8_load(filename=filename, logfile=outfile, )
- biff_count_records(workbook.mem, workbook.base, workbook.stream_len, outfile)
-
-# Information relating to a named reference, formula, macro, etc.
-# - New in version 0.6.0
-# - Name information is **not** extracted from files older than
-# Excel 5.0 (Book.biff_version < 50)
-
-class Name(BaseObject):
-
- _repr_these = ['stack']
- book = None # parent
-
- # 0 = Visible; 1 = Hidden
- hidden = 0
-
- # 0 = Command macro; 1 = Function macro. Relevant only if macro == 1
- func = 0
-
- # 0 = Sheet macro; 1 = VisualBasic macro. Relevant only if macro == 1
- vbasic = 0
-
- # 0 = Standard name; 1 = Macro name
- macro = 0
-
- # 0 = Simple formula; 1 = Complex formula (array formula or user defined)
- # ´No examples have been sighted.´
- complex = 0
-
- # 0 = User-defined name; 1 = Built-in name
- # (common examples: Print_Area, Print_Titles; see OOo docs for full list)
- builtin = 0
-
- # Function group. Relevant only if macro == 1; see OOo docs for values.
- funcgroup = 0
-
- # 0 = Formula definition; 1 = Binary data ´No examples have been sighted.´
- binary = 0
-
- # The index of this object in book.name_obj_list
- name_index = 0
-
- # A Unicode string. If builtin, decoded as per OOo docs.
- name = ""
-
- # An 8-bit string.
- raw_formula = ""
-
- # -1: The name is global (visible in all calculation sheets).
- # -2: The name belongs to a macro sheet or VBA sheet.
- # -3: The name is invalid.
- # 0 <= scope < book.nsheets: The name is local to the sheet whose index is scope.
- scope = -1
-
- # The result of evaluating the formula, if any.
- # If no formula, or evaluation of the formula encountered problems,
- # the result is None. Otherwise the result is a single instance of the
- # Operand class.
- result = None
-
- # This is a convenience method for the frequent use case where the name
- # refers to a single cell.
- # @return An instance of the Cell class.
- # @throws XLRDError The name is not a constant absolute reference
- # to a single cell.
- def cell(self):
- res = self.result
- if res:
- # result should be an instance of the Operand class
- kind = res.kind
- value = res.value
- if kind == oREF and len(value) == 1:
- ref3d = value[0]
- if (0 <= ref3d.shtxlo == ref3d.shtxhi - 1
- and ref3d.rowxlo == ref3d.rowxhi - 1
- and ref3d.colxlo == ref3d.colxhi - 1):
- sh = self.book.sheet_by_index(ref3d.shtxlo)
- return sh.cell(ref3d.rowxlo, ref3d.colxlo)
- self.dump(self.book.logfile,
- header="=== Dump of Name object ===",
- footer="======= End of dump =======")
- raise XLRDError("Not a constant absolute reference to a single cell")
-
- # This is a convenience method for the use case where the name
- # refers to one rectangular area in one worksheet.
- # @param clipped If true (the default), the returned rectangle is clipped
- # to fit in (0, sheet.nrows, 0, sheet.ncols) -- it is guaranteed that
- # 0 <= rowxlo <= rowxhi <= sheet.nrows and that the number of usable rows
- # in the area (which may be zero) is rowxhi - rowxlo; likewise for columns.
- # @return a tuple (sheet_object, rowxlo, rowxhi, colxlo, colxhi).
- # @throws XLRDError The name is not a constant absolute reference
- # to a single area in a single sheet.
- def area2d(self, clipped=True):
- res = self.result
- if res:
- # result should be an instance of the Operand class
- kind = res.kind
- value = res.value
- if kind == oREF and len(value) == 1: # only 1 reference
- ref3d = value[0]
- if 0 <= ref3d.shtxlo == ref3d.shtxhi - 1: # only 1 usable sheet
- sh = self.book.sheet_by_index(ref3d.shtxlo)
- if not clipped:
- return sh, ref3d.rowxlo, ref3d.rowxhi, ref3d.colxlo, ref3d.colxhi
- rowxlo = min(ref3d.rowxlo, sh.nrows)
- rowxhi = max(rowxlo, min(ref3d.rowxhi, sh.nrows))
- colxlo = min(ref3d.colxlo, sh.ncols)
- colxhi = max(colxlo, min(ref3d.colxhi, sh.ncols))
- assert 0 <= rowxlo <= rowxhi <= sh.nrows
- assert 0 <= colxlo <= colxhi <= sh.ncols
- return sh, rowxlo, rowxhi, colxlo, colxhi
- self.dump(self.book.logfile,
- header="=== Dump of Name object ===",
- footer="======= End of dump =======",
- )
- raise XLRDError("Not a constant absolute reference to a single area in a single sheet")
-
-# Contents of a "workbook".
-# WARNING: You don't call this class yourself. You use the Book object that
-# was returned when you called xlrd.open_workbook("myfile.xls").
-
-class Book(BaseObject):
-
- # The number of worksheets present in the workbook file.
- # This information is available even when no sheets have yet been loaded.
- nsheets = 0
-
- # Which date system was in force when this file was last saved.
- # 0 => 1900 system (the Excel for Windows default).
- # 1 => 1904 system (the Excel for Macintosh default).
- datemode = 0 # In case it's not specified in the file.
-
- # Version of BIFF (Binary Interchange File Format) used to create the file.
- # Latest is 8.0 (represented here as 80), introduced with Excel 97.
- # Earliest supported by this module: 2.0 (represented as 20).
- biff_version = 0
-
- # List containing a Name object for each NAME record in the workbook.
- # - New in version 0.6.0
- name_obj_list = []
-
- # An integer denoting the character set used for strings in this file.
- # For BIFF 8 and later, this will be 1200, meaning Unicode; more precisely, UTF_16_LE.
- # For earlier versions, this is used to derive the appropriate Python encoding
- # to be used to convert to Unicode.
- # Examples: 1252 -> 'cp1252', 10000 -> 'mac_roman'
- codepage = None
-
- # The encoding that was derived from the codepage.
- encoding = None
-
- # A tuple containing the (telephone system) country code for:
- # [0]: the user-interface setting when the file was created.
- # [1]: the regional settings.
- # Example: (1, 61) meaning (USA, Australia).
- # This information may give a clue to the correct encoding for an unknown codepage.
- # For a long list of observed values, refer to the OpenOffice.org documentation for
- # the COUNTRY record.
- countries = (0, 0)
-
- # What (if anything) is recorded as the name of the last user to save the file.
- user_name = ''
-
- # A list of Font class instances, each corresponding to a FONT record.
- # - New in version 0.6.1
- font_list = []
-
- # A list of XF class instances, each corresponding to an XF record.
- # - New in version 0.6.1
- xf_list = []
-
- # A list of Format objects, each corresponding to a FORMAT record, in
- # the order that they appear in the input file.
- # It does <i>not</i> contain builtin formats.
- # If you are creating an output file using (for example) pyExcelerator,
- # use this list.
- # The collection to be used for all visual rendering purposes is format_map.
- # - New in version 0.6.1
- format_list = []
-
- # The mapping from XF.format_key to Format object.
- # - New in version 0.6.1
- format_map = {}
-
- # This provides access via name to the extended format information for
- # both built-in styles and user-defined styles.
- # It maps <i>name</i> to (<i>built_in</i>, <i>xf_index</i>), where:
- # <i>name</i> is either the name of a user-defined style,
- # or the name of one of the built-in styles. Known built-in names are
- # Normal, RowLevel_1 to RowLevel_7,
- # ColLevel_1 to ColLevel_7, Comma, Currency, Percent, "Comma [0]",
- # "Currency [0]", Hyperlink, and "Followed Hyperlink".
- # ´built_in´ 1 = built-in style, 0 = user-defined
- # ´xf_index´ is an index into Book.xf_list.
- # References: OOo docs s6.99 (STYLE record); Excel UI Format/Style
- # - New in version 0.6.1
- style_name_map = {}
-
- # This provides definitions for colour indexes. Please refer to the
- # above section "The Palette; Colour Indexes" for an explanation
- # of how colours are represented in Excel.
- # Colour indexes into the palette map into (red, green, blue) tuples.
- # "Magic" indexes e.g. 0x7FFF map to None.
- # ´colour_map´ is what you need if you want to render cells on screen or in a PDF
- # file. If you are writing an output XLS file, use <i>palette_record</i>.
- # - New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True)
- colour_map = {}
-
- # If the user has changed any of the colours in the standard palette, the XLS
- # file will contain a PALETTE record with 56 (16 for Excel 4.0 and earlier)
- # RGB values in it, and this list will be e.g. [(r0, b0, g0), ..., (r55, b55, g55)].
- # Otherwise this list will be empty. This is what you need if you are
- # writing an output XLS file. If you want to render cells on screen or in a PDF
- # file, use colour_map.
- # - New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True)
- palette_record = []
-
- # Time in seconds to extract the XLS image as a contiguous string (or mmap equivalent).
- load_time_stage_1 = -1.0
-
- # Time in seconds to parse the data from the contiguous string (or mmap equivalent).
- load_time_stage_2 = -1.0
-
- # @return A list of all sheets in the book.
- # All sheets not already loaded will be loaded.
- def sheets(self):
- for sheetx in range(self.nsheets):
- if not self._sheet_list[sheetx]:
- self.get_sheet(sheetx)
- return self._sheet_list[:]
-
- # @param sheetx Sheet index in range(nsheets)
- # @return An object of the Sheet class
- def sheet_by_index(self, sheetx):
- return self._sheet_list[sheetx] or self.get_sheet(sheetx)
-
- # @param sheet_name Name of sheet required
- # @return An object of the Sheet class
- def sheet_by_name(self, sheet_name):
- try:
- sheetx = self._sheet_names.index(sheet_name)
- except ValueError:
- raise XLRDError('No sheet named <%r>' % sheet_name)
- return self.sheet_by_index(sheetx)
-
- # @return A list of the names of all the worksheets in the workbook file.
- # This information is available even when no sheets have yet been loaded.
- def sheet_names(self):
- return self._sheet_names[:]
-
- # @param sheet_name_or_index Name or index of sheet enquired upon
- # @return true if sheet is loaded, false otherwise
- # -- New in version 0.7.1
- def sheet_loaded(self, sheet_name_or_index):
- # using type(1) because int won't work with Python 2.1
- if isinstance(sheet_name_or_index, type(1)):
- sheetx = sheet_name_or_index
- else:
- try:
- sheetx = self._sheet_names.index(sheet_name_or_index)
- except ValueError:
- raise XLRDError('No sheet named <%r>' % sheet_name_or_index)
- return self._sheet_list[sheetx] and True or False # Python 2.1 again
-
- # @param sheet_name_or_index Name or index of sheet to be unloaded.
- # - New in version 0.7.1
- def unload_sheet(self, sheet_name_or_index):
- # using type(1) because int won't work with Python 2.1
- if isinstance(sheet_name_or_index, type(1)):
- sheetx = sheet_name_or_index
- else:
- try:
- sheetx = self._sheet_names.index(sheet_name_or_index)
- except ValueError:
- raise XLRDError('No sheet named <%r>' % sheet_name_or_index)
- self._sheet_list[sheetx] = None
-
- # A mapping from (lower_case_name, scope) to a single Name object.
- # - New in version 0.6.0
- name_and_scope_map = {}
-
- # A mapping from lower_case_name to a list of Name objects. The list is
- # sorted in scope order. Typically there will be one item (of global scope)
- # in the list.
- # - New in version 0.6.0
- name_map = {}
-
- def __init__(self):
- self._sheet_list = []
- self._sheet_names = []
- self._sheet_visibility = [] # from BOUNDSHEET record
- self.nsheets = 0
- self._sh_abs_posn = [] # sheet's absolute position in the stream
- self._sharedstrings = []
- self.raw_user_name = False
- self._sheethdr_count = 0 # BIFF 4W only
- self.builtinfmtcount = -1 # unknown as yet. BIFF 3, 4S, 4W
- self.initialise_format_info()
- self._all_sheets_count = 0 # includes macro & VBA sheets
- self._supbook_count = 0
- self._supbook_locals_inx = None
- self._supbook_addins_inx = None
-
- # maps an all_sheets index to a calc-sheets index (or -1)
- self._all_sheets_map = []
- self._externsheet_info = []
- self._externsheet_type_b57 = []
- self._extnsht_name_from_num = {}
- self._sheet_num_from_name = {}
- self._extnsht_count = 0
- self._supbook_types = []
- self._resources_released = 0
- self.addin_func_names = []
- self.name_obj_list = []
- self.colour_map = {}
- self.palette_record = []
- self.xf_list = []
- self.style_name_map = {}
-
- def biff2_8_load(self, filename=None,
- file_contents=None,
- logfile=sys.stdout,
- verbosity=0,
- pickleable=True,
- use_mmap=True,
- encoding_override=None,
- formatting_info=False,
- on_demand=False):
-
- self.logfile = logfile
- self.verbosity = verbosity
- self.pickleable = pickleable
- self.use_mmap = use_mmap
- self.encoding_override = encoding_override
- self.formatting_info = formatting_info
- self.on_demand = on_demand
-
- need_close_filestr = 0
- if not file_contents:
- if self.use_mmap:
- open_mode = "r+b"
- else:
- open_mode = "rb"
- retry = False
- try:
- f = open(filename, open_mode)
- except IOError:
- e, v = sys.exc_info()[:2]
- if open_mode == "r+b" and \
- (v.errno == 13 or v.strerror == "Permission denied"):
- # Maybe the file is read-only
- retry = True
- self.use_mmap = False
- else:
- raise
- if retry:
- f = open(filename, "rb")
- if self.use_mmap:
- f.seek(0, 2) # EOF
- size = f.tell()
- f.seek(0, 0) # BOF
- filestr = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ)
- need_close_filestr = 1
- self.stream_len = size
- else:
- filestr = f.read()
- self.stream_len = len(filestr)
- f.close()
- else:
- filestr = file_contents
- self.stream_len = len(file_contents)
-
- self.base = 0
- if filestr[:8] != compdoc.SIGNATURE:
- # got this one at the antique store
- self.mem = filestr
- else:
- cd = compdoc.CompDoc(filestr, logfile=self.logfile)
- if USE_FANCY_CD:
- for qname in ['Workbook', 'Book']:
- self.mem, self.base, self.stream_len = cd.locate_named_stream(qname)
- if self.mem: break
- else:
- raise XLRDError("Can't find workbook in OLE2 compound document")
- else:
- for qname in ['Workbook', 'Book']:
- self.mem = cd.get_named_stream(qname)
- if self.mem: break
- else:
- raise XLRDError("Can't find workbook in OLE2 compound document")
- self.stream_len = len(self.mem)
- del cd
- if self.mem is not filestr:
- if need_close_filestr:
- filestr.close()
- del filestr
- self._position = self.base
- if DEBUG:
- print("mem: %s, base: %d, len: %d" % (type(self.mem), self.base, self.stream_len), file=self.logfile)
-
- def initialise_format_info(self):
- # needs to be done once per sheet for BIFF 4W :-(
- self.format_map = {}
- self.format_list = []
- self.xfcount = 0
- self.actualfmtcount = 0 # number of FORMAT records seen so far
- self._xf_index_to_xl_type_map = {}
- self._xf_epilogue_done = 0
- self.xf_list = []
- self.font_list = []
-
- def release_resources(self):
- self._resources_released = 1
- del self.mem
- del self._sharedstrings
-
- def get2bytes(self):
- pos = self._position
- buff_two = self.mem[pos:pos+2]
- lenbuff = len(buff_two)
- self._position += lenbuff
- if lenbuff < 2:
- return MY_EOF
- lo, hi = buff_two
- return (hi << 8) | lo #(to_py3):
-
- def get_record_parts(self):
- pos = self._position
- mem = self.mem
- code, length = unpack('<HH', mem[pos:pos+4])
- pos += 4
- data = mem[pos:pos+length]
- self._position = pos + length
- return (code, length, data)
-
- def get_record_parts_conditional(self, reqd_record):
- pos = self._position
- mem = self.mem
- code, length = unpack('<HH', mem[pos:pos+4])
- if code != reqd_record:
- return (None, 0, '')
- pos += 4
- data = mem[pos:pos+length]
- self._position = pos + length
- return (code, length, data)
-
- def get_sheet(self, sh_number, update_pos=True):
- if self._resources_released:
- raise XLRDError("Can't load sheets after releasing resources.")
- if update_pos:
- self._position = self._sh_abs_posn[sh_number]
- _unused_biff_version = self.getbof(XL_WORKSHEET)
- # assert biff_version == self.biff_version ### FAILS
- # Have an example where book is v7 but sheet reports v8!!!
- # It appears to work OK if the sheet version is ignored.
- # Confirmed by Daniel Rentz: happens when Excel does "save as"
- # creating an old version file; ignore version details on sheet BOF.
- sh = sheet.Sheet(self,
- self._position,
- self._sheet_names[sh_number],
- sh_number)
- sh.read(self)
- self._sheet_list[sh_number] = sh
- return sh
-
- def get_sheets(self):
- if DEBUG:
- print("GET_SHEETS:", self._sheet_names, self._sh_abs_posn,
- file=self.logfile)
- for sheetno in range(len(self._sheet_names)):
- if DEBUG:
- print("GET_SHEETS: sheetno =", sheetno, self._sheet_names,
- self._sh_abs_posn, file=self.logfile)
- self.get_sheet(sheetno)
-
- def fake_globals_get_sheet(self): # for BIFF 4.0 and earlier
- formatting.initialise_book(self)
- fake_sheet_name = 'Sheet 1'
- self._sheet_names = [fake_sheet_name]
- self._sh_abs_posn = [0]
- self._sheet_visibility = [0] # one sheet, visible
- self._sheet_list.append(None) # get_sheet updates _sheet_list but needs a None beforehand
- self.get_sheets()
-
- def handle_boundsheet(self, data):
- self.derive_encoding()
- if DEBUG:
- fprintf(self.logfile, "BOUNDSHEET: bv=%d data %r\n", self.biff_version, data)
- if self.biff_version == 45: # BIFF4W
- #### Not documented in OOo docs ...
- # In fact, the *only* data is the name of the sheet.
- sheet_name = unpack_string(data, 0, self.encoding, lenlen=1)
- visibility = 0
- sheet_type = XL_BOUNDSHEET_WORKSHEET # guess, patch later
- if len(self._sh_abs_posn) == 0:
- abs_posn = self._sheetsoffset + self.base
- # Note (a) this won't be used
- # (b) it's the position of the SHEETHDR record
- # (c) add 11 to get to the worksheet BOF record
- else:
- abs_posn = -1 # unknown
- else:
- offset, visibility, sheet_type = unpack('<iBB', data[0:6])
- abs_posn = offset + self.base # because global BOF is always at posn 0 in the stream
- if self.biff_version < BIFF_FIRST_UNICODE:
- sheet_name = unpack_string(data, 6, self.encoding, lenlen=1)
- else:
- sheet_name = unpack_unicode(data, 6, lenlen=1)
-
- if DEBUG or self.verbosity >= 2:
- fprintf(self.logfile,
- "BOUNDSHEET: inx=%d vis=%r sheet_name=%r abs_posn=%d sheet_type=0x%02x\n",
- self._all_sheets_count, visibility, sheet_name, abs_posn, sheet_type)
- self._all_sheets_count += 1
- if sheet_type != XL_BOUNDSHEET_WORKSHEET:
- self._all_sheets_map.append(-1)
- descr = {
- 1: 'Macro sheet',
- 2: 'Chart',
- 6: 'Visual Basic module',
- }.get(sheet_type, 'UNKNOWN')
-
- fprintf(self.logfile,
- "NOTE *** Ignoring non-worksheet data named %r (type 0x%02x = %s)\n",
- sheet_name, sheet_type, descr)
- else:
- snum = len(self._sheet_names)
- self._all_sheets_map.append(snum)
- self._sheet_names.append(sheet_name)
- self._sh_abs_posn.append(abs_posn)
- self._sheet_visibility.append(visibility)
- self._sheet_num_from_name[sheet_name] = snum
-
- def handle_builtinfmtcount(self, data):
- # N.B. This count appears to be utterly useless.
- builtinfmtcount = unpack('<H', data[0:2])[0]
- if DEBUG:
- fprintf(self.logfile, "BUILTINFMTCOUNT: %r\n", builtinfmtcount)
- self.builtinfmtcount = builtinfmtcount
-
- def derive_encoding(self):
- if self.encoding_override:
- self.encoding = self.encoding_override
- elif self.codepage is None:
- if self.biff_version < 80:
- fprintf(self.logfile,
- "*** No CODEPAGE record, no encoding_override: will use 'ascii'\n")
- self.encoding = 'ascii'
- else:
- self.codepage = 1200 # utf16le
- if self.verbosity >= 2:
- fprintf(self.logfile, "*** No CODEPAGE record; assuming 1200 (utf_16_le)\n")
- else:
- codepage = self.codepage
- if codepage in encoding_from_codepage:
- encoding = encoding_from_codepage[codepage]
- elif 300 <= codepage <= 1999:
- encoding = 'cp' + str(codepage)
- else:
- encoding = 'unknown_codepage_' + str(codepage)
- if DEBUG or (self.verbosity and encoding != self.encoding) :
- fprintf(self.logfile, "CODEPAGE: codepage %r -> encoding %r\n",
- codepage, encoding)
- self.encoding = encoding
- if self.codepage != 1200: # utf_16_le
- # If we don't have a codec that can decode ASCII into Unicode,
- # we're well & truly stuffed -- let the punter know ASAP.
- try:
- _unused = str(b'trial', self.encoding)
- except:
- ei = sys.exc_info()[:2]
- fprintf(self.logfile,
- "ERROR *** codepage %r -> encoding %r -> %s: %s\n",
- self.codepage, self.encoding, ei[0].__name__.split(".")[-1], ei[1])
- raise
- if self.raw_user_name:
- strg = unpack_string(self.user_name, 0, self.encoding, lenlen=1)
- strg = strg.rstrip()
- self.user_name = strg
- self.raw_user_name = False
- return self.encoding
-
- def handle_codepage(self, data):
- codepage = unpack('<H', data[0:2])[0]
- self.codepage = codepage
- self.derive_encoding()
-
- def handle_country(self, data):
- countries = unpack('<HH', data[0:4])
- if self.verbosity:
- print("Countries:", countries, file=self.logfile)
- # Note: in BIFF7 and earlier, country record was put (redundantly?) in each worksheet.
- assert self.countries == (0, 0) or self.countries == countries
- self.countries = countries
-
- def handle_datemode(self, data):
- datemode = unpack('<H', data[0:2])[0]
- if DEBUG or self.verbosity:
- fprintf(self.logfile, "DATEMODE: datemode %r\n", datemode)
- assert datemode in (0, 1)
- self.datemode = datemode
-
- def handle_externname(self, data):
- verbose = DEBUG or self.verbosity >= 2
- if self.biff_version >= 80:
- option_flags, other_info =unpack("<HI", data[:6])
- pos = 6
- name, pos = unpack_unicode_update_pos(data, pos, lenlen=1)
- extra = data[pos:]
- if self._supbook_types[-1] == SUPBOOK_ADDIN:
- self.addin_func_names.append(name)
- if verbose:
- fprintf(self.logfile,
- "EXTERNNAME: sbktype=%d oflags=0x%04x oinfo=0x%08x name=%r extra=%r\n",
- self._supbook_types[-1], option_flags, other_info, name, extra)
-
- def handle_externsheet(self, data):
- self.derive_encoding() # in case CODEPAGE record missing/out of order/wrong
- self._extnsht_count += 1 # for use as a 1-based index
- verbose1 = DEBUG or self.verbosity >= 1
- verbose2 = DEBUG or self.verbosity >= 2
- if self.biff_version >= 80:
- num_refs = unpack("<H", data[0:2])[0]
- bytes_reqd = num_refs * 6 + 2
- while len(data) < bytes_reqd:
- if verbose1:
- fprintf(
- self.logfile,
- "INFO: EXTERNSHEET needs %d bytes, have %d\n",
- bytes_reqd, len(data))
- code2, length2, data2 = self.get_record_parts()
- if code2 != XL_CONTINUE:
- raise XLRDError("Missing CONTINUE after EXTERNSHEET record")
- data += data2
- pos = 2
- for k in range(num_refs):
- info = unpack("<HHH", data[pos:pos+6])
- ref_recordx, ref_first_sheetx, ref_last_sheetx = info
- self._externsheet_info.append(info)
- pos += 6
- if verbose2:
- fprintf(
- self.logfile,
- "EXTERNSHEET(b8): k = %2d, record = %2d, first_sheet = %5d, last sheet = %5d\n",
- k, ref_recordx, ref_first_sheetx, ref_last_sheetx)
- else:
- nc, ty = unpack("<BB", data[:2])
- if verbose2:
- print("EXTERNSHEET(b7-):")
- hex_char_dump(data, 0, len(data))
- msg = {
- 1: "Encoded URL",
- 2: "Current sheet!!",
- 3: "Specific sheet in own doc't",
- 4: "Nonspecific sheet in own doc't!!",
- }.get(ty, "Not encoded")
- print(" %3d chars, type is %d (%s)" % (nc, ty, msg))
- if ty == 3:
- sheet_name = str(data[2:nc+2], self.encoding)
- self._extnsht_name_from_num[self._extnsht_count] = sheet_name
- if verbose2: print(self._extnsht_name_from_num)
- if not (1 <= ty <= 4):
- ty = 0
- self._externsheet_type_b57.append(ty)
-
- def handle_filepass(self, data):
- if self.verbosity >= 2:
- logf = self.logfile
- fprintf(logf, "FILEPASS:\n")
- hex_char_dump(data, 0, len(data), base=0, fout=logf)
- if self.biff_version >= 80:
- kind1, = unpack('<H', data[:2])
- if kind1 == 0: # weak XOR encryption
- key, hash_value = unpack('<HH', data[2:])
- fprintf(logf,
- 'weak XOR: key=0x%04x hash=0x%04x\n',
- key, hash_value)
- elif kind1 == 1:
- kind2, = unpack('<H', data[4:6])
- if kind2 == 1: # BIFF8 standard encryption
- caption = "BIFF8 std"
- elif kind2 == 2:
- caption = "BIFF8 strong"
- else:
- caption = "** UNKNOWN ENCRYPTION METHOD **"
- fprintf(logf, "%s\n", caption)
- raise XLRDError("Workbook is encrypted")
-
- def handle_name(self, data):
- verbose = DEBUG or self.verbosity >= 2
- if self.biff_version < 50:
- return
- self.derive_encoding()
-
- # unpack
- (option_flags,
- kb_shortcut,
- name_len,
- fmla_len,
- extsht_index,
- sheet_index,
- menu_text_len,
- description_text_len,
- help_topic_text_len,
- status_bar_text_len) = unpack("<HBBHHH4B", data[0:14])
-
- nobj = Name()
- nobj.book = self ### CIRCULAR ###
- name_index = len(self.name_obj_list)
- nobj.name_index = name_index
- self.name_obj_list.append(nobj)
- nobj.option_flags = option_flags
- for attr, mask, nshift in (
- ('hidden', 1, 0),
- ('func', 2, 1),
- ('vbasic', 4, 2),
- ('macro', 8, 3),
- ('complex', 0x10, 4),
- ('builtin', 0x20, 5),
- ('funcgroup', 0xFC0, 6),
- ('binary', 0x1000, 12),
- ):
- setattr(nobj, attr, (option_flags & mask) >> nshift)
-
- macro_flag = " M"[nobj.macro]
- if self.biff_version < 80:
- internal_name, pos = unpack_string_update_pos(data, 14, self.encoding, known_len=name_len)
- else:
- internal_name, pos = unpack_unicode_update_pos(data, 14, known_len=name_len)
- nobj.extn_sheet_num = extsht_index
- nobj.excel_sheet_index = sheet_index
- nobj.scope = None # patched up in the names_epilogue() method
- if verbose:
- print("NAME[%d]:%s oflags=%d, name_len=%d, fmla_len=%d, extsht_index=%d, sheet_index=%d, name=%r" \
- % (name_index, macro_flag, option_flags, name_len,
- fmla_len, extsht_index, sheet_index, internal_name))
- name = internal_name
- if nobj.builtin:
- name = builtin_name_from_code.get(name, "??Unknown??")
- if verbose: print(" builtin: %s" % name)
- nobj.name = name
- nobj.raw_formula = data[pos:]
- nobj.basic_formula_len = fmla_len
- nobj.evaluated = 0
- if verbose:
- nobj.dump(self.logfile,
- header="--- handle_name: name[%d] ---" % name_index,
- footer="-------------------")
-
- def names_epilogue(self):
- verbose = self.verbosity >= 2
- f = self.logfile
- if verbose:
- print("+++++ names_epilogue +++++", file=f)
- print("_all_sheets_map", self._all_sheets_map, file=f)
- print("_extnsht_name_from_num", self._extnsht_name_from_num, file=f)
- print("_sheet_num_from_name", self._sheet_num_from_name, file=f)
- num_names = len(self.name_obj_list)
- for namex in range(num_names):
- nobj = self.name_obj_list[namex]
- # Convert from excel_sheet_index to scope.
- # This is done here because in BIFF7 and earlier, the
- # BOUNDSHEET records (from which _all_sheets_map is derived)
- # come after the NAME records.
- if self.biff_version >= 80:
- sheet_index = nobj.excel_sheet_index
- if sheet_index == 0:
- intl_sheet_index = -1 # global
- elif 1 <= sheet_index <= len(self._all_sheets_map):
- intl_sheet_index = self._all_sheets_map[sheet_index-1]
- if intl_sheet_index == -1: # maps to a macro or VBA sheet
- intl_sheet_index = -2 # valid sheet reference but not useful
- else:
- # huh?
- intl_sheet_index = -3 # invalid
- elif 50 <= self.biff_version <= 70:
- sheet_index = nobj.extn_sheet_num
- if sheet_index == 0:
- intl_sheet_index = -1 # global
- else:
- sheet_name = self._extnsht_name_from_num[sheet_index]
- intl_sheet_index = self._sheet_num_from_name.get(sheet_name, -2)
- nobj.scope = intl_sheet_index
-
- for namex in range(num_names):
- nobj = self.name_obj_list[namex]
- # Parse the formula ...
- if nobj.macro or nobj.binary: continue
- if nobj.evaluated: continue
- evaluate_name_formula(self, nobj, namex, verbose=verbose)
-
- if self.verbosity >= 2:
- print("---------- name object dump ----------", file=f)
- for namex in range(num_names):
- nobj = self.name_obj_list[namex]
- nobj.dump(f, header="--- name[%d] ---" % namex)
- print("--------------------------------------", file=f)
- #
- # Build some dicts for access to the name objects
- #
- name_and_scope_map = {}
- name_map = {}
- for namex in range(num_names):
- nobj = self.name_obj_list[namex]
- name_lcase = nobj.name.lower()
- key = (name_lcase, nobj.scope)
- if key in name_and_scope_map:
- msg = 'Duplicate entry %r in name_and_scope_map' % (key, )
- if 0:
- raise XLRDError(msg)
- else:
- if self.verbosity:
- print(msg, file=f)
- name_and_scope_map[key] = nobj
- if name_lcase in name_map:
- name_map[name_lcase].append((nobj.scope, nobj))
- else:
- name_map[name_lcase] = [(nobj.scope, nobj)]
- for key in list(name_map.keys()):
- alist = name_map[key]
- alist.sort()
- name_map[key] = [x[1] for x in alist]
- self.name_and_scope_map = name_and_scope_map
- self.name_map = name_map
-
- def handle_obj(self, data):
- # Not doing much handling at all.
- # Worrying about embedded (BOF ... EOF) substreams is done elsewhere.
- obj_type, obj_id = unpack('<HI', data[4:10])
-
- def handle_supbook(self, data):
- self._supbook_types.append(None)
- verbose = DEBUG or self.verbosity >= 2
- num_sheets = unpack("<H", data[0:2])[0]
- sbn = self._supbook_count
- self._supbook_count += 1
- if data[2:4] == b"\x01\x04":
- self._supbook_types[-1] = SUPBOOK_INTERNAL
- self._supbook_locals_inx = self._supbook_count - 1
- if verbose:
- print("SUPBOOK[%d]: internal 3D refs; %d sheets" % (sbn, num_sheets))
- print(" _all_sheets_map", self._all_sheets_map)
- return
-
- if data[0:4] == b"\x01\x00\x01\x3A":
- self._supbook_types[-1] = SUPBOOK_ADDIN
- self._supbook_addins_inx = self._supbook_count - 1
- if verbose:
- print("SUPBOOK[%d]: add-in functions" % sbn)
- return
-
- url, pos = unpack_unicode_update_pos(data, 2, lenlen=2)
- if num_sheets == 0:
- self._supbook_types[-1] = SUPBOOK_DDEOLE
- if verbose:
- print("SUPBOOK[%d]: DDE/OLE document = %r" % (sbn, url))
- return
-
- self._supbook_types[-1] = SUPBOOK_EXTERNAL
- if verbose:
- print("SUPBOOK[%d]: url = %r" % (sbn, url))
- sheet_names = []
- for x in range(num_sheets):
- shname, pos = unpack_unicode_update_pos(data, pos, lenlen=2)
- sheet_names.append(shname)
- if verbose:
- print(" sheet %d: %r" % (x, shname))
-
- def handle_sheethdr(self, data):
- # This a BIFF 4W special.
- # The SHEETHDR record is followed by a (BOF ... EOF) substream containing
- # a worksheet.
- self.derive_encoding()
- sheet_len = unpack('<i', data[:4])[0]
- sheet_name = unpack_string(data, 4, self.encoding, lenlen=1)
- sheetno = self._sheethdr_count
- assert sheet_name == self._sheet_names[sheetno]
- self._sheethdr_count += 1
- BOF_posn = self._position
- posn = BOF_posn - 4 - len(data)
- if DEBUG:
- print('SHEETHDR %d at posn %d: len=%d name=%r' % (sheetno, posn, sheet_len, sheet_name), file=self.logfile)
- self.initialise_format_info()
- if DEBUG:
- print('SHEETHDR: xf epilogue flag is %d' % self._xf_epilogue_done, file=self.logfile)
- self._sheet_list.append(None) # get_sheet updates _sheet_list but needs a None beforehand
- self.get_sheet(sheetno, update_pos=False)
- if DEBUG:
- print('SHEETHDR: posn after get_sheet() =', self._position, file=self.logfile)
- self._position = BOF_posn + sheet_len
-
- def handle_sheetsoffset(self, data):
- posn = unpack('<i', data)[0]
- if DEBUG:
- print('SHEETSOFFSET:', posn, file=self.logfile)
- self._sheetsoffset = posn
-
- def handle_sst(self, data):
- if DEBUG:
- print("SST Processing", file=self.logfile)
- t0 = time.time()
- nbt = len(data)
- strlist = [data]
- uniquestrings = unpack('<i', data[4:8])[0]
- if DEBUG or self.verbosity >= 2:
- fprintf(self.logfile, "SST: unique strings: %d\n", uniquestrings)
- while True:
- code, nb, data = self.get_record_parts_conditional(XL_CONTINUE)
- if code is None:
- break
- nbt += nb
- if DEBUG:
- fprintf(self.logfile, "CONTINUE: adding %d bytes to SST -> %d\n", nb, nbt)
- strlist.append(data)
- self._sharedstrings = unpack_SST_table(strlist, uniquestrings)
- if DEBUG:
- t1 = time.time()
- print("SST processing took %.2f seconds" % (t1 - t0, ), file=self.logfile)
-
- def handle_writeaccess(self, data):
- if self.biff_version < 80:
- if not self.encoding:
- self.raw_user_name = True
- self.user_name = data
- return
- strg = unpack_string(data, 0, self.encoding, lenlen=1)
- else:
- strg = unpack_unicode(data, 0, lenlen=2)
- if DEBUG:
- print("WRITEACCESS: %d bytes; raw=%d %r" % (len(data), self.raw_user_name, strg), file=self.logfile)
- strg = strg.rstrip()
- self.user_name = strg
-
- def parse_globals(self):
- # no need to position, just start reading (after the BOF)
- formatting.initialise_book(self)
- while True:
- rc, length, data = self.get_record_parts()
- if DEBUG:
- print("parse_globals: record code is 0x%04x" % rc)
- if rc == XL_SST:
- self.handle_sst(data)
- elif rc == XL_FONT or rc == XL_FONT_B3B4:
- self.handle_font(data)
- elif rc == XL_FORMAT: # XL_FORMAT2 is BIFF <= 3.0, can't appear in globals
- self.handle_format(data)
- elif rc == XL_XF:
- self.handle_xf(data)
- elif rc == XL_BOUNDSHEET:
- self.handle_boundsheet(data)
- elif rc == XL_DATEMODE:
- self.handle_datemode(data)
- elif rc == XL_CODEPAGE:
- self.handle_codepage(data)
- elif rc == XL_COUNTRY:
- self.handle_country(data)
- elif rc == XL_EXTERNNAME:
- self.handle_externname(data)
- elif rc == XL_EXTERNSHEET:
- self.handle_externsheet(data)
- elif rc == XL_FILEPASS:
- self.handle_filepass(data)
- elif rc == XL_WRITEACCESS:
- self.handle_writeaccess(data)
- elif rc == XL_SHEETSOFFSET:
- self.handle_sheetsoffset(data)
- elif rc == XL_SHEETHDR:
- self.handle_sheethdr(data)
- elif rc == XL_SUPBOOK:
- self.handle_supbook(data)
- elif rc == XL_NAME:
- self.handle_name(data)
- elif rc == XL_PALETTE:
- self.handle_palette(data)
- elif rc == XL_STYLE:
- self.handle_style(data)
- elif rc & 0xff == 9:
- print("*** Unexpected BOF at posn %d: 0x%04x len=%d data=%r" \
- % (self._position - length - 4, rc, length, data), file=self.logfile)
- elif rc == XL_EOF:
- self.xf_epilogue()
- self.names_epilogue()
- self.palette_epilogue()
- if not self.encoding:
- self.derive_encoding()
- if self.biff_version == 45:
- if DEBUG:
- print("global EOF: position", self._position)
- return
-
- def read(self, pos, length):
- data = self.mem[pos:pos+length]
- self._position = pos + len(data)
- return data
-
- def getbof(self, rqd_stream):
- def bof_error(msg):
- raise XLRDError('Unsupported format, or corrupt file: ' + msg)
-
- if DEBUG:
- print("reqd: 0x%04x" % rqd_stream, file=self.logfile)
-
- savpos = self._position
- opcode = self.get2bytes()
-
- if opcode == MY_EOF:
- bof_error('Expected BOF record; met end of file')
-
- if opcode not in bofcodes:
- bof_error('Expected BOF record; found %r' % self.mem[savpos:savpos+8])
-
- length = self.get2bytes()
- if length == MY_EOF:
- bof_error('Incomplete BOF record[1]; met end of file')
-
- if length < boflen[opcode] or length > 20:
- bof_error('Invalid length (%d) for BOF record type 0x%04x' % (length, opcode))
-
- data = self.read(self._position, length);
- if DEBUG: print("\ngetbof(): data=%r" % data, file=self.logfile)
- if len(data) < length:
- bof_error('Incomplete BOF record[2]; met end of file')
- version1 = opcode >> 8
- version2, streamtype = unpack('<HH', data[0:4])
- if DEBUG:
- print("getbof(): op=0x%04x version2=0x%04x streamtype=0x%04x" \
- % (opcode, version2, streamtype), file=self.logfile)
- bof_offset = self._position - 4 - length
- if DEBUG:
- print("getbof(): BOF found at offset %d; savpos=%d" \
- % (bof_offset, savpos), file=self.logfile)
- version = build = year = 0
- if version1 == 0x08:
- build, year = unpack('<HH', data[4:8])
- if version2 == 0x0600:
- version = 80
- elif version2 == 0x0500:
- if year < 1994 or build in (2412, 3218, 3321):
- version = 50
- else:
- version = 70
- else:
- # dodgy one, created by a 3rd-party tool
- version = {
- 0x0000: 21,
- 0x0007: 21,
- 0x0200: 21,
- 0x0300: 30,
- 0x0400: 40,
- }.get(version2, 0)
- elif version1 in (0x04, 0x02, 0x00):
- version = {0x04: 40, 0x02: 30, 0x00: 21}[version1]
-
- if version == 40 and streamtype == XL_WORKBOOK_GLOBALS_4W:
- version = 45 # i.e. 4W
-
- if DEBUG or self.verbosity >= 2:
- print("BOF: op=0x%04x vers=0x%04x stream=0x%04x buildid=%d buildyr=%d -> BIFF%d" \
- % (opcode, version2, streamtype, build, year, version), file=self.logfile)
- got_globals = streamtype == XL_WORKBOOK_GLOBALS or (
- version == 45 and streamtype == XL_WORKBOOK_GLOBALS_4W)
- if (rqd_stream == XL_WORKBOOK_GLOBALS and got_globals) or streamtype == rqd_stream:
- return version
- if version < 50 and streamtype == XL_WORKSHEET:
- return version
- if version >= 50 and streamtype == 0x0100:
- bof_error("Workspace file -- no spreadsheet data")
- bof_error(
- 'BOF not workbook/worksheet: op=0x%04x vers=0x%04x strm=0x%04x build=%d year=%d -> BIFF%d' \
- % (opcode, version2, streamtype, build, year, version))
-
-# === helper functions
-
-def expand_cell_address(inrow, incol):
- # Ref : OOo docs, "4.3.4 Cell Addresses in BIFF8"
- outrow = inrow
- if incol & 0x8000:
- if outrow >= 32768:
- outrow -= 65536
- relrow = 1
- else:
- relrow = 0
- outcol = incol & 0xFF
- if incol & 0x4000:
- if outcol >= 128:
- outcol -= 256
- relcol = 1
- else:
- relcol = 0
- return outrow, outcol, relrow, relcol
-
-def colname(colx, _A2Z="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
- assert colx >= 0
- name = ''
- while True:
- quot, rem = divmod(colx, 26)
- name = _A2Z[rem] + name
- if not quot:
- return name
- colx = quot - 1
-
-def display_cell_address(rowx, colx, relrow, relcol):
- if relrow:
- rowpart = "(*%s%d)" % ("+-"[rowx < 0], abs(rowx))
- else:
- rowpart = "$%d" % (rowx+1,)
- if relcol:
- colpart = "(*%s%d)" % ("+-"[colx < 0], abs(colx))
- else:
- colpart = "$" + colname(colx)
- return colpart + rowpart
-
-def unpack_SST_table(datatab, nstrings):
- """ Return list of strings """
- datainx = 0
- ndatas = len(datatab)
- data = datatab[0]
- datalen = len(data)
- pos = 8
- strings = []
- strappend = strings.append
- local_unpack = unpack
- local_min = min
- #(to_py3): local_ord = ord
- latin_1 = "latin_1"
- for _unused_i in range(nstrings):
- nchars = local_unpack('<H', data[pos:pos+2])[0]
- pos += 2
- #(to_py3): options = local_ord(data[pos])
- options = data[pos]
- pos += 1
- rtsz = 0
- if options & 0x08: # richtext
- rtsz = 4 * local_unpack('<H', data[pos:pos+2])[0]
- pos += 2
- if options & 0x04: # phonetic
- rtsz += local_unpack('<i', data[pos:pos+4])[0]
- pos += 4
- accstrg = ''
- charsgot = 0
- while True:
- charsneed = nchars - charsgot
- if options & 0x01:
- # Uncompressed UTF-16
- charsavail = local_min((datalen - pos) >> 1, charsneed)
- rawstrg = data[pos:pos+2*charsavail]
- try:
- #(to_py3) accstrg += unicode(rawstrg, "utf_16_le")
- accstrg += str(rawstrg, "utf_16_le")
- except:
- # print "SST U16: nchars=%d pos=%d rawstrg=%r" % (nchars, pos, rawstrg)
- # Probable cause: dodgy data e.g. unfinished surrogate pair.
- # E.g. file unicode2.xls in pyExcelerator's examples has cells containing
- # unichr(i) for i in range(0x100000)
- # so this will include 0xD800 etc
- raise
- pos += (2 * charsavail)
- else:
- # Note: this is COMPRESSED (not ASCII!) encoding!!!
- charsavail = local_min(datalen - pos, charsneed)
- rawstrg = data[pos:pos+charsavail]
- #(to_py3) accstrg += unicode(rawstrg, latin_1)
- accstrg += str(rawstrg, latin_1)
- pos += charsavail
- charsgot += charsavail
- if charsgot == nchars:
- break
- datainx += 1
- data = datatab[datainx]
- datalen = len(data)
- #(to_py3): options = local_ord(data[0])
- options = data[0]
- pos = 1
- pos += rtsz # size of richtext & phonetic stuff to skip
- # also allow for the rich text etc being split ...
- if pos >= datalen:
- # adjust to correct position in next record
- pos = pos - datalen
- datainx += 1
- if datainx < ndatas:
- data = datatab[datainx]
- datalen = len(data)
- else:
- assert _unused_i == nstrings - 1
- strappend(accstrg)
- return strings
diff --git a/tablib/packages/xlrd3/biffh.py b/tablib/packages/xlrd3/biffh.py deleted file mode 100644 index d99e3a3..0000000 --- a/tablib/packages/xlrd3/biffh.py +++ /dev/null @@ -1,620 +0,0 @@ -# Support module for the xlrd3 package.
-#
-# Portions copyright (c) 2005-2008 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd package, which is released under a
-# BSD-style licence.
-#
-# 2010-12-08 mozman refactoring for python 3
-# 2008-02-10 SJM BIFF2 BLANK record
-# 2008-02-08 SJM Preparation for Excel 2.0 support
-# 2008-02-02 SJM Added suffixes (_B2, _B2_ONLY, etc) on record names for
-# biff_dump & biff_count
-# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files.
-# 2007-09-08 SJM Avoid crash when zero-length Unicode string missing options byte.
-# 2007-04-22 SJM Remove experimental "trimming" facility.
-
-import sys
-from struct import unpack
-
-encoding_from_codepage = {
- 1200 : 'utf_16_le',
- 10000: 'mac_roman',
- 10006: 'mac_greek', # guess
- 10007: 'mac_cyrillic', # guess
- 10029: 'mac_latin2', # guess
- 10079: 'mac_iceland', # guess
- 10081: 'mac_turkish', # guess
- 32768: 'mac_roman',
- 32769: 'cp1252',
- }
-
-# some more guessing, for Indic scripts
-# codepage 57000 range:
-# 2 Devanagari [0]
-# 3 Bengali [1]
-# 4 Tamil [5]
-# 5 Telegu [6]
-# 6 Assamese [1] c.f. Bengali
-# 7 Oriya [4]
-# 8 Kannada [7]
-# 9 Malayalam [8]
-# 10 Gujarati [3]
-# 11 Gurmukhi [2]
-
-FUN = 0 # unknown
-FDT = 1 # date
-FNU = 2 # number
-FGE = 3 # general
-FTX = 4 # text
-
-DATEFORMAT = FDT
-NUMBERFORMAT = FNU
-
-XL_CELL_EMPTY = 0
-XL_CELL_TEXT = 1
-XL_CELL_NUMBER = 2
-XL_CELL_DATE = 3
-XL_CELL_BOOLEAN = 4
-XL_CELL_ERROR = 5
-XL_CELL_BLANK = 6 # for use in debugging, gathering stats, etc
-
-biff_text_from_num = {
- 0: "(not BIFF)",
- 20: "2.0",
- 21: "2.1",
- 30: "3",
- 40: "4S",
- 45: "4W",
- 50: "5",
- 70: "7",
- 80: "8",
- 85: "8X",
-}
-
-# This dictionary can be used to produce a text version of the internal codes
-# that Excel uses for error cells. Here are its contents:
-error_text_from_code = {
- 0x00: '#NULL!', # Intersection of two cell ranges is empty
- 0x07: '#DIV/0!', # Division by zero
- 0x0F: '#VALUE!', # Wrong type of operand
- 0x17: '#REF!', # Illegal or deleted cell reference
- 0x1D: '#NAME?', # Wrong function or range name
- 0x24: '#NUM!', # Value range overflow
- 0x2A: '#N/A!', # Argument or function not available
-}
-
-BIFF_FIRST_UNICODE = 80
-
-XL_WORKBOOK_GLOBALS = WBKBLOBAL = 0x5
-XL_WORKBOOK_GLOBALS_4W = 0x100
-XL_WORKSHEET = WRKSHEET = 0x10
-
-XL_BOUNDSHEET_WORKSHEET = 0x00
-XL_BOUNDSHEET_CHART = 0x02
-XL_BOUNDSHEET_VB_MODULE = 0x06
-
-# XL_RK2 = 0x7e
-XL_ARRAY = 0x0221
-XL_ARRAY2 = 0x0021
-XL_BLANK = 0x0201
-XL_BLANK_B2 = 0x01
-XL_BOF = 0x809
-XL_BOOLERR = 0x205
-XL_BOOLERR_B2 = 0x5
-XL_BOUNDSHEET = 0x85
-XL_BUILTINFMTCOUNT = 0x56
-XL_CF = 0x01B1
-XL_CODEPAGE = 0x42
-XL_COLINFO = 0x7D
-XL_COLUMNDEFAULT = 0x20 # BIFF2 only
-XL_COLWIDTH = 0x24 # BIFF2 only
-XL_CONDFMT = 0x01B0
-XL_CONTINUE = 0x3c
-XL_COUNTRY = 0x8C
-XL_DATEMODE = 0x22
-XL_DEFAULTROWHEIGHT = 0x0225
-XL_DEFCOLWIDTH = 0x55
-XL_DIMENSION = 0x200
-XL_DIMENSION2 = 0x0
-XL_EFONT = 0x45
-XL_EOF = 0x0a
-XL_EXTERNNAME = 0x23
-XL_EXTERNSHEET = 0x17
-XL_EXTSST = 0xff
-XL_FEAT11 = 0x872
-XL_FILEPASS = 0x2f
-XL_FONT = 0x31
-XL_FONT_B3B4 = 0x231
-XL_FORMAT = 0x41e
-XL_FORMAT2 = 0x1E # BIFF2, BIFF3
-XL_FORMULA = 0x6
-XL_FORMULA3 = 0x206
-XL_FORMULA4 = 0x406
-XL_GCW = 0xab
-XL_INDEX = 0x20b
-XL_INTEGER = 0x2 # BIFF2 only
-XL_IXFE = 0x44 # BIFF2 only
-XL_LABEL = 0x204
-XL_LABEL_B2 = 0x04
-XL_LABELRANGES = 0x15f
-XL_LABELSST = 0xfd
-XL_MERGEDCELLS = 0xE5
-XL_MSO_DRAWING = 0x00EC
-XL_MSO_DRAWING_GROUP = 0x00EB
-XL_MSO_DRAWING_SELECTION = 0x00ED
-XL_MULRK = 0xbd
-XL_MULBLANK = 0xbe
-XL_NAME = 0x18
-XL_NOTE = 0x1c
-XL_NUMBER = 0x203
-XL_NUMBER_B2 = 0x3
-XL_OBJ = 0x5D
-XL_PALETTE = 0x92
-XL_RK = 0x27e
-XL_ROW = 0x208
-XL_ROW_B2 = 0x08
-XL_RSTRING = 0xd6
-XL_SHEETHDR = 0x8F # BIFF4W only
-XL_SHEETSOFFSET = 0x8E # BIFF4W only
-XL_SHRFMLA = 0x04bc
-XL_SST = 0xfc
-XL_STANDARDWIDTH = 0x99
-XL_STRING = 0x207
-XL_STRING_B2 = 0x7
-XL_STYLE = 0x293
-XL_SUPBOOK = 0x1AE
-XL_TABLEOP = 0x236
-XL_TABLEOP2 = 0x37
-XL_TABLEOP_B2 = 0x36
-XL_TXO = 0x1b6
-XL_UNCALCED = 0x5e
-XL_UNKNOWN = 0xffff
-XL_WINDOW2 = 0x023E
-XL_WRITEACCESS = 0x5C
-XL_XF = 0xe0
-XL_XF2 = 0x0043 # BIFF2 version of XF record
-XL_XF3 = 0x0243 # BIFF3 version of XF record
-XL_XF4 = 0x0443 # BIFF4 version of XF record
-
-boflen = {
- 0x0809: 8,
- 0x0409: 6,
- 0x0209: 6,
- 0x0009: 4,
-}
-
-bofcodes = (0x0809, 0x0409, 0x0209, 0x0009)
-
-XL_FORMULA_OPCODES = (0x0006, 0x0406, 0x0206)
-
-_cell_opcode_list = (
- XL_BOOLERR,
- XL_FORMULA,
- XL_FORMULA3,
- XL_FORMULA4,
- XL_LABEL,
- XL_LABELSST,
- XL_MULRK,
- XL_NUMBER,
- XL_RK,
- XL_RSTRING,
-)
-
-biff_rec_name_dict = {
- 0x0000: 'DIMENSIONS_B2',
- 0x0001: 'BLANK_B2',
- 0x0002: 'INTEGER_B2_ONLY',
- 0x0003: 'NUMBER_B2',
- 0x0004: 'LABEL_B2',
- 0x0005: 'BOOLERR_B2',
- 0x0006: 'FORMULA',
- 0x0007: 'STRING_B2',
- 0x0008: 'ROW_B2',
- 0x0009: 'BOF_B2',
- 0x000A: 'EOF',
- 0x000B: 'INDEX_B2_ONLY',
- 0x000C: 'CALCCOUNT',
- 0x000D: 'CALCMODE',
- 0x000E: 'PRECISION',
- 0x000F: 'REFMODE',
- 0x0010: 'DELTA',
- 0x0011: 'ITERATION',
- 0x0012: 'PROTECT',
- 0x0013: 'PASSWORD',
- 0x0014: 'HEADER',
- 0x0015: 'FOOTER',
- 0x0016: 'EXTERNCOUNT',
- 0x0017: 'EXTERNSHEET',
- 0x0018: 'NAME_B2,5+',
- 0x0019: 'WINDOWPROTECT',
- 0x001A: 'VERTICALPAGEBREAKS',
- 0x001B: 'HORIZONTALPAGEBREAKS',
- 0x001C: 'NOTE',
- 0x001D: 'SELECTION',
- 0x001E: 'FORMAT_B2-3',
- 0x001F: 'BUILTINFMTCOUNT_B2',
- 0x0020: 'COLUMNDEFAULT_B2_ONLY',
- 0x0021: 'ARRAY_B2_ONLY',
- 0x0022: 'DATEMODE',
- 0x0023: 'EXTERNNAME',
- 0x0024: 'COLWIDTH_B2_ONLY',
- 0x0025: 'DEFAULTROWHEIGHT_B2_ONLY',
- 0x0026: 'LEFTMARGIN',
- 0x0027: 'RIGHTMARGIN',
- 0x0028: 'TOPMARGIN',
- 0x0029: 'BOTTOMMARGIN',
- 0x002A: 'PRINTHEADERS',
- 0x002B: 'PRINTGRIDLINES',
- 0x002F: 'FILEPASS',
- 0x0031: 'FONT',
- 0x0032: 'FONT2_B2_ONLY',
- 0x0036: 'TABLEOP_B2',
- 0x0037: 'TABLEOP2_B2',
- 0x003C: 'CONTINUE',
- 0x003D: 'WINDOW1',
- 0x003E: 'WINDOW2_B2',
- 0x0040: 'BACKUP',
- 0x0041: 'PANE',
- 0x0042: 'CODEPAGE',
- 0x0043: 'XF_B2',
- 0x0044: 'IXFE_B2_ONLY',
- 0x0045: 'EFONT_B2_ONLY',
- 0x004D: 'PLS',
- 0x0051: 'DCONREF',
- 0x0055: 'DEFCOLWIDTH',
- 0x0056: 'BUILTINFMTCOUNT_B3-4',
- 0x0059: 'XCT',
- 0x005A: 'CRN',
- 0x005B: 'FILESHARING',
- 0x005C: 'WRITEACCESS',
- 0x005D: 'OBJECT',
- 0x005E: 'UNCALCED',
- 0x005F: 'SAVERECALC',
- 0x0063: 'OBJECTPROTECT',
- 0x007D: 'COLINFO',
- 0x007E: 'RK2_mythical_?',
- 0x0080: 'GUTS',
- 0x0081: 'WSBOOL',
- 0x0082: 'GRIDSET',
- 0x0083: 'HCENTER',
- 0x0084: 'VCENTER',
- 0x0085: 'BOUNDSHEET',
- 0x0086: 'WRITEPROT',
- 0x008C: 'COUNTRY',
- 0x008D: 'HIDEOBJ',
- 0x008E: 'SHEETSOFFSET',
- 0x008F: 'SHEETHDR',
- 0x0090: 'SORT',
- 0x0092: 'PALETTE',
- 0x0099: 'STANDARDWIDTH',
- 0x009B: 'FILTERMODE',
- 0x009C: 'FNGROUPCOUNT',
- 0x009D: 'AUTOFILTERINFO',
- 0x009E: 'AUTOFILTER',
- 0x00A0: 'SCL',
- 0x00A1: 'SETUP',
- 0x00AB: 'GCW',
- 0x00BD: 'MULRK',
- 0x00BE: 'MULBLANK',
- 0x00C1: 'MMS',
- 0x00D6: 'RSTRING',
- 0x00D7: 'DBCELL',
- 0x00DA: 'BOOKBOOL',
- 0x00DD: 'SCENPROTECT',
- 0x00E0: 'XF',
- 0x00E1: 'INTERFACEHDR',
- 0x00E2: 'INTERFACEEND',
- 0x00E5: 'MERGEDCELLS',
- 0x00E9: 'BITMAP',
- 0x00EB: 'MSO_DRAWING_GROUP',
- 0x00EC: 'MSO_DRAWING',
- 0x00ED: 'MSO_DRAWING_SELECTION',
- 0x00EF: 'PHONETIC',
- 0x00FC: 'SST',
- 0x00FD: 'LABELSST',
- 0x00FF: 'EXTSST',
- 0x013D: 'TABID',
- 0x015F: 'LABELRANGES',
- 0x0160: 'USESELFS',
- 0x0161: 'DSF',
- 0x01AE: 'SUPBOOK',
- 0x01AF: 'PROTECTIONREV4',
- 0x01B0: 'CONDFMT',
- 0x01B1: 'CF',
- 0x01B2: 'DVAL',
- 0x01B6: 'TXO',
- 0x01B7: 'REFRESHALL',
- 0x01B8: 'HLINK',
- 0x01BC: 'PASSWORDREV4',
- 0x01BE: 'DV',
- 0x01C0: 'XL9FILE',
- 0x01C1: 'RECALCID',
- 0x0200: 'DIMENSIONS',
- 0x0201: 'BLANK',
- 0x0203: 'NUMBER',
- 0x0204: 'LABEL',
- 0x0205: 'BOOLERR',
- 0x0206: 'FORMULA_B3',
- 0x0207: 'STRING',
- 0x0208: 'ROW',
- 0x0209: 'BOF',
- 0x020B: 'INDEX_B3+',
- 0x0218: 'NAME',
- 0x0221: 'ARRAY',
- 0x0223: 'EXTERNNAME_B3-4',
- 0x0225: 'DEFAULTROWHEIGHT',
- 0x0231: 'FONT_B3B4',
- 0x0236: 'TABLEOP',
- 0x023E: 'WINDOW2',
- 0x0243: 'XF_B3',
- 0x027E: 'RK',
- 0x0293: 'STYLE',
- 0x0406: 'FORMULA_B4',
- 0x0409: 'BOF',
- 0x041E: 'FORMAT',
- 0x0443: 'XF_B4',
- 0x04BC: 'SHRFMLA',
- 0x0800: 'QUICKTIP',
- 0x0809: 'BOF',
- 0x0862: 'SHEETLAYOUT',
- 0x0867: 'SHEETPROTECTION',
- 0x0868: 'RANGEPROTECTION',
-}
-
-class XLRDError(Exception):
- pass
-
-class BaseObject:
- """
- Parent of almost all other classes in the package. Defines a common
- 'dump' method for debugging.
- """
- _repr_these = []
-
- def dump(self, f=None, header=None, footer=None, indent=0):
- """
- :param f: open file object, to which the dump is written
- :param header: text to write before the dump
- :param footer: text to write after the dump
- :param indent: number of leading spaces (for recursive calls)
- """
- if f is None:
- f = sys.stderr
- pad = " " * indent
-
- if header is not None:
- print(header, file=f)
-
- for attr, value in sorted(self.__dict__.items()):
- if getattr(value, 'dump', None) and attr != 'book':
- value.dump(f,
- header="%s%s (%s object):" % (pad, attr, value.__class__.__name__),
- indent=indent+4)
- elif attr not in self._repr_these and \
- (isinstance(value, list) or
- isinstance(value, dict)):
- print("%s%s: %s, len = %d" % (pad, attr, type(value), len(value)), file=f)
- else:
- print("%s%s: %r" % (pad, attr, value), file=f)
- if footer is not None:
- print(footer, file=f)
-
-def fprintf(f, fmt, *vargs):
- print(fmt.rstrip('\n') % vargs, file=f)
-
-def upkbits(tgt_obj, src, manifest, local_setattr=setattr):
- for n, mask, attr in manifest:
- local_setattr(tgt_obj, attr, (src & mask) >> n)
-
-def upkbitsL(tgt_obj, src, manifest, local_setattr=setattr, local_int=int):
- for n, mask, attr in manifest:
- local_setattr(tgt_obj, attr, local_int((src & mask) >> n))
-
-def unpack_string(data, pos, encoding, lenlen=1):
- nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0]
- pos += lenlen
- return str(data[pos:pos+nchars], encoding)
-
-def unpack_string_update_pos(data, pos, encoding, lenlen=1, known_len=None):
- if known_len is not None:
- # On a NAME record, the length byte is detached from the front of the string.
- nchars = known_len
- else:
- nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0]
- pos += lenlen
-
- newpos = pos + nchars
- return (str(data[pos:newpos], encoding), newpos)
-
-def unpack_unicode(data, pos, lenlen=2):
- """ Return unicode_strg """
- nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0]
- if not nchars:
- # Ambiguous whether 0-length string should have an "options" byte.
- # Avoid crash if missing.
- return ""
- pos += lenlen
- options = data[pos]
- pos += 1
-
- if options & 0x08: # richtext
- pos += 2
-
- if options & 0x04: # phonetic
- pos += 4
-
- if options & 0x01:
- # Uncompressed UTF-16-LE
- rawstrg = data[pos:pos+2*nchars]
- strg = str(rawstrg, 'utf_16_le')
- else:
- # Note: this is COMPRESSED (not ASCII!) encoding!!!
- # Merely returning the raw bytes would work OK 99.99% of the time
- # if the local codepage was cp1252 -- however this would rapidly go pear-shaped
- # for other codepages so we grit our Anglocentric teeth and return Unicode :-)
- strg = str(data[pos:pos+nchars], "latin_1")
- return strg
-
-def unpack_unicode_update_pos(data, pos, lenlen=2, known_len=None):
- """ Return (unicode_strg, updated value of pos) """
- if known_len is not None:
- # On a NAME record, the length byte is detached from the front of the string.
- nchars = known_len
- else:
- nchars = unpack('<' + 'BH'[lenlen-1], data[pos:pos+lenlen])[0]
- pos += lenlen
-
- if not nchars and not data[pos:]:
- # Zero-length string with no options byte
- return ("", pos)
-
- options = data[pos]
- pos += 1
- phonetic = options & 0x04
- richtext = options & 0x08
-
- if richtext:
- rt = unpack('<H', data[pos:pos+2])[0]
- pos += 2
-
- if phonetic:
- sz = unpack('<i', data[pos:pos+4])[0]
- pos += 4
-
- if options & 0x01:
- # Uncompressed UTF-16-LE
- strg = str(data[pos:pos+2*nchars], 'utf_16_le')
- pos += 2*nchars
- else:
- # Note: this is COMPRESSED (not ASCII!) encoding!!!
- strg = str(data[pos:pos+nchars], "latin_1")
- pos += nchars
-
- if richtext:
- pos += 4 * rt
-
- if phonetic:
- pos += sz
-
- return (strg, pos)
-
-def unpack_cell_range_address_list_update_pos(
- output_list, data, pos, biff_version, addr_size=6):
- # output_list is updated in situ
- if biff_version < 80:
- assert addr_size == 6
- else:
- assert addr_size in (6, 8)
- n, = unpack("<H", data[pos:pos+2])
- pos += 2
- if n:
- fmt = "<HHBB" if addr_size == 6 else "<HHHH"
- for _unused in range(n):
- ra, rb, ca, cb = unpack(fmt, data[pos:pos+addr_size])
- output_list.append((ra, rb+1, ca, cb+1))
- pos += addr_size
- return pos
-
-def hex_char_dump(strg, ofs, dlen, base=0, fout=sys.stdout, unnumbered=False):
- endpos = min(ofs + dlen, len(strg))
- pos = ofs
- numbered = not unnumbered
- num_prefix = ''
- while pos < endpos:
- endsub = min(pos + 16, endpos)
- substrg = strg[pos:endsub]
- lensub = endsub - pos
- if lensub <= 0 or lensub != len(substrg):
- fprintf(
- sys.stdout,
- '??? hex_char_dump: ofs=%d dlen=%d base=%d -> endpos=%d pos=%d endsub=%d substrg=%r\n',
- ofs, dlen, base, endpos, pos, endsub, substrg)
- break
- hexd = ''.join(["%02x " % c for c in substrg])
- chard = ''
- for c in substrg:
- if c == ord('\0'):
- c = '~'
- elif not (' ' <= chr(c) <= '~'):
- c = '?'
- if isinstance(c, int):
- c = chr(c)
- chard += c
- if numbered:
- num_prefix = "%5d: " % (base+pos-ofs)
- fprintf(fout, "%s %-48s %s\n", num_prefix, hexd, chard)
- pos = endsub
-
-def biff_dump(mem, stream_offset, stream_len, base=0, fout=sys.stdout,
- unnumbered=False):
- pos = stream_offset
- stream_end = stream_offset + stream_len
- adj = base - stream_offset
- dummies = 0
- numbered = not unnumbered
- num_prefix = ''
- while stream_end - pos >= 4:
- rc, length = unpack('<HH', mem[pos:pos+4])
- if rc == 0 and length == 0:
- if mem[pos:] == '\0' * (stream_end - pos):
- dummies = stream_end - pos
- savpos = pos
- pos = stream_end
- break
-
- if dummies:
- dummies += 4
- else:
- savpos = pos
- dummies = 4
- pos += 4
- else:
- if dummies:
- if numbered:
- num_prefix = "%5d: " % (adj + savpos)
- fprintf(fout, "%s---- %d zero bytes skipped ----\n",
- num_prefix, dummies)
- dummies = 0
-
- recname = biff_rec_name_dict.get(rc, '<UNKNOWN>')
- if numbered:
- num_prefix = "%5d: " % (adj + pos)
- fprintf(fout, "%s%04x %s len = %04x (%d)\n",
- num_prefix, rc, recname, length, length)
- pos += 4
- hex_char_dump(mem, pos, length, adj+pos, fout, unnumbered)
- pos += length
- if dummies:
- if numbered:
- num_prefix = "%5d: " % (adj + savpos)
- fprintf(fout, "%s---- %d zero bytes skipped ----\n", num_prefix, dummies)
-
- if pos < stream_end:
- if numbered:
- num_prefix = "%5d: " % (adj + pos)
- fprintf(fout, "%s---- Misc bytes at end ----\n", num_prefix)
- hex_char_dump(mem, pos, stream_end-pos, adj + pos, fout, unnumbered)
- elif pos > stream_end:
- fprintf(fout, "Last dumped record has length (%d) that is too large\n", length)
-
-def biff_count_records(mem, stream_offset, stream_len, fout=sys.stdout):
- pos = stream_offset
- stream_end = stream_offset + stream_len
- tally = {}
- while stream_end - pos >= 4:
- rc, length = unpack('<HH', mem[pos:pos+4])
- if rc == 0 and length == 0:
- if mem[pos:] == '\0' * (stream_end - pos):
- break
- recname = "<Dummy (zero)>"
- else:
- recname = biff_rec_name_dict.get(rc, None)
- if recname is None:
- recname = "Unknown_0x%04X" % rc
- if recname in tally:
- tally[recname] += 1
- else:
- tally[recname] = 1
- pos += length + 4
- for recname, count in sorted(tally.items()):
- fprintf(fout, "%8d %s", count, recname)
diff --git a/tablib/packages/xlrd3/compdoc.py b/tablib/packages/xlrd3/compdoc.py deleted file mode 100644 index c2ce764..0000000 --- a/tablib/packages/xlrd3/compdoc.py +++ /dev/null @@ -1,346 +0,0 @@ -# Implements the minimal functionality required
-# to extract a "Workbook" or "Book" stream (as one big string)
-# from an OLE2 Compound Document file.
-#
-# Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd3 package, which is released under a BSD-style licence.
-
-# No part of the content of this file was derived from the works of David Giffin.
-
-# 2008-11-04 SJM Avoid assertion error when -1 used instead of -2 for first_SID of empty SCSS [Frank Hoffsuemmer]
-# 2007-09-08 SJM Warning message if sector sizes are extremely large.
-# 2007-05-07 SJM Meaningful exception instead of IndexError if a SAT (sector allocation table) is corrupted.
-# 2007-04-22 SJM Missing "<" in a struct.unpack call => can't open files on bigendian platforms.
-
-
-import sys
-from struct import unpack
-
-# Magic cookie that should appear in the first 8 bytes of the file.
-SIGNATURE = b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
-
-EOCSID = -2
-FREESID = -1
-SATSID = -3
-MSATSID = -4
-
-def int_floor_div(x, y):
- return divmod(x, y)[0]
-
-class CompDocError(Exception):
- pass
-
-class DirNode(object):
-
- def __init__(self, DID, dent, DEBUG=0):
- # dent is the 128-byte directory entry
- self.DID = DID
- # (cbufsize, self.etype, self.colour, self.left_DID, self.right_DID,
- # self.root_DID,
- # self.first_SID,
- # self.tot_size) = \
- # unpack('<HBBiii16x4x8x8xii4x', dent[64:128])
- (cbufsize, self.etype, self.colour, self.left_DID, self.right_DID,
- self.root_DID) = \
- unpack('<HBBiii', dent[64:80])
- (self.first_SID, self.tot_size) = \
- unpack('<ii', dent[116:124])
- if cbufsize == 0:
- self.name = ''
- else:
- self.name = str(dent[0:cbufsize-2], 'utf_16_le') # omit the trailing U+0000
- self.children = [] # filled in later
- self.parent = -1 # indicates orphan; fixed up later
- self.tsinfo = unpack('<IIII', dent[100:116])
- if DEBUG:
- self.dump(DEBUG)
-
- def dump(self, DEBUG=1):
- print("DID=%d name=%r etype=%d DIDs(left=%d right=%d root=%d parent=%d kids=%r) first_SID=%d tot_size=%d" \
- % (self.DID, self.name, self.etype, self.left_DID,
- self.right_DID, self.root_DID, self.parent, self.children, self.first_SID, self.tot_size))
- if DEBUG == 2:
- # cre_lo, cre_hi, mod_lo, mod_hi = tsinfo
- print("timestamp info", self.tsinfo)
-
-def _build_family_tree(dirlist, parent_DID, child_DID):
- if child_DID < 0: return
- _build_family_tree(dirlist, parent_DID, dirlist[child_DID].left_DID)
- dirlist[parent_DID].children.append(child_DID)
- dirlist[child_DID].parent = parent_DID
- _build_family_tree(dirlist, parent_DID, dirlist[child_DID].right_DID)
- if dirlist[child_DID].etype == 1: # storage
- _build_family_tree(dirlist, child_DID, dirlist[child_DID].root_DID)
-
-# Compound document handler.
-# @param mem The raw contents of the file, as a string, or as an mmap.mmap() object. The
-# only operation it needs to support is slicing.
-
-class CompDoc(object):
-
- def __init__(self, mem, logfile=sys.stdout, DEBUG=0):
- self.logfile = logfile
- if mem[0:8] != SIGNATURE:
- raise CompDocError('Not an OLE2 compound document')
- if mem[28:30] != b'\xFE\xFF':
- raise CompDocError('Expected "little-endian" marker, found %r' % mem[28:30])
- revision, version = unpack('<HH', mem[24:28])
- if DEBUG:
- print("\nCompDoc format: version=0x%04x revision=0x%04x" % (version, revision), file=logfile)
- self.mem = mem
- ssz, sssz = unpack('<HH', mem[30:34])
- if ssz > 20: # allows for 2**20 bytes i.e. 1MB
- print("WARNING: sector size (2**%d) is preposterous; assuming 512 and continuing ..." \
- % ssz, file=logfile)
- ssz = 9
- if sssz > ssz:
- print("WARNING: short stream sector size (2**%d) is preposterous; assuming 64 and continuing ..." \
- % sssz, file=logfile)
- sssz = 6
- self.sec_size = sec_size = 1 << ssz
- self.short_sec_size = 1 << sssz
- (
- SAT_tot_secs, self.dir_first_sec_sid, _unused, self.min_size_std_stream,
- SSAT_first_sec_sid, SSAT_tot_secs,
- MSAT_first_sec_sid, MSAT_tot_secs,
- # ) = unpack('<ii4xiiiii', mem[44:76])
- ) = unpack('<iiiiiiii', mem[44:76])
- mem_data_len = len(mem) - 512
- mem_data_secs, left_over = divmod(mem_data_len, sec_size)
- if left_over:
- #### raise CompDocError("Not a whole number of sectors")
- print("WARNING *** file size (%d) not 512 + multiple of sector size (%d)" \
- % (len(mem), sec_size), file=logfile)
- if DEBUG:
- print('sec sizes', ssz, sssz, sec_size, self.short_sec_size, file=logfile)
- print("mem data: %d bytes == %d sectors" % (mem_data_len, mem_data_secs), file=logfile)
- print("SAT_tot_secs=%d, dir_first_sec_sid=%d, min_size_std_stream=%d" \
- % (SAT_tot_secs, self.dir_first_sec_sid, self.min_size_std_stream,), file=logfile)
- print("SSAT_first_sec_sid=%d, SSAT_tot_secs=%d" % (SSAT_first_sec_sid, SSAT_tot_secs,), file=logfile)
- print("MSAT_first_sec_sid=%d, MSAT_tot_secs=%d" % (MSAT_first_sec_sid, MSAT_tot_secs,), file=logfile)
- nent = int_floor_div(sec_size, 4) # number of SID entries in a sector
- fmt = "<%di" % nent
- trunc_warned = 0
- #
- # === build the MSAT ===
- #
- MSAT = list(unpack('<109i', mem[76:512]))
- sid = MSAT_first_sec_sid
- while sid >= 0:
- if sid >= mem_data_secs:
- raise CompDocError(
- "MSAT extension: accessing sector %d but only %d in file" % (sid, mem_data_secs)
- )
- offset = 512 + sec_size * sid
- news = list(unpack(fmt, mem[offset:offset+sec_size]))
- sid = news.pop()
- MSAT.extend(news)
- if DEBUG:
- print("MSAT: len =", len(MSAT), file=logfile)
- print(MSAT, file=logfile)
- #
- # === build the SAT ===
- #
- self.SAT = []
- for msid in MSAT:
- if msid == FREESID: continue
- if msid >= mem_data_secs:
- if not trunc_warned:
- print("WARNING *** File is truncated, or OLE2 MSAT is corrupt!!", file=logfile)
- print("INFO: Trying to access sector %d but only %d available" \
- % (msid, mem_data_secs), file=logfile)
- trunc_warned = 1
- continue
- offset = 512 + sec_size * msid
- news = list(unpack(fmt, mem[offset:offset+sec_size]))
- self.SAT.extend(news)
- if DEBUG:
- print("SAT: len =", len(self.SAT), file=logfile)
- print(self.SAT, file=logfile)
- # print >> logfile, "SAT ",
- # for i, s in enumerate(self.SAT):
- # print >> logfile, "entry: %4d offset: %6d, next entry: %4d" % (i, 512 + sec_size * i, s)
- # print >> logfile, "%d:%d " % (i, s),
- print()
-
- # === build the directory ===
- #
- dbytes = self._get_stream(
- self.mem, 512, self.SAT, self.sec_size, self.dir_first_sec_sid,
- name="directory")
- dirlist = []
- did = -1
- for pos in range(0, len(dbytes), 128):
- did += 1
- dirlist.append(DirNode(did, dbytes[pos:pos+128], 0))
- self.dirlist = dirlist
- _build_family_tree(dirlist, 0, dirlist[0].root_DID) # and stand well back ...
- if DEBUG:
- for d in dirlist:
- d.dump(DEBUG)
- #
- # === get the SSCS ===
- #
- sscs_dir = self.dirlist[0]
- assert sscs_dir.etype == 5 # root entry
- if sscs_dir.first_SID < 0 and sscs_dir.tot_size == 0:
- # Problem reported by Frank Hoffsuemmer: some software was
- # writing -1 instead of -2 (EOCSID) for the first_SID
- # when the SCCS was empty. Not having EOCSID caused assertion
- # failure in _get_stream.
- # Solution: avoid calling _get_stream in any case when the
- # SCSS appears to be empty.
- self.SSCS = ""
- else:
- self.SSCS = self._get_stream(
- self.mem, 512, self.SAT, sec_size, sscs_dir.first_SID,
- sscs_dir.tot_size, name="SSCS")
- # if DEBUG: print >> logfile, "SSCS", repr(self.SSCS)
- #
- # === build the SSAT ===
- #
- self.SSAT = []
- if SSAT_tot_secs > 0 and sscs_dir.tot_size == 0:
- print("WARNING *** OLE2 inconsistency: SSCS size is 0 but SSAT size is non-zero", file=logfile)
- if sscs_dir.tot_size > 0:
- sid = SSAT_first_sec_sid
- nsecs = SSAT_tot_secs
- while sid >= 0 and nsecs > 0:
- nsecs -= 1
- start_pos = 512 + sid * sec_size
- news = list(unpack(fmt, mem[start_pos:start_pos+sec_size]))
- self.SSAT.extend(news)
- sid = self.SAT[sid]
- # assert SSAT_tot_secs == 0 or sid == EOCSID
- if DEBUG: print("SSAT last sid %d; remaining sectors %d" % (sid, nsecs), file=logfile)
- assert nsecs == 0 and sid == EOCSID
- if DEBUG: print("SSAT", self.SSAT, file=logfile)
-
- def _get_stream(self, mem, base, sat, sec_size, start_sid, size=None, name=''):
- # print >> self.logfile, "_get_stream", base, sec_size, start_sid, size
- sectors = []
- s = start_sid
- if size is None:
- # nothing to check against
- while s >= 0:
- start_pos = base + s * sec_size
- sectors.append(mem[start_pos:start_pos+sec_size])
- try:
- s = sat[s]
- except IndexError:
- raise CompDocError(
- "OLE2 stream %r: sector allocation table invalid entry (%d)" %
- (name, s)
- )
- assert s == EOCSID
- else:
- todo = size
- while s >= 0:
- start_pos = base + s * sec_size
- grab = sec_size
- if grab > todo:
- grab = todo
- todo -= grab
- sectors.append(mem[start_pos:start_pos+grab])
- try:
- s = sat[s]
- except IndexError:
- raise CompDocError(
- "OLE2 stream %r: sector allocation table invalid entry (%d)" %
- (name, s)
- )
- assert s == EOCSID
- if todo != 0:
- print("WARNING *** OLE2 stream %r: expected size %d, actual size %d" \
- % (name, size, size - todo), file=self.logfile)
- return b''.join(sectors)
-
- def _dir_search(self, path, storage_DID=0):
- # Return matching DirNode instance, or None
- head = path[0]
- tail = path[1:]
- dl = self.dirlist
- for child in dl[storage_DID].children:
- if dl[child].name.lower() == head.lower():
- et = dl[child].etype
- if et == 2:
- return dl[child]
- if et == 1:
- if not tail:
- raise CompDocError("Requested component is a 'storage'")
- return self._dir_search(tail, child)
- dl[child].dump(1)
- raise CompDocError("Requested stream is not a 'user stream'")
- return None
-
- ##
- # Interrogate the compound document's directory; return the stream as a string if found, otherwise
- # return None.
- # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto.
-
- def get_named_stream(self, qname):
- d = self._dir_search(qname.split("/"))
- if d is None:
- return None
- if d.tot_size >= self.min_size_std_stream:
- return self._get_stream(
- self.mem, 512, self.SAT, self.sec_size, d.first_SID,
- d.tot_size, name=qname)
- else:
- return self._get_stream(
- self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID,
- d.tot_size, name=qname + " (from SSCS)")
-
- # Interrogate the compound document's directory.
- # If the named stream is not found, (None, 0, 0) will be returned.
- # If the named stream is found and is contiguous within the original byte sequence ("mem")
- # used when the document was opened,
- # then (mem, offset_to_start_of_stream, length_of_stream) is returned.
- # Otherwise a new string is built from the fragments and (new_string, 0, length_of_stream) is returned.
- # @param qname Name of the desired stream e.g. u'Workbook'. Should be in Unicode or convertible thereto.
-
- def locate_named_stream(self, qname):
- d = self._dir_search(qname.split("/"))
- if d is None:
- return (None, 0, 0)
- if d.tot_size >= self.min_size_std_stream:
- return self._locate_stream(self.mem, 512, self.SAT, self.sec_size, d.first_SID, d.tot_size)
- else:
- return (
- self._get_stream(
- self.SSCS, 0, self.SSAT, self.short_sec_size, d.first_SID,
- d.tot_size, qname + " (from SSCS)"),
- 0,
- d.tot_size
- )
- return (None, 0, 0) # not found
-
- def _locate_stream(self, mem, base, sat, sec_size, start_sid, size):
- # print >> self.logfile, "_locate_stream", base, sec_size, start_sid, size
- s = start_sid
- if s < 0:
- raise CompDocError("_locate_stream: start_sid (%d) is -ve" % start_sid)
- p = -99 # dummy previous SID
- start_pos = -9999
- end_pos = -8888
- slices = []
- while s >= 0:
- if s == p+1:
- # contiguous sectors
- end_pos += sec_size
- else:
- # start new slice
- if p >= 0:
- # not first time
- slices.append((start_pos, end_pos))
- start_pos = base + s * sec_size
- end_pos = start_pos + sec_size
- p = s
- s = sat[s]
- assert s == EOCSID
- # print >> self.logfile, len(slices) + 1, "slices"
- if not slices:
- # The stream is contiguous ... just what we like!
- return (mem, start_pos, size)
- slices.append((start_pos, end_pos))
- return (b''.join([mem[start_pos:end_pos] for start_pos, end_pos in slices]), 0, size)
diff --git a/tablib/packages/xlrd3/formatting.py b/tablib/packages/xlrd3/formatting.py deleted file mode 100644 index 85484da..0000000 --- a/tablib/packages/xlrd3/formatting.py +++ /dev/null @@ -1,1186 +0,0 @@ -# Module for formatting information.
-#
-# Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd
-# Copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd3 package, which is released under
-# a BSD-style licence.
-
-# No part of the content of this file was derived from the works of David Giffin.
-
-# 2009-05-31 SJM Fixed problem with non-zero reserved bits in some STYLE records in Mac Excel files
-# 2008-08-03 SJM Ignore PALETTE record when Book.formatting_info is false
-# 2008-08-03 SJM Tolerate up to 4 bytes trailing junk on PALETTE record
-# 2008-05-10 SJM Do some XF checks only when Book.formatting_info is true
-# 2008-02-08 SJM Preparation for Excel 2.0 support
-# 2008-02-03 SJM Another tweak to is_date_format_string()
-# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files.
-# 2007-10-13 SJM Warning: style XF whose parent XF index != 0xFFF
-# 2007-09-08 SJM Work around corrupt STYLE record
-# 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file
-
-DEBUG = False
-import copy
-import re
-from struct import unpack
-
-from .biffh import BaseObject, unpack_unicode, unpack_string, \
- upkbits, upkbitsL, fprintf, \
- FUN, FDT, FNU, FGE, FTX, XL_CELL_NUMBER, XL_CELL_DATE, \
- XL_FORMAT, XL_FORMAT2, \
- XLRDError
-
-
-excel_default_palette_b5 = (
- ( 0, 0, 0), (255, 255, 255), (255, 0, 0), ( 0, 255, 0),
- ( 0, 0, 255), (255, 255, 0), (255, 0, 255), ( 0, 255, 255),
- (128, 0, 0), ( 0, 128, 0), ( 0, 0, 128), (128, 128, 0),
- (128, 0, 128), ( 0, 128, 128), (192, 192, 192), (128, 128, 128),
- (153, 153, 255), (153, 51, 102), (255, 255, 204), (204, 255, 255),
- (102, 0, 102), (255, 128, 128), ( 0, 102, 204), (204, 204, 255),
- ( 0, 0, 128), (255, 0, 255), (255, 255, 0), ( 0, 255, 255),
- (128, 0, 128), (128, 0, 0), ( 0, 128, 128), ( 0, 0, 255),
- ( 0, 204, 255), (204, 255, 255), (204, 255, 204), (255, 255, 153),
- (153, 204, 255), (255, 153, 204), (204, 153, 255), (227, 227, 227),
- ( 51, 102, 255), ( 51, 204, 204), (153, 204, 0), (255, 204, 0),
- (255, 153, 0), (255, 102, 0), (102, 102, 153), (150, 150, 150),
- ( 0, 51, 102), ( 51, 153, 102), ( 0, 51, 0), ( 51, 51, 0),
- (153, 51, 0), (153, 51, 102), ( 51, 51, 153), ( 51, 51, 51),
- )
-
-excel_default_palette_b2 = excel_default_palette_b5[:16]
-
-# Following two tables borrowed from Gnumeric 1.4 source.
-excel_default_palette_b5_gnumeric_14 = (
- #### dodgy; didn't match Excel results
- ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0),
- ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255),
- (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0),
- (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128),
- (128,128,255), (128, 32, 96), (255,255,192), (160,224,224),
- ( 96, 0,128), (255,128,128), ( 0,128,192), (192,192,255),
- ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255),
- (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255),
- ( 0,204,255), (105,255,255), (204,255,204), (255,255,153),
- (166,202,240), (204,156,204), (204,153,255), (227,227,227),
- ( 51,102,255), ( 51,204,204), ( 51,153, 51), (153,153, 51),
- (153,102, 51), (153,102,102), (102,102,153), (150,150,150),
- ( 51, 51,204), ( 51,102,102), ( 0, 51, 0), ( 51, 51, 0),
- (102, 51, 0), (153, 51,102), ( 51, 51,153), ( 66, 66, 66),
- )
-excel_default_palette_b8 = ( # (red, green, blue)
- ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0),
- ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255),
- (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0),
- (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128),
- (153,153,255), (153, 51,102), (255,255,204), (204,255,255),
- (102, 0,102), (255,128,128), ( 0,102,204), (204,204,255),
- ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255),
- (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255),
- ( 0,204,255), (204,255,255), (204,255,204), (255,255,153),
- (153,204,255), (255,153,204), (204,153,255), (255,204,153),
- ( 51,102,255), ( 51,204,204), (153,204, 0), (255,204, 0),
- (255,153, 0), (255,102, 0), (102,102,153), (150,150,150),
- ( 0, 51,102), ( 51,153,102), ( 0, 51, 0), ( 51, 51, 0),
- (153, 51, 0), (153, 51,102), ( 51, 51,153), ( 51, 51, 51),
- )
-
-default_palette = {
- 80: excel_default_palette_b8,
- 70: excel_default_palette_b5,
- 50: excel_default_palette_b5,
- 45: excel_default_palette_b2,
- 40: excel_default_palette_b2,
- 30: excel_default_palette_b2,
- 21: excel_default_palette_b2,
- 20: excel_default_palette_b2,
- }
-
-"""
-00H = Normal
-01H = RowLevel_lv (see next field)
-02H = ColLevel_lv (see next field)
-03H = Comma
-04H = Currency
-05H = Percent
-06H = Comma [0] (BIFF4-BIFF8)
-07H = Currency [0] (BIFF4-BIFF8)
-08H = Hyperlink (BIFF8)
-09H = Followed Hyperlink (BIFF8)
-"""
-built_in_style_names = [
- "Normal",
- "RowLevel_",
- "ColLevel_",
- "Comma",
- "Currency",
- "Percent",
- "Comma [0]",
- "Currency [0]",
- "Hyperlink",
- "Followed Hyperlink",
- ]
-
-def initialise_colour_map(book):
- book.colour_map = {}
- book.colour_indexes_used = {}
- if not book.formatting_info:
- return
- # Add the 8 invariant colours
- for i in range(8):
- book.colour_map[i] = excel_default_palette_b8[i]
- # Add the default palette depending on the version
- dpal = default_palette[book.biff_version]
- ndpal = len(dpal)
- for i in range(ndpal):
- book.colour_map[i+8] = dpal[i]
- # Add the specials -- None means the RGB value is not known
- # System window text colour for border lines
- book.colour_map[ndpal+8] = None
- # System window background colour for pattern background
- book.colour_map[ndpal+8+1] = None #
- for ci in (
- 0x51, # System ToolTip text colour (used in note objects)
- 0x7FFF, # 32767, system window text colour for fonts
- ):
- book.colour_map[ci] = None
-
-def nearest_colour_index(colour_map, rgb, debug=0):
- # General purpose function. Uses Euclidean distance.
- # So far used only for pre-BIFF8 WINDOW2 record.
- # Doesn't have to be fast.
- # Doesn't have to be fancy.
- best_metric = 3 * 256 * 256
- best_colourx = 0
- for colourx, cand_rgb in list(colour_map.items()):
- if cand_rgb is None:
- continue
- metric = 0
- for v1, v2 in zip(rgb, cand_rgb):
- metric += (v1 - v2) * (v1 - v2)
- if metric < best_metric:
- best_metric = metric
- best_colourx = colourx
- if metric == 0:
- break
- if debug:
- print("nearest_colour_index for %r is %r -> %r; best_metric is %d" \
- % (rgb, best_colourx, colour_map[best_colourx], best_metric))
- return best_colourx
-
-# This mixin class exists solely so that Format, Font, and XF.... objects
-# can be compared by value of their attributes.
-class EqNeAttrs(object):
-
- def __eq__(self, other):
- return self.__dict__ == other.__dict__
-
- def __ne__(self, other):
- return self.__dict__ != other.__dict__
-
-# An Excel "font" contains the details of not only what is normally
-# considered a font, but also several other display attributes.
-# Items correspond to those in the Excel UI's Format/Cells/Font tab.
-# - New in version 0.6.1
-class Font(BaseObject, EqNeAttrs):
- # 1 = Characters are bold. Redundant; see "weight" attribute.
- bold = 0
-
- # Values: 0 = ANSI Latin, 1 = System default, 2 = Symbol,
- # 77 = Apple Roman,
- # 128 = ANSI Japanese Shift-JIS,
- # 129 = ANSI Korean (Hangul),
- # 130 = ANSI Korean (Johab),
- # 134 = ANSI Chinese Simplified GBK,
- # 136 = ANSI Chinese Traditional BIG5,
- # 161 = ANSI Greek,
- # 162 = ANSI Turkish,
- # 163 = ANSI Vietnamese,
- # 177 = ANSI Hebrew,
- # 178 = ANSI Arabic,
- # 186 = ANSI Baltic,
- # 204 = ANSI Cyrillic,
- # 222 = ANSI Thai,
- # 238 = ANSI Latin II (Central European),
- # 255 = OEM Latin I
- character_set = 0
- # An explanation of "colour index" is given in the Formatting
- # section at the start of this document.
- colour_index = 0
- # 1 = Superscript, 2 = Subscript.
- escapement = 0
- # 0 = None (unknown or don't care)<br />
- # 1 = Roman (variable width, serifed)<br />
- # 2 = Swiss (variable width, sans-serifed)<br />
- # 3 = Modern (fixed width, serifed or sans-serifed)<br />
- # 4 = Script (cursive)<br />
- # 5 = Decorative (specialised, for example Old English, Fraktur)
- family = 0
- # The 0-based index used to refer to this Font() instance.
- # Note that index 4 is never used; xlrd supplies a dummy place-holder.
- font_index = 0
- # Height of the font (in twips). A twip = 1/20 of a point.
- height = 0
- # 1 = Characters are italic.
- italic = 0
- # The name of the font. Example: u"Arial"
- name = ""
- # 1 = Characters are struck out.
- struck_out = 0
- # 0 = None<br />
- # 1 = Single; 0x21 (33) = Single accounting<br />
- # 2 = Double; 0x22 (34) = Double accounting
- underline_type = 0
- # 1 = Characters are underlined. Redundant; see "underline_type" attribute.
- underlined = 0
- # Font weight (100-1000). Standard values are 400 for normal text
- # and 700 for bold text.
- weight = 400
- # 1 = Font is outline style (Macintosh only)
- outline = 0
- # 1 = Font is shadow style (Macintosh only)
- shadow = 0
-
- # No methods ...
-
-def handle_efont(book, data): # BIFF2 only
- if not book.formatting_info:
- return
- book.font_list[-1].colour_index = unpack('<H', data)[0]
-
-def handle_font(book, data):
- if not book.formatting_info:
- return
- if not book.encoding:
- book.derive_encoding()
- verbose = DEBUG or book.verbosity >= 2
- bv = book.biff_version
- k = len(book.font_list)
- if k == 4:
- f = Font()
- f.name = 'Dummy Font'
- f.font_index = k
- book.font_list.append(f)
- k += 1
- f = Font()
- f.font_index = k
- book.font_list.append(f)
- if bv >= 50:
- (
- f.height, option_flags, f.colour_index, f.weight,
- f.escapement_type, f.underline_type, f.family,
- f.character_set,
- ) = unpack('<HHHHHBBB', data[0:13])
- f.bold = option_flags & 1
- f.italic = (option_flags & 2) >> 1
- f.underlined = (option_flags & 4) >> 2
- f.struck_out = (option_flags & 8) >> 3
- f.outline = (option_flags & 16) >> 4
- f.shadow = (option_flags & 32) >> 5
- if bv >= 80:
- f.name = unpack_unicode(data, 14, lenlen=1)
- else:
- f.name = unpack_string(data, 14, book.encoding, lenlen=1)
- elif bv >= 30:
- f.height, option_flags, f.colour_index = unpack('<HHH', data[0:6])
- f.bold = option_flags & 1
- f.italic = (option_flags & 2) >> 1
- f.underlined = (option_flags & 4) >> 2
- f.struck_out = (option_flags & 8) >> 3
- f.outline = (option_flags & 16) >> 4
- f.shadow = (option_flags & 32) >> 5
- f.name = unpack_string(data, 6, book.encoding, lenlen=1)
- # Now cook up the remaining attributes ...
- f.weight = [400, 700][f.bold]
- f.escapement_type = 0 # None
- f.underline_type = f.underlined # None or Single
- f.family = 0 # Unknown / don't care
- f.character_set = 1 # System default (0 means "ANSI Latin")
- else: # BIFF2
- f.height, option_flags = unpack('<HH', data[0:4])
- f.colour_index = 0x7FFF # "system window text colour"
- f.bold = option_flags & 1
- f.italic = (option_flags & 2) >> 1
- f.underlined = (option_flags & 4) >> 2
- f.struck_out = (option_flags & 8) >> 3
- f.outline = 0
- f.shadow = 0
- f.name = unpack_string(data, 4, book.encoding, lenlen=1)
- # Now cook up the remaining attributes ...
- f.weight = [400, 700][f.bold]
- f.escapement_type = 0 # None
- f.underline_type = f.underlined # None or Single
- f.family = 0 # Unknown / don't care
- f.character_set = 1 # System default (0 means "ANSI Latin")
- if verbose:
- f.dump(
- book.logfile,
- header="--- handle_font: font[%d] ---" % f.font_index,
- footer="-------------------",
- )
-
-# === "Number formats" ===
-
-# "Number format" information from a FORMAT record.
-# - New in version 0.6.1
-class Format(BaseObject, EqNeAttrs):
-
- # The key into Book.format_map
- format_key = 0
-
- # A classification that has been inferred from the format string.
- # Currently, this is used only to distinguish between numbers and dates.
- # Values:
- # FUN = 0 # unknown
- # FDT = 1 # date
- # FNU = 2 # number
- # FGE = 3 # general
- # FTX = 4 # text
- type = FUN
-
- # The format string
- format_str = ''
-
- def __init__(self, format_key, ty, format_str):
- self.format_key = format_key
- self.type = ty
- self.format_str = format_str
-
-std_format_strings = {
- # "std" == "standard for US English locale"
- # #### TODO ... a lot of work to tailor these to the user's locale.
- # See e.g. gnumeric-1.x.y/src/formats.c
- 0x00: "General",
- 0x01: "0",
- 0x02: "0.00",
- 0x03: "#,##0",
- 0x04: "#,##0.00",
- 0x05: "$#,##0_);($#,##0)",
- 0x06: "$#,##0_);[Red]($#,##0)",
- 0x07: "$#,##0.00_);($#,##0.00)",
- 0x08: "$#,##0.00_);[Red]($#,##0.00)",
- 0x09: "0%",
- 0x0a: "0.00%",
- 0x0b: "0.00E+00",
- 0x0c: "# ?/?",
- 0x0d: "# ??/??",
- 0x0e: "m/d/yy",
- 0x0f: "d-mmm-yy",
- 0x10: "d-mmm",
- 0x11: "mmm-yy",
- 0x12: "h:mm AM/PM",
- 0x13: "h:mm:ss AM/PM",
- 0x14: "h:mm",
- 0x15: "h:mm:ss",
- 0x16: "m/d/yy h:mm",
- 0x25: "#,##0_);(#,##0)",
- 0x26: "#,##0_);[Red](#,##0)",
- 0x27: "#,##0.00_);(#,##0.00)",
- 0x28: "#,##0.00_);[Red](#,##0.00)",
- 0x29: "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
- 0x2a: "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
- 0x2b: "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
- 0x2c: "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
- 0x2d: "mm:ss",
- 0x2e: "[h]:mm:ss",
- 0x2f: "mm:ss.0",
- 0x30: "##0.0E+0",
- 0x31: "@",
- }
-
-fmt_code_ranges = [ # both-inclusive ranges of "standard" format codes
- # Source: the openoffice.org doc't
- ( 0, 0, FGE),
- ( 1, 13, FNU),
- (14, 22, FDT),
- #### (27, 36, FDT), # Japanese dates -- not sure of reliability of this
- (37, 44, FNU),
- (45, 47, FDT),
- (48, 48, FNU),
- (49, 49, FTX),
- ####(50, 58, FDT), # Japanese dates -- but Gnumeric assumes
- # built-in formats finish at 49, not at 163
- ]
-
-std_format_code_types = {}
-for lo, hi, ty in fmt_code_ranges:
- for x in range(lo, hi+1):
- std_format_code_types[x] = ty
-del lo, hi, ty, x
-
-date_chars = 'ymdhs' # year, month/minute, day, hour, second
-date_char_dict = {}
-for _c in date_chars + date_chars.upper():
- date_char_dict[_c] = 5
-del _c, date_chars
-
-#(to_py3):
-skip_char_dict = frozenset('$-+/(): ')
-
-num_char_dict = {
- '0': 5,
- '#': 5,
- '?': 5,
- }
-
-non_date_formats = {
- '0.00E+00':1,
- '##0.0E+0':1,
- 'General' :1,
- 'GENERAL' :1, # OOo Calc 1.1.4 does this.
- 'general' :1, # pyExcelerator 0.6.3 does this.
- '@' :1,
- }
-
-fmt_bracketed_sub = re.compile(r'\[[^]]*\]').sub
-
-# Boolean format strings (actual cases)
-# u'"Yes";"Yes";"No"'
-# u'"True";"True";"False"'
-# u'"On";"On";"Off"'
-
-def is_date_format_string(book, fmt):
- # Heuristics:
- # Ignore "text" and [stuff in square brackets (aarrgghh -- see below)].
- # Handle backslashed-escaped chars properly.
- # E.g. hh\hmm\mss\s should produce a display like 23h59m59s
- # Date formats have one or more of ymdhs (caseless) in them.
- # Numeric formats have # and 0.
- # N.B. u'General"."' hence get rid of "text" first.
- # TODO: Find where formats are interpreted in Gnumeric
- # TODO: u'[h]\\ \\h\\o\\u\\r\\s' ([h] means don't care about hours > 23)
- state = 0
- s = ''
- # (to_py3): ignorable = skip_char_dict.has_key
- for c in fmt:
- if state == 0:
- if c == '"':
- state = 1
- elif c in r"\_*":
- state = 2
- elif c in skip_char_dict: # (to_py3):
- pass
- else:
- s += c
- elif state == 1:
- if c == '"':
- state = 0
- elif state == 2:
- # Ignore char after backslash, underscore or asterisk
- state = 0
- assert 0 <= state <= 2
- if book.verbosity >= 4:
- print("is_date_format_string: reduced format is %r" % s)
- s = fmt_bracketed_sub('', s)
- if s in non_date_formats:
- return False
- state = 0
- separator = ";"
- got_sep = 0
- date_count = num_count = 0
- for c in s:
- if c in date_char_dict:
- date_count += date_char_dict[c]
- elif c in num_char_dict:
- num_count += num_char_dict[c]
- elif c == separator:
- got_sep = 1
- # print num_count, date_count, repr(fmt)
- if date_count and not num_count:
- return True
- if num_count and not date_count:
- return False
- if date_count:
- fprintf(book.logfile,
- 'WARNING *** is_date_format: ambiguous d=%d n=%d fmt=%r\n',
- date_count, num_count, fmt)
- elif not got_sep:
- fprintf(book.logfile,
- "WARNING *** format %r produces constant result\n",
- fmt)
- return date_count > num_count
-
-def handle_format(self, data, rectype=XL_FORMAT):
- DEBUG = 0
- bv = self.biff_version
- if rectype == XL_FORMAT2:
- bv = min(bv, 30)
- if not self.encoding:
- self.derive_encoding()
- strpos = 2
- if bv >= 50:
- fmtkey = unpack('<H', data[0:2])[0]
- else:
- fmtkey = self.actualfmtcount
- if bv <= 30:
- strpos = 0
- self.actualfmtcount += 1
- if bv >= 80:
- unistrg = unpack_unicode(data, 2)
- else:
- unistrg = unpack_string(data, strpos, self.encoding, lenlen=1)
- verbose = DEBUG or self.verbosity >= 3
- if verbose:
- fprintf(self.logfile,
- "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n",
- self.actualfmtcount, fmtkey, fmtkey, unistrg)
- is_date_s = self.is_date_format_string(unistrg)
- ty = [FGE, FDT][is_date_s]
- if not(fmtkey > 163 or bv < 50):
- # user_defined if fmtkey > 163
- # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-(
- # if earlier than BIFF 5, standard info is useless
- std_ty = std_format_code_types.get(fmtkey, FUN)
- # print "std ty", std_ty
- is_date_c = std_ty == FDT
- if 0 < fmtkey < 50 and (is_date_c ^ is_date_s):
- DEBUG = 2
- fprintf(self.logfile,
- "WARNING *** Conflict between "
- "std format key %d and its format string %r\n",
- fmtkey, unistrg)
- if DEBUG == 2:
- fprintf(self.logfile,
- "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r",
- ty, is_date_c, is_date_s, unistrg)
- fmtobj = Format(fmtkey, ty, unistrg)
- if verbose:
- fmtobj.dump(self.logfile,
- header="--- handle_format [%d] ---" % (self.actualfmtcount-1, ))
- self.format_map[fmtkey] = fmtobj
- self.format_list.append(fmtobj)
-
-# =============================================================================
-
-def handle_palette(book, data):
- if not book.formatting_info:
- return
- verbose = DEBUG or book.verbosity >= 2
- n_colours, = unpack('<H', data[:2])
- expected_n_colours = (16, 56)[book.biff_version >= 50]
- if ((DEBUG or book.verbosity >= 1)
- and n_colours != expected_n_colours):
- fprintf(book.logfile,
- "NOTE *** Expected %d colours in PALETTE record, found %d\n",
- expected_n_colours, n_colours)
- elif verbose:
- fprintf(book.logfile,
- "PALETTE record with %d colours\n", n_colours)
- fmt = '<xx%di' % n_colours # use i to avoid long integers
- expected_size = 4 * n_colours + 2
- actual_size = len(data)
- tolerance = 4
- if not expected_size <= actual_size <= expected_size + tolerance:
- raise XLRDError('PALETTE record: expected size %d, actual size %d' % (expected_size, actual_size))
- colours = unpack(fmt, data[:expected_size])
- assert book.palette_record == [] # There should be only 1 PALETTE record
- # a colour will be 0xbbggrr
- # IOW, red is at the little end
- for i in range(n_colours):
- c = colours[i]
- red = c & 0xff
- green = (c >> 8) & 0xff
- blue = (c >> 16) & 0xff
- old_rgb = book.colour_map[8+i]
- new_rgb = (red, green, blue)
- book.palette_record.append(new_rgb)
- book.colour_map[8+i] = new_rgb
- if verbose:
- if new_rgb != old_rgb:
- print("%2d: %r -> %r" % (i, old_rgb, new_rgb), file=book.logfile)
-
-def palette_epilogue(book):
- # Check colour indexes in fonts etc.
- # This must be done here as FONT records
- # come *before* the PALETTE record :-(
- for font in book.font_list:
- if font.font_index == 4: # the missing font record
- continue
- cx = font.colour_index
- if cx == 0x7fff: # system window text colour
- continue
- if cx in book.colour_map:
- book.colour_indexes_used[cx] = 1
- else:
- print("Size of colour table:", len(book.colour_map))
- print("*** Font #%d (%r): colour index 0x%04x is unknown" \
- % (font.font_index, font.name, cx), file=book.logfile)
- if book.verbosity >= 1:
- used = list(book.colour_indexes_used.keys())
- used.sort()
- print("\nColour indexes used:\n%r\n" % used, file=book.logfile)
-
-def handle_style(book, data):
- verbose = DEBUG or book.verbosity >= 2
- bv = book.biff_version
- flag_and_xfx, built_in_id, level = unpack('<HBB', data[:4])
- xf_index = flag_and_xfx & 0x0fff
- if (data == "\0\0\0\0"
- and "Normal" not in book.style_name_map):
- # Erroneous record (doesn't have built-in bit set).
- # Example file supplied by Jeff Bell.
- built_in = 1
- built_in_id = 0
- xf_index = 0
- name = "Normal"
- level = 255
- elif flag_and_xfx & 0x8000:
- # built-in style
- built_in = 1
- name = built_in_style_names[built_in_id]
- if 1 <= built_in_id <= 2:
- name += str(level + 1)
- else:
- # user-defined style
- if bv >= 80:
- name = unpack_unicode(data, 2, lenlen=2)
- else:
- name = unpack_string(data, 2, book.encoding, lenlen=1)
- if verbose and not name:
- print("WARNING *** A user-defined style has a zero-length name", file=book.logfile)
- built_in = 0
- built_in_id = 0
- level = 0
- book.style_name_map[name] = (built_in, xf_index)
- if verbose:
- print("STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d name=%r" \
- % (built_in, xf_index, built_in_id, level, name), file=book.logfile)
-
-def check_colour_indexes_in_obj(book, obj, orig_index):
- alist = list(obj.__dict__.items())
- alist.sort()
- for attr, nobj in alist:
- if hasattr(nobj, 'dump'):
- check_colour_indexes_in_obj(book, nobj, orig_index)
- elif attr.find('colour_index') >= 0:
- if nobj in book.colour_map:
- book.colour_indexes_used[nobj] = 1
- continue
- oname = obj.__class__.__name__
- print("*** xf #%d : %s.%s = 0x%04x (unknown)" \
- % (orig_index, oname, attr, nobj), file=book.logfile)
-
-def handle_xf(self, data):
- ### self is a Book instance
- # DEBUG = 0
- verbose = DEBUG or self.verbosity >= 3
- bv = self.biff_version
- xf = XF()
- xf.alignment = XFAlignment()
- xf.alignment.indent_level = 0
- xf.alignment.shrink_to_fit = 0
- xf.alignment.text_direction = 0
- xf.border = XFBorder()
- xf.border.diag_up = 0
- xf.border.diag_down = 0
- xf.border.diag_colour_index = 0
- xf.border.diag_line_style = 0 # no line
- xf.background = XFBackground()
- xf.protection = XFProtection()
- # fill in the known standard formats
- if bv >= 50 and not self.xfcount:
- # i.e. do this once before we process the first XF record
- for x in list(std_format_code_types.keys()):
- if x not in self.format_map:
- ty = std_format_code_types[x]
- fmt_str = std_format_strings[x]
- fmtobj = Format(x, ty, fmt_str)
- self.format_map[x] = fmtobj
- if bv >= 80:
- unpack_fmt = '<HHHBBBBIiH'
- (xf.font_index, xf.format_key, pkd_type_par,
- pkd_align1, xf.alignment.rotation, pkd_align2,
- pkd_used, pkd_brdbkg1, pkd_brdbkg2, pkd_brdbkg3,
- ) = unpack(unpack_fmt, data[0:20])
- upkbits(xf.protection, pkd_type_par, (
- (0, 0x01, 'cell_locked'),
- (1, 0x02, 'formula_hidden'),
- ))
- upkbits(xf, pkd_type_par, (
- (2, 0x0004, 'is_style'),
- # Following is not in OOo docs, but is mentioned
- # in Gnumeric source and also in (deep breath)
- # org.apache.poi.hssf.record.ExtendedFormatRecord.java
- (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
- (4, 0xFFF0, 'parent_style_index'),
- ))
- upkbits(xf.alignment, pkd_align1, (
- (0, 0x07, 'hor_align'),
- (3, 0x08, 'text_wrapped'),
- (4, 0x70, 'vert_align'),
- ))
- upkbits(xf.alignment, pkd_align2, (
- (0, 0x0f, 'indent_level'),
- (4, 0x10, 'shrink_to_fit'),
- (6, 0xC0, 'text_direction'),
- ))
- reg = pkd_used >> 2
- for attr_stem in \
- "format font alignment border background protection".split():
- attr = "_" + attr_stem + "_flag"
- setattr(xf, attr, reg & 1)
- reg >>= 1
- upkbitsL(xf.border, pkd_brdbkg1, (
- (0, 0x0000000f, 'left_line_style'),
- (4, 0x000000f0, 'right_line_style'),
- (8, 0x00000f00, 'top_line_style'),
- (12, 0x0000f000, 'bottom_line_style'),
- (16, 0x007f0000, 'left_colour_index'),
- (23, 0x3f800000, 'right_colour_index'),
- (30, 0x40000000, 'diag_down'),
- (31, 0x80000000, 'diag_up'),
- ))
- upkbits(xf.border, pkd_brdbkg2, (
- (0, 0x0000007F, 'top_colour_index'),
- (7, 0x00003F80, 'bottom_colour_index'),
- (14, 0x001FC000, 'diag_colour_index'),
- (21, 0x01E00000, 'diag_line_style'),
- ))
- upkbitsL(xf.background, pkd_brdbkg2, (
- (26, 0xFC000000, 'fill_pattern'),
- ))
- upkbits(xf.background, pkd_brdbkg3, (
- (0, 0x007F, 'pattern_colour_index'),
- (7, 0x3F80, 'background_colour_index'),
- ))
- elif bv >= 50:
- unpack_fmt = '<HHHBBIi'
- (xf.font_index, xf.format_key, pkd_type_par,
- pkd_align1, pkd_orient_used,
- pkd_brdbkg1, pkd_brdbkg2,
- ) = unpack(unpack_fmt, data[0:16])
- upkbits(xf.protection, pkd_type_par, (
- (0, 0x01, 'cell_locked'),
- (1, 0x02, 'formula_hidden'),
- ))
- upkbits(xf, pkd_type_par, (
- (2, 0x0004, 'is_style'),
- (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
- (4, 0xFFF0, 'parent_style_index'),
- ))
- upkbits(xf.alignment, pkd_align1, (
- (0, 0x07, 'hor_align'),
- (3, 0x08, 'text_wrapped'),
- (4, 0x70, 'vert_align'),
- ))
- orientation = pkd_orient_used & 0x03
- xf.alignment.rotation = [0, 255, 90, 180][orientation]
- reg = pkd_orient_used >> 2
- for attr_stem in \
- "format font alignment border background protection".split():
- attr = "_" + attr_stem + "_flag"
- setattr(xf, attr, reg & 1)
- reg >>= 1
- upkbitsL(xf.background, pkd_brdbkg1, (
- ( 0, 0x0000007F, 'pattern_colour_index'),
- ( 7, 0x00003F80, 'background_colour_index'),
- (16, 0x003F0000, 'fill_pattern'),
- ))
- upkbitsL(xf.border, pkd_brdbkg1, (
- (22, 0x01C00000, 'bottom_line_style'),
- (25, 0xFE000000, 'bottom_colour_index'),
- ))
- upkbits(xf.border, pkd_brdbkg2, (
- ( 0, 0x00000007, 'top_line_style'),
- ( 3, 0x00000038, 'left_line_style'),
- ( 6, 0x000001C0, 'right_line_style'),
- ( 9, 0x0000FE00, 'top_colour_index'),
- (16, 0x007F0000, 'left_colour_index'),
- (23, 0x3F800000, 'right_colour_index'),
- ))
- elif bv >= 40:
- unpack_fmt = '<BBHBBHI'
- (xf.font_index, xf.format_key, pkd_type_par,
- pkd_align_orient, pkd_used,
- pkd_bkg_34, pkd_brd_34,
- ) = unpack(unpack_fmt, data[0:12])
- upkbits(xf.protection, pkd_type_par, (
- (0, 0x01, 'cell_locked'),
- (1, 0x02, 'formula_hidden'),
- ))
- upkbits(xf, pkd_type_par, (
- (2, 0x0004, 'is_style'),
- (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
- (4, 0xFFF0, 'parent_style_index'),
- ))
- upkbits(xf.alignment, pkd_align_orient, (
- (0, 0x07, 'hor_align'),
- (3, 0x08, 'text_wrapped'),
- (4, 0x30, 'vert_align'),
- ))
- orientation = (pkd_align_orient & 0xC0) >> 6
- xf.alignment.rotation = [0, 255, 90, 180][orientation]
- reg = pkd_used >> 2
- for attr_stem in \
- "format font alignment border background protection".split():
- attr = "_" + attr_stem + "_flag"
- setattr(xf, attr, reg & 1)
- reg >>= 1
- upkbits(xf.background, pkd_bkg_34, (
- ( 0, 0x003F, 'fill_pattern'),
- ( 6, 0x07C0, 'pattern_colour_index'),
- (11, 0xF800, 'background_colour_index'),
- ))
- upkbitsL(xf.border, pkd_brd_34, (
- ( 0, 0x00000007, 'top_line_style'),
- ( 3, 0x000000F8, 'top_colour_index'),
- ( 8, 0x00000700, 'left_line_style'),
- (11, 0x0000F800, 'left_colour_index'),
- (16, 0x00070000, 'bottom_line_style'),
- (19, 0x00F80000, 'bottom_colour_index'),
- (24, 0x07000000, 'right_line_style'),
- (27, 0xF8000000, 'right_colour_index'),
- ))
- elif bv == 30:
- unpack_fmt = '<BBBBHHI'
- (xf.font_index, xf.format_key, pkd_type_prot,
- pkd_used, pkd_align_par,
- pkd_bkg_34, pkd_brd_34,
- ) = unpack(unpack_fmt, data[0:12])
- upkbits(xf.protection, pkd_type_prot, (
- (0, 0x01, 'cell_locked'),
- (1, 0x02, 'formula_hidden'),
- ))
- upkbits(xf, pkd_type_prot, (
- (2, 0x0004, 'is_style'),
- (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
- ))
- upkbits(xf.alignment, pkd_align_par, (
- (0, 0x07, 'hor_align'),
- (3, 0x08, 'text_wrapped'),
- ))
- upkbits(xf, pkd_align_par, (
- (4, 0xFFF0, 'parent_style_index'),
- ))
- reg = pkd_used >> 2
- for attr_stem in \
- "format font alignment border background protection".split():
- attr = "_" + attr_stem + "_flag"
- setattr(xf, attr, reg & 1)
- reg >>= 1
- upkbits(xf.background, pkd_bkg_34, (
- ( 0, 0x003F, 'fill_pattern'),
- ( 6, 0x07C0, 'pattern_colour_index'),
- (11, 0xF800, 'background_colour_index'),
- ))
- upkbitsL(xf.border, pkd_brd_34, (
- ( 0, 0x00000007, 'top_line_style'),
- ( 3, 0x000000F8, 'top_colour_index'),
- ( 8, 0x00000700, 'left_line_style'),
- (11, 0x0000F800, 'left_colour_index'),
- (16, 0x00070000, 'bottom_line_style'),
- (19, 0x00F80000, 'bottom_colour_index'),
- (24, 0x07000000, 'right_line_style'),
- (27, 0xF8000000, 'right_colour_index'),
- ))
- xf.alignment.vert_align = 2 # bottom
- xf.alignment.rotation = 0
- elif bv == 21:
- #### Warning: incomplete treatment; formatting_info not fully supported.
- #### Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16],
- #### and create XF[0:16] like the standard ones in BIFF8
- #### *AND* add 16 to all XF references in cell records :-(
- (xf.font_index, format_etc, halign_etc) = unpack('<BxBB', data)
- xf.format_key = format_etc & 0x3F
- upkbits(xf.protection, format_etc, (
- (6, 0x40, 'cell_locked'),
- (7, 0x80, 'formula_hidden'),
- ))
- upkbits(xf.alignment, halign_etc, (
- (0, 0x07, 'hor_align'),
- ))
- for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')):
- if halign_etc & mask:
- colour_index, line_style = 8, 1 # black, thin
- else:
- colour_index, line_style = 0, 0 # none, none
- setattr(xf.border, side + '_colour_index', colour_index)
- setattr(xf.border, side + '_line_style', line_style)
- bg = xf.background
- if halign_etc & 0x80:
- bg.fill_pattern = 17
- else:
- bg.fill_pattern = 0
- bg.background_colour_index = 9 # white
- bg.pattern_colour_index = 8 # black
- xf.parent_style_index = 0 # ???????????
- xf.alignment.vert_align = 2 # bottom
- xf.alignment.rotation = 0
- for attr_stem in \
- "format font alignment border background protection".split():
- attr = "_" + attr_stem + "_flag"
- setattr(xf, attr, 1)
- else:
- raise XLRDError('programmer stuff-up: bv=%d' % bv)
-
- xf.xf_index = len(self.xf_list)
- self.xf_list.append(xf)
- self.xfcount += 1
- if verbose:
- xf.dump(
- self.logfile,
- header="--- handle_xf: xf[%d] ---" % xf.xf_index,
- footer=" ",
- )
- # Now for some assertions ...
- if self.formatting_info:
- if xf.is_style and xf.parent_style_index != 0x0FFF:
- msg = "WARNING *** XF[%d] is a style XF but parent_style_index is 0x%04x, not 0x0fff\n"
- fprintf(self.logfile, msg, xf.xf_index, xf.parent_style_index)
- check_colour_indexes_in_obj(self, xf, xf.xf_index)
- if xf.format_key not in self.format_map:
- msg = "WARNING *** XF[%d] unknown (raw) format key (%d, 0x%04x)\n"
- fprintf(self.logfile, msg,
- xf.xf_index, xf.format_key, xf.format_key)
- xf.format_key = 0
-
-def xf_epilogue(self):
- # self is a Book instance.
- self._xf_epilogue_done = 1
- num_xfs = len(self.xf_list)
- verbose = DEBUG or self.verbosity >= 3
- verbose1 = DEBUG or self.verbosity >= 1
- if verbose:
- fprintf(self.logfile, "xf_epilogue called ...\n")
-
- def check_same(book_arg, xf_arg, parent_arg, attr):
- # the _arg caper is to avoid a Warning msg from Python 2.1 :-(
- if getattr(xf_arg, attr) != getattr(parent_arg, attr):
- fprintf(book_arg.logfile,
- "NOTE !!! XF[%d] parent[%d] %s different\n",
- xf_arg.xf_index, parent_arg.xf_index, attr)
-
- for xfx in range(num_xfs):
- xf = self.xf_list[xfx]
- if xf.format_key not in self.format_map:
- msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n"
- fprintf(self.logfile, msg,
- xf.xf_index, xf.format_key, xf.format_key)
- xf.format_key = 0
- cellty_from_fmtty = {
- FNU: XL_CELL_NUMBER,
- FUN: XL_CELL_NUMBER,
- FGE: XL_CELL_NUMBER,
- FDT: XL_CELL_DATE,
- FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text.
- }
- fmt = self.format_map[xf.format_key]
- cellty = cellty_from_fmtty[fmt.type]
- self._xf_index_to_xl_type_map[xf.xf_index] = cellty
- # Now for some assertions etc
- if not self.formatting_info:
- continue
- if xf.is_style:
- continue
- if not(0 <= xf.parent_style_index < num_xfs):
- fprintf(self.logfile,
- "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n",
- xf.xf_index, xf.is_style, xf.parent_style_index)
- # make it conform
- xf.parent_style_index = 0
- if self.biff_version >= 30:
- assert xf.parent_style_index != xf.xf_index
- assert self.xf_list[xf.parent_style_index].is_style
- if verbose1 and xf.parent_style_index > xf.xf_index:
- fprintf(self.logfile,
- "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n",
- xf.xf_index, xf.parent_style_index)
- parent = self.xf_list[xf.parent_style_index]
- if not xf._alignment_flag and not parent._alignment_flag:
- if verbose1: check_same(self, xf, parent, 'alignment')
- if not xf._background_flag and not parent._background_flag:
- if verbose1: check_same(self, xf, parent, 'background')
- if not xf._border_flag and not parent._border_flag:
- if verbose1: check_same(self, xf, parent, 'border')
- if not xf._protection_flag and not parent._protection_flag:
- if verbose1: check_same(self, xf, parent, 'protection')
- if not xf._format_flag and not parent._format_flag:
- if verbose1 and xf.format_key != parent.format_key:
- fprintf(self.logfile,
- "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n",
- xf.xf_index, xf.format_key, parent.xf_index, parent.format_key,
- self.format_map[xf.format_key].format_str,
- self.format_map[parent.format_key].format_str)
- if not xf._font_flag and not parent._font_flag:
- if verbose1 and xf.font_index != parent.font_index:
- fprintf(self.logfile,
- "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n",
- xf.xf_index, xf.font_index, parent.xf_index, parent.font_index)
-
-def initialise_book(book):
- initialise_colour_map(book)
- book._xf_epilogue_done = 0
- methods = (
- handle_font,
- handle_efont,
- handle_format,
- is_date_format_string,
- handle_palette,
- palette_epilogue,
- handle_style,
- handle_xf,
- xf_epilogue,
- )
- for method in methods:
- setattr(book.__class__, method.__name__, method)
-
-class XFBorder(BaseObject, EqNeAttrs):
- """ A collection of the border-related attributes of an XF record.
-
- Items correspond to those in the Excel UI's Format/Cells/Border tab.
- An explanations of "colour index" is given in the Formatting
- section at the start of this document.
- There are five line style attributes; possible values and the
- associated meanings are:
-
- 0 = No line,
- 1 = Thin,
- 2 = Medium,
- 3 = Dashed,
- 4 = Dotted,
- 5 = Thick,
- 6 = Double,
- 7 = Hair,
- 8 = Medium dashed,
- 9 = Thin dash-dotted,
- 10 = Medium dash-dotted,
- 11 = Thin dash-dot-dotted,
- 12 = Medium dash-dot-dotted,
- 13 = Slanted medium dash-dotted.
- The line styles 8 to 13 appear in BIFF8 files (Excel 97 and later) only.
- For pictures of the line styles, refer to OOo docs s3.10 (p22)
- "Line Styles for Cell Borders (BIFF3-BIFF8)".</p>
- - New in version 0.6.1
- """
-
- # The colour index for the cell's top line
- top_colour_index = 0
- # The colour index for the cell's bottom line
- bottom_colour_index = 0
- # The colour index for the cell's left line
- left_colour_index = 0
- # The colour index for the cell's right line
- right_colour_index = 0
- # The colour index for the cell's diagonal lines, if any
- diag_colour_index = 0
- # The line style for the cell's top line
- top_line_style = 0
- # The line style for the cell's bottom line
- bottom_line_style = 0
- # The line style for the cell's left line
- left_line_style = 0
- # The line style for the cell's right line
- right_line_style = 0
- # The line style for the cell's diagonal lines, if any
- diag_line_style = 0
- # 1 = draw a diagonal from top left to bottom right
- diag_down = 0
- # 1 = draw a diagonal from bottom left to top right
- diag_up = 0
-
-# New in version 0.6.1
-class XFBackground(BaseObject, EqNeAttrs):
- """ A collection of the background-related attributes of an XF record.
-
- Items correspond to those in the Excel UI's Format/Cells/Patterns tab.
- An explanation of "colour index" is given in the Formatting
- section at the start of this document.
-
- """
- # See section 3.11 of the OOo docs.
- fill_pattern = 0
- # See section 3.11 of the OOo docs.
- background_colour_index = 0
- # See section 3.11 of the OOo docs.
- pattern_colour_index = 0
-
-# New in version 0.6.1
-class XFAlignment(BaseObject, EqNeAttrs):
- """ A collection of the alignment and similar attributes of an XF record.
-
- Items correspond to those in the Excel UI's Format/Cells/Alignment tab.
- """
- # Values: section 5.115 (p 219) of OOo docs
- hor_align = 0
- # Values: section 5.115 (p 220) of OOo docs
- vert_align = 0
- # Values: section 5.115 (p 220) of OOo docs.
- # Note: file versions BIFF7 and earlier use the documented
- # "orientation" attribute; this will be mapped (without loss)
- # into "rotation".
- rotation = 0
- # 1 = text is wrapped at right margin
- text_wrapped = 0
- # A number in range(15).
- indent_level = 0
- # 1 = shrink font size to fit text into cell.
- shrink_to_fit = 0
- # 0 = according to context; 1 = left-to-right; 2 = right-to-left
- text_direction = 0
-
-# New in version 0.6.1
-class XFProtection(BaseObject, EqNeAttrs):
- """ A collection of the protection-related attributes of an XF record.
-
- Items correspond to those in the Excel UI's Format/Cells/Protection tab.
- Note the OOo docs include the "cell or style" bit
- in this bundle of attributes.
- This is incorrect; the bit is used in determining which bundles to use.
-
- """
- # 1 = Cell is prevented from being changed, moved, resized, or deleted
- # (only if the sheet is protected).
- cell_locked = 0
- # 1 = Hide formula so that it doesn't appear in the formula bar when
- # the cell is selected (only if the sheet is protected).
- formula_hidden = 0
-
-# New in version 0.6.1
-class XF(BaseObject):
- """ eXtended Formatting information for cells, rows, columns and styles.
-
- Each of the 6 flags below describes the validity of
- a specific group of attributes.
-
- In cell XFs, flag==0 means the attributes of the parent style XF are used,
- (but only if the attributes are valid there); flag==1 means the attributes
- of this XF are used.
- In style XFs, flag==0 means the attribute setting is valid; flag==1 means
- the attribute should be ignored.
- Note that the API
- provides both "raw" XFs and "computed" XFs -- in the latter case, cell XFs
- have had the above inheritance mechanism applied.
- """
- # 0 = cell XF, 1 = style XF
- is_style = 0
- # cell XF: Index into Book.xf_list
- # of this XF's style XF
- # style XF: 0xFFF
- parent_style_index = 0
- _format_flag = 0
- _font_flag = 0
- _alignment_flag = 0
- _border_flag = 0
- _background_flag = 0
- _protection_flag = 0
- # Index into Book.xf_list
- xf_index = 0
- # Index into Book.font_list
- font_index = 0
- # Key into Book.format_map
- #
- # Warning: OOo docs on the XF record call this "Index to FORMAT record".
- # It is not an index in the Python sense. It is a key to a map.
- # It is true **only** for Excel 4.0 and earlier files
- # that the key into format_map from an XF instance
- # is the same as the index into format_list, and **only**
- # if the index is less than 164.
- #
- format_key = 0
- # An instance of an XFProtection object.
- protection = None
- # An instance of an XFBackground object.
- background = None
- # An instance of an XFAlignment object.
- alignment = None
- # An instance of an XFBorder object.
- border = None
diff --git a/tablib/packages/xlrd3/formula.py b/tablib/packages/xlrd3/formula.py deleted file mode 100644 index 445d761..0000000 --- a/tablib/packages/xlrd3/formula.py +++ /dev/null @@ -1,2083 +0,0 @@ -# Module for parsing/evaluating Microsoft Excel formulas.
-#
-# Copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd3 package, which is released under
-# a BSD-style licence.
-
-# No part of the content of this file was derived from the works of David Giffin.
-
-import copy
-from struct import unpack
-
-from .biffh import unpack_unicode_update_pos, unpack_string_update_pos, \
- XLRDError, hex_char_dump, error_text_from_code, BaseObject
-
-__all__ = [
- 'oBOOL', 'oERR', 'oNUM', 'oREF', 'oREL', 'oSTRG', 'oUNK',
- 'decompile_formula',
- 'dump_formula',
- 'evaluate_name_formula',
- 'okind_dict',
- 'rangename3d', 'rangename3drel', 'cellname', 'cellnameabs', 'colname',
- ]
-
-# sztabN[opcode] -> the number of bytes to consume.
-# -1 means variable
-# -2 means this opcode not implemented in this version.
-# Which N to use? Depends on biff_version; see szdict.
-sztab0 = [-2, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 8, 4, 2, 2, 3, 9, 8, 2, 3, 8, 4, 7, 5, 5, 5, 2, 4, 7, 4, 7, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2]
-sztab1 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 2, 3, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, 3, -2, -2, -2, -2, -2, -2, -2]
-sztab2 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, 11, 5, 2, 2, 3, 9, 9, 3, 4, 11, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2]
-sztab3 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 15, 4, 7, 7, 7, 7, 3, 4, 7, 4, 7, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 25, 18, 21, 18, 21, -2, -2]
-sztab4 = [-2, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -2, -2, 2, 2, 3, 9, 9, 3, 4, 5, 5, 9, 7, 7, 7, 3, 5, 9, 5, 9, 3, 3, -2, -2, -2, -2, -2, -2, -2, -2, -2, 7, 7, 11, 7, 11, -2, -2]
-
-szdict = {
- 20 : sztab0,
- 21 : sztab0, # Suppose 21 is same as 20....
- 30 : sztab1,
- 40 : sztab2,
- 45 : sztab2,
- 50 : sztab3,
- 70 : sztab3,
- 80 : sztab4,
- }
-
-# For debugging purposes ... the name for each opcode
-# (without the prefix "t" used on OOo docs)
-onames = ['Unk00', 'Exp', 'Tbl', 'Add', 'Sub', 'Mul', 'Div', 'Power', 'Concat', 'LT', 'LE', 'EQ', 'GE', 'GT', 'NE', 'Isect', 'List', 'Range', 'Uplus', 'Uminus', 'Percent', 'Paren', 'MissArg', 'Str', 'Extended', 'Attr', 'Sheet', 'EndSheet', 'Err', 'Bool', 'Int', 'Num', 'Array', 'Func', 'FuncVar', 'Name', 'Ref', 'Area', 'MemArea', 'MemErr', 'MemNoMem', 'MemFunc', 'RefErr', 'AreaErr', 'RefN', 'AreaN', 'MemAreaN', 'MemNoMemN', '', '', '', '', '', '', '', '', 'FuncCE', 'NameX', 'Ref3d', 'Area3d', 'RefErr3d', 'AreaErr3d', '', '']
-
-func_defs = {
- # index: (name, min#args, max#args, flags, #known_args, return_type, kargs)
- 0 : ('COUNT', 0, 30, 0x04, 1, 'V', 'R'),
- 1 : ('IF', 2, 3, 0x04, 3, 'V', 'VRR'),
- 2 : ('ISNA', 1, 1, 0x02, 1, 'V', 'V'),
- 3 : ('ISERROR', 1, 1, 0x02, 1, 'V', 'V'),
- 4 : ('SUM', 0, 30, 0x04, 1, 'V', 'R'),
- 5 : ('AVERAGE', 1, 30, 0x04, 1, 'V', 'R'),
- 6 : ('MIN', 1, 30, 0x04, 1, 'V', 'R'),
- 7 : ('MAX', 1, 30, 0x04, 1, 'V', 'R'),
- 8 : ('ROW', 0, 1, 0x04, 1, 'V', 'R'),
- 9 : ('COLUMN', 0, 1, 0x04, 1, 'V', 'R'),
- 10 : ('NA', 0, 0, 0x02, 0, 'V', ''),
- 11 : ('NPV', 2, 30, 0x04, 2, 'V', 'VR'),
- 12 : ('STDEV', 1, 30, 0x04, 1, 'V', 'R'),
- 13 : ('DOLLAR', 1, 2, 0x04, 1, 'V', 'V'),
- 14 : ('FIXED', 2, 3, 0x04, 3, 'V', 'VVV'),
- 15 : ('SIN', 1, 1, 0x02, 1, 'V', 'V'),
- 16 : ('COS', 1, 1, 0x02, 1, 'V', 'V'),
- 17 : ('TAN', 1, 1, 0x02, 1, 'V', 'V'),
- 18 : ('ATAN', 1, 1, 0x02, 1, 'V', 'V'),
- 19 : ('PI', 0, 0, 0x02, 0, 'V', ''),
- 20 : ('SQRT', 1, 1, 0x02, 1, 'V', 'V'),
- 21 : ('EXP', 1, 1, 0x02, 1, 'V', 'V'),
- 22 : ('LN', 1, 1, 0x02, 1, 'V', 'V'),
- 23 : ('LOG10', 1, 1, 0x02, 1, 'V', 'V'),
- 24 : ('ABS', 1, 1, 0x02, 1, 'V', 'V'),
- 25 : ('INT', 1, 1, 0x02, 1, 'V', 'V'),
- 26 : ('SIGN', 1, 1, 0x02, 1, 'V', 'V'),
- 27 : ('ROUND', 2, 2, 0x02, 2, 'V', 'VV'),
- 28 : ('LOOKUP', 2, 3, 0x04, 2, 'V', 'VR'),
- 29 : ('INDEX', 2, 4, 0x0c, 4, 'R', 'RVVV'),
- 30 : ('REPT', 2, 2, 0x02, 2, 'V', 'VV'),
- 31 : ('MID', 3, 3, 0x02, 3, 'V', 'VVV'),
- 32 : ('LEN', 1, 1, 0x02, 1, 'V', 'V'),
- 33 : ('VALUE', 1, 1, 0x02, 1, 'V', 'V'),
- 34 : ('TRUE', 0, 0, 0x02, 0, 'V', ''),
- 35 : ('FALSE', 0, 0, 0x02, 0, 'V', ''),
- 36 : ('AND', 1, 30, 0x04, 1, 'V', 'R'),
- 37 : ('OR', 1, 30, 0x04, 1, 'V', 'R'),
- 38 : ('NOT', 1, 1, 0x02, 1, 'V', 'V'),
- 39 : ('MOD', 2, 2, 0x02, 2, 'V', 'VV'),
- 40 : ('DCOUNT', 3, 3, 0x02, 3, 'V', 'RRR'),
- 41 : ('DSUM', 3, 3, 0x02, 3, 'V', 'RRR'),
- 42 : ('DAVERAGE', 3, 3, 0x02, 3, 'V', 'RRR'),
- 43 : ('DMIN', 3, 3, 0x02, 3, 'V', 'RRR'),
- 44 : ('DMAX', 3, 3, 0x02, 3, 'V', 'RRR'),
- 45 : ('DSTDEV', 3, 3, 0x02, 3, 'V', 'RRR'),
- 46 : ('VAR', 1, 30, 0x04, 1, 'V', 'R'),
- 47 : ('DVAR', 3, 3, 0x02, 3, 'V', 'RRR'),
- 48 : ('TEXT', 2, 2, 0x02, 2, 'V', 'VV'),
- 49 : ('LINEST', 1, 4, 0x04, 4, 'A', 'RRVV'),
- 50 : ('TREND', 1, 4, 0x04, 4, 'A', 'RRRV'),
- 51 : ('LOGEST', 1, 4, 0x04, 4, 'A', 'RRVV'),
- 52 : ('GROWTH', 1, 4, 0x04, 4, 'A', 'RRRV'),
- 56 : ('PV', 3, 5, 0x04, 5, 'V', 'VVVVV'),
- 57 : ('FV', 3, 5, 0x04, 5, 'V', 'VVVVV'),
- 58 : ('NPER', 3, 5, 0x04, 5, 'V', 'VVVVV'),
- 59 : ('PMT', 3, 5, 0x04, 5, 'V', 'VVVVV'),
- 60 : ('RATE', 3, 6, 0x04, 6, 'V', 'VVVVVV'),
- 61 : ('MIRR', 3, 3, 0x02, 3, 'V', 'RVV'),
- 62 : ('IRR', 1, 2, 0x04, 2, 'V', 'RV'),
- 63 : ('RAND', 0, 0, 0x0a, 0, 'V', ''),
- 64 : ('MATCH', 2, 3, 0x04, 3, 'V', 'VRR'),
- 65 : ('DATE', 3, 3, 0x02, 3, 'V', 'VVV'),
- 66 : ('TIME', 3, 3, 0x02, 3, 'V', 'VVV'),
- 67 : ('DAY', 1, 1, 0x02, 1, 'V', 'V'),
- 68 : ('MONTH', 1, 1, 0x02, 1, 'V', 'V'),
- 69 : ('YEAR', 1, 1, 0x02, 1, 'V', 'V'),
- 70 : ('WEEKDAY', 1, 2, 0x04, 2, 'V', 'VV'),
- 71 : ('HOUR', 1, 1, 0x02, 1, 'V', 'V'),
- 72 : ('MINUTE', 1, 1, 0x02, 1, 'V', 'V'),
- 73 : ('SECOND', 1, 1, 0x02, 1, 'V', 'V'),
- 74 : ('NOW', 0, 0, 0x0a, 0, 'V', ''),
- 75 : ('AREAS', 1, 1, 0x02, 1, 'V', 'R'),
- 76 : ('ROWS', 1, 1, 0x02, 1, 'V', 'R'),
- 77 : ('COLUMNS', 1, 1, 0x02, 1, 'V', 'R'),
- 78 : ('OFFSET', 3, 5, 0x04, 5, 'R', 'RVVVV'),
- 82 : ('SEARCH', 2, 3, 0x04, 3, 'V', 'VVV'),
- 83 : ('TRANSPOSE', 1, 1, 0x02, 1, 'A', 'A'),
- 86 : ('TYPE', 1, 1, 0x02, 1, 'V', 'V'),
- 92 : ('SERIESSUM', 4, 4, 0x02, 4, 'V', 'VVVA'),
- 97 : ('ATAN2', 2, 2, 0x02, 2, 'V', 'VV'),
- 98 : ('ASIN', 1, 1, 0x02, 1, 'V', 'V'),
- 99 : ('ACOS', 1, 1, 0x02, 1, 'V', 'V'),
- 100: ('CHOOSE', 2, 30, 0x04, 2, 'V', 'VR'),
- 101: ('HLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'),
- 102: ('VLOOKUP', 3, 4, 0x04, 4, 'V', 'VRRV'),
- 105: ('ISREF', 1, 1, 0x02, 1, 'V', 'R'),
- 109: ('LOG', 1, 2, 0x04, 2, 'V', 'VV'),
- 111: ('CHAR', 1, 1, 0x02, 1, 'V', 'V'),
- 112: ('LOWER', 1, 1, 0x02, 1, 'V', 'V'),
- 113: ('UPPER', 1, 1, 0x02, 1, 'V', 'V'),
- 114: ('PROPER', 1, 1, 0x02, 1, 'V', 'V'),
- 115: ('LEFT', 1, 2, 0x04, 2, 'V', 'VV'),
- 116: ('RIGHT', 1, 2, 0x04, 2, 'V', 'VV'),
- 117: ('EXACT', 2, 2, 0x02, 2, 'V', 'VV'),
- 118: ('TRIM', 1, 1, 0x02, 1, 'V', 'V'),
- 119: ('REPLACE', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 120: ('SUBSTITUTE', 3, 4, 0x04, 4, 'V', 'VVVV'),
- 121: ('CODE', 1, 1, 0x02, 1, 'V', 'V'),
- 124: ('FIND', 2, 3, 0x04, 3, 'V', 'VVV'),
- 125: ('CELL', 1, 2, 0x0c, 2, 'V', 'VR'),
- 126: ('ISERR', 1, 1, 0x02, 1, 'V', 'V'),
- 127: ('ISTEXT', 1, 1, 0x02, 1, 'V', 'V'),
- 128: ('ISNUMBER', 1, 1, 0x02, 1, 'V', 'V'),
- 129: ('ISBLANK', 1, 1, 0x02, 1, 'V', 'V'),
- 130: ('T', 1, 1, 0x02, 1, 'V', 'R'),
- 131: ('N', 1, 1, 0x02, 1, 'V', 'R'),
- 140: ('DATEVALUE', 1, 1, 0x02, 1, 'V', 'V'),
- 141: ('TIMEVALUE', 1, 1, 0x02, 1, 'V', 'V'),
- 142: ('SLN', 3, 3, 0x02, 3, 'V', 'VVV'),
- 143: ('SYD', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 144: ('DDB', 4, 5, 0x04, 5, 'V', 'VVVVV'),
- 148: ('INDIRECT', 1, 2, 0x0c, 2, 'R', 'VV'),
- 162: ('CLEAN', 1, 1, 0x02, 1, 'V', 'V'),
- 163: ('MDETERM', 1, 1, 0x02, 1, 'V', 'A'),
- 164: ('MINVERSE', 1, 1, 0x02, 1, 'A', 'A'),
- 165: ('MMULT', 2, 2, 0x02, 2, 'A', 'AA'),
- 167: ('IPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'),
- 168: ('PPMT', 4, 6, 0x04, 6, 'V', 'VVVVVV'),
- 169: ('COUNTA', 0, 30, 0x04, 1, 'V', 'R'),
- 183: ('PRODUCT', 0, 30, 0x04, 1, 'V', 'R'),
- 184: ('FACT', 1, 1, 0x02, 1, 'V', 'V'),
- 189: ('DPRODUCT', 3, 3, 0x02, 3, 'V', 'RRR'),
- 190: ('ISNONTEXT', 1, 1, 0x02, 1, 'V', 'V'),
- 193: ('STDEVP', 1, 30, 0x04, 1, 'V', 'R'),
- 194: ('VARP', 1, 30, 0x04, 1, 'V', 'R'),
- 195: ('DSTDEVP', 3, 3, 0x02, 3, 'V', 'RRR'),
- 196: ('DVARP', 3, 3, 0x02, 3, 'V', 'RRR'),
- 197: ('TRUNC', 1, 2, 0x04, 2, 'V', 'VV'),
- 198: ('ISLOGICAL', 1, 1, 0x02, 1, 'V', 'V'),
- 199: ('DCOUNTA', 3, 3, 0x02, 3, 'V', 'RRR'),
- 204: ('USDOLLAR', 1, 2, 0x04, 2, 'V', 'VV'),
- 205: ('FINDB', 2, 3, 0x04, 3, 'V', 'VVV'),
- 206: ('SEARCHB', 2, 3, 0x04, 3, 'V', 'VVV'),
- 207: ('REPLACEB', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 208: ('LEFTB', 1, 2, 0x04, 2, 'V', 'VV'),
- 209: ('RIGHTB', 1, 2, 0x04, 2, 'V', 'VV'),
- 210: ('MIDB', 3, 3, 0x02, 3, 'V', 'VVV'),
- 211: ('LENB', 1, 1, 0x02, 1, 'V', 'V'),
- 212: ('ROUNDUP', 2, 2, 0x02, 2, 'V', 'VV'),
- 213: ('ROUNDDOWN', 2, 2, 0x02, 2, 'V', 'VV'),
- 214: ('ASC', 1, 1, 0x02, 1, 'V', 'V'),
- 215: ('DBCS', 1, 1, 0x02, 1, 'V', 'V'),
- 216: ('RANK', 2, 3, 0x04, 3, 'V', 'VRV'),
- 219: ('ADDRESS', 2, 5, 0x04, 5, 'V', 'VVVVV'),
- 220: ('DAYS360', 2, 3, 0x04, 3, 'V', 'VVV'),
- 221: ('TODAY', 0, 0, 0x0a, 0, 'V', ''),
- 222: ('VDB', 5, 7, 0x04, 7, 'V', 'VVVVVVV'),
- 227: ('MEDIAN', 1, 30, 0x04, 1, 'V', 'R'),
- 228: ('SUMPRODUCT', 1, 30, 0x04, 1, 'V', 'A'),
- 229: ('SINH', 1, 1, 0x02, 1, 'V', 'V'),
- 230: ('COSH', 1, 1, 0x02, 1, 'V', 'V'),
- 231: ('TANH', 1, 1, 0x02, 1, 'V', 'V'),
- 232: ('ASINH', 1, 1, 0x02, 1, 'V', 'V'),
- 233: ('ACOSH', 1, 1, 0x02, 1, 'V', 'V'),
- 234: ('ATANH', 1, 1, 0x02, 1, 'V', 'V'),
- 235: ('DGET', 3, 3, 0x02, 3, 'V', 'RRR'),
- 244: ('INFO', 1, 1, 0x02, 1, 'V', 'V'),
- 247: ('DB', 4, 5, 0x04, 5, 'V', 'VVVVV'),
- 252: ('FREQUENCY', 2, 2, 0x02, 2, 'A', 'RR'),
- 261: ('ERROR.TYPE', 1, 1, 0x02, 1, 'V', 'V'),
- 269: ('AVEDEV', 1, 30, 0x04, 1, 'V', 'R'),
- 270: ('BETADIST', 3, 5, 0x04, 1, 'V', 'V'),
- 271: ('GAMMALN', 1, 1, 0x02, 1, 'V', 'V'),
- 272: ('BETAINV', 3, 5, 0x04, 1, 'V', 'V'),
- 273: ('BINOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 274: ('CHIDIST', 2, 2, 0x02, 2, 'V', 'VV'),
- 275: ('CHIINV', 2, 2, 0x02, 2, 'V', 'VV'),
- 276: ('COMBIN', 2, 2, 0x02, 2, 'V', 'VV'),
- 277: ('CONFIDENCE', 3, 3, 0x02, 3, 'V', 'VVV'),
- 278: ('CRITBINOM', 3, 3, 0x02, 3, 'V', 'VVV'),
- 279: ('EVEN', 1, 1, 0x02, 1, 'V', 'V'),
- 280: ('EXPONDIST', 3, 3, 0x02, 3, 'V', 'VVV'),
- 281: ('FDIST', 3, 3, 0x02, 3, 'V', 'VVV'),
- 282: ('FINV', 3, 3, 0x02, 3, 'V', 'VVV'),
- 283: ('FISHER', 1, 1, 0x02, 1, 'V', 'V'),
- 284: ('FISHERINV', 1, 1, 0x02, 1, 'V', 'V'),
- 285: ('FLOOR', 2, 2, 0x02, 2, 'V', 'VV'),
- 286: ('GAMMADIST', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 287: ('GAMMAINV', 3, 3, 0x02, 3, 'V', 'VVV'),
- 288: ('CEILING', 2, 2, 0x02, 2, 'V', 'VV'),
- 289: ('HYPGEOMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 290: ('LOGNORMDIST', 3, 3, 0x02, 3, 'V', 'VVV'),
- 291: ('LOGINV', 3, 3, 0x02, 3, 'V', 'VVV'),
- 292: ('NEGBINOMDIST', 3, 3, 0x02, 3, 'V', 'VVV'),
- 293: ('NORMDIST', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 294: ('NORMSDIST', 1, 1, 0x02, 1, 'V', 'V'),
- 295: ('NORMINV', 3, 3, 0x02, 3, 'V', 'VVV'),
- 296: ('NORMSINV', 1, 1, 0x02, 1, 'V', 'V'),
- 297: ('STANDARDIZE', 3, 3, 0x02, 3, 'V', 'VVV'),
- 298: ('ODD', 1, 1, 0x02, 1, 'V', 'V'),
- 299: ('PERMUT', 2, 2, 0x02, 2, 'V', 'VV'),
- 300: ('POISSON', 3, 3, 0x02, 3, 'V', 'VVV'),
- 301: ('TDIST', 3, 3, 0x02, 3, 'V', 'VVV'),
- 302: ('WEIBULL', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 303: ('SUMXMY2', 2, 2, 0x02, 2, 'V', 'AA'),
- 304: ('SUMX2MY2', 2, 2, 0x02, 2, 'V', 'AA'),
- 305: ('SUMX2PY2', 2, 2, 0x02, 2, 'V', 'AA'),
- 306: ('CHITEST', 2, 2, 0x02, 2, 'V', 'AA'),
- 307: ('CORREL', 2, 2, 0x02, 2, 'V', 'AA'),
- 308: ('COVAR', 2, 2, 0x02, 2, 'V', 'AA'),
- 309: ('FORECAST', 3, 3, 0x02, 3, 'V', 'VAA'),
- 310: ('FTEST', 2, 2, 0x02, 2, 'V', 'AA'),
- 311: ('INTERCEPT', 2, 2, 0x02, 2, 'V', 'AA'),
- 312: ('PEARSON', 2, 2, 0x02, 2, 'V', 'AA'),
- 313: ('RSQ', 2, 2, 0x02, 2, 'V', 'AA'),
- 314: ('STEYX', 2, 2, 0x02, 2, 'V', 'AA'),
- 315: ('SLOPE', 2, 2, 0x02, 2, 'V', 'AA'),
- 316: ('TTEST', 4, 4, 0x02, 4, 'V', 'AAVV'),
- 317: ('PROB', 3, 4, 0x04, 3, 'V', 'AAV'),
- 318: ('DEVSQ', 1, 30, 0x04, 1, 'V', 'R'),
- 319: ('GEOMEAN', 1, 30, 0x04, 1, 'V', 'R'),
- 320: ('HARMEAN', 1, 30, 0x04, 1, 'V', 'R'),
- 321: ('SUMSQ', 0, 30, 0x04, 1, 'V', 'R'),
- 322: ('KURT', 1, 30, 0x04, 1, 'V', 'R'),
- 323: ('SKEW', 1, 30, 0x04, 1, 'V', 'R'),
- 324: ('ZTEST', 2, 3, 0x04, 2, 'V', 'RV'),
- 325: ('LARGE', 2, 2, 0x02, 2, 'V', 'RV'),
- 326: ('SMALL', 2, 2, 0x02, 2, 'V', 'RV'),
- 327: ('QUARTILE', 2, 2, 0x02, 2, 'V', 'RV'),
- 328: ('PERCENTILE', 2, 2, 0x02, 2, 'V', 'RV'),
- 329: ('PERCENTRANK', 2, 3, 0x04, 2, 'V', 'RV'),
- 330: ('MODE', 1, 30, 0x04, 1, 'V', 'A'),
- 331: ('TRIMMEAN', 2, 2, 0x02, 2, 'V', 'RV'),
- 332: ('TINV', 2, 2, 0x02, 2, 'V', 'VV'),
- 336: ('CONCATENATE', 0, 30, 0x04, 1, 'V', 'V'),
- 337: ('POWER', 2, 2, 0x02, 2, 'V', 'VV'),
- 342: ('RADIANS', 1, 1, 0x02, 1, 'V', 'V'),
- 343: ('DEGREES', 1, 1, 0x02, 1, 'V', 'V'),
- 344: ('SUBTOTAL', 2, 30, 0x04, 2, 'V', 'VR'),
- 345: ('SUMIF', 2, 3, 0x04, 3, 'V', 'RVR'),
- 346: ('COUNTIF', 2, 2, 0x02, 2, 'V', 'RV'),
- 347: ('COUNTBLANK', 1, 1, 0x02, 1, 'V', 'R'),
- 350: ('ISPMT', 4, 4, 0x02, 4, 'V', 'VVVV'),
- 351: ('DATEDIF', 3, 3, 0x02, 3, 'V', 'VVV'),
- 352: ('DATESTRING', 1, 1, 0x02, 1, 'V', 'V'),
- 353: ('NUMBERSTRING', 2, 2, 0x02, 2, 'V', 'VV'),
- 354: ('ROMAN', 1, 2, 0x04, 2, 'V', 'VV'),
- 358: ('GETPIVOTDATA', 2, 2, 0x02, 2, 'V', 'RV'),
- 359: ('HYPERLINK', 1, 2, 0x04, 2, 'V', 'VV'),
- 360: ('PHONETIC', 1, 1, 0x02, 1, 'V', 'V'),
- 361: ('AVERAGEA', 1, 30, 0x04, 1, 'V', 'R'),
- 362: ('MAXA', 1, 30, 0x04, 1, 'V', 'R'),
- 363: ('MINA', 1, 30, 0x04, 1, 'V', 'R'),
- 364: ('STDEVPA', 1, 30, 0x04, 1, 'V', 'R'),
- 365: ('VARPA', 1, 30, 0x04, 1, 'V', 'R'),
- 366: ('STDEVA', 1, 30, 0x04, 1, 'V', 'R'),
- 367: ('VARA', 1, 30, 0x04, 1, 'V', 'R'),
- 368: ('BAHTTEXT', 1, 1, 0x02, 1, 'V', 'V'),
- 369: ('THAIDAYOFWEEK', 1, 1, 0x02, 1, 'V', 'V'),
- 370: ('THAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'),
- 371: ('THAIMONTHOFYEAR', 1, 1, 0x02, 1, 'V', 'V'),
- 372: ('THAINUMSOUND', 1, 1, 0x02, 1, 'V', 'V'),
- 373: ('THAINUMSTRING', 1, 1, 0x02, 1, 'V', 'V'),
- 374: ('THAISTRINGLENGTH', 1, 1, 0x02, 1, 'V', 'V'),
- 375: ('ISTHAIDIGIT', 1, 1, 0x02, 1, 'V', 'V'),
- 376: ('ROUNDBAHTDOWN', 1, 1, 0x02, 1, 'V', 'V'),
- 377: ('ROUNDBAHTUP', 1, 1, 0x02, 1, 'V', 'V'),
- 378: ('THAIYEAR', 1, 1, 0x02, 1, 'V', 'V'),
- 379: ('RTD', 2, 5, 0x04, 1, 'V', 'V'),
- }
-
-tAttrNames = {
- 0x00: "Skip??", # seen in SAMPLES.XLS which shipped with Excel 5.0
- 0x01: "Volatile",
- 0x02: "If",
- 0x04: "Choose",
- 0x08: "Skip",
- 0x10: "Sum",
- 0x20: "Assign",
- 0x40: "Space",
- 0x41: "SpaceVolatile",
- }
-
-_error_opcodes = frozenset([0x07, 0x08, 0x0A, 0x0B, 0x1C, 0x1D, 0x2F])
-
-tRangeFuncs = (min, max, min, max, min, max)
-tIsectFuncs = (max, min, max, min, max, min)
-
-def do_box_funcs(box_funcs, boxa, boxb):
- return tuple([
- func(numa, numb)
- for func, numa, numb in zip(box_funcs, boxa.coords, boxb.coords)
- ])
-
-def adjust_cell_addr_biff8(rowval, colval, reldelta, browx=None, bcolx=None):
- row_rel = (colval >> 15) & 1
- col_rel = (colval >> 14) & 1
- rowx = rowval
- colx = colval & 0xff
- if reldelta:
- if row_rel and rowx >= 32768:
- rowx -= 65536
- if col_rel and colx >= 128:
- colx -= 256
- else:
- if row_rel:
- rowx -= browx
- if col_rel:
- colx -= bcolx
- return rowx, colx, row_rel, col_rel
-
-def adjust_cell_addr_biff_le7(
- rowval, colval, reldelta, browx=None, bcolx=None):
- row_rel = (rowval >> 15) & 1
- col_rel = (rowval >> 14) & 1
- rowx = rowval & 0x3fff
- colx = colval
- if reldelta:
- if row_rel and rowx >= 8192:
- rowx -= 16384
- if col_rel and colx >= 128:
- colx -= 256
- else:
- if row_rel:
- rowx -= browx
- if col_rel:
- colx -= bcolx
- return rowx, colx, row_rel, col_rel
-
-def get_cell_addr(data, pos, bv, reldelta, browx=None, bcolx=None):
- if bv >= 80:
- rowval, colval = unpack("<HH", data[pos:pos+4])
- # print " rv=%04xh cv=%04xh" % (rowval, colval)
- return adjust_cell_addr_biff8(rowval, colval, reldelta, browx, bcolx)
- else:
- rowval, colval = unpack("<HB", data[pos:pos+3])
- # print " rv=%04xh cv=%04xh" % (rowval, colval)
- return adjust_cell_addr_biff_le7(
- rowval, colval, reldelta, browx, bcolx)
-
-def get_cell_range_addr(data, pos, bv, reldelta, browx=None, bcolx=None):
- if bv >= 80:
- row1val, row2val, col1val, col2val = unpack("<HHHH", data[pos:pos+8])
- # print " rv=%04xh cv=%04xh" % (row1val, col1val)
- # print " rv=%04xh cv=%04xh" % (row2val, col2val)
- res1 = adjust_cell_addr_biff8(row1val, col1val, reldelta, browx, bcolx)
- res2 = adjust_cell_addr_biff8(row2val, col2val, reldelta, browx, bcolx)
- return res1, res2
- else:
- row1val, row2val, col1val, col2val = unpack("<HHBB", data[pos:pos+6])
- # print " rv=%04xh cv=%04xh" % (row1val, col1val)
- # print " rv=%04xh cv=%04xh" % (row2val, col2val)
- res1 = adjust_cell_addr_biff_le7(
- row1val, col1val, reldelta, browx, bcolx)
- res2 = adjust_cell_addr_biff_le7(
- row2val, col2val, reldelta, browx, bcolx)
- return res1, res2
-
-def get_externsheet_local_range(bk, refx, verbose=0):
- try:
- info = bk._externsheet_info[refx]
- except IndexError:
- print("!!! get_externsheet_local_range: refx=%d, not in range(%d)" \
- % (refx, len(bk._externsheet_info)))
- return (-101, -101)
- ref_recordx, ref_first_sheetx, ref_last_sheetx = info
- if ref_recordx == bk._supbook_addins_inx:
- if verbose:
- print("/// get_externsheet_local_range(refx=%d) -> addins %r" % (refx, info))
- assert ref_first_sheetx == 0xFFFE == ref_last_sheetx
- return (-5, -5)
- if ref_recordx != bk._supbook_locals_inx:
- if verbose:
- print("/// get_externsheet_local_range(refx=%d) -> external %r" % (refx, info))
- return (-4, -4) # external reference
- if ref_first_sheetx == 0xFFFE == ref_last_sheetx:
- if verbose:
- print("/// get_externsheet_local_range(refx=%d) -> unspecified sheet %r" % (refx, info))
- return (-1, -1) # internal reference, any sheet
- if ref_first_sheetx == 0xFFFF == ref_last_sheetx:
- if verbose:
- print("/// get_externsheet_local_range(refx=%d) -> deleted sheet(s)" % (refx, ))
- return (-2, -2) # internal reference, deleted sheet(s)
- nsheets = len(bk._all_sheets_map)
- if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets):
- if verbose:
- print("/// get_externsheet_local_range(refx=%d) -> %r" % (refx, info))
- print("--- first/last sheet not in range(%d)" % nsheets)
- return (-102, -102) # stuffed up somewhere :-(
- xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx]
- xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx]
- if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2):
- return (-3, -3) # internal reference, but to a macro sheet
- return xlrd_sheetx1, xlrd_sheetx2
-
-def get_externsheet_local_range_b57(
- bk, raw_extshtx, ref_first_sheetx, ref_last_sheetx, verbose=0):
- if raw_extshtx > 0:
- if verbose:
- print("/// get_externsheet_local_range_b57(raw_extshtx=%d) -> external" % raw_extshtx)
- return (-4, -4) # external reference
- if ref_first_sheetx == -1 and ref_last_sheetx == -1:
- return (-2, -2) # internal reference, deleted sheet(s)
- nsheets = len(bk._all_sheets_map)
- if not(0 <= ref_first_sheetx <= ref_last_sheetx < nsheets):
- if verbose:
- print("/// get_externsheet_local_range_b57(%d, %d, %d) -> ???" \
- % (raw_extshtx, ref_first_sheetx, ref_last_sheetx))
- print("--- first/last sheet not in range(%d)" % nsheets)
- return (-103, -103) # stuffed up somewhere :-(
- xlrd_sheetx1 = bk._all_sheets_map[ref_first_sheetx]
- xlrd_sheetx2 = bk._all_sheets_map[ref_last_sheetx]
- if not(0 <= xlrd_sheetx1 <= xlrd_sheetx2):
- return (-3, -3) # internal reference, but to a macro sheet
- return xlrd_sheetx1, xlrd_sheetx2
-
-class FormulaError(Exception):
- pass
-
-oBOOL = 3
-oERR = 4
-oMSNG = 5 # tMissArg
-oNUM = 2
-oREF = -1
-oREL = -2
-oSTRG = 1
-oUNK = 0
-
-okind_dict = {
- -2: "oREL",
- -1: "oREF",
- 0 : "oUNK",
- 1 : "oSTRG",
- 2 : "oNUM",
- 3 : "oBOOL",
- 4 : "oERR",
- 5 : "oMSNG",
- }
-
-listsep = ',' #### probably should depend on locale
-
-##
-# Used in evaluating formulas.
-# The following table describes the kinds and how their values
-# are represented.</p>
-#
-# <table border="1" cellpadding="7">
-# <tr>
-# <th>Kind symbol</th>
-# <th>Kind number</th>
-# <th>Value representation</th>
-# </tr>
-# <tr>
-# <td>oBOOL</td>
-# <td align="center">3</td>
-# <td>integer: 0 => False; 1 => True</td>
-# </tr>
-# <tr>
-# <td>oERR</td>
-# <td align="center">4</td>
-# <td>None, or an int error code (same as XL_CELL_ERROR in the Cell class).
-# </td>
-# </tr>
-# <tr>
-# <td>oMSNG</td>
-# <td align="center">5</td>
-# <td>Used by Excel as a placeholder for a missing (not supplied) function
-# argument. Should *not* appear as a final formula result. Value is None.</td>
-# </tr>
-# <tr>
-# <td>oNUM</td>
-# <td align="center">2</td>
-# <td>A float. Note that there is no way of distinguishing dates.</td>
-# </tr>
-# <tr>
-# <td>oREF</td>
-# <td align="center">-1</td>
-# <td>The value is either None or a non-empty list of
-# absolute Ref3D instances.<br>
-# </td>
-# </tr>
-# <tr>
-# <td>oREL</td>
-# <td align="center">-2</td>
-# <td>The value is None or a non-empty list of
-# fully or partially relative Ref3D instances.
-# </td>
-# </tr>
-# <tr>
-# <td>oSTRG</td>
-# <td align="center">1</td>
-# <td>A Unicode string.</td>
-# </tr>
-# <tr>
-# <td>oUNK</td>
-# <td align="center">0</td>
-# <td>The kind is unknown or ambiguous. The value is None</td>
-# </tr>
-# </table>
-#<p></p>
-
-class Operand(object):
-
- ##
- # None means that the actual value of the operand is a variable
- # (depends on cell data), not a constant.
- value = None
- ##
- # oUNK means that the kind of operand is not known unambiguously.
- kind = oUNK
- ##
- # The reconstituted text of the original formula. Function names will be
- # in English irrespective of the original language, which doesn't seem
- # to be recorded anywhere. The separator is ",", not ";" or whatever else
- # might be more appropriate for the end-user's locale; patches welcome.
- text = '?'
-
- def __init__(self, akind=None, avalue=None, arank=0, atext='?'):
- if akind is not None:
- self.kind = akind
- if avalue is not None:
- self.value = avalue
- self.rank = arank
- # rank is an internal gizmo (operator precedence);
- # it's used in reconstructing formula text.
- self.text = atext
-
- def __repr__(self):
- kind_text = okind_dict.get(self.kind, "?Unknown kind?")
- return "Operand(kind=%s, value=%r, text=%r)" \
- % (kind_text, self.value, self.text)
-
-#(to_py3) if CAN_SUBCLASS_BUILTIN:
-# _ref3d_base = tuple
-
-# Represents an absolute or relative 3-dimensional reference to a box
-# of one or more cells.
-# - New in version 0.6.0
-#
-# The `coords` attribute is a tuple of the form:
-# (shtxlo, shtxhi, rowxlo, rowxhi, colxlo, colxhi)
-# where 0 <= thingxlo <= thingx < thingxhi.
-# Note that it is quite possible to have thingx > nthings; for example
-# Print_Titles could have colxhi == 256 and/or rowxhi == 65536
-# irrespective of how many columns/rows are actually used in the worksheet.
-# The caller will need to decide how to handle this situation.
-# Keyword: IndexError :-)
-#
-# The components of the coords attribute are also available as individual
-# attributes: shtxlo, shtxhi, rowxlo, rowxhi, colxlo, and colxhi.
-#
-# The `relflags` attribute is a 6-tuple of flags which indicate whether
-# the corresponding (sheet|row|col)(lo|hi) is relative (1) or absolute (0).
-# Note that there is necessarily no information available as to what cell(s)
-# the reference could possibly be relative to. The caller must decide what if
-# any use to make of oREL operands. Note also that a partially relative
-# reference may well be a typo.
-# For example, define name A1Z10 as $a$1:$z10 (missing $ after z)
-# while the cursor is on cell Sheet3!A27.<br>
-# The resulting Ref3D instance will have coords = (2, 3, 0, -16, 0, 26)
-# and relflags = (0, 0, 0, 1, 0, 0).<br>
-# So far, only one possibility of a sheet-relative component in
-# a reference has been noticed: a 2D reference located in the "current sheet".
-# This will appear as coords = (0, 1, ...) and relflags = (1, 1, ...).
-
-class Ref3D(tuple):
-
- def __init__(self, atuple):
- self.coords = atuple[0:6]
- self.relflags = atuple[6:12]
- if not self.relflags:
- self.relflags = (0, 0, 0, 0, 0, 0)
- (self.shtxlo, self.shtxhi,
- self.rowxlo, self.rowxhi,
- self.colxlo, self.colxhi) = self.coords
-
- def __repr__(self):
- if not self.relflags or self.relflags == (0, 0, 0, 0, 0, 0):
- return "Ref3D(coords=%r)" % (self.coords, )
- else:
- return "Ref3D(coords=%r, relflags=%r)" \
- % (self.coords, self.relflags)
-
-tAdd = 0x03
-tSub = 0x04
-tMul = 0x05
-tDiv = 0x06
-tPower = 0x07
-tConcat = 0x08
-tLT, tLE, tEQ, tGE, tGT, tNE = list(range(0x09, 0x0F))
-
-import operator as opr
-
-def nop(x):
- return x
-
-def _opr_pow(x, y): return x ** y
-
-def _opr_lt(x, y): return x < y
-def _opr_le(x, y): return x <= y
-def _opr_eq(x, y): return x == y
-def _opr_ge(x, y): return x >= y
-def _opr_gt(x, y): return x > y
-def _opr_ne(x, y): return x != y
-
-def num2strg(num):
- """Attempt to emulate Excel's default conversion
- from number to string.
- """
- s = str(num)
- if s.endswith(".0"):
- s = s[:-2]
- return s
-
-_arith_argdict = {oNUM: nop, oSTRG: float}
-_cmp_argdict = {oNUM: nop, oSTRG: nop}
-# Seems no conversions done on relops; in Excel, "1" > 9 produces TRUE.
-_strg_argdict = {oNUM:num2strg, oSTRG:nop}
-binop_rules = {
- tAdd: (_arith_argdict, oNUM, opr.add, 30, '+'),
- tSub: (_arith_argdict, oNUM, opr.sub, 30, '-'),
- tMul: (_arith_argdict, oNUM, opr.mul, 40, '*'),
- tDiv: (_arith_argdict, oNUM, opr.truediv, 40, '/'),
- tPower: (_arith_argdict, oNUM, _opr_pow, 50, '^',),
- tConcat:(_strg_argdict, oSTRG, opr.add, 20, '&'),
- tLT: (_cmp_argdict, oBOOL, _opr_lt, 10, '<'),
- tLE: (_cmp_argdict, oBOOL, _opr_le, 10, '<='),
- tEQ: (_cmp_argdict, oBOOL, _opr_eq, 10, '='),
- tGE: (_cmp_argdict, oBOOL, _opr_ge, 10, '>='),
- tGT: (_cmp_argdict, oBOOL, _opr_gt, 10, '>'),
- tNE: (_cmp_argdict, oBOOL, _opr_ne, 10, '<>'),
- }
-
-unop_rules = {
- 0x13: (lambda x: -x, 70, '-', ''), # unary minus
- 0x12: (lambda x: x, 70, '+', ''), # unary plus
- 0x14: (lambda x: x / 100.0, 60, '', '%'),# percent
- }
-
-LEAF_RANK = 90
-FUNC_RANK = 90
-
-STACK_ALARM_LEVEL = 5
-STACK_PANIC_LEVEL = 10
-
-def evaluate_name_formula(bk, nobj, namex, verbose=0, level=0):
- if level > STACK_ALARM_LEVEL:
- verbose = 1
- data = nobj.raw_formula
- fmlalen = nobj.basic_formula_len
- bv = bk.biff_version
- reldelta = 1 # All defined name formulas use "Method B" [OOo docs]
- if verbose:
- print("::: evaluate_name_formula %r %r %d %d %r level=%d" \
- % (namex, nobj.name, fmlalen, bv, data, level))
- hex_char_dump(data, 0, fmlalen)
- if level > STACK_PANIC_LEVEL:
- raise XLRDError("Excessive indirect references in NAME formula")
- sztab = szdict[bv]
- pos = 0
- stack = []
- any_rel = 0
- any_err = 0
- any_external = 0
- unk_opnd = Operand(oUNK, None)
- error_opnd = Operand(oERR, None)
- spush = stack.append
-
- def do_binop(opcd, stk):
- assert len(stk) >= 2
- bop = stk.pop()
- aop = stk.pop()
- argdict, result_kind, func, rank, sym = binop_rules[opcd]
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- resop = Operand(result_kind, None, rank, otext)
- try:
- bconv = argdict[bop.kind]
- aconv = argdict[aop.kind]
- except KeyError:
- stk.append(resop)
- return
- if bop.value is None or aop.value is None:
- stk.append(resop)
- return
- bval = bconv(bop.value)
- aval = aconv(aop.value)
- result = func(aval, bval)
- if result_kind == oBOOL:
- result = 1 if result else 0 # (to_py3)
- resop.value = result
- stk.append(resop)
-
- def do_unaryop(opcode, arglist, result_kind, stk):
- assert len(stk) >= 1
- aop = stk.pop()
- assert aop.kind in arglist
- val = aop.value
- func, rank, sym1, sym2 = unop_rules[opcode]
- otext = ''.join([
- sym1,
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym2,
- ])
- if val is not None:
- val = func(val)
- stk.append(Operand(result_kind, val, rank, otext))
-
- def not_in_name_formula(op_arg, oname_arg):
- msg = "ERROR *** Token 0x%02x (%s) found in NAME formula" \
- % (op_arg, oname_arg)
- raise FormulaError(msg)
-
- if fmlalen == 0:
- stack = [unk_opnd]
-
- while 0 <= pos < fmlalen:
- op = data[pos]
- opcode = op & 0x1f
- optype = (op & 0x60) >> 5
- if optype:
- opx = opcode + 32
- else:
- opx = opcode
- oname = onames[opx] # + [" RVA"][optype]
- sz = sztab[opx]
- if verbose:
- print("Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \
- % (pos, op, oname, sz, opcode, optype))
- print("Stack =", stack)
- if sz == -2:
- msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \
- % (op, oname, bv)
- raise FormulaError(msg)
- if not optype:
- if 0x00 <= opcode <= 0x02: # unk_opnd, tExp, tTbl
- not_in_name_formula(op, oname)
- elif 0x03 <= opcode <= 0x0E:
- # Add, Sub, Mul, Div, Power
- # tConcat
- # tLT, ..., tNE
- do_binop(opcode, stack)
- elif opcode == 0x0F: # tIsect
- if verbose: print("tIsect pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- sym = ' '
- rank = 80 ########## check #######
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- res = Operand(oREF)
- res.text = otext
- if bop.kind == oERR or aop.kind == oERR:
- res.kind = oERR
- elif bop.kind == oUNK or aop.kind == oUNK:
- # This can happen with undefined
- # (go search in the current sheet) labels.
- # For example =Bob Sales
- # Each label gets a NAME record with an empty formula (!)
- # Evaluation of the tName token classifies it as oUNK
- # res.kind = oREF
- pass
- elif bop.kind == oREF == aop.kind:
- if aop.value is not None and bop.value is not None:
- assert len(aop.value) == 1
- assert len(bop.value) == 1
- coords = do_box_funcs(
- tIsectFuncs, aop.value[0], bop.value[0])
- res.value = [Ref3D(coords)]
- elif bop.kind == oREL == aop.kind:
- res.kind = oREL
- if aop.value is not None and bop.value is not None:
- assert len(aop.value) == 1
- assert len(bop.value) == 1
- coords = do_box_funcs(
- tIsectFuncs, aop.value[0], bop.value[0])
- relfa = aop.value[0].relflags
- relfb = bop.value[0].relflags
- if relfa == relfb:
- res.value = [Ref3D(coords + relfa)]
- else:
- pass
- spush(res)
- if verbose: print("tIsect post", stack, file=bk.logfile)
- elif opcode == 0x10: # tList
- if verbose: print("tList pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- sym = ','
- rank = 80 ########## check #######
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- res = Operand(oREF, None, rank, otext)
- if bop.kind == oERR or aop.kind == oERR:
- res.kind = oERR
- elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL):
- res.kind = oREF
- if aop.kind == oREL or bop.kind == oREL:
- res.kind = oREL
- if aop.value is not None and bop.value is not None:
- assert len(aop.value) >= 1
- assert len(bop.value) == 1
- res.value = aop.value + bop.value
- else:
- pass
- spush(res)
- if verbose: print("tList post", stack, file=bk.logfile)
- elif opcode == 0x11: # tRange
- if verbose: print("tRange pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- sym = ':'
- rank = 80 ########## check #######
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- res = Operand(oREF, None, rank, otext)
- if bop.kind == oERR or aop.kind == oERR:
- res = oERR
- elif bop.kind == oREF == aop.kind:
- if aop.value is not None and bop.value is not None:
- assert len(aop.value) == 1
- assert len(bop.value) == 1
- coords = do_box_funcs(
- tRangeFuncs, aop.value[0], bop.value[0])
- res.value = [Ref3D(coords)]
- elif bop.kind == oREL == aop.kind:
- res.kind = oREL
- if aop.value is not None and bop.value is not None:
- assert len(aop.value) == 1
- assert len(bop.value) == 1
- coords = do_box_funcs(
- tRangeFuncs, aop.value[0], bop.value[0])
- relfa = aop.value[0].relflags
- relfb = bop.value[0].relflags
- if relfa == relfb:
- res.value = [Ref3D(coords + relfa)]
- else:
- pass
- spush(res)
- if verbose: print("tRange post", stack, file=bk.logfile)
- elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent
- do_unaryop(opcode, (oUNK, oNUM,), oNUM, stack)
- elif opcode == 0x15: # tParen
- # source cosmetics
- pass
- elif opcode == 0x16: # tMissArg
- spush(Operand(oMSNG, None, LEAF_RANK, ''))
- elif opcode == 0x17: # tStr
- if bv <= 70:
- strg, newpos = unpack_string_update_pos(
- data, pos+1, bk.encoding, lenlen=1)
- else:
- strg, newpos = unpack_unicode_update_pos(
- data, pos+1, lenlen=1)
- sz = newpos - pos
- if verbose: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile)
- text = '"' + strg.replace('"', '""') + '"'
- spush(Operand(oSTRG, strg, LEAF_RANK, text))
- elif opcode == 0x18: # tExtended
- # new with BIFF 8
- assert bv >= 80
- # not in OOo docs
- raise FormulaError("tExtended token not implemented")
- elif opcode == 0x19: # tAttr
- subop, nc = unpack("<BH", data[pos+1:pos+4])
- subname = tAttrNames.get(subop, "??Unknown??")
- if subop == 0x04: # Choose
- sz = nc * 2 + 6
- elif subop == 0x10: # Sum (single arg)
- sz = 4
- if verbose: print("tAttrSum", stack, file=bk.logfile)
- assert len(stack) >= 1
- aop = stack[-1]
- otext = 'SUM(%s)' % aop.text
- stack[-1] = Operand(oNUM, None, FUNC_RANK, otext)
- else:
- sz = 4
- if verbose:
- print(" subop=%02xh subname=t%s sz=%d nc=%02xh" \
- % (subop, subname, sz, nc))
- elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet
- assert bv < 50
- raise FormulaError("tSheet & tEndsheet tokens not implemented")
- elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum
- inx = opcode - 0x1C
- nb = [1, 1, 2, 8][inx]
- kind = [oERR, oBOOL, oNUM, oNUM][inx]
- value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb])
- if inx == 2: # tInt
- value = float(value)
- text = str(value)
- elif inx == 3: # tNum
- text = str(value)
- elif inx == 1: # tBool
- text = ('FALSE', 'TRUE')[value]
- else:
- text = '"' +error_text_from_code[value] + '"'
- spush(Operand(kind, value, LEAF_RANK, text))
- else:
- raise FormulaError("Unhandled opcode: 0x%02x" % opcode)
- if sz <= 0:
- raise FormulaError("Size not set for opcode 0x%02x" % opcode)
- pos += sz
- continue
- if opcode == 0x00: # tArray
- spush(unk_opnd)
- elif opcode == 0x01: # tFunc
- nb = 1 + int(bv >= 40)
- funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0]
- func_attrs = func_defs.get(funcx, None)
- if not func_attrs:
- print("*** formula/tFunc unknown FuncID:%d" \
- % funcx, file=bk.logfile)
- spush(unk_opnd)
- else:
- func_name, nargs = func_attrs[:2]
- if verbose:
- print(" FuncID=%d name=%s nargs=%d" \
- % (funcx, func_name, nargs))
- assert len(stack) >= nargs
- argtext = listsep.join([arg.text for arg in stack[-nargs:]])
- otext = "%s(%s)" % (func_name, argtext)
- del stack[-nargs:]
- res = Operand(oUNK, None, FUNC_RANK, otext)
- spush(res)
- elif opcode == 0x02: #tFuncVar
- nb = 1 + int(bv >= 40)
- nargs, funcx = unpack("<B" + " BH"[nb], data[pos+1:pos+2+nb])
- prompt, nargs = divmod(nargs, 128)
- macro, funcx = divmod(funcx, 32768)
- if verbose:
- print(" FuncID=%d nargs=%d macro=%d prompt=%d" \
- % (funcx, nargs, macro, prompt))
- func_attrs = func_defs.get(funcx, None)
- if not func_attrs:
- print("*** formula/tFuncVar unknown FuncID:%d" \
- % funcx, file=bk.logfile)
- spush(unk_opnd)
- else:
- func_name, minargs, maxargs = func_attrs[:3]
- if verbose:
- print(" name: %r, min~max args: %d~%d" \
- % (func_name, minargs, maxargs))
- assert minargs <= nargs <= maxargs
- assert len(stack) >= nargs
- assert len(stack) >= nargs
- argtext = listsep.join([arg.text for arg in stack[-nargs:]])
- otext = "%s(%s)" % (func_name, argtext)
- res = Operand(oUNK, None, FUNC_RANK, otext)
- if funcx == 1: # IF
- testarg = stack[-nargs]
- if testarg.kind not in (oNUM, oBOOL):
- if verbose and testarg.kind != oUNK:
- print("IF testarg kind?")
- elif testarg.value not in (0, 1):
- if verbose and testarg.value is not None:
- print("IF testarg value?")
- else:
- if nargs == 2 and not testarg.value:
- # IF(FALSE, tv) => FALSE
- res.kind, res.value = oBOOL, 0
- else:
- respos = -nargs + 2 - int(testarg.value)
- chosen = stack[respos]
- if chosen.kind == oMSNG:
- res.kind, res.value = oNUM, 0
- else:
- res.kind, res.value = chosen.kind, chosen.value
- if verbose:
- print("$$$$$$ IF => constant")
- elif funcx == 100: # CHOOSE
- testarg = stack[-nargs]
- if testarg.kind == oNUM:
- if 1 <= testarg.value < nargs:
- chosen = stack[-nargs + int(testarg.value)]
- if chosen.kind == oMSNG:
- res.kind, res.value = oNUM, 0
- else:
- res.kind, res.value = chosen.kind, chosen.value
- del stack[-nargs:]
- spush(res)
- elif opcode == 0x03: #tName
- tgtnamex = unpack("<H", data[pos+1:pos+3])[0] - 1
- # Only change with BIFF version is number of trailing UNUSED bytes!
- if verbose: print(" tgtnamex=%d" % tgtnamex, file=bk.logfile)
- tgtobj = bk.name_obj_list[tgtnamex]
- if not tgtobj.evaluated:
- ### recursive ###
- evaluate_name_formula(bk, tgtobj, tgtnamex, verbose, level+1)
- if tgtobj.macro or tgtobj.binary \
- or tgtobj.any_err:
- if verbose:
- tgtobj.dump(
- bk.logfile,
- header="!!! tgtobj has problems!!!",
- footer="----------- --------",
- )
- res = Operand(oUNK, None)
- any_err = any_err or tgtobj.macro or tgtobj.binary or tgtobj.any_err
- any_rel = any_rel or tgtobj.any_rel
- else:
- assert len(tgtobj.stack) == 1
- res = copy.deepcopy(tgtobj.stack[0])
- res.rank = LEAF_RANK
- if tgtobj.scope == -1:
- res.text = tgtobj.name
- else:
- res.text = "%s!%s" \
- % (bk._sheet_names[tgtobj.scope], tgtobj.name)
- if verbose:
- print(" tName: setting text to", repr(res.text), file=bk.logfile)
- spush(res)
- elif opcode == 0x04: # tRef
- # not_in_name_formula(op, oname)
- res = get_cell_addr(data, pos+1, bv, reldelta)
- if verbose: print(" ", res, file=bk.logfile)
- rowx, colx, row_rel, col_rel = res
- shx1 = shx2 = 0 ####### N.B. relative to the CURRENT SHEET
- any_rel = 1
- coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1)
- if verbose: print(" ", coords, file=bk.logfile)
- res = Operand(oUNK, None)
- if optype == 1:
- relflags = (1, 1, row_rel, row_rel, col_rel, col_rel)
- res = Operand(oREL, [Ref3D(coords + relflags)])
- spush(res)
- elif opcode == 0x05: # tArea
- # not_in_name_formula(op, oname)
- res1, res2 = get_cell_range_addr(data, pos+1, bv, reldelta)
- if verbose: print(" ", res1, res2, file=bk.logfile)
- rowx1, colx1, row_rel1, col_rel1 = res1
- rowx2, colx2, row_rel2, col_rel2 = res2
- shx1 = shx2 = 0 ####### N.B. relative to the CURRENT SHEET
- any_rel = 1
- coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1)
- if verbose: print(" ", coords, file=bk.logfile)
- res = Operand(oUNK, None)
- if optype == 1:
- relflags = (1, 1, row_rel1, row_rel2, col_rel1, col_rel2)
- res = Operand(oREL, [Ref3D(coords + relflags)])
- spush(res)
- elif opcode == 0x06: # tMemArea
- not_in_name_formula(op, oname)
- elif opcode == 0x09: # tMemFunc
- nb = unpack("<H", data[pos+1:pos+3])[0]
- if verbose: print(" %d bytes of cell ref formula" % nb, file=bk.logfile)
- # no effect on stack
- elif opcode == 0x0C: #tRefN
- not_in_name_formula(op, oname)
- # res = get_cell_addr(data, pos+1, bv, reldelta=1)
- # # note *ALL* tRefN usage has signed offset for relative addresses
- # any_rel = 1
- # if verbose: print >> bk.logfile, " ", res
- # spush(res)
- elif opcode == 0x0D: #tAreaN
- not_in_name_formula(op, oname)
- # res = get_cell_range_addr(data, pos+1, bv, reldelta=1)
- # # note *ALL* tAreaN usage has signed offset for relative addresses
- # any_rel = 1
- # if verbose: print >> bk.logfile, " ", res
- elif opcode == 0x1A: # tRef3d
- if bv >= 80:
- res = get_cell_addr(data, pos+3, bv, reldelta)
- refx = unpack("<H", data[pos+1:pos+3])[0]
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- else:
- res = get_cell_addr(data, pos+15, bv, reldelta)
- raw_extshtx, raw_shx1, raw_shx2 = \
- unpack("<hxxxxxxxxhh", data[pos+1:pos+15])
- if verbose:
- print("tRef3d", raw_extshtx, raw_shx1, raw_shx2, file=bk.logfile)
- shx1, shx2 = get_externsheet_local_range_b57(
- bk, raw_extshtx, raw_shx1, raw_shx2, verbose)
- rowx, colx, row_rel, col_rel = res
- is_rel = row_rel or col_rel
- any_rel = any_rel or is_rel
- coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1)
- any_err |= shx1 < -1
- if verbose: print(" ", coords, file=bk.logfile)
- res = Operand(oUNK, None)
- if is_rel:
- relflags = (0, 0, row_rel, row_rel, col_rel, col_rel)
- ref3d = Ref3D(coords + relflags)
- res.kind = oREL
- res.text = rangename3drel(bk, ref3d)
- else:
- ref3d = Ref3D(coords)
- res.kind = oREF
- res.text = rangename3d(bk, ref3d)
- res.rank = LEAF_RANK
- if optype == 1:
- res.value = [ref3d]
- spush(res)
- elif opcode == 0x1B: # tArea3d
- if bv >= 80:
- res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta)
- refx = unpack("<H", data[pos+1:pos+3])[0]
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- else:
- res1, res2 = get_cell_range_addr(data, pos+15, bv, reldelta)
- raw_extshtx, raw_shx1, raw_shx2 = \
- unpack("<hxxxxxxxxhh", data[pos+1:pos+15])
- if verbose:
- print("tArea3d", raw_extshtx, raw_shx1, raw_shx2, file=bk.logfile)
- shx1, shx2 = get_externsheet_local_range_b57(
- bk, raw_extshtx, raw_shx1, raw_shx2, verbose)
- any_err |= shx1 < -1
- rowx1, colx1, row_rel1, col_rel1 = res1
- rowx2, colx2, row_rel2, col_rel2 = res2
- is_rel = row_rel1 or col_rel1 or row_rel2 or col_rel2
- any_rel = any_rel or is_rel
- coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1)
- if verbose: print(" ", coords, file=bk.logfile)
- res = Operand(oUNK, None)
- if is_rel:
- relflags = (0, 0, row_rel1, row_rel2, col_rel1, col_rel2)
- ref3d = Ref3D(coords + relflags)
- res.kind = oREL
- res.text = rangename3drel(bk, ref3d)
- else:
- ref3d = Ref3D(coords)
- res.kind = oREF
- res.text = rangename3d(bk, ref3d)
- res.rank = LEAF_RANK
- if optype == 1:
- res.value = [ref3d]
-
- spush(res)
- elif opcode == 0x19: # tNameX
- dodgy = 0
- res = Operand(oUNK, None)
- if bv >= 80:
- refx, tgtnamex = unpack("<HH", data[pos+1:pos+5])
- tgtnamex -= 1
- origrefx = refx
- else:
- refx, tgtnamex = unpack("<hxxxxxxxxH", data[pos+1:pos+13])
- tgtnamex -= 1
- origrefx = refx
- if refx > 0:
- refx -= 1
- elif refx < 0:
- refx = -refx - 1
- else:
- dodgy = 1
- if verbose:
- print(" origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \
- % (origrefx, refx, tgtnamex, dodgy), file=bk.logfile)
- if tgtnamex == namex:
- if verbose: print("!!!! Self-referential !!!!", file=bk.logfile)
- dodgy = any_err = 1
- if not dodgy:
- if bv >= 80:
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- elif origrefx > 0:
- shx1, shx2 = (-4, -4) # external ref
- else:
- exty = bk._externsheet_type_b57[refx]
- if exty == 4: # non-specific sheet in own doc't
- shx1, shx2 = (-1, -1) # internal, any sheet
- else:
- shx1, shx2 = (-666, -666)
- if dodgy or shx1 < -1:
- otext = "<<Name #%d in external(?) file #%d>>" \
- % (tgtnamex, origrefx)
- res = Operand(oUNK, None, LEAF_RANK, otext)
- else:
- tgtobj = bk.name_obj_list[tgtnamex]
- if not tgtobj.evaluated:
- ### recursive ###
- evaluate_name_formula(bk, tgtobj, tgtnamex, verbose, level+1)
- if tgtobj.macro or tgtobj.binary \
- or tgtobj.any_err:
- if verbose:
- tgtobj.dump(
- bk.logfile,
- header="!!! bad tgtobj !!!",
- footer="------------------",
- )
- res = Operand(oUNK, None)
- any_err = any_err or tgtobj.macro or tgtobj.binary or tgtobj.any_err
- any_rel = any_rel or tgtobj.any_rel
- else:
- assert len(tgtobj.stack) == 1
- res = copy.deepcopy(tgtobj.stack[0])
- res.rank = LEAF_RANK
- if tgtobj.scope == -1:
- res.text = tgtobj.name
- else:
- res.text = "%s!%s" \
- % (bk._sheet_names[tgtobj.scope], tgtobj.name)
- if verbose:
- print(" tNameX: setting text to", repr(res.text), file=bk.logfile)
- spush(res)
- elif opcode in _error_opcodes:
- any_err = 1
- spush(error_opnd)
- else:
- if verbose:
- print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile)
- any_err = 1
- if sz <= 0:
- raise FormulaError("Fatal: token size is not positive")
- pos += sz
- any_rel = not not any_rel
- if verbose:
- print("End of formula. level=%d any_rel=%d any_err=%d stack=%r" % \
- (level, not not any_rel, any_err, stack))
- if len(stack) >= 2:
- print("*** Stack has unprocessed args")
- print()
- nobj.stack = stack
- if len(stack) != 1:
- nobj.result = None
- else:
- nobj.result = stack[0]
- nobj.any_rel = any_rel
- nobj.any_err = any_err
- nobj.any_external = any_external
- nobj.evaluated = 1
-
-#### under construction ####
-def decompile_formula(bk, fmla, fmlalen,
- reldelta, browx=None, bcolx=None,
- # browx & bcolx are required when reldelta == 0
- verbose=0, level=0):
- if level > STACK_ALARM_LEVEL:
- verbose = 1
- data = fmla
- bv = bk.biff_version
- if verbose:
- print("::: decompile_formula len=%d reldelta=%d %r level=%d" \
- % (fmlalen, reldelta, data, level))
- hex_char_dump(data, 0, fmlalen)
- if level > STACK_PANIC_LEVEL:
- raise XLRDError("Excessive indirect references in formula")
- sztab = szdict[bv]
- pos = 0
- stack = []
- any_rel = 0
- any_err = 0
- any_external = 0
- unk_opnd = Operand(oUNK, None)
- error_opnd = Operand(oERR, None)
- spush = stack.append
-
- def do_binop(opcd, stk):
- assert len(stk) >= 2
- bop = stk.pop()
- aop = stk.pop()
- argdict, result_kind, func, rank, sym = binop_rules[opcd]
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- resop = Operand(result_kind, None, rank, otext)
- stk.append(resop)
-
- def do_unaryop(opcode, arglist, result_kind, stk):
- assert len(stk) >= 1
- aop = stk.pop()
- assert aop.kind in arglist
- func, rank, sym1, sym2 = unop_rules[opcode]
- otext = ''.join([
- sym1,
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym2,
- ])
- stk.append(Operand(result_kind, None, rank, otext))
-
- def not_in_name_formula(op_arg, oname_arg):
- msg = "ERROR *** Unexpected token 0x%02x (%s) found in formula" \
- % (op_arg, oname_arg)
- # print msg
- raise FormulaError(msg)
-
- if fmlalen == 0:
- stack = [unk_opnd]
-
- while 0 <= pos < fmlalen:
- op = data[pos]
- opcode = op & 0x1f
- optype = (op & 0x60) >> 5
- if optype:
- opx = opcode + 32
- else:
- opx = opcode
- oname = onames[opx] # + [" RVA"][optype]
- sz = sztab[opx]
- if verbose:
- print("Pos:%d Op:0x%02x opname:t%s Sz:%d opcode:%02xh optype:%02xh" \
- % (pos, op, oname, sz, opcode, optype))
- print("Stack =", stack)
- if sz == -2:
- msg = 'ERROR *** Unexpected token 0x%02x ("%s"); biff_version=%d' \
- % (op, oname, bv)
- raise FormulaError(msg)
- if not optype:
- if 0x00 <= opcode <= 0x02: # unk_opnd, tExp, tTbl
- not_in_name_formula(op, oname)
- elif 0x03 <= opcode <= 0x0E:
- # Add, Sub, Mul, Div, Power
- # tConcat
- # tLT, ..., tNE
- do_binop(opcode, stack)
- elif opcode == 0x0F: # tIsect
- if verbose: print("tIsect pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- sym = ' '
- rank = 80 ########## check #######
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- res = Operand(oREF)
- res.text = otext
- if bop.kind == oERR or aop.kind == oERR:
- res.kind = oERR
- elif bop.kind == oUNK or aop.kind == oUNK:
- # This can happen with undefined
- # (go search in the current sheet) labels.
- # For example =Bob Sales
- # Each label gets a NAME record with an empty formula (!)
- # Evaluation of the tName token classifies it as oUNK
- # res.kind = oREF
- pass
- elif bop.kind == oREF == aop.kind:
- pass
- elif bop.kind == oREL == aop.kind:
- res.kind = oREL
- else:
- pass
- spush(res)
- if verbose: print("tIsect post", stack, file=bk.logfile)
- elif opcode == 0x10: # tList
- if verbose: print("tList pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- sym = ','
- rank = 80 ########## check #######
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- res = Operand(oREF, None, rank, otext)
- if bop.kind == oERR or aop.kind == oERR:
- res.kind = oERR
- elif bop.kind in (oREF, oREL) and aop.kind in (oREF, oREL):
- res.kind = oREF
- if aop.kind == oREL or bop.kind == oREL:
- res.kind = oREL
- else:
- pass
- spush(res)
- if verbose: print("tList post", stack, file=bk.logfile)
- elif opcode == 0x11: # tRange
- if verbose: print("tRange pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- sym = ':'
- rank = 80 ########## check #######
- otext = ''.join([
- '('[:aop.rank < rank],
- aop.text,
- ')'[:aop.rank < rank],
- sym,
- '('[:bop.rank < rank],
- bop.text,
- ')'[:bop.rank < rank],
- ])
- res = Operand(oREF, None, rank, otext)
- if bop.kind == oERR or aop.kind == oERR:
- res = oERR
- elif bop.kind == oREF == aop.kind:
- pass
- else:
- pass
- spush(res)
- if verbose: print("tRange post", stack, file=bk.logfile)
- elif 0x12 <= opcode <= 0x14: # tUplus, tUminus, tPercent
- do_unaryop(opcode, (oUNK, oNUM,), oNUM, stack)
- elif opcode == 0x15: # tParen
- # source cosmetics
- pass
- elif opcode == 0x16: # tMissArg
- spush(Operand(oMSNG, None, LEAF_RANK, ''))
- elif opcode == 0x17: # tStr
- if bv <= 70:
- strg, newpos = unpack_string_update_pos(
- data, pos+1, bk.encoding, lenlen=1)
- else:
- strg, newpos = unpack_unicode_update_pos(
- data, pos+1, lenlen=1)
- sz = newpos - pos
- if verbose: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile)
- text = '"' + strg.replace('"', '""') + '"'
- spush(Operand(oSTRG, None, LEAF_RANK, text))
- elif opcode == 0x18: # tExtended
- # new with BIFF 8
- assert bv >= 80
- # not in OOo docs
- raise FormulaError("tExtended token not implemented")
- elif opcode == 0x19: # tAttr
- subop, nc = unpack("<BH", data[pos+1:pos+4])
- subname = tAttrNames.get(subop, "??Unknown??")
- if subop == 0x04: # Choose
- sz = nc * 2 + 6
- elif subop == 0x10: # Sum (single arg)
- sz = 4
- if verbose: print("tAttrSum", stack, file=bk.logfile)
- assert len(stack) >= 1
- aop = stack[-1]
- otext = 'SUM(%s)' % aop.text
- stack[-1] = Operand(oNUM, None, FUNC_RANK, otext)
- else:
- sz = 4
- if verbose:
- print(" subop=%02xh subname=t%s sz=%d nc=%02xh" \
- % (subop, subname, sz, nc))
- elif 0x1A <= opcode <= 0x1B: # tSheet, tEndSheet
- assert bv < 50
- raise FormulaError("tSheet & tEndsheet tokens not implemented")
- elif 0x1C <= opcode <= 0x1F: # tErr, tBool, tInt, tNum
- inx = opcode - 0x1C
- nb = [1, 1, 2, 8][inx]
- kind = [oERR, oBOOL, oNUM, oNUM][inx]
- value, = unpack("<" + "BBHd"[inx], data[pos+1:pos+1+nb])
- if inx == 2: # tInt
- value = float(value)
- text = str(value)
- elif inx == 3: # tNum
- text = str(value)
- elif inx == 1: # tBool
- text = ('FALSE', 'TRUE')[value]
- else:
- text = '"' +error_text_from_code[value] + '"'
- spush(Operand(kind, None, LEAF_RANK, text))
- else:
- raise FormulaError("Unhandled opcode: 0x%02x" % opcode)
- if sz <= 0:
- raise FormulaError("Size not set for opcode 0x%02x" % opcode)
- pos += sz
- continue
- if opcode == 0x00: # tArray
- spush(unk_opnd)
- elif opcode == 0x01: # tFunc
- nb = 1 + int(bv >= 40)
- funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])[0]
- func_attrs = func_defs.get(funcx, None)
- if not func_attrs:
- print("*** formula/tFunc unknown FuncID:%d" % funcx, file=bk.logfile)
- spush(unk_opnd)
- else:
- func_name, nargs = func_attrs[:2]
- if verbose:
- print(" FuncID=%d name=%s nargs=%d" \
- % (funcx, func_name, nargs))
- assert len(stack) >= nargs
- argtext = listsep.join([arg.text for arg in stack[-nargs:]])
- otext = "%s(%s)" % (func_name, argtext)
- del stack[-nargs:]
- res = Operand(oUNK, None, FUNC_RANK, otext)
- spush(res)
- elif opcode == 0x02: #tFuncVar
- nb = 1 + int(bv >= 40)
- nargs, funcx = unpack("<B" + " BH"[nb], data[pos+1:pos+2+nb])
- prompt, nargs = divmod(nargs, 128)
- macro, funcx = divmod(funcx, 32768)
- if verbose:
- print(" FuncID=%d nargs=%d macro=%d prompt=%d" \
- % (funcx, nargs, macro, prompt))
- #### TODO #### if funcx == 255: # call add-in function
- if funcx == 255:
- func_attrs = ("CALL_ADDIN", 1, 30)
- else:
- func_attrs = func_defs.get(funcx, None)
- if not func_attrs:
- print("*** formula/tFuncVar unknown FuncID:%d" \
- % funcx, file=bk.logfile)
- spush(unk_opnd)
- else:
- func_name, minargs, maxargs = func_attrs[:3]
- if verbose:
- print(" name: %r, min~max args: %d~%d" \
- % (func_name, minargs, maxargs))
- assert minargs <= nargs <= maxargs
- assert len(stack) >= nargs
- assert len(stack) >= nargs
- argtext = listsep.join([arg.text for arg in stack[-nargs:]])
- otext = "%s(%s)" % (func_name, argtext)
- res = Operand(oUNK, None, FUNC_RANK, otext)
- del stack[-nargs:]
- spush(res)
- elif opcode == 0x03: #tName
- tgtnamex = unpack("<H", data[pos+1:pos+3])[0] - 1
- # Only change with BIFF version is number of trailing UNUSED bytes!
- if verbose: print(" tgtnamex=%d" % tgtnamex, file=bk.logfile)
- tgtobj = bk.name_obj_list[tgtnamex]
- if tgtobj.scope == -1:
- otext = tgtobj.name
- else:
- otext = "%s!%s" % (bk._sheet_names[tgtobj.scope], tgtobj.name)
- if verbose:
- print(" tName: setting text to", repr(otext), file=bk.logfile)
- res = Operand(oUNK, None, LEAF_RANK, otext)
- spush(res)
- elif opcode == 0x04: # tRef
- res = get_cell_addr(data, pos+1, bv, reldelta, browx, bcolx)
- if verbose: print(" ", res, file=bk.logfile)
- rowx, colx, row_rel, col_rel = res
- is_rel = row_rel or col_rel
- if is_rel:
- okind = oREL
- else:
- okind = oREF
- otext = cellnamerel(rowx, colx, row_rel, col_rel)
- res = Operand(okind, None, LEAF_RANK, otext)
- spush(res)
- elif opcode == 0x05: # tArea
- res1, res2 = get_cell_range_addr(
- data, pos+1, bv, reldelta, browx, bcolx)
- if verbose: print(" ", res1, res2, file=bk.logfile)
- rowx1, colx1, row_rel1, col_rel1 = res1
- rowx2, colx2, row_rel2, col_rel2 = res2
- coords = (rowx1, rowx2+1, colx1, colx2+1)
- relflags = (row_rel1, row_rel2, col_rel1, col_rel2)
- is_rel = 1 if sum(relflags) else 0 # (to_py3)
- if is_rel:
- okind = oREL
- else:
- okind = oREF
- if verbose: print(" ", coords, relflags, file=bk.logfile)
- otext = rangename2drel(coords, relflags)
- res = Operand(okind, None, LEAF_RANK, otext)
- spush(res)
- elif opcode == 0x06: # tMemArea
- not_in_name_formula(op, oname)
- elif opcode == 0x09: # tMemFunc
- nb = unpack("<H", data[pos+1:pos+3])[0]
- if verbose: print(" %d bytes of cell ref formula" % nb, file=bk.logfile)
- # no effect on stack
- elif opcode == 0x0C: #tRefN
- not_in_name_formula(op, oname)
- # res = get_cell_addr(data, pos+1, bv, reldelta=1)
- # # note *ALL* tRefN usage has signed offset for relative addresses
- # any_rel = 1
- # if verbose: print >> bk.logfile, " ", res
- # spush(res)
- elif opcode == 0x0D: #tAreaN
- not_in_name_formula(op, oname)
- # res = get_cell_range_addr(data, pos+1, bv, reldelta=1)
- # # note *ALL* tAreaN usage has signed offset for relative addresses
- # any_rel = 1
- # if verbose: print >> bk.logfile, " ", res
- elif opcode == 0x1A: # tRef3d
- if bv >= 80:
- res = get_cell_addr(data, pos+3, bv, reldelta, browx, bcolx)
- refx = unpack("<H", data[pos+1:pos+3])[0]
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- else:
- res = get_cell_addr(data, pos+15, bv, reldelta, browx, bcolx)
- raw_extshtx, raw_shx1, raw_shx2 = \
- unpack("<hxxxxxxxxhh", data[pos+1:pos+15])
- if verbose:
- print("tRef3d", raw_extshtx, raw_shx1, raw_shx2, file=bk.logfile)
- shx1, shx2 = get_externsheet_local_range_b57(
- bk, raw_extshtx, raw_shx1, raw_shx2, verbose)
- rowx, colx, row_rel, col_rel = res
- is_rel = row_rel or col_rel
- any_rel = any_rel or is_rel
- coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1)
- any_err |= shx1 < -1
- if verbose: print(" ", coords, file=bk.logfile)
- res = Operand(oUNK, None)
- if is_rel:
- relflags = (0, 0, row_rel, row_rel, col_rel, col_rel)
- ref3d = Ref3D(coords + relflags)
- res.kind = oREL
- res.text = rangename3drel(bk, ref3d)
- else:
- ref3d = Ref3D(coords)
- res.kind = oREF
- res.text = rangename3d(bk, ref3d)
- res.rank = LEAF_RANK
- res.value = None
- spush(res)
- elif opcode == 0x1B: # tArea3d
- if bv >= 80:
- res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta)
- refx = unpack("<H", data[pos+1:pos+3])[0]
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- else:
- res1, res2 = get_cell_range_addr(data, pos+15, bv, reldelta)
- raw_extshtx, raw_shx1, raw_shx2 = \
- unpack("<hxxxxxxxxhh", data[pos+1:pos+15])
- if verbose:
- print("tArea3d", raw_extshtx, raw_shx1, raw_shx2, file=bk.logfile)
- shx1, shx2 = get_externsheet_local_range_b57(
- bk, raw_extshtx, raw_shx1, raw_shx2, verbose)
- any_err |= shx1 < -1
- rowx1, colx1, row_rel1, col_rel1 = res1
- rowx2, colx2, row_rel2, col_rel2 = res2
- is_rel = row_rel1 or col_rel1 or row_rel2 or col_rel2
- any_rel = any_rel or is_rel
- coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1)
- if verbose: print(" ", coords, file=bk.logfile)
- res = Operand(oUNK, None)
- if is_rel:
- relflags = (0, 0, row_rel1, row_rel2, col_rel1, col_rel2)
- ref3d = Ref3D(coords + relflags)
- res.kind = oREL
- res.text = rangename3drel(bk, ref3d)
- else:
- ref3d = Ref3D(coords)
- res.kind = oREF
- res.text = rangename3d(bk, ref3d)
- res.rank = LEAF_RANK
- spush(res)
- elif opcode == 0x19: # tNameX
- dodgy = 0
- res = Operand(oUNK, None)
- if bv >= 80:
- refx, tgtnamex = unpack("<HH", data[pos+1:pos+5])
- tgtnamex -= 1
- origrefx = refx
- else:
- refx, tgtnamex = unpack("<hxxxxxxxxH", data[pos+1:pos+13])
- tgtnamex -= 1
- origrefx = refx
- if refx > 0:
- refx -= 1
- elif refx < 0:
- refx = -refx - 1
- else:
- dodgy = 1
- if verbose:
- print(" origrefx=%d refx=%d tgtnamex=%d dodgy=%d" \
- % (origrefx, refx, tgtnamex, dodgy), file=bk.logfile)
- # if tgtnamex == namex:
- # if verbose: print >> bk.logfile, "!!!! Self-referential !!!!"
- # dodgy = any_err = 1
- if not dodgy:
- if bv >= 80:
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- elif origrefx > 0:
- shx1, shx2 = (-4, -4) # external ref
- else:
- exty = bk._externsheet_type_b57[refx]
- if exty == 4: # non-specific sheet in own doc't
- shx1, shx2 = (-1, -1) # internal, any sheet
- else:
- shx1, shx2 = (-666, -666)
- okind = oUNK
- ovalue = None
- if shx1 == -5: # addin func name
- okind = oSTRG
- ovalue = bk.addin_func_names[tgtnamex]
- otext = '"' + ovalue.replace('"', '""') + '"'
- elif dodgy or shx1 < -1:
- otext = "<<Name #%d in external(?) file #%d>>" \
- % (tgtnamex, origrefx)
- else:
- tgtobj = bk.name_obj_list[tgtnamex]
- if tgtobj.scope == -1:
- otext = tgtobj.name
- else:
- otext = "%s!%s" \
- % (bk._sheet_names[tgtobj.scope], tgtobj.name)
- if verbose:
- print(" tNameX: setting text to", repr(res.text), file=bk.logfile)
- res = Operand(okind, ovalue, LEAF_RANK, otext)
- spush(res)
- elif opcode in _error_opcodes:
- any_err = 1
- spush(error_opnd)
- else:
- if verbose:
- print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile)
- any_err = 1
- if sz <= 0:
- raise FormulaError("Fatal: token size is not positive")
- pos += sz
- any_rel = not not any_rel
- if verbose:
- print("End of formula. level=%d any_rel=%d any_err=%d stack=%r" % \
- (level, not not any_rel, any_err, stack))
- if len(stack) >= 2:
- print("*** Stack has unprocessed args")
- print()
-
- if len(stack) != 1:
- result = None
- else:
- result = stack[0].text
- return result
-
-#### under deconstruction ###
-def dump_formula(bk, data, fmlalen, bv, reldelta, verbose=0, isname=0):
- if verbose:
- print("dump_formula", fmlalen, bv, len(data))
- hex_char_dump(data, 0, fmlalen)
- assert bv >= 80 #### this function needs updating ####
- sztab = szdict[bv]
- pos = 0
- stack = []
- any_rel = 0
- any_err = 0
- spush = stack.append
- while 0 <= pos < fmlalen:
- op = data[pos]
- opcode = op & 0x1f
- optype = (op & 0x60) >> 5
- if optype:
- opx = opcode + 32
- else:
- opx = opcode
- oname = onames[opx] # + [" RVA"][optype]
-
- sz = sztab[opx]
- if verbose:
- print("Pos:%d Op:0x%02x Name:t%s Sz:%d opcode:%02xh optype:%02xh" \
- % (pos, op, oname, sz, opcode, optype))
- if not optype:
- if 0x01 <= opcode <= 0x02: # tExp, tTbl
- # reference to a shared formula or table record
- rowx, colx = unpack("<HH", data[pos+1:pos+5])
- if verbose: print(" ", (rowx, colx), file=bk.logfile)
- elif opcode == 0x10: # tList
- if verbose: print("tList pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- spush(aop + bop)
- if verbose: print("tlist post", stack, file=bk.logfile)
- elif opcode == 0x11: # tRange
- if verbose: print("tRange pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- assert len(aop) == 1
- assert len(bop) == 1
- result = do_box_funcs(tRangeFuncs, aop[0], bop[0])
- spush(result)
- if verbose: print("tRange post", stack, file=bk.logfile)
- elif opcode == 0x0F: # tIsect
- if verbose: print("tIsect pre", stack, file=bk.logfile)
- assert len(stack) >= 2
- bop = stack.pop()
- aop = stack.pop()
- assert len(aop) == 1
- assert len(bop) == 1
- result = do_box_funcs(tIsectFuncs, aop[0], bop[0])
- spush(result)
- if verbose: print("tIsect post", stack, file=bk.logfile)
- elif opcode == 0x19: # tAttr
- subop, nc = unpack("<BH", data[pos+1:pos+4])
- subname = tAttrNames.get(subop, "??Unknown??")
- if subop == 0x04: # Choose
- sz = nc * 2 + 6
- else:
- sz = 4
- if verbose: print(" subop=%02xh subname=t%s sz=%d nc=%02xh" % (subop, subname, sz, nc), file=bk.logfile)
- elif opcode == 0x17: # tStr
- if bv <= 70:
- nc = data[pos+1]
- strg = data[pos+2:pos+2+nc] # left in 8-bit encoding
- sz = nc + 2
- else:
- strg, newpos = unpack_unicode_update_pos(data, pos+1, lenlen=1)
- sz = newpos - pos
- if verbose: print(" sz=%d strg=%r" % (sz, strg), file=bk.logfile)
- else:
- if sz <= 0:
- print("**** Dud size; exiting ****")
- return
- pos += sz
- continue
- if opcode == 0x00: # tArray
- pass
- elif opcode == 0x01: # tFunc
- nb = 1 + int(bv >= 40)
- funcx = unpack("<" + " BH"[nb], data[pos+1:pos+1+nb])
- if verbose: print(" FuncID=%d" % funcx, file=bk.logfile)
- elif opcode == 0x02: #tFuncVar
- nb = 1 + int(bv >= 40)
- nargs, funcx = unpack("<B" + " BH"[nb], data[pos+1:pos+2+nb])
- prompt, nargs = divmod(nargs, 128)
- macro, funcx = divmod(funcx, 32768)
- if verbose: print(" FuncID=%d nargs=%d macro=%d prompt=%d" % (funcx, nargs, macro, prompt), file=bk.logfile)
- elif opcode == 0x03: #tName
- namex = unpack("<H", data[pos+1:pos+3])
- # Only change with BIFF version is the number of trailing UNUSED bytes!!!
- if verbose: print(" namex=%d" % namex, file=bk.logfile)
- elif opcode == 0x04: # tRef
- res = get_cell_addr(data, pos+1, bv, reldelta)
- if verbose: print(" ", res, file=bk.logfile)
- elif opcode == 0x05: # tArea
- res = get_cell_range_addr(data, pos+1, bv, reldelta)
- if verbose: print(" ", res, file=bk.logfile)
- elif opcode == 0x09: # tMemFunc
- nb = unpack("<H", data[pos+1:pos+3])[0]
- if verbose: print(" %d bytes of cell ref formula" % nb, file=bk.logfile)
- elif opcode == 0x0C: #tRefN
- res = get_cell_addr(data, pos+1, bv, reldelta=1)
- # note *ALL* tRefN usage has signed offset for relative addresses
- any_rel = 1
- if verbose: print(" ", res, file=bk.logfile)
- elif opcode == 0x0D: #tAreaN
- res = get_cell_range_addr(data, pos+1, bv, reldelta=1)
- # note *ALL* tAreaN usage has signed offset for relative addresses
- any_rel = 1
- if verbose: print(" ", res, file=bk.logfile)
- elif opcode == 0x1A: # tRef3d
- refx = unpack("<H", data[pos+1:pos+3])[0]
- res = get_cell_addr(data, pos+3, bv, reldelta)
- if verbose: print(" ", refx, res, file=bk.logfile)
- rowx, colx, row_rel, col_rel = res
- any_rel = any_rel or row_rel or col_rel
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- any_err |= shx1 < -1
- coords = (shx1, shx2+1, rowx, rowx+1, colx, colx+1)
- if verbose: print(" ", coords, file=bk.logfile)
- if optype == 1: spush([coords])
- elif opcode == 0x1B: # tArea3d
- refx = unpack("<H", data[pos+1:pos+3])[0]
- res1, res2 = get_cell_range_addr(data, pos+3, bv, reldelta)
- if verbose: print(" ", refx, res1, res2, file=bk.logfile)
- rowx1, colx1, row_rel1, col_rel1 = res1
- rowx2, colx2, row_rel2, col_rel2 = res2
- any_rel = any_rel or row_rel1 or col_rel1 or row_rel2 or col_rel2
- shx1, shx2 = get_externsheet_local_range(bk, refx, verbose)
- any_err |= shx1 < -1
- coords = (shx1, shx2+1, rowx1, rowx2+1, colx1, colx2+1)
- if verbose: print(" ", coords, file=bk.logfile)
- if optype == 1: spush([coords])
- elif opcode == 0x19: # tNameX
- refx, namex = unpack("<HH", data[pos+1:pos+5])
- if verbose: print(" refx=%d namex=%d" % (refx, namex), file=bk.logfile)
- elif opcode in _error_opcodes:
- any_err = 1
- else:
- if verbose: print("FORMULA: /// Not handled yet: t" + oname, file=bk.logfile)
- any_err = 1
- if sz <= 0:
- print("**** Dud size; exiting ****")
- return
- pos += sz
- if verbose:
- print("End of formula. any_rel=%d any_err=%d stack=%r" % \
- (not not any_rel, any_err, stack), file=bk.logfile)
- if len(stack) >= 2:
- print("*** Stack has unprocessed args", file=bk.logfile)
-
-# === Some helper functions for displaying cell references ===
-
-# Note that a "non-standard" syntax is used in row and column
-# components in relative references.
-# For example, consider a relative reference: up two rows, right 3 columns.
-# On screen, with cursor in cell D10, this would appear as G8.
-# On screen, with cursor in cell Z100, this would appear as AC98.
-# On screen, with cursor in cell A1, this would appear as D65535.
-# These functions will display such a reference as [@+3,#-2].
-# "@" refers to the unknown base column.
-# "#" refers to the unknown base row.
-#
-# I'm aware of only one possibility of a sheet-relative component in
-# a reference: a 2D reference located in the "current sheet".
-# xlrd stores this internally with bounds of (0, 1, ...) and
-# relative flags of (1, 1, ...). These functions display the
-# sheet component as empty, just like Excel etc.
-
-def rownamerel(rowx, rowxrel):
- if not rowxrel:
- return "$%d" % rowx
- if rowx > 0:
- return "#+%d" % rowx
- if rowx < 0:
- return "#-%d" % (-rowx)
- return "#"
-
-def colnamerel(colx, colxrel):
- if not colxrel:
- return "$" + colname(colx)
- if colx > 0:
- return "@+%d" % colx
- if colx < 0:
- return "@-%d" % (-colx)
- return "@"
-##
-# Utility function: (5, 7) => 'H6'
-def cellname(rowx, colx):
- """ (5, 7) => 'H6' """
- return "%s%d" % (colname(colx), rowx+1)
-
-##
-# Utility function: (5, 7) => '$H$6'
-def cellnameabs(rowx, colx):
- """ (5, 7) => '$H$6' """
- return "$%s$%d" % (colname(colx), rowx+1)
-
-def cellnamerel(rowx, colx, rowxrel, colxrel):
- if not rowxrel and not colxrel:
- return cellnameabs(rowx, colx)
- return "[%s,%s]" % (
- colnamerel(colx, colxrel),
- rownamerel(rowx, rowxrel))
-##
-# Utility function: 7 => 'H', 27 => 'AB'
-def colname(colx):
- """ 7 => 'H', 27 => 'AB' """
- alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- if colx <= 25:
- return alphabet[colx]
- else:
- xdiv26, xmod26 = divmod(colx, 26)
- return alphabet[xdiv26 - 1] + alphabet[xmod26]
-
-def rangename2d(rlo, rhi, clo, chi):
- """ (5, 20, 7, 10) => '$H$6:$J$20' """
- if rhi == rlo+1 and chi == clo+1:
- return cellnameabs(rlo, clo)
- return "%s:%s" % (cellnameabs(rlo, clo), cellnameabs(rhi-1, chi-1))
-
-def rangename2drel(xxx_todo_changeme, xxx_todo_changeme1):
- (rlo, rhi, clo, chi) = xxx_todo_changeme
- (rlorel, rhirel, clorel, chirel) = xxx_todo_changeme1
- return "%s:%s" % (
- cellnamerel(rlo, clo, rlorel, clorel),
- cellnamerel(rhi-1, chi-1, rhirel, chirel)
- )
-##
-# Utility function:
-# <br /> Ref3D((1, 4, 5, 20, 7, 10)) => 'Sheet2:Sheet3!$H$6:$J$20'
-def rangename3d(book, ref3d):
- """ Ref3D(1, 4, 5, 20, 7, 10) => 'Sheet2:Sheet3!$H$6:$J$20'
- (assuming Excel's default sheetnames) """
- coords = ref3d.coords
- return "%s!%s" % (
- sheetrange(book, *coords[:2]),
- rangename2d(*coords[2:6]))
-
-##
-# Utility function:
-# <br /> Ref3D(coords=(0, 1, -32, -22, -13, 13), relflags=(0, 0, 1, 1, 1, 1))
-# => 'Sheet1![@-13,#-32]:[@+12,#-23]'
-# where '@' refers to the current or base column and '#'
-# refers to the current or base row.
-def rangename3drel(book, ref3d):
- coords = ref3d.coords
- relflags = ref3d.relflags
- shdesc = sheetrangerel(book, coords[:2], relflags[:2])
- rngdesc = rangename2drel(coords[2:6], relflags[2:6])
- if not shdesc:
- return rngdesc
- return "%s!%s" % (shdesc, rngdesc)
-
-def quotedsheetname(shnames, shx):
- if shx >= 0:
- shname = shnames[shx]
- else:
- shname = {
- -1: "?internal; any sheet?",
- -2: "internal; deleted sheet",
- -3: "internal; macro sheet",
- -4: "<<external>>",
- }.get(shx, "?error %d?" % shx)
- if "'" in shname:
- return "'" + shname.replace("'", "''") + "'"
- if " " in shname:
- return "'" + shname + "'"
- return shname
-
-def sheetrange(book, slo, shi):
- shnames = book.sheet_names()
- shdesc = quotedsheetname(shnames, slo)
- if slo != shi-1:
- shdesc += ":" + quotedsheetname(shnames, shi-1)
- return shdesc
-
-def sheetrangerel(book, xxx_todo_changeme2, xxx_todo_changeme3):
- (slo, shi) = xxx_todo_changeme2
- (slorel, shirel) = xxx_todo_changeme3
- if not slorel and not shirel:
- return sheetrange(book, slo, shi)
- assert (slo == 0 == shi-1) and slorel and shirel
- return ""
-
-# ==============================================================
diff --git a/tablib/packages/xlrd3/sheet.py b/tablib/packages/xlrd3/sheet.py deleted file mode 100644 index 5911fb0..0000000 --- a/tablib/packages/xlrd3/sheet.py +++ /dev/null @@ -1,1611 +0,0 @@ -# Portions copyright © 2005-2009 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd3 package, which is released under a
-# BSD-style licence.
-
-# 2009-05-31 SJM Fixed problem with no CODEPAGE record on extremely minimal BIFF2.x 3rd-party file
-# 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo
-# 2008-02-09 SJM Excel 2.0: build XFs on the fly from cell attributes
-# 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files.
-# 2007-10-11 SJM Added missing entry for blank cell type to ctype_text
-# 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file
-# 2007-04-22 SJM Remove experimental "trimming" facility.
-
-#for debugging only
-from math import isnan
-
-import time
-from struct import unpack
-from array import array
-
-from .biffh import *
-from .formula import dump_formula, decompile_formula, rangename2d
-from .formatting import nearest_colour_index, Format
-from .xfcell import XFCell
-
-DEBUG = 0
-OBJ_MSO_DEBUG = 0
-
-_WINDOW2_options = (
- # Attribute names and initial values to use in case
- # a WINDOW2 record is not written.
- ("show_formulas", 0),
- ("show_grid_lines", 1),
- ("show_sheet_headers", 1),
- ("panes_are_frozen", 0),
- ("show_zero_values", 1),
- ("automatic_grid_line_colour", 1),
- ("columns_from_right_to_left", 0),
- ("show_outline_symbols", 1),
- ("remove_splits_if_pane_freeze_is_removed", 0),
- ("sheet_selected", 0),
- # "sheet_visible" appears to be merely a clone of "sheet_selected".
- # The real thing is the visibility attribute from the BOUNDSHEET record.
- ("sheet_visible", 0),
- ("show_in_page_break_preview", 0),
- )
-
-def int_floor_div(x, y):
- return divmod(x, y)[0]
-
-class Sheet(BaseObject):
- """Contains the data for one worksheet.
-
- In the cell access functions, "rowx" is a row index, counting from zero,
- and "colx" is a column index, counting from zero.
- Negative values for row/column indexes and slice positions are supported in
- the expected fashion.
-
- For information about cell types and cell values, refer to the documentation
- of the Cell class.
-
- WARNING: You don't call this class yourself. You access Sheet objects via
- the Book object that was returned when you called xlrd.open_workbook("myfile.xls").
- """
-
- # Name of sheet.
- name = ''
-
- # Number of rows in sheet. A row index is in range(thesheet.nrows).
- nrows = 0
-
- # Number of columns in sheet. A column index is in range(thesheet.ncols).
- ncols = 0
-
- # The map from a column index to a Colinfo object. Often there is an entry
- # in COLINFO records for all column indexes in range(257).
- # Note that xlrd ignores the entry for the non-existent
- # 257th column. On the other hand, there may be no entry for unused columns.
- # - New in version 0.6.1
- colinfo_map = {}
-
- # The map from a row index to a Rowinfo object. Note that it is possible
- # to have missing entries -- at least one source of XLS files doesn't
- # bother writing ROW records.
- # - New in version 0.6.1
- rowinfo_map = {}
-
- # List of address ranges of cells containing column labels.
- # These are set up in Excel by Insert > Name > Labels > Columns.
- # - New in version 0.6.0
- # How to deconstruct the list::
- #
- # for crange in thesheet.col_label_ranges:
- # rlo, rhi, clo, chi = crange
- # for rx in xrange(rlo, rhi):
- # for cx in xrange(clo, chi):
- # print "Column label at (rowx=%d, colx=%d) is %r" \
- # (rx, cx, thesheet.cell_value(rx, cx))
- #
- col_label_ranges = []
-
- # List of address ranges of cells containing row labels.
- # For more details, see <i>col_label_ranges</i> above.
- # - New in version 0.6.0
- row_label_ranges = []
-
- # List of address ranges of cells which have been merged.
- # These are set up in Excel by Format > Cells > Alignment, then ticking
- # the "Merge cells" box.
- # - New in version 0.6.1. Extracted only if open_workbook(..., formatting_info=True)
- # How to deconstruct the list::
- #
- # for crange in thesheet.merged_cells:
- # rlo, rhi, clo, chi = crange
- # for rowx in xrange(rlo, rhi):
- # for colx in xrange(clo, chi):
- # # cell (rlo, clo) (the top left one) will carry the data
- # # and formatting info; the remainder will be recorded as
- # # blank cells, but a renderer will apply the formatting info
- # # for the top left cell (e.g. border, pattern) to all cells in
- # # the range.
- #
- merged_cells = []
-
- # Default column width from DEFCOLWIDTH record, else None.
- # From the OOo docs:
- # """Column width in characters, using the width of the zero character
- # from default font (first FONT record in the file). Excel adds some
- # extra space to the default width, depending on the default font and
- # default font size. The algorithm how to exactly calculate the resulting
- # column width is not known.
- # Example: The default width of 8 set in this record results in a column
- # width of 8.43 using Arial font with a size of 10 points."""
- # For the default hierarchy, refer to the Colinfo class above.
- # - New in version 0.6.1
- defcolwidth = None
-
- # Default column width from STANDARDWIDTH record, else None.
- # From the OOo docs:
- # """Default width of the columns in 1/256 of the width of the zero
- # character, using default font (first FONT record in the file)."""
- # For the default hierarchy, refer to the Colinfo class above.
- # - New in version 0.6.1
- standardwidth = None
-
- # Default value to be used for a row if there is
- # no ROW record for that row.
- # From the <i>optional</i> DEFAULTROWHEIGHT record.
- default_row_height = None
-
- # Default value to be used for a row if there is
- # no ROW record for that row.
- # From the ´optional´ DEFAULTROWHEIGHT record.
- default_row_height_mismatch = None
-
- # Default value to be used for a row if there is
- # no ROW record for that row.
- # From the ´optional´ DEFAULTROWHEIGHT record.
- default_row_hidden = None
-
- # Default value to be used for a row if there is
- # no ROW record for that row.
- # From the <i>optional</i> DEFAULTROWHEIGHT record.
- default_additional_space_above = None
-
- # Default value to be used for a row if there is
- # no ROW record for that row.
- # From the <i>optional</i> DEFAULTROWHEIGHT record.
- default_additional_space_below = None
-
- # Visibility of the sheet. 0 = visible, 1 = hidden (can be unhidden
- # by user -- Format/Sheet/Unhide), 2 = "very hidden" (can be unhidden
- # only by VBA macro).
- visibility = 0
-
- # A 256-element tuple corresponding to the contents of the GCW record for this sheet.
- # If no such record, treat as all bits zero.
- # Applies to BIFF4-7 only. See docs of Colinfo class for discussion.
- gcw = (0, ) * 256
-
- def __init__(self, book, position, name, number):
- self.book = book
- self.biff_version = book.biff_version
- self._position = position
- self.logfile = book.logfile
- self.pickleable = book.pickleable
- # (to_py3) self.dont_use_array = not(array_array and (CAN_PICKLE_ARRAY or not book.pickleable))
- self.name = name
- self.number = number
- self.verbosity = book.verbosity
- self.formatting_info = book.formatting_info
- self._xf_index_to_xl_type_map = book._xf_index_to_xl_type_map
- self.nrows = 0 # actual, including possibly empty cells
- self.ncols = 0
- self._maxdatarowx = -1 # highest rowx containing a non-empty cell
- self._maxdatacolx = -1 # highest colx containing a non-empty cell
- self._dimnrows = 0 # as per DIMENSIONS record
- self._dimncols = 0
- self._cell_values = []
- self._cell_types = []
- self._cell_xf_indexes = []
- self._need_fix_ragged_rows = 0
- self.defcolwidth = None
- self.standardwidth = None
- self.default_row_height = None
- self.default_row_height_mismatch = 0
- self.default_row_hidden = 0
- self.default_additional_space_above = 0
- self.default_additional_space_below = 0
- self.colinfo_map = {}
- self.rowinfo_map = {}
- self.col_label_ranges = []
- self.row_label_ranges = []
- self.merged_cells = []
- self._xf_index_stats = [0, 0, 0, 0]
- self.visibility = book._sheet_visibility[number] # from BOUNDSHEET record
- for attr, defval in _WINDOW2_options:
- setattr(self, attr, defval)
- self.first_visible_rowx = 0
- self.first_visible_colx = 0
- self.gridline_colour_index = 0x40
- self.gridline_colour_rgb = None # pre-BIFF8
- self.cached_page_break_preview_mag_factor = 0
- self.cached_normal_view_mag_factor = 0
- self._ixfe = None # BIFF2 only
- self._cell_attr_to_xfx = {} # BIFF2.0 only
-
- #### Don't initialise this here, use class attribute initialisation.
- #### self.gcw = (0, ) * 256 ####
-
- if self.biff_version >= 80:
- self.utter_max_rows = 65536
- else:
- self.utter_max_rows = 16384
- self.utter_max_cols = 256
-
- def cell(self, rowx, colx):
- """ Get the XFCell() object in the given row and column. """
- if self.formatting_info:
- xf_index = self.cell_xf_index(rowx, colx)
- else:
- xf_index = None
- ctype = self.cell_type(rowx, colx)
- value = self.cell_value(rowx, colx)
- return Cell(ctype, value, xf_index, self)
-
- def cell_value(self, rowx, colx):
- """ Value of the cell in the given row and column. """
- return self._cell_values[rowx][colx]
-
- def cell_type(self, rowx, colx):
- """ Type of the cell in the given row and column.
- Refer to the documentation of the Cell class.
- """
- return self._cell_types[rowx][colx]
-
- # New in version 0.6.1
- def cell_xf_index(self, rowx, colx):
- """ XF index of the cell in the given row and column.
- This is an index into Book.xf_list.
- """
- self.req_fmt_info()
- xfx = self._cell_xf_indexes[rowx][colx]
- if xfx > -1:
- self._xf_index_stats[0] += 1
- return xfx
- # Check for a row xf_index
- try:
- xfx = self.rowinfo_map[rowx].xf_index
- if xfx > -1:
- self._xf_index_stats[1] += 1
- return xfx
- except KeyError:
- pass
- # Check for a column xf_index
- try:
- xfx = self.colinfo_map[colx].xf_index
- assert xfx > -1
- self._xf_index_stats[2] += 1
- return xfx
- except KeyError:
- # If all else fails, 15 is used as hardwired global default xf_index.
- self._xf_index_stats[3] += 1
- return 15
-
-
- def row(self, rowx):
- """ Returns a sequence of the Cell objects in the given row. """
- return [self.cell(rowx, colx) for colx in range(self.ncols)]
-
- def row_types(self, rowx, start_colx=0, end_colx=None):
- """ Returns a slice of the types of the cells in the given row. """
- if end_colx is None:
- return self._cell_types[rowx][start_colx:]
- return self._cell_types[rowx][start_colx:end_colx]
-
- def row_values(self, rowx, start_colx=0, end_colx=None):
- """ Returns a slice of the values of the cells in the given row. """
- if end_colx is None:
- return self._cell_values[rowx][start_colx:]
- return self._cell_values[rowx][start_colx:end_colx]
-
- def row_slice(self, rowx, start_colx=0, end_colx=None):
- """ Returns a slice of the Cell objects in the given row. """
- nc = self.ncols
- if start_colx < 0:
- start_colx += nc
- if start_colx < 0:
- start_colx = 0
- if end_colx is None or end_colx > nc:
- end_colx = nc
- elif end_colx < 0:
- end_colx += nc
- return [self.cell(rowx, colx) for colx in range(start_colx, end_colx)]
-
- def col_slice(self, colx, start_rowx=0, end_rowx=None):
- """ Returns a slice of the Cell objects in the given column. """
- nr = self.nrows
- if start_rowx < 0:
- start_rowx += nr
- if start_rowx < 0:
- start_rowx = 0
- if end_rowx is None or end_rowx > nr:
- end_rowx = nr
- elif end_rowx < 0:
- end_rowx += nr
- return [self.cell(rowx, colx) for rowx in range(start_rowx, end_rowx)]
-
- col = col_slice
- """ Returns a sequence of the Cell objects in the given column. """
-
- def col_values(self, colx, start_rowx=0, end_rowx=None):
- """ Returns a slice of the values of the cells in the given column. """
- nr = self.nrows
- if start_rowx < 0:
- start_rowx += nr
- if start_rowx < 0:
- start_rowx = 0
- if end_rowx is None or end_rowx > nr:
- end_rowx = nr
- elif end_rowx < 0:
- end_rowx += nr
- return [self._cell_values[rowx][colx] for rowx in range(start_rowx, end_rowx)]
-
- def col_types(self, colx, start_rowx=0, end_rowx=None):
- """ Returns a slice of the types of the cells in the given column. """
- nr = self.nrows
- if start_rowx < 0:
- start_rowx += nr
- if start_rowx < 0:
- start_rowx = 0
- if end_rowx is None or end_rowx > nr:
- end_rowx = nr
- elif end_rowx < 0:
- end_rowx += nr
- return [self._cell_types[rowx][colx] for rowx in range(start_rowx, end_rowx)]
-
- # Following methods are used in building the worksheet.
- # They are not part of the API.
-
- def extend_cells(self, nr, nc):
- assert 1 <= nc <= self.utter_max_cols
- assert 1 <= nr <= self.utter_max_rows
- if nr <= self.nrows:
- # New cell is in an existing row, so extend that row (if necessary).
- # Note that nr < self.nrows means that the cell data
- # is not in ascending row order!!
- self._need_fix_ragged_rows = 1
- nrx = nr - 1
- trow = self._cell_types[nrx]
- tlen = len(trow)
- nextra = max(nc, self.ncols) - tlen
- if nextra > 0:
- xce = XL_CELL_EMPTY
- #(to_py3) if self.dont_use_array: ... removed
- trow.extend(array('B', [xce]) * nextra)
- if self.formatting_info:
- self._cell_xf_indexes[nrx].extend(array('h', [-1]) * nextra)
- self._cell_values[nrx].extend([''] * nextra)
- if nc > self.ncols:
- self.ncols = nc
- self._need_fix_ragged_rows = 1
- if nr > self.nrows:
- scta = self._cell_types.append
- scva = self._cell_values.append
- scxa = self._cell_xf_indexes.append
- fmt_info = self.formatting_info
- xce = XL_CELL_EMPTY
- nc = self.ncols
-
- #(to_py3) if self.dont_use_array: ... removed
- for _unused in range(self.nrows, nr):
- scta(array('B', [xce]) * nc)
- scva([''] * nc)
- if fmt_info:
- scxa(array('h', [-1]) * nc)
- self.nrows = nr
-
- def fix_ragged_rows(self):
- t0 = time.time()
- ncols = self.ncols
- xce = XL_CELL_EMPTY
- s_cell_types = self._cell_types
- s_cell_values = self._cell_values
- s_cell_xf_indexes = self._cell_xf_indexes
- s_fmt_info = self.formatting_info
- totrowlen = 0
- for rowx in range(self.nrows):
- trow = s_cell_types[rowx]
- rlen = len(trow)
- totrowlen += rlen
- nextra = ncols - rlen
- if nextra > 0:
- s_cell_values[rowx][rlen:] = [''] * nextra
- trow.extend(array('B', [xce]) * nextra)
- if s_fmt_info:
- s_cell_xf_indexes[rowx][rlen:] = array('h', [-1]) * nextra
- self._fix_ragged_rows_time = time.time() - t0
-
- def tidy_dimensions(self):
- if self.verbosity >= 3:
- fprintf(self.logfile,
- "tidy_dimensions: nrows=%d ncols=%d _need_fix_ragged_rows=%d\n",
- self.nrows, self.ncols, self._need_fix_ragged_rows)
- if self.merged_cells:
- nr = nc = 0
- umaxrows = self.utter_max_rows
- umaxcols = self.utter_max_cols
- for crange in self.merged_cells:
- rlo, rhi, clo, chi = crange
- if not (0 <= rlo < rhi <= umaxrows) \
- or not (0 <= clo < chi <= umaxcols):
- fprintf(self.logfile,
- "*** WARNING: sheet #%d (%r), MERGEDCELLS bad range %r\n",
- self.number, self.name, crange)
- if rhi > nr: nr = rhi
- if chi > nc: nc = chi
- self.extend_cells(nr, nc)
- if self.verbosity >= 1 and \
- (self.nrows != self._dimnrows or self.ncols != self._dimncols):
- fprintf(self.logfile,
- "NOTE *** sheet %d (%r): DIMENSIONS R,C = %d,%d should be %d,%d\n",
- self.number,
- self.name,
- self._dimnrows,
- self._dimncols,
- self.nrows,
- self.ncols,
- )
- if self._need_fix_ragged_rows:
- self.fix_ragged_rows()
-
- def put_cell(self, rowx, colx, ctype, value, xf_index):
- try:
- self._cell_types[rowx][colx] = ctype
- self._cell_values[rowx][colx] = value
- if self.formatting_info:
- self._cell_xf_indexes[rowx][colx] = xf_index
- except IndexError:
- self.extend_cells(rowx+1, colx+1)
- try:
- self._cell_types[rowx][colx] = ctype
- self._cell_values[rowx][colx] = value
- if self.formatting_info:
- self._cell_xf_indexes[rowx][colx] = xf_index
- except:
- print("put_cell", rowx, colx, file=self.logfile)
- raise
- except:
- print("put_cell", rowx, colx, file=self.logfile)
- raise
-
- def put_blank_cell(self, rowx, colx, xf_index):
- # This is used for cells from BLANK and MULBLANK records
- ctype = XL_CELL_BLANK
- value = ''
- try:
- self._cell_types[rowx][colx] = ctype
- self._cell_values[rowx][colx] = value
- self._cell_xf_indexes[rowx][colx] = xf_index
- except IndexError:
- self.extend_cells(rowx+1, colx+1)
- try:
- self._cell_types[rowx][colx] = ctype
- self._cell_values[rowx][colx] = value
- self._cell_xf_indexes[rowx][colx] = xf_index
- except:
- print("put_cell", rowx, colx, file=self.logfile)
- raise
- except:
- print("put_cell", rowx, colx, file=self.logfile)
- raise
-
- def put_number_cell(self, rowx, colx, value, xf_index):
- # for debugging
- if type(value) == float and isnan(value):
- pass
- ctype = self._xf_index_to_xl_type_map[xf_index]
- try:
- self._cell_types[rowx][colx] = ctype
- self._cell_values[rowx][colx] = value
- if self.formatting_info:
- self._cell_xf_indexes[rowx][colx] = xf_index
- except IndexError:
- self.extend_cells(rowx+1, colx+1)
- try:
- self._cell_types[rowx][colx] = ctype
- self._cell_values[rowx][colx] = value
- if self.formatting_info:
- self._cell_xf_indexes[rowx][colx] = xf_index
- except:
- print("put_number_cell", rowx, colx, file=self.logfile)
- raise
- except:
- print("put_number_cell", rowx, colx, file=self.logfile)
- raise
-
- # === Methods after this line neither know nor care about how cells are stored.
-
- def read(self, bk):
- global rc_stats
- DEBUG = 0
- verbose = DEBUG or self.verbosity >= 2
- verbose_rows = DEBUG or self.verbosity >= 4
- verbose_formulas = 1 and verbose
- oldpos = bk._position
- bk._position = self._position
- XL_SHRFMLA_ETC_ETC = (
- XL_SHRFMLA, XL_ARRAY, XL_TABLEOP, XL_TABLEOP2,
- XL_ARRAY2, XL_TABLEOP_B2,
- )
- self_put_number_cell = self.put_number_cell
- self_put_cell = self.put_cell
- self_put_blank_cell = self.put_blank_cell
- local_unpack = unpack
- bk_get_record_parts = bk.get_record_parts
- bv = self.biff_version
- fmt_info = self.formatting_info
- eof_found = 0
- while 1:
- rc, data_len, data = bk_get_record_parts()
- if rc == XL_NUMBER:
- rowx, colx, xf_index, d = local_unpack('<HHHd', data)
- self_put_number_cell(rowx, colx, d, xf_index)
- elif rc == XL_LABELSST:
- rowx, colx, xf_index, sstindex = local_unpack('<HHHi', data)
- self_put_cell(rowx, colx, XL_CELL_TEXT, bk._sharedstrings[sstindex], xf_index)
- elif rc == XL_LABEL or rc == XL_RSTRING:
- rowx, colx, xf_index = local_unpack('<HHH', data[0:6])
- if bv < BIFF_FIRST_UNICODE:
- strg = unpack_string(data, 6, bk.encoding or bk.derive_encoding, lenlen=2)
- else:
- strg = unpack_unicode(data, 6, lenlen=2)
- self_put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index)
- elif rc == XL_RK:
- rowx, colx, xf_index = local_unpack('<HHH', data[:6])
- d = unpack_RK(data[6:10])
- self_put_number_cell(rowx, colx, d, xf_index)
- elif rc == XL_MULRK:
- mulrk_row, mulrk_first = local_unpack('<HH', data[0:4])
- mulrk_last, = local_unpack('<H', data[-2:])
- pos = 4
- for colx in range(mulrk_first, mulrk_last+1):
- xf_index, = local_unpack('<H', data[pos:pos+2])
- d = unpack_RK(data[pos+2:pos+6])
- pos += 6
- self_put_number_cell(mulrk_row, colx, d, xf_index)
- elif rc == XL_ROW:
- # Version 0.6.0a3: ROW records are just not worth using (for memory allocation).
- # Version 0.6.1: now used for formatting info.
- if not fmt_info: continue
- rowx, bits1, bits2 = local_unpack('<H4xH4xi', data[0:16])
- if not(0 <= rowx < self.utter_max_rows):
- print("*** NOTE: ROW record has row index %d; " \
- "should have 0 <= rowx < %d -- record ignored!" \
- % (rowx, self.utter_max_rows), file=self.logfile)
- continue
- r = Rowinfo()
- # Using upkbits() is far too slow on a file
- # with 30 sheets each with 10K rows :-(
- # upkbits(r, bits1, (
- # ( 0, 0x7FFF, 'height'),
- # (15, 0x8000, 'has_default_height'),
- # ))
- # upkbits(r, bits2, (
- # ( 0, 0x00000007, 'outline_level'),
- # ( 4, 0x00000010, 'outline_group_starts_ends'),
- # ( 5, 0x00000020, 'hidden'),
- # ( 6, 0x00000040, 'height_mismatch'),
- # ( 7, 0x00000080, 'has_default_xf_index'),
- # (16, 0x0FFF0000, 'xf_index'),
- # (28, 0x10000000, 'additional_space_above'),
- # (29, 0x20000000, 'additional_space_below'),
- # ))
- # So:
- r.height = bits1 & 0x7fff
- r.has_default_height = (bits1 >> 15) & 1
- r.outline_level = bits2 & 7
- r.outline_group_starts_ends = (bits2 >> 4) & 1
- r.hidden = (bits2 >> 5) & 1
- r.height_mismatch = (bits2 >> 6) & 1
- r.has_default_xf_index = (bits2 >> 7) & 1
- r.xf_index = (bits2 >> 16) & 0xfff
- r.additional_space_above = (bits2 >> 28) & 1
- r.additional_space_below = (bits2 >> 29) & 1
- if not r.has_default_xf_index:
- r.xf_index = -1
- self.rowinfo_map[rowx] = r
- if 0 and r.xf_index > -1:
- fprintf(self.logfile,
- "**ROW %d %d %d\n",
- self.number, rowx, r.xf_index)
- if verbose_rows:
- print('ROW', rowx, bits1, bits2, file=self.logfile)
- r.dump(self.logfile,
- header="--- sh #%d, rowx=%d ---" % (self.number, rowx))
- elif rc in XL_FORMULA_OPCODES: # 06, 0206, 0406
- if bv >= 50:
- # IMPORTANT result_str is bytes
- rowx, colx, xf_index, result_str, flags = local_unpack('<HHH8sH', data[0:16])
- lenlen = 2
- tkarr_offset = 20
- elif bv >= 30:
- rowx, colx, xf_index, result_str, flags = local_unpack('<HHH8sH', data[0:16])
- lenlen = 2
- tkarr_offset = 16
- else: # BIFF2
- rowx, colx, cell_attr, result_str, flags = local_unpack('<HH3s8sB', data[0:16])
- xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)
- lenlen = 1
- tkarr_offset = 16
- if verbose_formulas: # testing formula dumper
- #### XXXX FIXME
- fprintf(self.logfile, "FORMULA: rowx=%d colx=%d\n", rowx, colx)
- fmlalen = local_unpack("<H", data[20:22])[0]
- decompile_formula(bk, data[22:], fmlalen,
- reldelta=0, browx=rowx, bcolx=colx, verbose=1)
- if result_str[6:8] == b'\xFF\xFF':
- if result_str[0] == 0: #b'\x00':
- # need to read next record (STRING)
- gotstring = 0
- # if flags & 8:
- if 1: # "flags & 8" applies only to SHRFMLA
- # actually there's an optional SHRFMLA or ARRAY etc record to skip over
- rc2, data2_len, data2 = bk.get_record_parts()
- if rc2 == XL_STRING or rc2 == XL_STRING_B2:
- gotstring = 1
- elif rc2 == XL_ARRAY:
- row1x, rownx, col1x, colnx, array_flags, tokslen = \
- local_unpack("<HHBBBxxxxxH", data2[:14])
- if verbose_formulas:
- fprintf(self.logfile, "ARRAY: %d %d %d %d %d\n",
- row1x, rownx, col1x, colnx, array_flags)
- dump_formula(bk, data2[14:], tokslen, bv, reldelta=0, verbose=1)
- elif rc2 == XL_SHRFMLA:
- row1x, rownx, col1x, colnx, nfmlas, tokslen = \
- local_unpack("<HHBBxBH", data2[:10])
- if verbose_formulas:
- fprintf(self.logfile, "SHRFMLA (sub): %d %d %d %d %d\n",
- row1x, rownx, col1x, colnx, nfmlas)
- decompile_formula(bk, data2[10:], tokslen, reldelta=1, verbose=1)
- elif rc2 not in XL_SHRFMLA_ETC_ETC:
- raise XLRDError(
- "Expected SHRFMLA, ARRAY, TABLEOP* or STRING record; found 0x%04x" % rc2)
- # if DEBUG: print "gotstring:", gotstring
- # now for the STRING record
- if not gotstring:
- rc2, _unused_len, data2 = bk.get_record_parts()
- if rc2 not in (XL_STRING, XL_STRING_B2):
- raise XLRDError("Expected STRING record; found 0x%04x" % rc2)
- # if DEBUG: print "STRING: data=%r BIFF=%d cp=%d" % (data2, self.biff_version, bk.encoding)
- if self.biff_version < BIFF_FIRST_UNICODE:
- strg = unpack_string(data2, 0, bk.encoding or bk.derive_encoding, lenlen=1 + int(bv > 20))
- else:
- strg = unpack_unicode(data2, 0, lenlen=2)
- self.put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index)
- # if DEBUG: print "FORMULA strg %r" % strg
- elif result_str[0] == 1: #b'\x01':
- # boolean formula result
- value = result_str[2]
- self.put_cell(rowx, colx, XL_CELL_BOOLEAN, value, xf_index)
- elif result_str[0] == 2: #b'\x02':
- # Error in cell
- value = result_str[2]
- self.put_cell(rowx, colx, XL_CELL_ERROR, value, xf_index)
- elif result_str[0] == 3:#b'\x03':
- # empty ... i.e. empty (zero-length) string, NOT an empty cell.
- self.put_cell(rowx, colx, XL_CELL_TEXT, "", xf_index)
- else:
- raise XLRDError("unexpected special case (0x%02x) in FORMULA" % result_str[0])
- else:
- # it is a number
- d = local_unpack('<d', result_str)[0]
- self_put_number_cell(rowx, colx, d, xf_index)
- elif rc == XL_BOOLERR:
- rowx, colx, xf_index, value, is_err = local_unpack('<HHHBB', data[:8])
- # Note OOo Calc 2.0 writes 9-byte BOOLERR records.
- # OOo docs say 8. Excel writes 8.
- cellty = (XL_CELL_BOOLEAN, XL_CELL_ERROR)[is_err]
- # if DEBUG: print "XL_BOOLERR", rowx, colx, xf_index, value, is_err
- self.put_cell(rowx, colx, cellty, value, xf_index)
- elif rc == XL_COLINFO:
- if not fmt_info: continue
- c = Colinfo()
- first_colx, last_colx, c.width, c.xf_index, flags \
- = local_unpack("<HHHHH", data[:10])
- #### Colinfo.width is denominated in 256ths of a character,
- #### *not* in characters.
- if not(0 <= first_colx <= last_colx <= 256):
- # Note: 256 instead of 255 is a common mistake.
- # We silently ignore the non-existing 257th column in that case.
- print("*** NOTE: COLINFO record has first col index %d, last %d; " \
- "should have 0 <= first <= last <= 255 -- record ignored!" \
- % (first_colx, last_colx), file=self.logfile)
- del c
- continue
- upkbits(c, flags, (
- ( 0, 0x0001, 'hidden'),
- ( 1, 0x0002, 'bit1_flag'),
- # *ALL* colinfos created by Excel in "default" cases are 0x0002!!
- # Maybe it's "locked" by analogy with XFProtection data.
- ( 8, 0x0700, 'outline_level'),
- (12, 0x1000, 'collapsed'),
- ))
- for colx in range(first_colx, last_colx+1):
- if colx > 255: break # Excel does 0 to 256 inclusive
- self.colinfo_map[colx] = c
- if 0:
- fprintf(self.logfile,
- "**COL %d %d %d\n",
- self.number, colx, c.xf_index)
- if verbose:
- fprintf(
- self.logfile,
- "COLINFO sheet #%d cols %d-%d: wid=%d xf_index=%d flags=0x%04x\n",
- self.number, first_colx, last_colx, c.width, c.xf_index, flags,
- )
- c.dump(self.logfile, header='===')
- elif rc == XL_DEFCOLWIDTH:
- self.defcolwidth, = local_unpack("<H", data[:2])
- if 0: print('DEFCOLWIDTH', self.defcolwidth, file=self.logfile)
- elif rc == XL_STANDARDWIDTH:
- if data_len != 2:
- print('*** ERROR *** STANDARDWIDTH', data_len, repr(data), file=self.logfile)
- self.standardwidth, = local_unpack("<H", data[:2])
- if 0: print('STANDARDWIDTH', self.standardwidth, file=self.logfile)
- elif rc == XL_GCW:
- if not fmt_info: continue # useless w/o COLINFO
- assert data_len == 34
- assert data[0:2] == "\x20\x00"
- iguff = unpack("<8i", data[2:34])
- gcw = []
- for bits in iguff:
- for j in range(32):
- gcw.append(bits & 1)
- bits >>= 1
- self.gcw = tuple(gcw)
- if 0:
- showgcw = "".join(["F "[x] for x in gcw]).rstrip().replace(' ', '.')
- print("GCW:", showgcw)
- elif rc == XL_BLANK:
- if not fmt_info: continue
- rowx, colx, xf_index = local_unpack('<HHH', data[:6])
- if 0: print("BLANK", rowx, colx, xf_index, file=self.logfile)
- self_put_blank_cell(rowx, colx, xf_index)
- elif rc == XL_MULBLANK: # 00BE
- if not fmt_info: continue
- mul_row, mul_first = local_unpack('<HH', data[0:4])
- mul_last, = local_unpack('<H', data[-2:])
- if 0:
- print("MULBLANK", mul_row, mul_first, mul_last, file=self.logfile)
- pos = 4
- for colx in range(mul_first, mul_last+1):
- xf_index, = local_unpack('<H', data[pos:pos+2])
- pos += 2
- self_put_blank_cell(mul_row, colx, xf_index)
- elif rc == XL_DIMENSION or rc == XL_DIMENSION2:
- # if data_len == 10:
- # Was crashing on BIFF 4.0 file w/o the two trailing unused bytes.
- # Reported by Ralph Heimburger.
- if bv < 80:
- dim_tuple = local_unpack('<HxxH', data[2:8])
- else:
- dim_tuple = local_unpack('<ixxH', data[4:12])
- self.nrows, self.ncols = 0, 0
- self._dimnrows, self._dimncols = dim_tuple
- if not self.book._xf_epilogue_done:
- # Needed for bv <= 40
- self.book.xf_epilogue()
- if verbose:
- fprintf(self.logfile,
- "sheet %d(%r) DIMENSIONS: ncols=%d nrows=%d\n",
- self.number, self.name, self._dimncols, self._dimnrows
- )
- elif rc == XL_EOF:
- DEBUG = 0
- if DEBUG: print("SHEET.READ: EOF", file=self.logfile)
- eof_found = 1
- break
- elif rc == XL_OBJ:
- # handle SHEET-level objects; note there's a separate Book.handle_obj
- self.handle_obj(data)
- elif rc == XL_MSO_DRAWING:
- self.handle_msodrawingetc(rc, data_len, data)
- elif rc == XL_TXO:
- self.handle_txo(data)
- elif rc == XL_NOTE:
- self.handle_note(data)
- elif rc == XL_FEAT11:
- self.handle_feat11(data)
- elif rc in bofcodes: ##### EMBEDDED BOF #####
- version, boftype = local_unpack('<HH', data[0:4])
- if boftype != 0x20: # embedded chart
- print("*** Unexpected embedded BOF (0x%04x) at offset %d: version=0x%04x type=0x%04x" \
- % (rc, bk._position - data_len - 4, version, boftype), file=self.logfile)
- while 1:
- code, data_len, data = bk.get_record_parts()
- if code == XL_EOF:
- break
- if DEBUG: print("---> found EOF", file=self.logfile)
- elif rc == XL_COUNTRY:
- bk.handle_country(data)
- elif rc == XL_LABELRANGES:
- pos = 0
- pos = unpack_cell_range_address_list_update_pos(
- self.row_label_ranges, data, pos, bv, addr_size=8,
- )
- pos = unpack_cell_range_address_list_update_pos(
- self.col_label_ranges, data, pos, bv, addr_size=8,
- )
- assert pos == data_len
- elif rc == XL_ARRAY:
- row1x, rownx, col1x, colnx, array_flags, tokslen = \
- local_unpack("<HHBBBxxxxxH", data[:14])
- if verbose_formulas:
- print("ARRAY:", row1x, rownx, col1x, colnx, array_flags)
- dump_formula(bk, data[14:], tokslen, bv, reldelta=0, verbose=1)
- elif rc == XL_SHRFMLA:
- row1x, rownx, col1x, colnx, nfmlas, tokslen = \
- local_unpack("<HHBBxBH", data[:10])
- if verbose_formulas:
- print("SHRFMLA (main):", row1x, rownx, col1x, colnx, nfmlas)
- decompile_formula(bk, data[10:], tokslen, reldelta=0, verbose=1)
- elif rc == XL_CONDFMT:
- if not fmt_info: continue
- assert bv >= 80
- num_CFs, needs_recalc, browx1, browx2, bcolx1, bcolx2 = \
- unpack("<6H", data[0:12])
- if self.verbosity >= 1:
- fprintf(self.logfile,
- "\n*** WARNING: Ignoring CONDFMT (conditional formatting) record\n" \
- "*** in Sheet %d (%r).\n" \
- "*** %d CF record(s); needs_recalc_or_redraw = %d\n" \
- "*** Bounding box is %s\n",
- self.number, self.name, num_CFs, needs_recalc,
- rangename2d(browx1, browx2+1, bcolx1, bcolx2+1),
- )
- olist = [] # updated by the function
- pos = unpack_cell_range_address_list_update_pos(
- olist, data, 12, bv, addr_size=8)
- # print >> self.logfile, repr(result), len(result)
- if self.verbosity >= 1:
- fprintf(self.logfile,
- "*** %d individual range(s):\n" \
- "*** %s\n",
- len(olist),
- ", ".join([rangename2d(*coords) for coords in olist]),
- )
- elif rc == XL_CF:
- if not fmt_info: continue
- cf_type, cmp_op, sz1, sz2, flags = unpack("<BBHHi", data[0:10])
- font_block = (flags >> 26) & 1
- bord_block = (flags >> 28) & 1
- patt_block = (flags >> 29) & 1
- if self.verbosity >= 1:
- fprintf(self.logfile,
- "\n*** WARNING: Ignoring CF (conditional formatting) sub-record.\n" \
- "*** cf_type=%d, cmp_op=%d, sz1=%d, sz2=%d, flags=0x%08x\n" \
- "*** optional data blocks: font=%d, border=%d, pattern=%d\n",
- cf_type, cmp_op, sz1, sz2, flags,
- font_block, bord_block, patt_block,
- )
- # hex_char_dump(data, 0, data_len)
- pos = 12
- if font_block:
- (font_height, font_options, weight, escapement, underline,
- font_colour_index, two_bits, font_esc, font_underl) = \
- unpack("<64x i i H H B 3x i 4x i i i 18x", data[pos:pos+118])
- font_style = (two_bits > 1) & 1
- posture = (font_options > 1) & 1
- font_canc = (two_bits > 7) & 1
- cancellation = (font_options > 7) & 1
- if self.verbosity >= 1:
- fprintf(self.logfile,
- "*** Font info: height=%d, weight=%d, escapement=%d,\n" \
- "*** underline=%d, colour_index=%d, esc=%d, underl=%d,\n" \
- "*** style=%d, posture=%d, canc=%d, cancellation=%d\n",
- font_height, weight, escapement, underline,
- font_colour_index, font_esc, font_underl,
- font_style, posture, font_canc, cancellation,
- )
- pos += 118
- if bord_block:
- pos += 8
- if patt_block:
- pos += 4
- fmla1 = data[pos:pos+sz1]
- pos += sz1
- if verbose and sz1:
- fprintf(self.logfile,
- "*** formula 1:\n",
- )
- dump_formula(bk, fmla1, sz1, bv, reldelta=0, verbose=1)
- fmla2 = data[pos:pos+sz2]
- pos += sz2
- assert pos == data_len
- if verbose and sz2:
- fprintf(self.logfile,
- "*** formula 2:\n",
- )
- dump_formula(bk, fmla2, sz2, bv, reldelta=0, verbose=1)
- elif rc == XL_DEFAULTROWHEIGHT:
- if data_len == 4:
- bits, self.default_row_height = unpack("<HH", data[:4])
- elif data_len == 2:
- self.default_row_height, = unpack("<H", data)
- bits = 0
- fprintf(self.logfile,
- "*** WARNING: DEFAULTROWHEIGHT record len is 2, " \
- "should be 4; assuming BIFF2 format\n")
- else:
- bits = 0
- fprintf(self.logfile,
- "*** WARNING: DEFAULTROWHEIGHT record len is %d, " \
- "should be 4; ignoring this record\n",
- data_len)
- self.default_row_height_mismatch = bits & 1
- self.default_row_hidden = (bits >> 1) & 1
- self.default_additional_space_above = (bits >> 2) & 1
- self.default_additional_space_below = (bits >> 3) & 1
- elif rc == XL_MERGEDCELLS:
- if not fmt_info: continue
- pos = unpack_cell_range_address_list_update_pos(
- self.merged_cells, data, 0, bv, addr_size=8)
- if verbose:
- fprintf(self.logfile,
- "MERGEDCELLS: %d ranges\n", int_floor_div(pos - 2, 8))
- assert pos == data_len, \
- "MERGEDCELLS: pos=%d data_len=%d" % (pos, data_len)
- elif rc == XL_WINDOW2:
- if bv >= 80:
- (options,
- self.first_visible_rowx, self.first_visible_colx,
- self.gridline_colour_index,
- self.cached_page_break_preview_mag_factor,
- self.cached_normal_view_mag_factor
- ) = unpack("<HHHHxxHH", data[:14])
- else: # BIFF3-7
- (options,
- self.first_visible_rowx, self.first_visible_colx,
- ) = unpack("<HHH", data[:6])
- self.gridline_colour_rgb = unpack("<BBB", data[6:9])
- self.gridline_colour_index = \
- nearest_colour_index(
- self.book.colour_map,
- self.gridline_colour_rgb,
- debug=0)
- self.cached_page_break_preview_mag_factor = 0 # default (60%)
- self.cached_normal_view_mag_factor = 0 # default (100%)
- # options -- Bit, Mask, Contents:
- # 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 (6.71) describes unfrozen or frozen panes.
- for attr, _unused_defval in _WINDOW2_options:
- setattr(self, attr, options & 1)
- options >>= 1
- # print "WINDOW2: visible=%d selected=%d" \
- # % (self.sheet_visible, self.sheet_selected)
- #### all of the following are for BIFF <= 4W
- elif bv <= 45:
- if rc == XL_FORMAT or rc == XL_FORMAT2:
- bk.handle_format(data, rc)
- elif rc == XL_FONT or rc == XL_FONT_B3B4:
- bk.handle_font(data)
- elif rc == XL_STYLE:
- if not self.book._xf_epilogue_done:
- self.book.xf_epilogue()
- bk.handle_style(data)
- elif rc == XL_PALETTE:
- bk.handle_palette(data)
- elif rc == XL_BUILTINFMTCOUNT:
- bk.handle_builtinfmtcount(data)
- elif rc == XL_XF4 or rc == XL_XF3 or rc == XL_XF2: #### N.B. not XL_XF
- bk.handle_xf(data)
- elif rc == XL_DATEMODE:
- bk.handle_datemode(data)
- elif rc == XL_CODEPAGE:
- bk.handle_codepage(data)
- elif rc == XL_FILEPASS:
- bk.handle_filepass(data)
- elif rc == XL_WRITEACCESS:
- bk.handle_writeaccess(data)
- elif rc == XL_IXFE:
- self._ixfe = local_unpack('<H', data)[0]
- elif rc == XL_NUMBER_B2:
- rowx, colx, cell_attr, d = local_unpack('<HH3sd', data)
- self_put_number_cell(rowx, colx, d, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
- elif rc == XL_INTEGER:
- rowx, colx, cell_attr, d = local_unpack('<HH3sH', data)
- self_put_number_cell(rowx, colx, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
- elif rc == XL_LABEL_B2:
- rowx, colx, cell_attr = local_unpack('<HH3s', data[0:7])
- strg = unpack_string(data, 7, bk.encoding or bk.derive_encoding(), lenlen=1)
- self_put_cell(rowx, colx, XL_CELL_TEXT, strg, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
- elif rc == XL_BOOLERR_B2:
- rowx, colx, cell_attr, value, is_err = local_unpack('<HH3sBB', data)
- cellty = (XL_CELL_BOOLEAN, XL_CELL_ERROR)[is_err]
- # if DEBUG: print "XL_BOOLERR_B2", rowx, colx, cell_attr, value, is_err
- self.put_cell(rowx, colx, cellty, value, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
- elif rc == XL_BLANK_B2:
- if not fmt_info: continue
- rowx, colx, cell_attr = local_unpack('<HH3s', data[:7])
- self_put_blank_cell(rowx, colx, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
- elif rc == XL_EFONT:
- bk.handle_efont(data)
- elif rc == XL_ROW_B2:
- if not fmt_info: continue
- rowx, bits1, has_defaults = local_unpack('<H4xH2xB', data[0:11])
- if not(0 <= rowx < self.utter_max_rows):
- print("*** NOTE: ROW_B2 record has row index %d; " \
- "should have 0 <= rowx < %d -- record ignored!" \
- % (rowx, self.utter_max_rows), file=self.logfile)
- continue
- r = Rowinfo()
- r.height = bits1 & 0x7fff
- r.has_default_height = (bits1 >> 15) & 1
- r.outline_level = 0
- r.outline_group_starts_ends = 0
- r.hidden = 0
- r.height_mismatch = 0
- r.has_default_xf_index = has_defaults & 1
- r.additional_space_above = 0
- r.additional_space_below = 0
- if not r.has_default_xf_index:
- r.xf_index = -1
- elif data_len == 18:
- # Seems the XF index in the cell_attr is dodgy
- xfx = local_unpack('<H', data[16:18])[0]
- r.xf_index = self.fixed_BIFF2_xfindex(cell_attr=None, rowx=rowx, colx=-1, true_xfx=xfx)
- else:
- cell_attr = data[13:16]
- r.xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx, colx=-1)
- self.rowinfo_map[rowx] = r
- if 0 and r.xf_index > -1:
- fprintf(self.logfile,
- "**ROW %d %d %d\n",
- self.number, rowx, r.xf_index)
- if verbose_rows:
- print('ROW_B2', rowx, bits1, has_defaults, file=self.logfile)
- r.dump(self.logfile,
- header="--- sh #%d, rowx=%d ---" % (self.number, rowx))
- elif rc == XL_COLWIDTH: # BIFF2 only
- if not fmt_info: continue
- first_colx, last_colx, width\
- = local_unpack("<BBH", data[:4])
- if not(first_colx <= last_colx):
- print("*** NOTE: COLWIDTH record has first col index %d, last %d; " \
- "should have first <= last -- record ignored!" \
- % (first_colx, last_colx), file=self.logfile)
- continue
- for colx in range(first_colx, last_colx+1):
- if colx in self.colinfo_map:
- c = self.colinfo_map[colx]
- else:
- c = Colinfo()
- self.colinfo_map[colx] = c
- c.width = width
- if verbose:
- fprintf(
- self.logfile,
- "COLWIDTH sheet #%d cols %d-%d: wid=%d\n",
- self.number, first_colx, last_colx, width
- )
- elif rc == XL_COLUMNDEFAULT: # BIFF2 only
- if not fmt_info: continue
- first_colx, last_colx = local_unpack("<HH", data[:4])
- #### Warning OOo docs wrong; first_colx <= colx < last_colx
- if verbose:
- fprintf(
- self.logfile,
- "COLUMNDEFAULT sheet #%d cols in range(%d, %d)\n",
- self.number, first_colx, last_colx
- )
- if not(0 <= first_colx < last_colx <= 256):
- print("*** NOTE: COLUMNDEFAULT record has first col index %d, last %d; " \
- "should have 0 <= first < last <= 256" \
- % (first_colx, last_colx), file=self.logfile)
- last_colx = min(last_colx, 256)
- for colx in range(first_colx, last_colx):
- offset = 4 + 3 * (colx - first_colx)
- cell_attr = data[offset:offset+3]
- xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx=-1, colx=colx)
- if colx in self.colinfo_map:
- c = self.colinfo_map[colx]
- else:
- c = Colinfo()
- self.colinfo_map[colx] = c
- c.xf_index = xf_index
- if not eof_found:
- raise XLRDError("Sheet %d (%r) missing EOF record" \
- % (self.number, self.name))
- self.tidy_dimensions()
- bk._position = oldpos
- return 1
-
- def fixed_BIFF2_xfindex(self, cell_attr, rowx, colx, true_xfx=None):
- DEBUG = 0
- verbose = DEBUG or self.verbosity >= 2
- if self.biff_version == 21:
- if self._xf_index_to_xl_type_map:
- if true_xfx is not None:
- xfx = true_xfx
- else:
- xfx = cell_attr[0] & 0x3F
- if xfx == 0x3F:
- if self._ixfe is None:
- raise XLRDError("BIFF2 cell record has XF index 63 but no preceding IXFE record.")
- xfx = self._ixfe
- # OOo docs are capable of interpretation that each
- # cell record is preceded immediately by its own IXFE record.
- # Empirical evidence is that (sensibly) an IXFE record applies to all
- # following cell records until another IXFE comes along.
- return xfx
- # Have either Excel 2.0, or broken 2.1 w/o XF records -- same effect.
- self.biff_version = self.book.biff_version = 20
- #### check that XF slot in cell_attr is zero
- xfx_slot = cell_attr[0] & 0x3F
- assert xfx_slot == 0
- xfx = self._cell_attr_to_xfx.get(cell_attr)
- if xfx is not None:
- return xfx
- if verbose:
- fprintf(self.logfile, "New cell_attr %r at (%r, %r)\n", cell_attr, rowx, colx)
- book = self.book
- xf = self.fake_XF_from_BIFF20_cell_attr(cell_attr)
- xfx = len(book.xf_list)
- xf.xf_index = xfx
- book.xf_list.append(xf)
- if verbose:
- xf.dump(self.logfile, header="=== Faked XF %d ===" % xfx, footer="======")
- if xf.format_key not in book.format_map:
- msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n"
- fprintf(self.logfile, msg,
- xf.xf_index, xf.format_key, xf.format_key)
- fmt = Format(xf.format_key, FUN, "General")
- book.format_map[xf.format_key] = fmt
- while len(book.format_list) <= xf.format_key:
- book.format_list.append(fmt)
- cellty_from_fmtty = {
- FNU: XL_CELL_NUMBER,
- FUN: XL_CELL_NUMBER,
- FGE: XL_CELL_NUMBER,
- FDT: XL_CELL_DATE,
- FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text.
- }
- fmt = book.format_map[xf.format_key]
- cellty = cellty_from_fmtty[fmt.type]
- self._xf_index_to_xl_type_map[xf.xf_index] = cellty
- self._cell_attr_to_xfx[cell_attr] = xfx
- return xfx
-
- def fake_XF_from_BIFF20_cell_attr(self, cell_attr):
- from .formatting import XF, XFAlignment, XFBorder, XFBackground, XFProtection
- xf = XF()
- xf.alignment = XFAlignment()
- xf.alignment.indent_level = 0
- xf.alignment.shrink_to_fit = 0
- xf.alignment.text_direction = 0
- xf.border = XFBorder()
- xf.border.diag_up = 0
- xf.border.diag_down = 0
- xf.border.diag_colour_index = 0
- xf.border.diag_line_style = 0 # no line
- xf.background = XFBackground()
- xf.protection = XFProtection()
- (prot_bits, font_and_format, halign_etc) = unpack('<BBB', cell_attr)
- xf.format_key = font_and_format & 0x3F
- xf.font_index = (font_and_format & 0xC0) >> 6
- upkbits(xf.protection, prot_bits, (
- (6, 0x40, 'cell_locked'),
- (7, 0x80, 'formula_hidden'),
- ))
- xf.alignment.hor_align = halign_etc & 0x07
- for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')):
- if halign_etc & mask:
- colour_index, line_style = 8, 1 # black, thin
- else:
- colour_index, line_style = 0, 0 # none, none
- setattr(xf.border, side + '_colour_index', colour_index)
- setattr(xf.border, side + '_line_style', line_style)
- bg = xf.background
- if halign_etc & 0x80:
- bg.fill_pattern = 17
- else:
- bg.fill_pattern = 0
- bg.background_colour_index = 9 # white
- bg.pattern_colour_index = 8 # black
- xf.parent_style_index = 0 # ???????????
- xf.alignment.vert_align = 2 # bottom
- xf.alignment.rotation = 0
- for attr_stem in ("format", "font", "alignment", "border", \
- "background", "protection"):
- attr = "_%s_flag" % attr_stem
- setattr(xf, attr, 1)
- return xf
-
- def req_fmt_info(self):
- if not self.formatting_info:
- raise XLRDError("Feature requires open_workbook(..., formatting_info=True)")
-
- # Determine column display width.
- # - New in version 0.6.1
- #
- # @param colx Index of the queried column, range 0 to 255.
- # Note that it is possible to find out the width that will be used to display
- # columns with no cell information e.g. column IV (colx=255).
- # @return The column width that will be used for displaying
- # the given column by Excel, in units of 1/256th of the width of a
- # standard character (the digit zero in the first font).
-
- def computed_column_width(self, colx):
- self.req_fmt_info()
- if self.biff_version >= 80:
- colinfo = self.colinfo_map.get(colx, None)
- if colinfo is not None:
- return colinfo.width
- if self.standardwidth is not None:
- return self.standardwidth
- elif self.biff_version >= 40:
- if self.gcw[colx]:
- if self.standardwidth is not None:
- return self.standardwidth
- else:
- colinfo = self.colinfo_map.get(colx, None)
- if colinfo is not None:
- return colinfo.width
- elif self.biff_version == 30:
- colinfo = self.colinfo_map.get(colx, None)
- if colinfo is not None:
- return colinfo.width
- # All roads lead to Rome and the DEFCOLWIDTH ...
- if self.defcolwidth is not None:
- return self.defcolwidth * 256
- return 8 * 256 # 8 is what Excel puts in a DEFCOLWIDTH record
-
- def handle_msodrawingetc(self, recid, data_len, data):
- if not OBJ_MSO_DEBUG:
- return
- DEBUG = 1
- if self.biff_version < 80:
- return
- o = MSODrawing()
- pos = 0
- while pos < data_len:
- tmp, fbt, cb = unpack('<HHI', data[pos:pos+8])
- ver = tmp & 0xF
- inst = (tmp >> 4) & 0xFFF
- if ver == 0xF:
- ndb = 0 # container
- else:
- ndb = cb
- if DEBUG:
- hex_char_dump(data, pos, ndb + 8, base=0, fout=self.logfile)
- fprintf(self.logfile,
- "fbt:0x%04X inst:%d ver:0x%X cb:%d (0x%04X)\n",
- fbt, inst, ver, cb, cb)
- if fbt == 0xF010: # Client Anchor
- assert ndb == 18
- (o.anchor_unk,
- o.anchor_colx_lo, o.anchor_rowx_lo,
- o.anchor_colx_hi, o.anchor_rowx_hi) = unpack('<Hiiii', data[pos+8:pos+8+ndb])
- elif fbt == 0xF011: # Client Data
- # must be followed by an OBJ record
- assert cb == 0
- assert pos + 8 == data_len
- else:
- pass
- pos += ndb + 8
- else:
- # didn't break out of while loop
- assert pos == data_len
- if DEBUG:
- o.dump(self.logfile, header="=== MSODrawing ===", footer= " ")
-
-
- def handle_obj(self, data):
- if not OBJ_MSO_DEBUG:
- return
- DEBUG = 1
- if self.biff_version < 80:
- return
- o = MSObj()
- data_len = len(data)
- pos = 0
- if DEBUG:
- fprintf(self.logfile, "... OBJ record ...\n")
- while pos < data_len:
- ft, cb = unpack('<HH', data[pos:pos+4])
- if DEBUG:
- hex_char_dump(data, pos, cb, base=0, fout=self.logfile)
- if ft == 0x15: # ftCmo ... s/b first
- assert pos == 0
- o.type, o.id, option_flags = unpack('<HHH', data[pos+4:pos+10])
- upkbits(o, option_flags, (
- ( 0, 0x0001, 'locked'),
- ( 4, 0x0010, 'printable'),
- ( 8, 0x0100, 'autofilter'), # not documented in Excel 97 dev kit
- ( 9, 0x0200, 'scrollbar_flag'), # not documented in Excel 97 dev kit
- (13, 0x2000, 'autofill'),
- (14, 0x4000, 'autoline'),
- ))
- elif ft == 0x00:
- assert cb == 0
- assert pos + 4 == data_len
- elif ft == 0x0C: # Scrollbar
- values = unpack('<5H', data[pos+8:pos+18])
- for value, tag in zip(values, ('value', 'min', 'max', 'inc', 'page')):
- setattr(o, 'scrollbar_' + tag, value)
- elif ft == 0x0D: # "Notes structure" [used for cell comments]
- pass ############## not documented in Excel 97 dev kit
- elif ft == 0x13: # list box data
- if o.autofilter: # non standard exit. NOT documented
- break
- else:
- pass
- pos += cb + 4
- else:
- # didn't break out of while loop
- assert pos == data_len
- if DEBUG:
- o.dump(self.logfile, header="=== MSOBj ===", footer= " ")
-
- def handle_note(self, data):
- if not OBJ_MSO_DEBUG:
- return
- DEBUG = 1
- if self.biff_version < 80:
- return
- if DEBUG:
- fprintf(self.logfile, '... NOTE record ...\n')
- hex_char_dump(data, 0, len(data), base=0, fout=self.logfile)
- o = MSNote()
- data_len = len(data)
- o.rowx, o.colx, option_flags, o.object_id = unpack('<4H', data[:8])
- o.show = (option_flags >> 1) & 1
- # Docs say NULL [sic] bytes padding between string count and string data
- # to ensure that string is word-aligned. Appears to be nonsense.
- # There also seems to be a random(?) byte after the string (not counted in the
- # string length.
- o.original_author, endpos = unpack_unicode_update_pos(data, 8, lenlen=2)
- assert endpos == data_len - 1
- o.last_byte = data[-1]
- if DEBUG:
- o.dump(self.logfile, header="=== MSNote ===", footer= " ")
-
- def handle_txo(self, data):
- if not OBJ_MSO_DEBUG:
- return
- DEBUG = 1
- if self.biff_version < 80:
- return
- o = MSTxo()
- data_len = len(data)
- option_flags, o.rot, cchText, cbRuns = unpack('<HH6xHH4x', data)
- upkbits(o, option_flags, (
- (3, 0x000E, 'horz_align'),
- (6, 0x0070, 'vert_align'),
- (9, 0x0200, 'lock_text'),
- ))
- rc2, data2_len, data2 = self.book.get_record_parts()
- assert rc2 == XL_CONTINUE
- o.text, endpos = unpack_unicode_update_pos(data2, 0, known_len=cchText)
- assert endpos == data2_len
- rc3, data3_len, data3 = self.book.get_record_parts()
- assert rc3 == XL_CONTINUE
- # ignore the formatting runs for the moment
- if DEBUG:
- o.dump(self.logfile, header="=== MSTxo ===", footer= " ")
-
- def handle_feat11(self, data):
- if not OBJ_MSO_DEBUG:
- return
- # rt: Record type; this matches the BIFF rt in the first two bytes of the record; =0872h
- # grbitFrt: FRT cell reference flag (see table below for details)
- # Ref0: Range reference to a worksheet cell region if grbitFrt=1 (bitFrtRef). Otherwise blank.
- # isf: Shared feature type index =5 for Table
- # fHdr: =0 since this is for feat not feat header
- # reserved0: Reserved for future use =0 for Table
- # cref: Count of ref ranges this feature is on
- # cbFeatData: Count of byte for the current feature data.
- # reserved1: =0 currently not used
- # Ref1: Repeat of Ref0. UNDOCUMENTED
- rt, grbitFrt, Ref0, isf, fHdr, reserved0, cref, cbFeatData, reserved1, Ref1 = unpack('<HH8sHBiHiH8s', data[0:35])
- assert reserved0 == 0
- assert reserved1 == 0
- assert isf == 5
- assert rt == 0x872
- assert fHdr == 0
- assert Ref1 == Ref0
- print("FEAT11: grbitFrt=%d Ref0=%r cref=%d cbFeatData=%d" % (grbitFrt, Ref0, cref, cbFeatData))
- # lt: Table data source type:
- # =0 for Excel Worksheet Table =1 for read-write SharePoint linked List
- # =2 for XML mapper Table =3 for Query Table
- # idList: The ID of the Table (unique per worksheet)
- # crwHeader: How many header/title rows the Table has at the top
- # crwTotals: How many total rows the Table has at the bottom
- # idFieldNext: Next id to try when assigning a unique id to a new field
- # cbFSData: The size of the Fixed Data portion of the Table data structure.
- # rupBuild: the rupBuild that generated the record
- # unusedShort: UNUSED short that can be used later. The value is reserved during round-tripping.
- # listFlags: Collection of bit flags: (see listFlags' bit setting table below for detail.)
- # lPosStmCache: Table data stream position of cached data
- # cbStmCache: Count of bytes of cached data
- # cchStmCache: Count of characters of uncompressed cached data in the stream
- # lem: Table edit mode (see List (Table) Editing Mode (lem) setting table below for details.)
- # rgbHashParam: Hash value for SharePoint Table
- # cchName: Count of characters in the Table name string rgbName
- (lt, idList, crwHeader, crwTotals, idFieldNext, cbFSData,
- rupBuild, unusedShort, listFlags, lPosStmCache, cbStmCache,
- cchStmCache, lem, rgbHashParam, cchName) = unpack('<iiiiiiHHiiiii16sH', data[35:35+66])
- print("lt=%d idList=%d crwHeader=%d crwTotals=%d idFieldNext=%d cbFSData=%d\n"\
- "rupBuild=%d unusedShort=%d listFlags=%04X lPosStmCache=%d cbStmCache=%d\n"\
- "cchStmCache=%d lem=%d rgbHashParam=%r cchName=%d" % (
- lt, idList, crwHeader, crwTotals, idFieldNext, cbFSData,
- rupBuild, unusedShort,listFlags, lPosStmCache, cbStmCache,
- cchStmCache, lem, rgbHashParam, cchName))
-
-class MSODrawing(BaseObject):
- pass
-
-class MSObj(BaseObject):
- pass
-
-class MSTxo(BaseObject):
- pass
-
-class MSNote(BaseObject):
- pass
-
-# === helpers ===
-
-def unpack_RK(rk_str):
- #(to_py3): flags = ord(rk_str[0])
- flags = rk_str[0]
- if flags & 2:
- # There's a SIGNED 30-bit integer in there!
- i, = unpack('<i', rk_str)
- i >>= 2 # div by 4 to drop the 2 flag bits
- if flags & 1:
- return i / 100.0
- return float(i)
- else:
- # It's the most significant 30 bits of an IEEE 754 64-bit FP number
- # (to_py3): replaced b'\0\0\0\0' + chr(flags & 252) + rk_str[1:4]
- _bytes = array('B', b'\0\0\0\0')
- _bytes.append(flags & 252)
- _bytes.extend(rk_str[1:4])
- d, = unpack('<d', _bytes)
- if flags & 1:
- d = d / 100.
- return d
-
-##### =============== Cell ======================================== #####
-
-cellty_from_fmtty = {
- FNU: XL_CELL_NUMBER,
- FUN: XL_CELL_NUMBER,
- FGE: XL_CELL_NUMBER,
- FDT: XL_CELL_DATE,
- FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text.
- }
-
-ctype_text = {
- XL_CELL_EMPTY: 'empty',
- XL_CELL_TEXT: 'text',
- XL_CELL_NUMBER: 'number',
- XL_CELL_DATE: 'xldate',
- XL_CELL_BOOLEAN: 'bool',
- XL_CELL_ERROR: 'error',
- XL_CELL_BLANK: 'blank',
- }
-
-# Contains the data for one cell -> see XFCell() class in the xfcell module.
-class Cell(XFCell):
- def __repr__(self):
- if not self.has_xf:
- return "%s:%r" % (ctype_text[self.ctype], self.value)
- else:
- return "%s:%r (XF:%r)" % (ctype_text[self.ctype], self.value, self.xf_index)
-
-# There is one and only one instance of an empty cell -- it's a singleton. This is it.
-# You may use a test like "acell is empty_cell".
-empty_cell = Cell(XL_CELL_EMPTY, '')
-
-##### =============== Colinfo and Rowinfo ============================== #####
-
-
-# Width and default formatting information that applies to one or
-# more columns in a sheet. Derived from COLINFO records.
-#
-#
-# Here is the default hierarchy for width, according to the OOo docs:
-#
-# In BIFF3, if a COLINFO record is missing for a column,
-# the width specified in the record DEFCOLWIDTH is used instead.
-#
-# In BIFF4-BIFF7, the width set in this [COLINFO] record is only used,
-# if the corresponding bit for this column is cleared in the GCW
-# record, otherwise the column width set in the DEFCOLWIDTH record
-# is used (the STANDARDWIDTH record is always ignored in this case [see footnote!]).
-#
-# In BIFF8, if a COLINFO record is missing for a column,
-# the width specified in the record STANDARDWIDTH is used.
-# If this [STANDARDWIDTH] record is also missing,
-# the column width of the record DEFCOLWIDTH is used instead.
-#
-# Footnote: The docs on the GCW record say this:
-#
-# If a bit is set, the corresponding column uses the width set in the STANDARDWIDTH
-# record. If a bit is cleared, the corresponding column uses the width set in the
-# COLINFO record for this column.
-#
-# If a bit is set, and the worksheet does not contain the STANDARDWIDTH record, or if
-# the bit is cleared, and the worksheet does not contain the COLINFO record, the DEFCOLWIDTH
-# record of the worksheet will be used instead.
-#
-# At the moment (2007-01-17) xlrd is going with the GCW version of the story.
-# Reference to the source may be useful: see the computed_column_width(colx) method
-# of the Sheet class.
-# - New in version 0.6.1
-
-class Colinfo(BaseObject):
- # Width of the column in 1/256 of the width of the zero character,
- # using default font (first FONT record in the file).
- width = 0
- # XF index to be used for formatting empty cells.
- xf_index = -1
- # 1 = column is hidden
- hidden = 0
- # Value of a 1-bit flag whose purpose is unknown
- # but is often seen set to 1
- bit1_flag = 0
- # Outline level of the column, in range(7).
- # (0 = no outline)
- outline_level = 0
- # 1 = column is collapsed
- collapsed = 0
-
-# Height and default formatting information that applies to a row in a sheet.
-# Derived from ROW records.
-# - New in version 0.6.1
-
-class Rowinfo(BaseObject):
- ##
- # Height of the row, in twips. One twip == 1/20 of a point
- height = 0
- ##
- # 0 = Row has custom height; 1 = Row has default height
- has_default_height = 0
- ##
- # Outline level of the row
- outline_level = 0
- ##
- # 1 = Outline group starts or ends here (depending on where the
- # outline buttons are located, see WSBOOL record [TODO ??]),
- # <i>and</i> is collapsed
- outline_group_starts_ends = 0
- ##
- # 1 = Row is hidden (manually, or by a filter or outline group)
- hidden = 0
- ##
- # 1 = Row height and default font height do not match
- height_mismatch = 0
- ##
- # 1 = the xf_index attribute is usable; 0 = ignore it
- has_default_xf_index = 0
- ##
- # Index to default XF record for empty cells in this row.
- # Don't use this if has_default_xf_index == 0.
- xf_index = -9999
- ##
- # 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.
- additional_space_above = 0
- ##
- # 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.
- additional_space_below = 0
diff --git a/tablib/packages/xlrd3/xfcell.py b/tablib/packages/xlrd3/xfcell.py deleted file mode 100644 index 213b4bd..0000000 --- a/tablib/packages/xlrd3/xfcell.py +++ /dev/null @@ -1,276 +0,0 @@ -# Author: mozman <mozman@gmx.at>
-# Purpose: xfcell -- cell with convenient xf function
-# Created: 04.12.2010
-# Copyright (C) 2010, Manfred Moitzi
-# License: BSD-style licence
-
-"""
-The XFCell() object contains the data for one cell.
-
-WARNING: You don't call this class yourself. You access Cell objects
-via methods of the Sheet object(s) that you found in the Book object that
-was returned when you called xlrd.open_workbook("myfile.xls").
-
-Cell objects have four attributes: `ctype` is an int, `value` (which depends
-on `ctype`), `xf_index` and `sheet`, a reference to the containing sheet. If
-**formatting_info** is not enabled when the workbook is opened, xf_index will
-be **None**.
-
-The following table describes the types of cells and how their values
-are represented in Python.
-
-=============== ===== ============ ==========================================
-Type symbol Const Python value Note
-=============== ===== ============ ==========================================
-XL_CELL_EMPTY 0 ""
-XL_CELL_TEXT 1 str
-XL_CELL_NUMBER 2 float
-XL_CELL_DATE 3 float
-XL_CELL_BOOLEAN 4 int 1 means TRUE, 0 means FALSE
-XL_CELL_ERROR 5 int representing internal Excel codes; for a
- text representation, refer to the supplied
- dictionary error_text_from_code
-XL_CELL_BLANK 6 "" this type will appear only when
- open_workbook(..., formatting_info=True)
- is used.
-=============== ===== ============ ==========================================
-"""
-
-import datetime
-
-from .xldate import xldate_as_tuple
-from .biffh import XL_CELL_DATE, BaseObject
-
-class XFCell(BaseObject):
- """ Extended Cell() class with convenient methods for easy access of cell
- properties.
- """
- __slots__ = ['sheet', 'ctype', 'value', 'xf']
-
- def __init__(self, ctype, value, xf_index=None, sheet=None):
- self.sheet = sheet
- self.ctype = ctype
- self.value = value
-
- if xf_index is not None:
- self.xf = self.book.xf_list[xf_index]
- else:
- self.xf = None
-
- @property
- def book(self):
- return self.sheet.book
-
- @property
- def has_xf(self):
- return (self.xf is not None)
-
- @property
- def xf_index(self):
- if self.has_xf:
- return self.xf.xf_index
- else:
- return None
-
- @property
- def parent_style(self):
- return self.book.xf_list[self.xf.parent_style_index]
-
- @property
- def is_datetime(self):
- return self.ctype == XL_CELL_DATE
-
- @property
- def has_date(self):
- if self.is_datetime:
- return self.value > 1.
- return False
-
- def get_color(self, index):
- return self.book.colour_map[index]
-
- def datetime(self):
- """ Returns a datetime.datetime object if cell type is XL_CELL_DATE
- else raises a TypeError, and raises ValueError if the the cell has
- not date value (only time value is present).
- """
- if self.is_datetime:
- if self.has_date:
- date = xldate_as_tuple(self.value, self.book.datemode)
- return datetime.datetime(*date)
- else:
- raise ValueError("Cell has no date value.")
- else:
- raise TypeError("Cell is not a XL_CELL_DATE.")
-
- def date(self):
- """ Returns a datetime.date object if cell type is XL_CELL_DATE
- else raises a **TypeError**. Raises **ValueError** if the cell
- doesn't have a date value (only time value is present).
- """
- dt = self.datetime()
- return dt.date()
-
- def time(self):
- """ Returns a datetime.time object if cell type is XL_CELL_DATE else
- raises a TypeError.
- """
- if self.is_datetime:
- date = xldate_as_tuple(self.value, self.book.datemode)
- return datetime.time(date[3], date[4], date[5])
- else:
- raise TypeError("Cell is not a XL_CELL_DATE.")
-
- #
- # access the XFBackground() class
- #
-
- @property
- def background(self):
- if self.xf.is_style and \
- self.xf._background_flag == 0:
- return self.xf.background
- elif self.xf._background_flag:
- return self.xf.background
- else:
- return self.parent_style.background
-
- def background_color(self):
- """ Get cell background-color as 3-tuple. """
- color_index = self.xf.background.background_colour_index
- return self.get_color(color_index)
-
- def fill_pattern(self):
- return self.xf.background.fill_pattern
-
- def pattern_color(self):
- color_index = self.xf.background.pattern_colour_index
- return self.get_color(color_index)
-
- #
- # access the Font() class
- #
-
- @property
- def font_index(self):
- if self.xf.is_style and \
- self.xf._font_flag == 0:
- return self.xf.font_index
- elif self.xf._font_flag:
- return self.xf.font_index
- else:
- return self.parent_style.font_index
-
- @property
- def font(self):
- """ Get the Font() class. """
- return self.book.font_list[self.xf.font_index]
-
- def font_color(self):
- """ Get cell foreground-color as 3-tuple. """
- return self.get_color(self.font.colour_index)
-
- #
- # access the Format() class
- #
-
- @property
- def format_key(self):
- if self.xf.is_style and \
- self.xf._format_flag == 0:
- return self.xf.format_key
- elif self.xf._format_flag:
- return self.xf.format_key
- else:
- return self.parent_style.format_key
-
- @property
- def format(self):
- """ Get the Format() class. """
- return self.book.format_map[self.format_key]
-
- def format_str(self):
- """ Get the associated 'format_str'. """
- return self.format.format_str
-
- #
- # access the XFAligment() class
- #
-
- @property
- def alignment(self):
- if self.xf.is_style and \
- self.xf._alignment_flag == 0:
- return self.xf.alignment
- elif self.xf._alignment_flag:
- return self.xf.alignment
- else:
- return self.parent_style.alignment
-
- #
- # access the XFBorder() class
- #
-
- @property
- def border(self):
- if self.xf.is_style and \
- self.xf._border_flag == 0:
- return self.xf.border
- elif self.xf._border_flag:
- return self.xf.border
- else:
- return self.parent_style.border
-
- def bordercolors(self):
- """ Get border color as dict of rgb-color-tuples. """
- border = self.border
- return {
- 'top': self.get_color(border.top_colour_index),
- 'bottom': self.get_color(border.bottom_colour_index),
- 'left': self.get_color(border.left_colour_index),
- 'right': self.get_color(border.right_colour_index),
- 'diag': self.get_color(border.diag_colour_index),
- }
-
- def borderstyles(self):
- """ Get border styles as dict of ints. """
- border = self.border
- return {
- 'top': border.top_line_style,
- 'bottom': border.bottom_line_style,
- 'left': border.left_line_style,
- 'right': border.right_line_style,
- 'diag': border.diag_line_style,
- }
-
- @property
- def has_up_diag(self):
- """ Draw a line across the cell from bottom left to top right. """
- return bool(self.border.diag_up)
-
- @property
- def has_down_diag(self):
- """ Draw a line across the cell from top left to bottom right. """
- return bool(self.border.diag_down)
-
- #
- # access the XFProtection() class
- #
-
- @property
- def protection(self):
- if self.xf.is_style and \
- self.xf._protection_flag == 0:
- return self.xf.protection
- elif self.xf._protection_flag:
- return self.xf.protection
- else:
- return self.parent_style.protection
-
- @property
- def is_cell_locked(self):
- return bool(self.protection.cell_locked)
-
- @property
- def is_formula_hidden(self):
- return bool(self.protection.cell_locked)
diff --git a/tablib/packages/xlrd3/xfconst.py b/tablib/packages/xlrd3/xfconst.py deleted file mode 100644 index 24f6533..0000000 --- a/tablib/packages/xlrd3/xfconst.py +++ /dev/null @@ -1,84 +0,0 @@ -# Author: mozman <mozman@gmx.at>
-# Purpose: xfconst -- xf constants
-# Created: 05.12.2010
-# Copyright (C) 2010, Manfred Moitzi
-# License: BSD-style licence
-
-# excelfileformat section 5.115.1 pg. 219
-HOR_ALIGN_GENERAL = 0
-HOR_ALIGN_LEFT = 1
-HOR_ALIGN_CENTRED = 2
-HOR_ALIGN_RIGHT = 3
-HOR_ALIGN_FILLED = 4
-HOR_ALIGN_JUSTIFIED = 5
-HOR_ALIGN_CENTRED_ACROSS_SELECTION = 6
-HOR_ALIGN_DISTRIBUTED = 7
-
-# excelfileformat section 5.115.1 pg. 220
-VERT_ALIGN_TOP = 0
-VERT_ALIGN_CENTRED = 1
-VERT_ALIGN_BOTTOM = 2
-VERT_ALIGN_JUSTIFIED = 3
-VERT_ALIGN_DISTRIBUTED = 4
-
-# excelfileformat section 5.115.1 pg. 220
-ORIENTATION_NONE = 0
-ORIENTATION_STACKED = 1
-ORIENTATION_90_COUNTERCLOCKWISE = 2
-ORIENTATION_90_CLOCKWISE = 3
-
-# excelfileformat section 5.115.1 pg. 220
-ROTATION_NONE = 0
-ROTATION_STACKED = 255
-# other values:
-# Value Description
-# ======= =================================
-# 1-90 1 to 90 degrees counterclockwise
-# 91-180 1 to 90 degrees clockwise
-
-# excelfileformat section 2.5.11 Line Styles for Cell Borders pg. 24
-LS_NOLINE = 0
-
-# solid line
-LS_THIN = 1
-
-# solid line
-LS_MEDIUM = 2
-
-# - - - - - - - - -
-LS_DASHED = 3
-
-# .................
-LS_DOTTED = 4
-
-# solid line
-LS_THICK = 5
-
-# =================
-LS_DOUBLE = 6
-
-# very thin dotted
-LS_HAIR = 7
-
-# - - - - - - - - -
-LS_MEDIUM_DASHED = 8
-
-# - . - . - . - . -
-LS_THIN_DASH_DOTTED = 9
-
-# - . - . - . - . -
-LS_MEDIUM_DASH_DOTTED = 10
-
-# - .. - .. - .. - .. -
-LS_THIN_DASH_DOT_DOTTED = 11
-
-# - .. - .. - .. - .. -
-LS_MEDIUM_DASH_DOT_DOTTED = 12
-
-# \\\ . \\\ . \\\ . \\\ . \\\
-LS_SLANTED_MEDIUM_DASH_DOTTED = 13
-
-
-
-
-
diff --git a/tablib/packages/xlrd3/xldate.py b/tablib/packages/xlrd3/xldate.py deleted file mode 100644 index 634709d..0000000 --- a/tablib/packages/xlrd3/xldate.py +++ /dev/null @@ -1,167 +0,0 @@ -# No part of the content of this file was derived from the works of David Giffin.
-#
-# Copyright © 2005-2008 Stephen John Machin, Lingfo Pty Ltd
-# This module is part of the xlrd3 package, which is released under a
-# BSD-style licence.
-#
-# Provides function(s) for dealing with Microsoft Excel â„¢ dates.
-#
-# 2008-10-18 SJM Fix bug in xldate_from_date_tuple (affected some years after 2099)
-#
-# The conversion from days to (year, month, day) starts with
-# an integral "julian day number" aka JDN.
-# FWIW, JDN 0 corresponds to noon on Monday November 24 in Gregorian year -4713.
-# More importantly:
-# Noon on Gregorian 1900-03-01 (day 61 in the 1900-based system) is JDN 2415080.0
-# Noon on Gregorian 1904-01-02 (day 1 in the 1904-based system) is JDN 2416482.0
-
-def ifd(x, y):
- return divmod(x, y)[0]
-
-_JDN_delta = (2415080 - 61, 2416482 - 1)
-assert _JDN_delta[1] - _JDN_delta[0] == 1462
-
-class XLDateError(ValueError): pass
-
-class XLDateNegative(XLDateError): pass
-class XLDateAmbiguous(XLDateError): pass
-class XLDateTooLarge(XLDateError): pass
-class XLDateBadDatemode(XLDateError): pass
-class XLDateBadTuple(XLDateError): pass
-
-_XLDAYS_TOO_LARGE = (2958466, 2958466 - 1462) # This is equivalent to 10000-01-01
-
-# Convert an Excel number (presumed to represent a date, a datetime or a time) into
-# a tuple suitable for feeding to datetime or mx.DateTime constructors.
-# @param xldate The Excel number
-# @param datemode 0: 1900-based, 1: 1904-based.
-# <br>WARNING: when using this function to
-# interpret the contents of a workbook, you should pass in the Book.datemode
-# attribute of that workbook. Whether
-# the workbook has ever been anywhere near a Macintosh is irrelevant.
-# @return Gregorian (year, month, day, hour, minute, nearest_second).
-# <br>Special case: if 0.0 <= xldate < 1.0, it is assumed to represent a time;
-# (0, 0, 0, hour, minute, second) will be returned.
-# <br>Note: 1904-01-01 is not regarded as a valid date in the datemode 1 system; its "serial number"
-# is zero.
-# @throws XLDateNegative xldate < 0.00
-# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0)
-# @throws XLDateTooLarge Gregorian year 10000 or later
-# @throws XLDateBadDatemode datemode arg is neither 0 nor 1
-# @throws XLDateError Covers the 4 specific errors
-
-def xldate_as_tuple(xldate, datemode):
- if datemode not in (0, 1):
- raise XLDateBadDatemode(datemode)
- if xldate == 0.00:
- return (0, 0, 0, 0, 0, 0)
- if xldate < 0.00:
- raise XLDateNegative(xldate)
- xldays = int(xldate)
- frac = xldate - xldays
- seconds = int(round(frac * 86400.0))
- assert 0 <= seconds <= 86400
- if seconds == 86400:
- hour = minute = second = 0
- xldays += 1
- else:
- # second = seconds % 60; minutes = seconds // 60
- minutes, second = divmod(seconds, 60)
- # minute = minutes % 60; hour = minutes // 60
- hour, minute = divmod(minutes, 60)
- if xldays >= _XLDAYS_TOO_LARGE[datemode]:
- raise XLDateTooLarge(xldate)
-
- if xldays == 0:
- return (0, 0, 0, hour, minute, second)
-
- if xldays < 61 and datemode == 0:
- raise XLDateAmbiguous(xldate)
-
- jdn = xldays + _JDN_delta[datemode]
- yreg = (ifd(ifd(jdn * 4 + 274277, 146097) * 3, 4) + jdn + 1363) * 4 + 3
- mp = ifd(yreg % 1461, 4) * 535 + 333
- d = ifd(mp % 16384, 535) + 1
- # mp /= 16384
- mp >>= 14
- if mp >= 10:
- return (ifd(yreg, 1461) - 4715, mp - 9, d, hour, minute, second)
- else:
- return (ifd(yreg, 1461) - 4716, mp + 3, d, hour, minute, second)
-
-# === conversions from date/time to xl numbers
-
-def _leap(y):
- if y % 4: return 0
- if y % 100: return 1
- if y % 400: return 0
- return 1
-
-_days_in_month = (None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
-
-# Convert a date tuple (year, month, day) to an Excel date.
-# @param year Gregorian year.
-# @param month 1 <= month <= 12
-# @param day 1 <= day <= last day of that (year, month)
-# @param datemode 0: 1900-based, 1: 1904-based.
-# @throws XLDateAmbiguous The 1900 leap-year problem (datemode == 0 and 1.0 <= xldate < 61.0)
-# @throws XLDateBadDatemode datemode arg is neither 0 nor 1
-# @throws XLDateBadTuple (year, month, day) is too early/late or has invalid component(s)
-# @throws XLDateError Covers the specific errors
-
-def xldate_from_date_tuple(datetuple, datemode):
-
- (year, month, day) = datetuple
- if datemode not in (0, 1):
- raise XLDateBadDatemode(datemode)
-
- if year == 0 and month == 0 and day == 0:
- return 0.00
-
- if not (1900 <= year <= 9999):
- raise XLDateBadTuple("Invalid year: %r" % ((year, month, day),))
- if not (1 <= month <= 12):
- raise XLDateBadTuple("Invalid month: %r" % ((year, month, day),))
- if day < 1 \
- or (day > _days_in_month[month] and not(day == 29 and month == 2 and _leap(year))):
- raise XLDateBadTuple("Invalid day: %r" % ((year, month, day),))
-
- Yp = year + 4716
- M = month
- if M <= 2:
- Yp = Yp - 1
- Mp = M + 9
- else:
- Mp = M - 3
- jdn = ifd(1461 * Yp, 4) + ifd(979 * Mp + 16, 32) + \
- day - 1364 - ifd(ifd(Yp + 184, 100) * 3, 4)
- xldays = jdn - _JDN_delta[datemode]
- if xldays <= 0:
- raise XLDateBadTuple("Invalid (year, month, day): %r" % ((year, month, day),))
- if xldays < 61 and datemode == 0:
- raise XLDateAmbiguous("Before 1900-03-01: %r" % ((year, month, day),))
- return float(xldays)
-
-# Convert a time tuple (hour, minute, second) to an Excel "date" value (fraction of a day).
-# @param hour 0 <= hour < 24
-# @param minute 0 <= minute < 60
-# @param second 0 <= second < 60
-# @throws XLDateBadTuple Out-of-range hour, minute, or second
-
-def xldate_from_time_tuple(timetuple):
- (hour, minute, second) = timetuple
- if 0 <= hour < 24 and 0 <= minute < 60 and 0 <= second < 60:
- return ((second / 60.0 + minute) / 60.0 + hour) / 24.0
- raise XLDateBadTuple("Invalid (hour, minute, second): %r" % ((hour, minute, second),))
-
-# Convert a datetime tuple (year, month, day, hour, minute, second) to an Excel date value.
-# For more details, refer to other xldate_from_*_tuple functions.
-# @param datetime_tuple (year, month, day, hour, minute, second)
-# @param datemode 0: 1900-based, 1: 1904-based.
-
-def xldate_from_datetime_tuple(datetime_tuple, datemode):
- return (
- xldate_from_date_tuple(datetime_tuple[:3], datemode)
- +
- xldate_from_time_tuple(datetime_tuple[3:])
- )
diff --git a/tablib/packages/xlwt/BIFFRecords.py b/tablib/packages/xlwt/BIFFRecords.py deleted file mode 100644 index 4660c03..0000000 --- a/tablib/packages/xlwt/BIFFRecords.py +++ /dev/null @@ -1,2393 +0,0 @@ -# -*- coding: cp1252 -*- -from struct import pack -from UnicodeUtils import upack1, upack2 -import sys - -class SharedStringTable(object): - _SST_ID = 0x00FC - _CONTINUE_ID = 0x003C - - def __init__(self, encoding): - self.encoding = encoding - self._str_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) - self._str_indexes[s] = idx - self._tally.append(1) - else: - idx = self._str_indexes[s] - self._tally[idx] += 1 - return idx - - def del_str(self, idx): - # This is called when we are replacing the contents of a string cell. - assert self._tally[idx] > 0 - self._tally[idx] -= 1 - self._add_calls -= 1 - - def str_index(self, s): - return self._str_indexes[s] - - def get_biff_record(self): - self._sst_record = '' - self._continues = [None, None] - self._current_piece = pack('<II', 0, 0) - data = [(idx, s) for s, idx in self._str_indexes.iteritems()] - data.sort() # in index order - for idx, s in data: - if self._tally[idx] == 0: - s = u'' - self._add_to_sst(s) - del data - self._new_piece() - self._continues[0] = pack('<2HII', self._SST_ID, len(self._sst_record), self._add_calls, len(self._str_indexes)) - self._continues[1] = self._sst_record[8:] - self._sst_record = None - self._current_piece = None - result = ''.join(self._continues) - self._continues = None - return result - - - def _add_to_sst(self, s): - u_str = upack2(s, self.encoding) - - is_unicode_str = u_str[2] == '\x01' - if is_unicode_str: - atom_len = 5 # 2 byte -- len, - # 1 byte -- options, - # 2 byte -- 1st sym - else: - atom_len = 4 # 2 byte -- len, - # 1 byte -- options, - # 1 byte -- 1st sym - - self._save_atom(u_str[0:atom_len]) - self._save_splitted(u_str[atom_len:], is_unicode_str) - - def _new_piece(self): - if self._sst_record == '': - self._sst_record = self._current_piece - else: - curr_piece_len = len(self._current_piece) - self._continues.append(pack('<2H%ds'%curr_piece_len, self._CONTINUE_ID, curr_piece_len, self._current_piece)) - self._current_piece = '' - - def _save_atom(self, s): - atom_len = len(s) - free_space = 0x2020 - len(self._current_piece) - if free_space < atom_len: - self._new_piece() - self._current_piece += s - - def _save_splitted(self, s, is_unicode_str): - i = 0 - str_len = len(s) - while i < str_len: - piece_len = len(self._current_piece) - free_space = 0x2020 - piece_len - tail_len = str_len - i - need_more_space = free_space < tail_len - - if not need_more_space: - atom_len = tail_len - else: - if is_unicode_str: - atom_len = free_space & 0xFFFE - else: - atom_len = free_space - - self._current_piece += s[i:i+atom_len] - - if need_more_space: - self._new_piece() - if is_unicode_str: - self._current_piece += '\x01' - else: - self._current_piece += '\x00' - - i += atom_len - - -class BiffRecord(object): - - _rec_data = '' # class attribute; child classes need to set this. - - # Sheer waste. - # def __init__(self): - # self._rec_data = '' - - def get_rec_id(self): - return _REC_ID - - def get_rec_header(self): - return pack('<2H', self._REC_ID, len(self._rec_data)) - - # Not over-ridden by any child classes, never called (except by "get"; see below). - # def get_rec_data(self): - # return self._rec_data - - def get(self): - # data = self.get_rec_data() - data = self._rec_data - - if len(data) > 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('<H', 0x00) - - -class WriteAccessRecord(BiffRecord): - """ - This record is part of the file protection. It contains the name of the - user that has saved the file. The user name is always stored as an - equal-sized string. All unused characters after the name are filled - with space characters. It is not required to write the mentioned string - length. Every other length will be accepted too. - """ - _REC_ID = 0x005C - - def __init__(self, owner): - uowner = owner[0:0x30] - uowner_len = len(uowner) - self._rec_data = pack('%ds%ds' % (uowner_len, 0x70 - uowner_len), uowner, ' '*(0x70 - uowner_len)) - - -class DSFRecord(BiffRecord): - """ - This record specifies if the file contains an additional BIFF5/BIFF7 - workbook stream. - Record DSF, BIFF8: - Offset Size Contents - 0 2 0 = Only the BIFF8 Workbook stream is present - 1 = Additional BIFF5/BIFF7 Book stream is in the file - A double stream file can be read by Excel 5.0 and Excel 95, and still - contains all new features added to BIFF8 (which are left out in the - BIFF5/BIFF7 Book stream). - """ - _REC_ID = 0x0161 - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class TabIDRecord(BiffRecord): - _REC_ID = 0x013D - - def __init__(self, sheetcount): - for i in range(sheetcount): - self._rec_data += pack('<H', i+1) - - -class FnGroupCountRecord(BiffRecord): - _REC_ID = 0x009C - - def __init__(self): - self._rec_data = pack('BB', 0x0E, 0x00) - - -class WindowProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It determines - whether the window configuration of this document is protected. Window - protection is not active, if this record is omitted. - """ - _REC_ID = 0x0019 - - def __init__(self, wndprotect): - self._rec_data = pack('<H', wndprotect) - - -class ObjectProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. - It determines whether the objects of the current sheet are protected. - Object protection is not active, if this record is omitted. - """ - _REC_ID = 0x0063 - - - def __init__(self, objprotect): - self._rec_data = pack('<H', objprotect) - - -class ScenProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It - determines whether the scenarios of the current sheet are protected. - Scenario protection is not active, if this record is omitted. - """ - _REC_ID = 0x00DD - - - def __init__(self, scenprotect): - self._rec_data = pack('<H', scenprotect) - - -class ProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It specifies - whether a worksheet or a workbook is protected against modification. - Protection is not active, if this record is omitted. - """ - - _REC_ID = 0x0012 - - def __init__(self, protect): - self._rec_data = pack('<H', protect) - - -class PasswordRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It - stores a 16-bit hash value, calculated from the worksheet or workbook - protection password. - """ - _REC_ID = 0x0013 - def passwd_hash(self, plaintext): - """ - Based on the algorithm provided by Daniel Rentz of OpenOffice. - """ - if plaintext == "": - return 0 - - passwd_hash = 0x0000 - for i, char in enumerate(plaintext): - c = ord(char) << (i + 1) - low_15 = c & 0x7fff - high_15 = c & 0x7fff << 15 - high_15 = high_15 >> 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('<H', self.passwd_hash(passwd)) - - -class Prot4RevRecord(BiffRecord): - _REC_ID = 0x01AF - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class Prot4RevPassRecord(BiffRecord): - _REC_ID = 0x01BC - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class BackupRecord(BiffRecord): - """ - This record contains a Boolean value determining whether Excel makes - a backup of the file while saving. - """ - _REC_ID = 0x0040 - - def __init__(self, backup): - self._rec_data = pack('<H', backup) - -class HideObjRecord(BiffRecord): - """ - This record specifies whether and how to show objects in the workbook. - - Record HIDEOBJ, BIFF3-BIFF8: - Offset Size Contents - 0 2 Viewing mode for objects: - 0 = Show all objects - 1 = Show placeholders - 2 = Do not show objects - """ - _REC_ID = 0x008D - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - - -class RefreshAllRecord(BiffRecord): - """ - """ - - _REC_ID = 0x01B7 - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class BookBoolRecord(BiffRecord): - """ - This record contains a Boolean value determining whether to save values - linked from external workbooks (CRN records and XCT records). In BIFF3 - and BIFF4 this option is stored in the WSBOOL record. - - Record BOOKBOOL, BIFF5-BIFF8: - - Offset Size Contents - 0 2 0 = Save external linked values; - 1 = Do not save external linked values - """ - - _REC_ID = 0x00DA - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class CountryRecord(BiffRecord): - """ - This record stores two Windows country identifiers. The first - represents the user interface language of the Excel version that has - saved the file, and the second represents the system regional settings - at the time the file was saved. - - Record COUNTRY, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Windows country identifier of the user interface language of Excel - 2 2 Windows country identifier of the system regional settings - - The following table shows most of the used country identifiers. Most - of these identifiers are equal to the international country calling - codes. - - 1 USA - 2 Canada - 7 Russia - """ - - _REC_ID = 0x008C - - def __init__(self, ui_id, sys_settings_id): - self._rec_data = pack('<2H', ui_id, sys_settings_id) - - -class UseSelfsRecord(BiffRecord): - """ - This record specifies if the formulas in the workbook can use natural - language formulas. This type of formula can refer to cells by its - content or the content of the column or row header cell. - - Record USESELFS, BIFF8: - - Offset Size Contents - 0 2 0 = Do not use natural language formulas - 1 = Use natural language formulas - - """ - - _REC_ID = 0x0160 - - def __init__(self): - self._rec_data = pack('<H', 0x01) - - -class EOFRecord(BiffRecord): - _REC_ID = 0x000A - - def __init__(self): - self._rec_data = '' - - -class DateModeRecord(BiffRecord): - """ - This record specifies the base date for displaying date values. All - dates are stored as count of days past this base date. In BIFF2-BIFF4 - this record is part of the Calculation Settings Block. - In BIFF5-BIFF8 it is stored in the Workbook Globals Substream. - - Record DATEMODE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Base is 1899-Dec-31 (the cell = 1 represents 1900-Jan-01) - 1 = Base is 1904-Jan-01 (the cell = 1 represents 1904-Jan-02) - """ - _REC_ID = 0x0022 - - def __init__(self, from1904): - if from1904: - self._rec_data = pack('<H', 1) - else: - self._rec_data = pack('<H', 0) - - -class PrecisionRecord(BiffRecord): - """ - This record stores if formulas use the real cell values for calculation - or the values displayed on the screen. In BIFF2- BIFF4 this record - is part of the Calculation Settings Block. In BIFF5-BIFF8 it is stored - in the Workbook Globals Substream. - - Record PRECISION, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Use displayed values; - 1 = Use real cell values - """ - _REC_ID = 0x000E - - def __init__(self, use_real_values): - if use_real_values: - self._rec_data = pack('<H', 1) - else: - self._rec_data = pack('<H', 0) - - -class CodepageBiff8Record(BiffRecord): - """ - This record stores the text encoding used to write byte strings, stored - as MS Windows code page identifier. The CODEPAGE record in BIFF8 always - contains the code page 1200 (UTF-16). Therefore it is not - possible to obtain the encoding used for a protection password (it is - not UTF-16). - - Record CODEPAGE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 Code page identifier used for byte string text encoding: - 016FH = 367 = ASCII - 01B5H = 437 = IBM PC CP-437 (US) - 02D0H = 720 = IBM PC CP-720 (OEM Arabic) - 02E1H = 737 = IBM PC CP-737 (Greek) - 0307H = 775 = IBM PC CP-775 (Baltic) - 0352H = 850 = IBM PC CP-850 (Latin I) - 0354H = 852 = IBM PC CP-852 (Latin II (Central European)) - 0357H = 855 = IBM PC CP-855 (Cyrillic) - 0359H = 857 = IBM PC CP-857 (Turkish) - 035AH = 858 = IBM PC CP-858 (Multilingual Latin I with Euro) - 035CH = 860 = IBM PC CP-860 (Portuguese) - 035DH = 861 = IBM PC CP-861 (Icelandic) - 035EH = 862 = IBM PC CP-862 (Hebrew) - 035FH = 863 = IBM PC CP-863 (Canadian (French)) - 0360H = 864 = IBM PC CP-864 (Arabic) - 0361H = 865 = IBM PC CP-865 (Nordic) - 0362H = 866 = IBM PC CP-866 (Cyrillic (Russian)) - 0365H = 869 = IBM PC CP-869 (Greek (Modern)) - 036AH = 874 = Windows CP-874 (Thai) - 03A4H = 932 = Windows CP-932 (Japanese Shift-JIS) - 03A8H = 936 = Windows CP-936 (Chinese Simplified GBK) - 03B5H = 949 = Windows CP-949 (Korean (Wansung)) - 03B6H = 950 = Windows CP-950 (Chinese Traditional BIG5) - 04B0H = 1200 = UTF-16 (BIFF8) - 04E2H = 1250 = Windows CP-1250 (Latin II) (Central European) - 04E3H = 1251 = Windows CP-1251 (Cyrillic) - 04E4H = 1252 = Windows CP-1252 (Latin I) (BIFF4-BIFF7) - 04E5H = 1253 = Windows CP-1253 (Greek) - 04E6H = 1254 = Windows CP-1254 (Turkish) - 04E7H = 1255 = Windows CP-1255 (Hebrew) - 04E8H = 1256 = Windows CP-1256 (Arabic) - 04E9H = 1257 = Windows CP-1257 (Baltic) - 04EAH = 1258 = Windows CP-1258 (Vietnamese) - 0551H = 1361 = Windows CP-1361 (Korean (Johab)) - 2710H = 10000 = Apple Roman - 8000H = 32768 = Apple Roman - 8001H = 32769 = Windows CP-1252 (Latin I) (BIFF2-BIFF3) - """ - _REC_ID = 0x0042 - UTF_16 = 0x04B0 - - def __init__(self): - self._rec_data = pack('<H', self.UTF_16) - -class Window1Record(BiffRecord): - """ - Offset Size Contents - 0 2 Horizontal position of the document window (in twips = 1/20 of a point) - 2 2 Vertical position of the document window (in twips = 1/20 of a point) - 4 2 Width of the document window (in twips = 1/20 of a point) - 6 2 Height of the document window (in twips = 1/20 of a point) - 8 2 Option flags: - Bits Mask Contents - 0 0001H 0 = Window is visible 1 = Window is hidden - 1 0002H 0 = Window is open 1 = Window is minimised - 3 0008H 0 = Horizontal scroll bar hidden 1 = Horizontal scroll bar visible - 4 0010H 0 = Vertical scroll bar hidden 1 = Vertical scroll bar visible - 5 0020H 0 = Worksheet tab bar hidden 1 = Worksheet tab bar visible - 10 2 Index to active (displayed) worksheet - 12 2 Index of first visible tab in the worksheet tab bar - 14 2 Number of selected worksheets (highlighted in the worksheet tab bar) - 16 2 Width of worksheet tab bar (in 1/1000 of window width). The remaining space is used by the - horizontal scrollbar. - """ - _REC_ID = 0x003D - # flags - - def __init__(self, - hpos_twips, vpos_twips, - width_twips, height_twips, - flags, - active_sheet, - first_tab_index, selected_tabs, tab_width): - self._rec_data = pack('<9H', hpos_twips, vpos_twips, - width_twips, height_twips, - flags, - active_sheet, - first_tab_index, selected_tabs, tab_width) - -class FontRecord(BiffRecord): - """ - WARNING - The font with index 4 is omitted in all BIFF versions. - This means the first four fonts have zero-based indexes, and - the fifth font and all following fonts are referenced with one-based - indexes. - - Offset Size Contents - 0 2 Height of the font (in twips = 1/20 of a point) - 2 2 Option flags: - Bit Mask Contents - 0 0001H 1 = Characters are bold (redundant, see below) - 1 0002H 1 = Characters are italic - 2 0004H 1 = Characters are underlined (redundant, see below) - 3 0008H 1 = Characters are struck out - 0010H 1 = Outline - 0020H 1 = Shadow - 4 2 Colour index - 6 2 Font weight (100-1000). - Standard values are 0190H (400) for normal text and 02BCH - (700) for bold text. - 8 2 Escapement type: - 0000H = None - 0001H = Superscript - 0002H = Subscript - 10 1 Underline type: - 00H = None - 01H = Single - 21H = Single accounting - 02H = Double - 22H = Double accounting - 11 1 Font family: - 00H = None (unknown or don't care) - 01H = Roman (variable width, serifed) - 02H = Swiss (variable width, sans-serifed) - 03H = Modern (fixed width, serifed or sans-serifed) - 04H = Script (cursive) - 05H = Decorative (specialised, i.e. Old English, Fraktur) - 12 1 Character set: - 00H = 0 = ANSI Latin - 01H = 1 = System default - 02H = 2 = Symbol - 4DH = 77 = Apple Roman - 80H = 128 = ANSI Japanese Shift-JIS - 81H = 129 = ANSI Korean (Hangul) - 82H = 130 = ANSI Korean (Johab) - 86H = 134 = ANSI Chinese Simplified GBK - 88H = 136 = ANSI Chinese Traditional BIG5 - A1H = 161 = ANSI Greek - A2H = 162 = ANSI Turkish - A3H = 163 = ANSI Vietnamese - B1H = 177 = ANSI Hebrew - B2H = 178 = ANSI Arabic - BAH = 186 = ANSI Baltic - CCH = 204 = ANSI Cyrillic - DEH = 222 = ANSI Thai - EEH = 238 = ANSI Latin II (Central European) - FFH = 255 = OEM Latin I - 13 1 Not used - 14 var. Font name: - BIFF5/BIFF7: Byte string, 8-bit string length - BIFF8: Unicode string, 8-bit string length - The boldness and underline flags are still set in the options field, - but not used on reading the font. Font weight and underline type - are specified in separate fields instead. - """ - _REC_ID = 0x0031 - - def __init__(self, - height, options, colour_index, weight, escapement, - underline, family, charset, - name): - uname = upack1(name) - uname_len = len(uname) - - self._rec_data = pack('<5H4B%ds' % uname_len, height, options, colour_index, weight, escapement, - underline, family, charset, 0x00, - uname) - -class NumberFormatRecord(BiffRecord): - """ - Record FORMAT, BIFF8: - Offset Size Contents - 0 2 Format index used in other records - 2 var. Number format string (Unicode string, 16-bit string length) - - From BIFF5 on, the built-in number formats will be omitted. The built-in - formats are dependent on the current regional settings of the operating - system. The following table shows which number formats are used by default - in a US-English environment. All indexes from 0 to 163 are reserved for - built-in formats. The first user-defined format starts at 164. - - The built-in number formats, BIFF5-BIFF8 - - Index Type Format string - 0 General General - 1 Decimal 0 - 2 Decimal 0.00 - 3 Decimal #,##0 - 4 Decimal #,##0.00 - 5 Currency "$"#,##0_);("$"#,## - 6 Currency "$"#,##0_);[Red]("$"#,## - 7 Currency "$"#,##0.00_);("$"#,## - 8 Currency "$"#,##0.00_);[Red]("$"#,## - 9 Percent 0% - 10 Percent 0.00% - 11 Scientific 0.00E+00 - 12 Fraction # ?/? - 13 Fraction # ??/?? - 14 Date M/D/YY - 15 Date D-MMM-YY - 16 Date D-MMM - 17 Date MMM-YY - 18 Time h:mm AM/PM - 19 Time h:mm:ss AM/PM - 20 Time h:mm - 21 Time h:mm:ss - 22 Date/Time M/D/YY h:mm - 37 Account _(#,##0_);(#,##0) - 38 Account _(#,##0_);[Red](#,##0) - 39 Account _(#,##0.00_);(#,##0.00) - 40 Account _(#,##0.00_);[Red](#,##0.00) - 41 Currency _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_) - 42 Currency _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) - 43 Currency _("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_) - 44 Currency _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_) - 45 Time mm:ss - 46 Time [h]:mm:ss - 47 Time mm:ss.0 - 48 Scientific ##0.0E+0 - 49 Text @ - """ - _REC_ID = 0x041E - - def __init__(self, idx, fmtstr): - ufmtstr = upack2(fmtstr) - ufmtstr_len = len(ufmtstr) - - self._rec_data = pack('<H%ds' % ufmtstr_len, idx, ufmtstr) - - -class XFRecord(BiffRecord): - """ - XF Substructures - ------------------------------------------------------------------------- - XF_TYPE_PROT XF Type and Cell Protection (3 Bits), BIFF3-BIFF8 - These 3 bits are part of a specific data byte. - Bit Mask Contents - 0 01H 1 = Cell is locked - 1 02H 1 = Formula is hidden - 2 04H 0 = Cell XF; 1 = Style XF - - XF_USED_ATTRIB Attributes Used from Parent Style XF (6 Bits), - BIFF3-BIFF8 Each bit describes the validity of a specific group - of attributes. In cell XFs a cleared bit means the attributes of the - parent style XF are used (but only if the attributes are valid there), - a set bit means the attributes of this XF are used. In style XFs - a cleared bit means the attribute setting is valid, a set bit means the - attribute should be ignored. - Bit Mask Contents - 0 01H Flag for number format - 1 02H Flag for font - 2 04H Flag for horizontal and vertical alignment, text wrap, indentation, orientation, rotation, and - text direction - 3 08H Flag for border lines - 4 10H Flag for background area style - 5 20H Flag for cell protection (cell locked and formula hidden) - - XF_HOR_ALIGN Horizontal Alignment (3 Bits), BIFF2-BIFF8 The horizontal - alignment consists of 3 bits and is part of a specific data byte. - Value Horizontal alignment - 00H General - 01H Left - 02H Centred - 03H Right - 04H Filled - 05H Justified (BIFF4-BIFF8X) - 06H Centred across selection (BIFF4-BIFF8X) - 07H Distributed (BIFF8X) - - XF_VERT_ALIGN Vertical Alignment (2 or 3 Bits), BIFF4-BIFF8 - The vertical alignment consists of 2 bits (BIFF4) or 3 bits (BIFF5-BIFF8) - and is part of a specific data byte. Vertical alignment is not available - in BIFF2 and BIFF3. - Value Vertical alignment - 00H Top - 01H Centred - 02H Bottom - 03H Justified (BIFF5-BIFF8X) - 04H Distributed (BIFF8X) - - XF_ORIENTATION Text Orientation (2 Bits), BIFF4-BIFF7 In the BIFF - versions BIFF4-BIFF7, text can be rotated in steps of 90 degrees - or stacked. The orientation mode consists of 2 bits and is part of - a specific data byte. In BIFF8 a rotation angle occurs instead of these - flags. - Value Text orientation - 00H Not rotated - 01H Letters are stacked top-to-bottom, but not rotated - 02H Text is rotated 90 degrees counterclockwise - 03H Text is rotated 90 degrees clockwise - - XF_ROTATION Text Rotation Angle (1 Byte), BIFF8 - Value Text rotation - 0 Not rotated - 1-90 1 to 90 degrees counterclockwise - 91-180 1 to 90 degrees clockwise - 255 Letters are stacked top-to-bottom, but not rotated - - XF_BORDER_34 Cell Border Style (4 Bytes), BIFF3-BIFF4 Cell borders - contain a line style and a line colour for each line of the border. - Bit Mask Contents - 2-0 00000007H Top line style - 7-3 000000F8H Colour index for top line colour - 10-8 00000700H Left line style - 15-11 0000F800H Colour index for left line colour - 18-16 00070000H Bottom line style - 23-19 00F80000H Colour index for bottom line colour - 26-24 07000000H Right line style - 31-27 F8000000H Colour index for right line colour - - XF_AREA_34 Cell Background Area Style (2 Bytes), BIFF3-BIFF4 A cell - background area style contains an area pattern and a foreground and - background colour. - Bit Mask Contents - 5-0 003FH Fill pattern - 10-6 07C0H Colour index for pattern colour - 15-11 F800H Colour index for pattern background - --------------------------------------------------------------------------------------------- - Record XF, BIFF8: - Offset Size Contents - 0 2 Index to FONT record - 2 2 Index to FORMAT record - 4 2 Bit Mask Contents - 2-0 0007H XF_TYPE_PROT . XF type, cell protection (see above) - 15-4 FFF0H Index to parent style XF (always FFFH in style XFs) - 6 1 Bit Mask Contents - 2-0 07H XF_HOR_ALIGN . Horizontal alignment (see above) - 3 08H 1 = Text is wrapped at right border - 6-4 70H XF_VERT_ALIGN . Vertical alignment (see above) - 7 1 XF_ROTATION: Text rotation angle (see above) - 8 1 Bit Mask Contents - 3-0 0FH Indent level - 4 10H 1 = Shrink content to fit into cell - 5 merge - 7-6 C0H Text direction (BIFF8X only) - 00b = According to context - 01b = Left-to-right - 10b = Right-to-left - 9 1 Bit Mask Contents - 7-2 FCH XF_USED_ATTRIB . Used attributes (see above) - 10 4 Cell border lines and background area: - Bit Mask Contents - 3-0 0000000FH Left line style - 7-4 000000F0H Right line style - 11-8 00000F00H Top line style - 15-12 0000F000H Bottom line style - 22-16 007F0000H Colour index for left line colour - 29-23 3F800000H Colour index for right line colour - 30 40000000H 1 = Diagonal line from top left to right bottom - 31 80000000H 1 = Diagonal line from bottom left to right top - 14 4 Bit Mask Contents - 6-0 0000007FH Colour index for top line colour - 13-7 00003F80H Colour index for bottom line colour - 20-14 001FC000H Colour index for diagonal line colour - 24-21 01E00000H Diagonal line style - 31-26 FC000000H Fill pattern - 18 2 Bit Mask Contents - 6-0 007FH Colour index for pattern colour - 13-7 3F80H Colour index for pattern background - - """ - _REC_ID = 0x00E0 - - def __init__(self, xf, xftype='cell'): - font_xf_idx, fmt_str_xf_idx, alignment, borders, pattern, protection = xf - fnt = pack('<H', font_xf_idx) - fmt = pack('<H', fmt_str_xf_idx) - if xftype == 'cell': - prt = pack('<H', - ((protection.cell_locked & 0x01) << 0) | - ((protection.formula_hidden & 0x01) << 1) - ) - else: - prt = pack('<H', 0xFFF5) - aln = pack('B', - ((alignment.horz & 0x07) << 0) | - ((alignment.wrap & 0x01) << 3) | - ((alignment.vert & 0x07) << 4) - ) - rot = pack('B', alignment.rota) - txt = pack('B', - ((alignment.inde & 0x0F) << 0) | - ((alignment.shri & 0x01) << 4) | - ((alignment.merg & 0x01) << 5) | - ((alignment.dire & 0x03) << 6) - ) - if xftype == 'cell': - used_attr = pack('B', 0xF8) - else: - used_attr = pack('B', 0xF4) - - if borders.left == borders.NO_LINE: - borders.left_colour = 0x00 - if borders.right == borders.NO_LINE: - borders.right_colour = 0x00 - if borders.top == borders.NO_LINE: - borders.top_colour = 0x00 - if borders.bottom == borders.NO_LINE: - borders.bottom_colour = 0x00 - if borders.diag == borders.NO_LINE: - borders.diag_colour = 0x00 - brd1 = pack('<L', - ((borders.left & 0x0F) << 0 ) | - ((borders.right & 0x0F) << 4 ) | - ((borders.top & 0x0F) << 8 ) | - ((borders.bottom & 0x0F) << 12) | - ((borders.left_colour & 0x7F) << 16) | - ((borders.right_colour & 0x7F) << 23) | - ((borders.need_diag1 & 0x01) << 30) | - ((borders.need_diag2 & 0x01) << 31) - ) - brd2 = pack('<L', - ((borders.top_colour & 0x7F) << 0 ) | - ((borders.bottom_colour & 0x7F) << 7 ) | - ((borders.diag_colour & 0x7F) << 14) | - ((borders.diag & 0x0F) << 21) | - ((pattern.pattern & 0x3F) << 26) - ) - pat = pack('<H', - ((pattern.pattern_fore_colour & 0x7F) << 0 ) | - ((pattern.pattern_back_colour & 0x7F) << 7 ) - ) - self._rec_data = fnt + fmt + prt + \ - aln + rot + txt + used_attr + \ - brd1 + brd2 + \ - pat - -class StyleRecord(BiffRecord): - """ - STYLE record for user-defined cell styles, BIFF3-BIFF8: - Offset Size Contents - 0 2 Bit Mask Contents - 11-0 0FFFH Index to style XF record - 15 8000H Always 0 for user-defined styles - 2 var. BIFF2-BIFF7: Non-empty byte string, 8-bit string length - BIFF8: Non-empty Unicode string, 16-bit string length - STYLE record for built-in cell styles, BIFF3-BIFF8: - Offset Size Contents - 0 2 Bit Mask Contents - 11-0 0FFFH Index to style XF record - 15 8000H Always 1 for built-in styles - 2 1 Identifier of the built-in cell style: - 00H = Normal - 01H = RowLevel_lv (see next field) - 02H = ColLevel_lv (see next field) - 03H = Comma - 04H = Currency - 05H = Percent - 06H = Comma [0] (BIFF4-BIFF8) - 07H = Currency [0] (BIFF4-BIFF8) - 08H = Hyperlink (BIFF8) - 09H = Followed Hyperlink (BIFF8) - 3 1 Level for RowLevel or ColLevel style - (zero-based, lv), FFH otherwise - The RowLevel and ColLevel styles specify the formatting of subtotal - cells in a specific outline level. The level is specified by the last - field in the STYLE record. Valid values are 0-6 for the outline levels - 1-7. - """ - _REC_ID = 0x0293 - - def __init__(self): - self._rec_data = pack('<HBB', 0x8000, 0x00, 0xFF) - # TODO: implement user-defined styles??? - - -class PaletteRecord(BiffRecord): - """ - This record contains the definition of all user-defined colours - available for cell and object formatting. - - Record PALETTE, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Number of following colours (nm). Contains 16 in BIFF3-BIFF4 and 56 in BIFF5-BIFF8. - 2 4*nm List of nm RGB colours - - The following table shows how colour indexes are used in other records: - - Colour index Resulting colour or internal list index - 00H Built-in Black (R = 00H, G = 00H, B = 00H) - 01H Built-in White (R = FFH, G = FFH, B = FFH) - 02H Built-in Red (R = FFH, G = 00H, B = 00H) - 03H Built-in Green (R = 00H, G = FFH, B = 00H) - 04H Built-in Blue (R = 00H, G = 00H, B = FFH) - 05H Built-in Yellow (R = FFH, G = FFH, B = 00H) - 06H Built-in Magenta (R = FFH, G = 00H, B = FFH) - 07H Built-in Cyan (R = 00H, G = FFH, B = FFH) - 08H First user-defined colour from the PALETTE record (entry 0 from record colour list) - ......................... - - 17H (BIFF3-BIFF4) Last user-defined colour from the PALETTE record (entry 15 or 55 from record colour list) - 3FH (BIFF5-BIFF8) - - 18H (BIFF3-BIFF4) System window text colour for border lines (used in records XF, CF, and - 40H (BIFF5-BIFF8) WINDOW2 (BIFF8 only)) - - 19H (BIFF3-BIFF4) System window background colour for pattern background (used in records XF, and CF) - 41H (BIFF5-BIFF8) - - 43H System face colour (dialogue background colour) - 4DH System window text colour for chart border lines - 4EH System window background colour for chart areas - 4FH Automatic colour for chart border lines (seems to be always Black) - 50H System ToolTip background colour (used in note objects) - 51H System ToolTip text colour (used in note objects) - 7FFFH System window text colour for fonts (used in records FONT, EFONT, and CF) - - """ - _REC_ID = 0x0092 - - -class BoundSheetRecord(BiffRecord): - """ - This record is located in the workbook globals area and represents - a sheet inside of the workbook. For each sheet a BOUNDSHEET record - is written. It stores the sheet name and a stream offset to the BOF - record within the workbook stream. The record is also known - as BUNDLESHEET. - - Record BOUNDSHEET, BIFF5-BIFF8: - Offset Size Contents - 0 4 Absolute stream position of the BOF record of the sheet represented by this record. This - field is never encrypted in protected files. - 4 1 Visibility: - 00H = Visible - 01H = Hidden - 02H = Strong hidden - 5 1 Sheet type: - 00H = Worksheet - 02H = Chart - 06H = Visual Basic module - 6 var. Sheet name: - BIFF5/BIFF7: Byte string, 8-bit string length - BIFF8: Unicode string, 8-bit string length - """ - _REC_ID = 0x0085 - - def __init__(self, stream_pos, visibility, sheetname, encoding='ascii'): - usheetname = upack1(sheetname, encoding) - uusheetname_len = len(usheetname) - - self._rec_data = pack('<LBB%ds' % uusheetname_len, stream_pos, visibility, 0x00, usheetname) - - -class ContinueRecord(BiffRecord): - """ - Whenever the content of a record exceeds the given limits (see table), - the record must be split. Several CONTINUE records containing the - additional data are added after the parent record. - - BIFF version Maximum data size of a record - BIFF2-BIFF7 2080 bytes (2084 bytes including record header) - BIFF8 8224 bytes (8228 bytes including record header) (0x2020) - - Record CONTINUE, BIFF2-BIFF8: - Offset Size Contents - 0 var. Data continuation of the previous record - - Unicode strings are split in a special way. At the beginning of each - CONTINUE record the option flags byte is repeated. Only the character - size flag will be set in this flags byte, the Rich-Text flag and the - Far-East flag are set to zero. In each CONTINUE record it is possible - that the character size changes from 8-bit characters to 16-bit - characters and vice versa. - - Never a Unicode string is split until and including the first - character. That means, all header fields (string length, option flags, - optional Rich-Text size, and optional Far-East data size) and the first - character of the string have to occur together in the leading record, - or have to be moved completely into the CONTINUE record. Formatting - runs cannot be split between their components (character index and FONT - record index). If a string is split between two formatting runs, the - option flags field will not be repeated in the CONTINUE record. - """ - _REC_ID = 0x003C - - -class SSTRecord(BiffRecord): - """ - This record contains a list of all strings used anywhere in the - workbook. Each string occurs only once. The workbook uses indexes into - the list to reference the strings. - - Record SST, BIFF8: - Offset Size Contents - 0 4 Total number of strings in the workbook (see below) - 4 4 Number of following strings (nm) - 8 var. List of nm Unicode strings, 16-bit string length - - The first field of the SST record counts the total occurrence - of strings in the workbook. For instance, the string AAA is used - 3 times and the string BBB is used 2 times. The first field contains - 5 and the second field contains 2, followed by the two strings. - """ - _REC_ID = 0x00FC - - -class ExtSSTRecord(BiffRecord): - """ - This record occurs in conjunction with the SST record. It is used - by Excel to create a hash table with stream offsets to the SST record - to optimise string search operations. Excel may not shorten this record - if strings are deleted from the shared string table, so the last part - might contain invalid data. The stream indexes in this record divide - the SST into portions containing a constant number of strings. - - Record EXTSST, BIFF8: - - Offset Size Contents - 0 2 Number of strings in a portion, this number is >=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('<H', exsst_str_count_delta) - str_counter = 0 - while str_counter < len(str_placement): - self._rec_data += pack('<IHH', extsst[str_counter][1], extsst[str_counter][0], 0) - str_counter += exsst_str_count_delta - -class DimensionsRecord(BiffRecord): - """ - Record DIMENSIONS, BIFF8: - - Offset Size Contents - 0 4 Index to first used row - 4 4 Index to last used row, increased by 1 - 8 2 Index to first used column - 10 2 Index to last used column, increased by 1 - 12 2 Not used - """ - _REC_ID = 0x0200 - def __init__(self, first_used_row, last_used_row, first_used_col, last_used_col): - if first_used_row > 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: - 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 - def __init__(self, px, py, first_row_bottom, first_col_right, active_pane): - 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('<H', last_col) - - -class BlankRecord(BiffRecord): - """ - This record represents an empty cell. - - Record BLANK, BIFF5-BIFF8: - - Offset Size Contents - 0 2 Index to row - 2 2 Index to first column (fc) - 4 2 indexes to XF record - """ - _REC_ID = 0x0201 - - def __init__(self, row, col, xf_index): - self._rec_data = pack('<3H', row, col, xf_index) - - -class RKRecord(BiffRecord): - """ - This record represents a cell that contains an RK value (encoded integer or - floating-point value). If a floating-point value cannot be encoded to an RK value, - a NUMBER record will be written. - """ - _REC_ID = 0x027E - - def __init__(self, row, col, xf_index, rk_encoded): - self._rec_data = pack('<3Hi', row, col, xf_index, rk_encoded) - - -class NumberRecord(BiffRecord): - """ - This record represents a cell that contains an IEEE-754 floating-point value. - """ - _REC_ID = 0x0203 - - def __init__(self, row, col, xf_index, number): - self._rec_data = pack('<3Hd', row, col, xf_index, number) - -class BoolErrRecord(BiffRecord): - """ - This record represents a cell that contains a boolean or error value. - """ - _REC_ID = 0x0205 - - def __init__(self, row, col, xf_index, number, is_error): - self._rec_data = pack('<3HBB', row, col, xf_index, number, is_error) - - -class FormulaRecord(BiffRecord): - """ - Offset Size Contents - 0 2 Index to row - 2 2 Index to column - 4 2 Index to XF record - 6 8 Result of the formula - 14 2 Option flags: - Bit Mask Contents - 0 0001H 1 = Recalculate always - 1 0002H 1 = Calculate on open - 3 0008H 1 = Part of a shared formula - 16 4 Not used - 20 var. Formula data (RPN token array) - - """ - _REC_ID = 0x0006 - - def __init__(self, row, col, xf_index, rpn, calc_flags=0): - self._rec_data = pack('<3HQHL', row, col, xf_index, 0xFFFF000000000003, calc_flags & 3, 0) + rpn - - -class GutsRecord(BiffRecord): - """ - This record contains information about the layout of outline symbols. - - Record GUTS, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Width of the area to display row outlines (left of the sheet), in pixel - 2 2 Height of the area to display column outlines (above the sheet), in pixel - 4 2 Number of visible row outline levels (used row levels + 1; or 0, if not used) - 6 2 Number of visible column outline levels (used column levels + 1; or 0, if not used) - - """ - - _REC_ID = 0x0080 - - def __init__(self, row_gut_width, col_gut_height, row_visible_levels, col_visible_levels): - self._rec_data = pack('<4H', row_gut_width, col_gut_height, row_visible_levels, col_visible_levels) - -class WSBoolRecord(BiffRecord): - """ - This record stores a 16 bit value with Boolean options for the current - sheet. From BIFF5 on the "Save external linked values" option is moved - to the record BOOKBOOL. - - Option flags of record WSBOOL, BIFF3-BIFF8: - - Bit Mask Contents - 0 0001H 0 = Do not show automatic page breaks - 1 = Show automatic page breaks - 4 0010H 0 = Standard sheet - 1 = Dialogue sheet (BIFF5-BIFF8) - 5 0020H 0 = No automatic styles in outlines - 1 = Apply automatic styles to outlines - 6 0040H 0 = Outline buttons above outline group - 1 = Outline buttons below outline group - 7 0080H 0 = Outline buttons left of outline group - 1 = Outline buttons right of outline group - 8 0100H 0 = Scale printout in percent - 1 = Fit printout to number of pages - 9 0200H 0 = Save external linked values (BIFF3?BIFF4 only) - 1 = Do not save external linked values (BIFF3?BIFF4 only) - 10 0400H 0 = Do not show row outline symbols - 1 = Show row outline symbols - 11 0800H 0 = Do not show column outline symbols - 1 = Show column outline symbols - 13-12 3000H These flags specify the arrangement of windows. - They are stored in BIFF4 only. - 00 = Arrange windows tiled - 01 = Arrange windows horizontal - 10 = Arrange windows vertical112 = Arrange windows cascaded - The following flags are valid for BIFF4-BIFF8 only: - 14 4000H 0 = Standard expression evaluation - 1 = Alternative expression evaluation - 15 8000H 0 = Standard formula entries - 1 = Alternative formula entries - - """ - _REC_ID = 0x0081 - - def __init__(self, options): - self._rec_data = pack('<H', options) - -class ColInfoRecord(BiffRecord): - """ - This record specifies the width for a given range of columns. - If a column does not have a corresponding COLINFO record, - the width specified in the record STANDARDWIDTH is used. If - this record is also not present, the contents of the record - DEFCOLWIDTH is used instead. - This record also specifies a default XF record to use for - cells in the columns that are not described by any cell record - (which contain the XF index for that cell). Additionally, - the option flags field contains hidden, outline, and collapsed - options applied at the columns. - - Record COLINFO, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Index to first column in the range - 2 2 Index to last column in the range - 4 2 Width of the columns in 1/256 of the width of the zero character, using default font - (first FONT record in the file) - 6 2 Index to XF record for default column formatting - 8 2 Option flags: - Bits Mask Contents - 0 0001H 1 = Columns are hidden - 10-8 0700H Outline level of the columns (0 = no outline) - 12 1000H 1 = Columns are collapsed - 10 2 Not used - - """ - _REC_ID = 0x007D - - def __init__(self, first_col, last_col, width, xf_index, options): - self._rec_data = pack('<6H', first_col, last_col, width, xf_index, options, 0) - -class CalcModeRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It specifies whether to calculate formulas manually, - automatically or automatically except for multiple table operations. - - Record CALCMODE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 FFFFH = automatic except for multiple table operations - 0000H = manually - 0001H = automatically (default) - """ - _REC_ID = 0x000D - - def __init__(self, calc_mode): - self._rec_data = pack('<h', calc_mode) - - -class CalcCountRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. It specifies the maximum - number of times the formulas should be iteratively calculated. This is a fail-safe - against mutually recursive formulas locking up a spreadsheet application. - - Record CALCCOUNT, BIFF2-BIFF8: - - Offset Size Contents - 0 2 Maximum number of iterations allowed in circular references - """ - - _REC_ID = 0x000C - - def __init__(self, calc_count): - self._rec_data = pack('<H', calc_count) - -class RefModeRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It stores which method is used to show cell addresses in formulas. - The “RC” mode uses numeric indexes for rows and columns, - i.e. “R(1)C(-1)”, or “R1C1:R2C2”. - The “A1” mode uses characters for columns and numbers for rows, - i.e. “B1”, or “$A$1:$B$2”. - - Record REFMODE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = RC mode; 1 = A1 mode - - """ - _REC_ID = 0x00F - - def __init__(self, ref_mode): - self._rec_data = pack('<H', ref_mode) - -class IterationRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It stores if iterations are allowed while calculating recursive formulas. - - Record ITERATION, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Iterations off; 1 = Iterations on - """ - _REC_ID = 0x011 - - def __init__(self, iterations_on): - self._rec_data = pack('<H', iterations_on) - -class DeltaRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It stores the maximum change of the result to exit an iteration. - - Record DELTA, BIFF2-BIFF8: - - Offset Size Contents - 0 8 Maximum change in iteration - (IEEE 754 floating-point value, - 64bit double precision) - """ - _REC_ID = 0x010 - - def __init__(self, delta): - self._rec_data = pack('<d', delta) - -class SaveRecalcRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It contains the “Recalculate before save” option in - Excel's calculation settings dialogue. - - Record SAVERECALC, BIFF3-BIFF8: - - Offset Size Contents - 0 2 0 = Do not recalculate; - 1 = Recalculate before saving the document - - """ - _REC_ID = 0x05F - - def __init__(self, recalc): - self._rec_data = pack('<H', recalc) - -class PrintHeadersRecord(BiffRecord): - """ - This record stores if the row and column headers - (the areas with row numbers and column letters) will be printed. - - Record PRINTHEADERS, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Do not print row/column headers; - 1 = Print row/column headers - """ - _REC_ID = 0x02A - - def __init__(self, print_headers): - self._rec_data = pack('<H', print_headers) - - -class PrintGridLinesRecord(BiffRecord): - """ - This record stores if sheet grid lines will be printed. - - Record PRINTGRIDLINES, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Do not print sheet grid lines; - 1 = Print sheet grid lines - - """ - _REC_ID = 0x02B - - def __init__(self, print_grid): - self._rec_data = pack('<H', print_grid) - - -class GridSetRecord(BiffRecord): - """ - This record specifies if the option to print sheet grid lines - (record PRINTGRIDLINES) has ever been changed. - - Record GRIDSET, BIFF3-BIFF8: - - Offset Size Contents - 0 2 0 = Print grid lines option never changed - 1 = Print grid lines option changed - """ - _REC_ID = 0x082 - - def __init__(self, print_grid_changed): - self._rec_data = pack('<H', print_grid_changed) - - -class DefaultRowHeightRecord(BiffRecord): - """ - This record specifies the default height and default flags - for rows that do not have a corresponding ROW record. - - Record DEFAULTROWHEIGHT, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Option flags: - Bit Mask Contents - 0 0001H 1 = Row height and default font height do not match - 1 0002H 1 = Row is hidden - 2 0004H 1 = Additional space above the row - 3 0008H 1 = Additional space below the row - 2 2 Default height for unused rows, in twips = 1/20 of a point - - """ - _REC_ID = 0x0225 - - def __init__(self, options, def_height): - self._rec_data = pack('<2H', options, def_height) - - -class DefColWidthRecord(BiffRecord): - """ - This record specifies the default column width for columns that - do not have a specific width set using the record COLINFO or COLWIDTH. - This record has no effect, if a STANDARDWIDTH record is present in the file. - - Record DEFCOLWIDTH, BIFF2-BIFF8: - - Offset Size Contents - 0 2 Column width in characters, using the width of the zero - character from default font (first FONT record in the file) - """ - _REC_ID = 0x0055 - - def __init__(self, def_width): - self._rec_data = pack('<H', options, def_width) - -class HorizontalPageBreaksRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains all - horizontal manual page breaks. - - Record HORIZONTALPAGEBREAKS, BIFF8: - Offset Size Contents - 0 2 Number of following row index structures (nm) - 2 6nm List of nm row index structures. Each row index - structure contains: - Offset Size Contents - 0 2 Index to first row below the page break - 2 2 Index to first column of this page break - 4 2 Index to last column of this page break - - The row indexes in the lists must be ordered ascending. - If in BIFF8 a row contains several page breaks, they must be ordered - ascending by start column index. - """ - _REC_ID = 0x001B - - def __init__(self, breaks_list): - self._rec_data = pack('<H', len(breaks_list)) - for r, c1, c2 in breaks_list: - self._rec_data += pack('<3H', r, c1, c2) - -class VerticalPageBreaksRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains all - vertical manual page breaks. - - Record VERTICALPAGEBREAKS, BIFF8: - Offset Size Contents - 0 2 Number of following column index structures (nm) - 2 6nm List of nm column index structures. Each column index - structure contains: - Offset Size Contents - 0 2 Index to first column following the page - break - 2 2 Index to first row of this page break - 4 2 Index to last row of this page break - - The column indexes in the lists must be ordered ascending. - If in BIFF8 a column contains several page breaks, they must be ordered - ascending by start row index. - """ - _REC_ID = 0x001A - - def __init__(self, breaks_list): - self._rec_data = pack('<H', len(breaks_list)) - for r, c1, c2 in breaks_list: - self._rec_data += pack('<3H', r, c1, c2) - -class HeaderRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It specifies the - page header string for the current worksheet. If this record is not - present or completely empty (record size is 0), the sheet does not - contain a page header. - - Record HEADER for non-empty page header, BIFF2-BIFF8: - Offset Size Contents - 0 var. Page header string - BIFF2-BIFF7: Non-empty byte string, 8bit string - length - BIFF8: Non-empty Unicode string, 16bit string length - The header string may contain special commands, i.e. placeholders for - the page number, current date, or text formatting attributes. These - fields are represented by single letters (exception: font name and - size, see below) with a leading ampersand ("&"). If the ampersand - is part of the regular header text, it will be duplicated ("&&"). The - page header is divided into 3 sections: the left, the centred, and the - right section. Each section is introduced by a special command. All - text and all commands following are part of the selected section. Each - section starts with the text formatting specified in the default font - (first FONT record in the file). Active formatting attributes from - a previous section do not go into the next section. - - The following table shows all available commands: - - Command Contents - && The "&" character itself - &L Start of the left section - &C Start of the centred section - &R Start of the right section - &P Current page number - &N Page count - &D Current date - &T Current time - &A Sheet name (BIFF5-BIFF8) - &F File name without path - &Z File path without file name (BIFF8X) - &G Picture (BIFF8X) - &B Bold on/off (BIFF2-BIFF4) - &I Italic on/off (BIFF2-BIFF4) - &U Underlining on/off - &E Double underlining on/off (BIFF5-BIFF8) - &S Strikeout on/off - &X Superscript on/off (BIFF5-BIFF8) - &Y Subscript on/off (BIFF5-BIFF8) - &"<fontname>" Set new font <fontname> - &"<fontname>,<fontstyle>" - Set new font with specified style <fontstyle>. - The style <fontstyle> 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) - &<fontheight> Set font height in points (<fontheight> 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('<H', is_horz_center) - - -class VCenterRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It specifies if the - sheet is centred vertically when printed. - - Record VCENTER, BIFF3-BIFF8: - - Offset Size Contents - 0 2 0 = Print sheet aligned at top page border - 1 = Print sheet vertically centred - - """ - _REC_ID = 0x0084 - - def __init__(self, is_vert_center): - self._rec_data = pack('<H', is_vert_center) - - -class LeftMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the left - page margin of the current worksheet. - - Record LEFTMARGIN, BIFF2-BIFF8: - - Offset Size Contents - 0 8 Left page margin in inches - (IEEE 754 floating-point value, 64bit double precision) - - """ - _REC_ID = 0x0026 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - - -class RightMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the right - page margin of the current worksheet. - - Offset Size Contents - 0 8 Right page margin in inches - (IEEE 754 floating-point value, 64?bit double precision) - - """ - _REC_ID = 0x0027 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - -class TopMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the top - page margin of the current worksheet. - - Offset Size Contents - 0 8 Top page margin in inches - (IEEE 754 floating-point value, 64?bit double precision) - - """ - _REC_ID = 0x0028 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - - -class BottomMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the bottom - page margin of the current worksheet. - - Offset Size Contents - 0 8 Bottom page margin in inches - (IEEE 754 floating-point value, 64?bit double precision) - - """ - _REC_ID = 0x0029 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - -class SetupPageRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It stores the page - format settings of the current sheet. The pages may be scaled in - percent or by using an absolute number of pages. This setting is - located in the WSBOOL record. If pages are scaled in percent, - the scaling factor in this record is used, otherwise the "Fit to - pages" values. One of the "Fit to pages" values may be 0. In this case - the sheet is scaled to fit only to the other value. - - Record SETUP, BIFF5-BIFF8: - - Offset Size Contents - 0 2 Paper size (see below) - 2 2 Scaling factor in percent - 4 2 Start page number - 6 2 Fit worksheet width to this number of pages - (0 = use as many as needed) - 8 2 Fit worksheet height to this number of pages - (0 = use as many as needed) - 10 2 Option flags: - Bit Mask Contents - 0 0001H 0 = Print pages in columns - 1 = Print pages in rows - 1 0002H 0 = Landscape - 1 = Portrait - 2 0004H 1 = Paper size, scaling factor, - paper orientation (portrait/landscape), - print resolution and number of copies - are not initialised - 3 0008H 0 = Print coloured - 1 = Print black and white - 4 0010H 0 = Default print quality - 1 = Draft quality - 5 0020H 0 = Do not print cell notes - 1 = Print cell notes - 6 0040H 0 = Paper orientation setting is valid - 1 = Paper orientation setting not - initialised - 7 0080H 0 = Automatic page numbers - 1 = Use start page number - The following flags are valid for BIFF8 only: - 9 0200H 0 = Print notes as displayed - 1 = Print notes at end of sheet - 11-10 0C00H 00 = Print errors as displayed - 01 = Do not print errors - 10 = Print errors as "--" - 11 = Print errors as "#N/A!" - 12 2 Print resolution in dpi - 14 2 Vertical print resolution in dpi - 16 8 Header margin (IEEE 754 floating-point value, - 64bit double precision) - 24 8 Footer margin (IEEE 754 floating-point value, - 64bit double precision) - 32 2 Number of copies to print - - - PAPER TYPES: - - Index Paper type Paper size - 0 Undefined - 1 Letter 8 1/2" x 11" - 2 Letter small 8 1/2" x 11" - 3 Tabloid 11" x 17" - 4 Ledger 17" x 11" - 5 Legal 8 1/2" x 14" - 6 Statement 5 1/2" x 8 1/2" - 7 Executive 7 1/4" x 10 1/2" - 8 A3 297mm x 420mm - 9 A4 210mm x 297mm - 10 A4 small 210mm x 297mm - 11 A5 148mm x 210mm - 12 B4 (JIS) 257mm x 364mm - 13 B5 (JIS) 182mm x 257mm - 14 Folio 8 1/2" x 13" - 15 Quarto 215mm x 275mm - 16 10x14 10" x 14" - 17 11x17 11" x 17" - 18 Note 8 1/2" x 11" - 19 Envelope #9 3 7/8" x 8 7/8" - 20 Envelope #10 4 1/8" x 9 1/2" - 21 Envelope #11 4 1/2" x 10 3/8" - 22 Envelope #12 4 3/4" x 11" - 23 Envelope #14 5" x 11 1/2" - 24 C 17" x 22" - 25 D 22" x 34" - 26 E 34" x 44" - 27 Envelope DL 110mm x 220mm - 28 Envelope C5 162mm x 229mm - 29 Envelope C3 324mm x 458mm - 30 Envelope C4 229mm x 324mm - 31 Envelope C6 114mm x 162mm - 32 Envelope C6/C5 114mm x 229mm - 33 B4 (ISO) 250mm x 353mm - 34 B5 (ISO) 176mm x 250mm - 35 B6 (ISO) 125mm x 176mm - 36 Envelope Italy 110mm x 230mm - 37 Envelope Monarch 3 7/8" x 7 1/2" - 38 63/4 Envelope 3 5/8" x 6 1/2" - 39 US Standard Fanfold 14 7/8" x 11" - 40 German Std. Fanfold 8 1/2" x 12" - 41 German Legal Fanfold 8 1/2" x 13" - 42 B4 (ISO) 250mm x 353mm - 43 Japanese Postcard 100mm x 148mm - 44 9x11 9" x 11" - 45 10x11 10" x 11" - 46 15x11 15" x 11" - 47 Envelope Invite 220mm x 220mm - 48 Undefined - 49 Undefined - 50 Letter Extra 9 1/2" x 12" - 51 Legal Extra 9 1/2" x 15" - 52 Tabloid Extra 11 11/16" x 18" - 53 A4 Extra 235mm x 322mm - 54 Letter Transverse 8 1/2" x 11" - 55 A4 Transverse 210mm x 297mm - 56 Letter Extra Transv. 9 1/2" x 12" - 57 Super A/A4 227mm x 356mm - 58 Super B/A3 305mm x 487mm - 59 Letter Plus 8 1/2" x 12 11/16" - 60 A4 Plus 210mm x 330mm - 61 A5 Transverse 148mm x 210mm - 62 B5 (JIS) Transverse 182mm x 257mm - 63 A3 Extra 322mm x 445mm - 64 A5 Extra 174mm x 235mm - 65 B5 (ISO) Extra 201mm x 276mm - 66 A2 420mm x 594mm - 67 A3 Transverse 297mm x 420mm - 68 A3 Extra Transverse 322mm x 445mm - 69 Dbl. Japanese Postcard 200mm x 148mm - 70 A6 105mm x 148mm - 71 - 72 - 73 - 74 - 75 Letter Rotated 11" x 8 1/2" - 76 A3 Rotated 420mm x 297mm - 77 A4 Rotated 297mm x 210mm - 78 A5 Rotated 210mm x 148mm - 79 B4 (JIS) Rotated 364mm x 257mm - 80 B5 (JIS) Rotated 257mm x 182mm - 81 Japanese Postcard Rot. 148mm x 100mm - 82 Dbl. Jap. Postcard Rot. 148mm x 200mm - 83 A6 Rotated 148mm x 105mm - 84 - 85 - 86 - 87 - 88 B6 (JIS) 128mm x 182mm - 89 B6 (JIS) Rotated 182mm x 128mm - 90 12x11 12" x 11" - - """ - _REC_ID = 0x00A1 - def __init__(self, paper, scaling, start_num, fit_width_to, fit_height_to, - options, - hres, vres, - header_margin, footer_margin, - num_copies): - self._rec_data = pack('<8H2dH', paper, scaling, start_num, - fit_width_to, fit_height_to, \ - options, - hres, vres, - header_margin, footer_margin, - num_copies) - -class NameRecord(BiffRecord): - """ - This record is part of a Link Table. It contains the name and the token - array of an internal defined name. Token arrays of defined names - contain tokens with aberrant token classes. - - Record NAME, BIFF5/BIFF7: - Offset Size Contents - 0 2 Option flags, see below - 2 1 Keyboard shortcut (only for command macro names, see below) - 3 1 Length of the name (character count, ln) - 4 2 Size of the formula data (sz) - 6 2 0 = Global name, otherwise index to EXTERNSHEET record (one-based) - 8 2 0 = Global name, otherwise index to sheet (one-based) - 10 1 Length of menu text (character count, lm) - 11 1 Length of description text (character count, ld) - 12 1 Length of help topic text (character count, lh) - 13 1 Length of status bar text (character count, ls) - 14 ln Character array of the name - 14+ln sz Formula data (RPN token array without size field, 4) - 14+ln+sz lm Character array of menu text - var. ld Character array of description text - var. lh Character array of help topic text - var. ls Character array of status bar text - - Record NAME, BIFF8: - Offset Size Contents - 0 2 Option flags, see below - 2 1 Keyboard shortcut (only for command macro names, see below) - 3 1 Length of the name (character count, ln) - 4 2 Size of the formula data (sz) - 6 2 Not used - 8 2 0 = Global name, otherwise index to sheet (one-based) - 10 1 Length of menu text (character count, lm) - 11 1 Length of description text (character count, ld) - 12 1 Length of help topic text (character count, lh) - 13 1 Length of status bar text (character count, ls) - 14 var. Name (Unicode string without length field, 3.4) - var. sz Formula data (RPN token array without size field, 4) - [var.] var. (optional, only if lm > 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('<HBBHHHBBBB%ds%ds' % (uname_len, len(rpn)), options, keyboard_shortcut, uname_len, len(rpn), 0x0000, sheet_index, len(menu_text), len(desc_text), len(help_text), len(status_text), uname, rpn) + menu_text + desc_text + help_text + status_text - self._rec_data = pack('<HBBHHHBBBBB%ds%ds' % (uname_len, len(rpn)), options, keyboard_shortcut, uname_len, len(rpn), 0x0000, sheet_index, 0x00, len(menu_text), len(desc_text), len(help_text), len(status_text), uname, rpn) + menu_text + desc_text + help_text + status_text - -# Excel (both 2003 and 2007) don't like refs -# split over a record boundary, which is what the -# standard BiffRecord.get method does. - -# 8224 max data bytes in a BIFF record -# 6 bytes per ref -# 1370 = floor((8224 - 2) / 6.0) max refs in a record - -_maxRefPerRecord = 1370 - -class ExternSheetRecord(BiffRecord): - """ - In BIFF8 the record stores a list with indexes to SUPBOOK - records (list of REF structures, 6.100). See 5.10.3 for - details about external references in BIFF8. - - Record EXTERNSHEET, BIFF8: - Offset Size Contents - 0 2 Number of following REF structures (nm) - 2 6nm List of nm REF structures. Each REF contains the following data: - Offset Size Contents - 0 2 Index to SUPBOOK record - 2 2 Index to first SUPBOOK sheet - 4 2 Index to last SUPBOOK sheet - """ - _REC_ID = 0x0017 - - def __init__(self, refs): - - # do we always need this ref? or only if there are no refs? - # (I believe that if there are no refs then we should not generate the link table - Ruben) - #refs.insert(0, (0,0,0)) - - self.refs = refs - - def get(self): - res = [] - nrefs = len(self.refs) - for idx in xrange(0, nrefs, _maxRefPerRecord): - chunk = self.refs[idx:idx+_maxRefPerRecord] - krefs = len(chunk) - if idx: # CONTINUE record - header = pack("<HH", 0x003C, 6 * krefs) - else: # ExternSheetRecord - header = pack("<HHH", self._REC_ID, 6 * krefs + 2, nrefs) - res.append(header) - res.extend([pack("<HHH", *r) for r in chunk]) - return ''.join(res) - -class SupBookRecord(BiffRecord): - """ - This record mainly stores the URL of an external document - and a list of sheet names inside this document. Furthermore - it is used to store DDE and OLE object links, or to indicate - an internal 3D reference or an add-in function. See 5.10.3 - for details about external references in BIFF8. - - """ - _REC_ID = 0x01AE - -class InternalReferenceSupBookRecord(SupBookRecord): - """ - In each file occurs a SUPBOOK that is used for internal 3D - references. It stores the number of sheets of the own document. - - Record SUPBOOK for 3D references, BIFF8: - Offset Size Contents - 0 2 Number of sheets in this document - 2 2 01H 04H (relict of BIFF5/BIFF7, the byte string "<04H>", see 3.9.1) - - """ - - def __init__(self, num_sheets): - self._rec_data = pack('<HBB', num_sheets, 0x01, 0x04) - -class XcallSupBookRecord(SupBookRecord): - """ - Add-in function names are stored in EXTERNNAME records following this record. - - Offset Size Contents - 0 2 0001H - 2 2 01H 3AH (relict of BIFF5, the byte string ':', see EXTERNSHEET record, 5.41) - - """ - - def __init__(self): - self._rec_data = pack('<HBB', 1, 0x01, 0x3A) - - -class ExternnameRecord(BiffRecord): - """ - Record EXTERNNAME for external names and Analysis add-in functions, BIFF5-BIFF8: - Offset Size Contents - 0 2 Option flags (see below) - 2 2 0 for global names, or: - BIFF5: One-based index to EXTERNSHEET record containing the sheet name, - BIFF8: One-based index to sheet list in preceding EXTERNALBOOK record. - 4 2 Not used - 6 var. BIFF5: Name (byte string, 8-bit string length, ?2.5.2). - BIFF8: Name (Unicode string, 8-bit string length, ?2.5.3). - See DEFINEDNAME record (?5.33) for a list of built-in names, if the built-in flag is set - in the option flags above. - var. var. Formula data (RPN token array, ?3) - - Option flags for external names (BIFF5-BIFF8) - Bit Mask Contents - 0 0001H 0 = Standard name; 1 = Built-in name - 1 0002H 0 = Manual link; 1 = Automatic link (DDE links and OLE links only) - 2 0004H 1 = Picture link (DDE links and OLE links only) - 3 0008H 1 = This is the “StdDocumentName” identifier (DDE links only) - 4 0010H 1 = OLE link - 14-5 7FE0H Clipboard format of last successful update (DDE links and OLE links only) - 15 8000H 1 = Iconified picture link (BIFF8 OLE links only) - """ - _REC_ID = 0x0023 - - def __init__(self, options=0, index=0, name=None, fmla=None): - self._rec_data = pack('<HHH', options, index, 0) + upack1(name) + fmla - diff --git a/tablib/packages/xlwt/Bitmap.py b/tablib/packages/xlwt/Bitmap.py deleted file mode 100644 index d271665..0000000 --- a/tablib/packages/xlwt/Bitmap.py +++ /dev/null @@ -1,262 +0,0 @@ -# -*- coding: windows-1251 -*- - -# Portions are Copyright (C) 2005 Roman V. Kiseliov -# Portions are Copyright (c) 2004 Evgeny Filatov <fufff@users.sourceforge.net> -# Portions are Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel) - -from BIFFRecords import BiffRecord -from struct import * - - -def _size_col(sheet, col): - return sheet.col_width(col) - - -def _size_row(sheet, row): - return sheet.row_height(row) - - -def _position_image(sheet, row_start, col_start, x1, y1, width, height): - """Calculate the vertices that define the position of the image as required by - the OBJ record. - - +------------+------------+ - | A | B | - +-----+------------+------------+ - | |(x1,y1) | | - | 1 |(A1)._______|______ | - | | | | | - | | | | | - +-----+----| BITMAP |-----+ - | | | | | - | 2 | |______________. | - | | | (B2)| - | | | (x2,y2)| - +---- +------------+------------+ - - Example of a bitmap that covers some of the area from cell A1 to cell B2. - - Based on the width and height of the bitmap we need to calculate 8 vars: - col_start, row_start, col_end, row_end, x1, y1, x2, y2. - The width and height of the cells are also variable and have to be taken into - account. - The values of col_start and row_start are passed in from the calling - function. The values of col_end and row_end are calculated by subtracting - the width and height of the bitmap from the width and height of the - underlying cells. - The vertices are expressed as a percentage of the underlying cell width as - follows (rhs values are in pixels): - - x1 = X / W *1024 - y1 = Y / H *256 - x2 = (X-1) / W *1024 - y2 = (Y-1) / H *256 - - Where: X is distance from the left side of the underlying cell - Y is distance from the top of the underlying cell - W is the width of the cell - H is the height of the cell - - Note: the SDK incorrectly states that the height should be expressed as a - percentage of 1024. - - col_start - Col containing upper left corner of object - row_start - Row containing top left corner of object - x1 - Distance to left side of object - y1 - Distance to top of object - width - Width of image frame - height - Height of image frame - - """ - # Adjust start column for offsets that are greater than the col width - while x1 >= _size_col(sheet, col_start): - x1 -= _size_col(sheet, col_start) - col_start += 1 - # Adjust start row for offsets that are greater than the row height - while y1 >= _size_row(sheet, row_start): - y1 -= _size_row(sheet, row_start) - row_start += 1 - # Initialise end cell to the same as the start cell - row_end = row_start # Row containing bottom right corner of object - col_end = col_start # Col containing lower right corner of object - width = width + x1 - 1 - height = height + y1 - 1 - # Subtract the underlying cell widths to find the end cell of the image - while (width >= _size_col(sheet, col_end)): - width -= _size_col(sheet, col_end) - col_end += 1 - # Subtract the underlying cell heights to find the end cell of the image - while (height >= _size_row(sheet, row_end)): - height -= _size_row(sheet, row_end) - row_end += 1 - # Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell - # with zero height or width. - if ((_size_col(sheet, col_start) == 0) or (_size_col(sheet, col_end) == 0) - or (_size_row(sheet, row_start) == 0) or (_size_row(sheet, row_end) == 0)): - return - # Convert the pixel values to the percentage value expected by Excel - x1 = int(float(x1) / _size_col(sheet, col_start) * 1024) - y1 = int(float(y1) / _size_row(sheet, row_start) * 256) - # Distance to right side of object - x2 = int(float(width) / _size_col(sheet, col_end) * 1024) - # Distance to bottom of object - y2 = int(float(height) / _size_row(sheet, row_end) * 256) - return (col_start, x1, row_start, y1, col_end, x2, row_end, y2) - - -class ObjBmpRecord(BiffRecord): - _REC_ID = 0x005D # Record identifier - - def __init__(self, row, col, sheet, im_data_bmp, x, y, scale_x, scale_y): - # Scale the frame of the image. - width = im_data_bmp.width * scale_x - height = im_data_bmp.height * scale_y - - # Calculate the vertices of the image and write the OBJ record - coordinates = _position_image(sheet, row, col, x, y, width, height) - # print coordinates - col_start, x1, row_start, y1, col_end, x2, row_end, y2 = coordinates - - """Store the OBJ record that precedes an IMDATA record. This could be generalise - to support other Excel objects. - - """ - cObj = 0x0001 # Count of objects in file (set to 1) - OT = 0x0008 # Object type. 8 = Picture - id = 0x0001 # Object ID - grbit = 0x0614 # Option flags - colL = col_start # Col containing upper left corner of object - dxL = x1 # Distance from left side of cell - rwT = row_start # Row containing top left corner of object - dyT = y1 # Distance from top of cell - colR = col_end # Col containing lower right corner of object - dxR = x2 # Distance from right of cell - rwB = row_end # Row containing bottom right corner of object - dyB = y2 # Distance from bottom of cell - cbMacro = 0x0000 # Length of FMLA structure - Reserved1 = 0x0000 # Reserved - Reserved2 = 0x0000 # Reserved - icvBack = 0x09 # Background colour - icvFore = 0x09 # Foreground colour - fls = 0x00 # Fill pattern - fAuto = 0x00 # Automatic fill - icv = 0x08 # Line colour - lns = 0xff # Line style - lnw = 0x01 # Line weight - fAutoB = 0x00 # Automatic border - frs = 0x0000 # Frame style - cf = 0x0009 # Image format, 9 = bitmap - Reserved3 = 0x0000 # Reserved - cbPictFmla = 0x0000 # Length of FMLA structure - Reserved4 = 0x0000 # Reserved - grbit2 = 0x0001 # Option flags - Reserved5 = 0x0000 # Reserved - - data = pack("<L", cObj) - data += pack("<H", OT) - data += pack("<H", id) - data += pack("<H", grbit) - data += pack("<H", colL) - data += pack("<H", dxL) - data += pack("<H", rwT) - data += pack("<H", dyT) - data += pack("<H", colR) - data += pack("<H", dxR) - data += pack("<H", rwB) - data += pack("<H", dyB) - data += pack("<H", cbMacro) - data += pack("<L", Reserved1) - data += pack("<H", Reserved2) - data += pack("<B", icvBack) - data += pack("<B", icvFore) - data += pack("<B", fls) - data += pack("<B", fAuto) - data += pack("<B", icv) - data += pack("<B", lns) - data += pack("<B", lnw) - data += pack("<B", fAutoB) - data += pack("<H", frs) - data += pack("<L", cf) - data += pack("<H", Reserved3) - data += pack("<H", cbPictFmla) - data += pack("<H", Reserved4) - data += pack("<H", grbit2) - data += pack("<L", Reserved5) - - self._rec_data = data - -def _process_bitmap(bitmap): - """Convert a 24 bit bitmap into the modified internal format used by Windows. - This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the - MSDN library. - - """ - # Open file and binmode the data in case the platform needs it. - fh = file(bitmap, "rb") - try: - # Slurp the file into a string. - data = fh.read() - finally: - fh.close() - # Check that the file is big enough to be a bitmap. - if len(data) <= 0x36: - raise Exception("bitmap doesn't contain enough data.") - # The first 2 bytes are used to identify the bitmap. - if (data[:2] != "BM"): - raise Exception("bitmap doesn't appear to to be a valid bitmap image.") - # Remove bitmap data: ID. - data = data[2:] - # Read and remove the bitmap size. This is more reliable than reading - # the data size at offset 0x22. - # - size = unpack("<L", data[:4])[0] - size -= 0x36 # Subtract size of bitmap header. - size += 0x0C # Add size of BIFF header. - data = data[4:] - # Remove bitmap data: reserved, offset, header length. - data = data[12:] - # Read and remove the bitmap width and height. Verify the sizes. - width, height = unpack("<LL", data[:8]) - data = data[8:] - if (width > 0xFFFF): - raise Exception("bitmap: largest image width supported is 65k.") - if (height > 0xFFFF): - raise Exception("bitmap: largest image height supported is 65k.") - # Read and remove the bitmap planes and bpp data. Verify them. - planes, bitcount = unpack("<HH", data[:4]) - data = data[4:] - if (bitcount != 24): - raise Exception("bitmap isn't a 24bit true color bitmap.") - if (planes != 1): - raise Exception("bitmap: only 1 plane supported in bitmap image.") - # Read and remove the bitmap compression. Verify compression. - compression = unpack("<L", data[:4])[0] - data = data[4:] - if (compression != 0): - raise Exception("bitmap: compression not supported in bitmap image.") - # Remove bitmap data: data size, hres, vres, colours, imp. colours. - data = data[20:] - # Add the BITMAPCOREHEADER data - header = pack("<LHHHH", 0x000c, width, height, 0x01, 0x18) - data = header + data - return (width, height, size, data) - - -class ImDataBmpRecord(BiffRecord): - _REC_ID = 0x007F - - def __init__(self, filename): - """Insert a 24bit bitmap image in a worksheet. The main record required is - IMDATA but it must be proceeded by a OBJ record to define its position. - - """ - BiffRecord.__init__(self) - - self.width, self.height, self.size, data = _process_bitmap(filename) - # Write the IMDATA record to store the bitmap data - cf = 0x09 - env = 0x01 - lcb = self.size - self._rec_data = pack("<HHL", cf, env, lcb) + data - - diff --git a/tablib/packages/xlwt/Cell.py b/tablib/packages/xlwt/Cell.py deleted file mode 100644 index 23adf8a..0000000 --- a/tablib/packages/xlwt/Cell.py +++ /dev/null @@ -1,243 +0,0 @@ -# -*- coding: windows-1252 -*- - -from struct import unpack, pack -import BIFFRecords - -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(''.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(''.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 ''.join(pieces) - diff --git a/tablib/packages/xlwt/Column.py b/tablib/packages/xlwt/Column.py deleted file mode 100644 index aac35bf..0000000 --- a/tablib/packages/xlwt/Column.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: windows-1252 -*- - -from BIFFRecords import ColInfoRecord - -class Column(object): - def __init__(self, colx, parent_sheet): - if not(isinstance(colx, int) and 0 <= colx <= 255): - raise ValueError("column index (%r) not an int in range(256)" % colx) - self._index = colx - self._parent = parent_sheet - self._parent_wb = parent_sheet.get_parent() - self._xf_index = 0x0F - - self.width = 0x0B92 - self.hidden = 0 - self.level = 0 - self.collapse = 0 - - def set_style(self, style): - self._xf_index = self._parent_wb.add_style(style) - - def width_in_pixels(self): - # *** Approximation **** - return int(round(self.width * 0.0272 + 0.446, 0)) - - def get_biff_record(self): - options = (self.hidden & 0x01) << 0 - options |= (self.level & 0x07) << 8 - options |= (self.collapse & 0x01) << 12 - - return ColInfoRecord(self._index, self._index, self.width, self._xf_index, options).get() - - - diff --git a/tablib/packages/xlwt/CompoundDoc.py b/tablib/packages/xlwt/CompoundDoc.py deleted file mode 100644 index f60856b..0000000 --- a/tablib/packages/xlwt/CompoundDoc.py +++ /dev/null @@ -1,516 +0,0 @@ -# -*- coding: windows-1252 -*- - -import sys -import struct - -class Reader: - def __init__(self, filename, dump = False): - self.dump = dump - self.STREAMS = {} - - doc = file(filename, 'rb').read() - self.header, self.data = doc[0:512], doc[512:] - del doc - - self.__build_header() - self.__build_MSAT() - self.__build_SAT() - self.__build_directory() - self.__build_short_sectors_data() - - if len(self.short_sectors_data) > 0: - self.__build_SSAT() - else: - if self.dump and (self.total_ssat_sectors != 0 or self.ssat_start_sid != -2): - print 'NOTE: header says that must be', self.total_ssat_sectors, 'short sectors' - print 'NOTE: starting at', self.ssat_start_sid, 'sector' - print 'NOTE: but file does not contains data in short sectors' - self.ssat_start_sid = -2 - self.total_ssat_sectors = 0 - self.SSAT = [-2] - - for dentry in self.dir_entry_list[1:]: - (did, - sz, name, - t, c, - did_left, did_right, did_root, - dentry_start_sid, - stream_size - ) = dentry - stream_data = '' - if stream_size > 0: - if stream_size >= self.min_stream_size: - args = (self.data, self.SAT, dentry_start_sid, self.sect_size) - else: - args = (self.short_sectors_data, self.SSAT, dentry_start_sid, self.short_sect_size) - stream_data = self.get_stream_data(*args) - - if name != '': - # BAD IDEA: names may be equal. NEED use full paths... - self.STREAMS[name] = stream_data - - - def __build_header(self): - self.doc_magic = self.header[0:8] - - if self.doc_magic != '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1': - raise Exception, 'Not an OLE file.' - - self.file_uid = self.header[8:24] - self.rev_num = self.header[24:26] - self.ver_num = self.header[26:28] - self.byte_order = self.header[28:30] - self.log2_sect_size, = struct.unpack('<H', self.header[30:32]) - self.log2_short_sect_size, = struct.unpack('<H', self.header[32:34]) - self.total_sat_sectors, = struct.unpack('<L', self.header[44:48]) - self.dir_start_sid, = struct.unpack('<l', self.header[48:52]) - self.min_stream_size, = struct.unpack('<L', self.header[56:60]) - self.ssat_start_sid, = struct.unpack('<l', self.header[60:64]) - self.total_ssat_sectors, = struct.unpack('<L', self.header[64:68]) - self.msat_start_sid, = struct.unpack('<l', self.header[68:72]) - self.total_msat_sectors, = struct.unpack('<L', self.header[72:76]) - - self.sect_size = 1 << self.log2_sect_size - self.short_sect_size = 1 << self.log2_short_sect_size - - if self.dump: - print 'file magic: ' - print_bin_data(self.doc_magic) - - print 'file uid: ' - print_bin_data(self.file_uid) - - print 'revision number: ' - print_bin_data(self.rev_num) - - print 'version number: ' - print_bin_data(self.ver_num) - - print 'byte order: ' - print_bin_data(self.byte_order) - - print 'sector size :', hex(self.sect_size), self.sect_size - #print 'total sectors in file :', hex(self.total_sectors), self.total_sectors - print 'short sector size :', hex(self.short_sect_size), self.short_sect_size - print 'Total number of sectors used for the SAT :', hex(self.total_sat_sectors), self.total_sat_sectors - print 'SID of first sector of the directory stream:', hex(self.dir_start_sid), self.dir_start_sid - print 'Minimum size of a standard stream :', hex(self.min_stream_size), self.min_stream_size - print 'SID of first sector of the SSAT :', hex(self.ssat_start_sid), self.ssat_start_sid - print 'Total number of sectors used for the SSAT :', hex(self.total_ssat_sectors), self.total_ssat_sectors - print 'SID of first additional sector of the MSAT :', hex(self.msat_start_sid), self.msat_start_sid - print 'Total number of sectors used for the MSAT :', hex(self.total_msat_sectors), self.total_msat_sectors - - - def __build_MSAT(self): - self.MSAT = list(struct.unpack('<109l', self.header[76:])) - - next = self.msat_start_sid - while next > 0: - msat_sector = struct.unpack('<128l', self.data[next*self.sect_size:(next+1)*self.sect_size]) - self.MSAT.extend(msat_sector[:127]) - next = msat_sector[-1] - - if self.dump: - print 'MSAT (header part): \n', self.MSAT[:109] - print 'additional MSAT sectors: \n', self.MSAT[109:] - - - def __build_SAT(self): - sat_stream = ''.join([self.data[i*self.sect_size:(i+1)*self.sect_size] for i in self.MSAT if i >= 0]) - - sat_sids_count = len(sat_stream) >> 2 - self.SAT = struct.unpack('<%dl' % sat_sids_count, sat_stream) # SIDs tuple - - if self.dump: - print 'SAT sid count:\n', sat_sids_count - print 'SAT content:\n', self.SAT - - - def __build_SSAT(self): - ssat_stream = self.get_stream_data(self.data, self.SAT, self.ssat_start_sid, self.sect_size) - - ssids_count = len(ssat_stream) >> 2 - self.SSAT = struct.unpack('<%dl' % ssids_count, ssat_stream) - - if self.dump: - print 'SSID count:', ssids_count - print 'SSAT content:\n', self.SSAT - - - def __build_directory(self): - dir_stream = self.get_stream_data(self.data, self.SAT, self.dir_start_sid, self.sect_size) - - self.dir_entry_list = [] - - i = 0 - while i < len(dir_stream): - dentry = dir_stream[i:i+128] # 128 -- dir entry size - i += 128 - - did = len(self.dir_entry_list) - sz, = struct.unpack('<H', dentry[64:66]) - if sz > 0 : - name = dentry[0:sz-2].decode('utf_16_le', 'replace') - else: - name = u'' - t, = struct.unpack('B', dentry[66]) - c, = struct.unpack('B', dentry[67]) - did_left , = struct.unpack('<l', dentry[68:72]) - did_right , = struct.unpack('<l', dentry[72:76]) - did_root , = struct.unpack('<l', dentry[76:80]) - dentry_start_sid , = struct.unpack('<l', dentry[116:120]) - stream_size , = struct.unpack('<L', dentry[120:124]) - - self.dir_entry_list.extend([(did, sz, name, t, c, - did_left, did_right, did_root, - dentry_start_sid, stream_size)]) - - if self.dump: - dentry_types = { - 0x00: 'Empty', - 0x01: 'User storage', - 0x02: 'User stream', - 0x03: 'LockBytes', - 0x04: 'Property', - 0x05: 'Root storage' - } - node_colours = { - 0x00: 'Red', - 0x01: 'Black' - } - print 'total directory entries:', len(self.dir_entry_list) - - for dentry in self.dir_entry_list: - (did, sz, name, t, c, - did_left, did_right, did_root, - dentry_start_sid, stream_size) = dentry - print 'DID', did - print 'Size of the used area of the character buffer of the name:', sz - print 'dir entry name:', repr(name) - print 'type of entry:', t, dentry_types[t] - print 'entry colour:', c, node_colours[c] - print 'left child DID :', did_left - print 'right child DID:', did_right - print 'root DID :', did_root - print 'start SID :', dentry_start_sid - print 'stream size :', stream_size - if stream_size == 0: - print 'stream is empty' - elif stream_size >= self.min_stream_size: - print 'stream stored as normal stream' - else: - print 'stream stored as short-stream' - - - def __build_short_sectors_data(self): - (did, sz, name, t, c, - did_left, did_right, did_root, - dentry_start_sid, stream_size) = self.dir_entry_list[0] - assert t == 0x05 # Short-Stream Container Stream (SSCS) resides in Root Storage - if stream_size == 0: - self.short_sectors_data = '' - else: - self.short_sectors_data = self.get_stream_data(self.data, self.SAT, dentry_start_sid, self.sect_size) - - - def get_stream_data(self, data, SAT, start_sid, sect_size): - sid = start_sid - chunks = [(sid, sid)] - stream_data = '' - - while SAT[sid] >= 0: - next_in_chain = SAT[sid] - last_chunk_start, last_chunk_finish = chunks[-1] - if next_in_chain == last_chunk_finish + 1: - chunks[-1] = last_chunk_start, next_in_chain - else: - chunks.extend([(next_in_chain, next_in_chain)]) - sid = next_in_chain - for s, f in chunks: - stream_data += data[s*sect_size:(f+1)*sect_size] - #print chunks - return stream_data - - -def print_bin_data(data): - i = 0 - while i < len(data): - j = 0 - while (i < len(data)) and (j < 16): - c = '0x%02X' % ord(data[i]) - sys.stdout.write(c) - sys.stdout.write(' ') - i += 1 - j += 1 - print - if i == 0: - print '<NO DATA>' - - - -# This implementation writes only 'Root Entry', 'Workbook' streams -# and 2 empty streams for aligning directory stream on sector boundary -# -# LAYOUT: -# 0 header -# 76 MSAT (1st part: 109 SID) -# 512 workbook stream -# ... additional MSAT sectors if streams' size > about 7 Mb == (109*512 * 128) -# ... SAT -# ... directory stream -# -# NOTE: this layout is "ad hoc". It can be more general. RTFM - -class XlsDoc: - SECTOR_SIZE = 0x0200 - MIN_LIMIT = 0x1000 - - SID_FREE_SECTOR = -1 - SID_END_OF_CHAIN = -2 - SID_USED_BY_SAT = -3 - SID_USED_BY_MSAT = -4 - - def __init__(self): - #self.book_stream = '' # padded - self.book_stream_sect = [] - - self.dir_stream = '' - self.dir_stream_sect = [] - - self.packed_SAT = '' - self.SAT_sect = [] - - self.packed_MSAT_1st = '' - self.packed_MSAT_2nd = '' - self.MSAT_sect_2nd = [] - - self.header = '' - - def __build_directory(self): # align on sector boundary - self.dir_stream = '' - - dentry_name = '\x00'.join('Root Entry\x00') + '\x00' - dentry_name_sz = len(dentry_name) - dentry_name_pad = '\x00'*(64 - dentry_name_sz) - dentry_type = 0x05 # root storage - dentry_colour = 0x01 # black - dentry_did_left = -1 - dentry_did_right = -1 - dentry_did_root = 1 - dentry_start_sid = -2 - dentry_stream_sz = 0 - - self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L', - dentry_name + dentry_name_pad, - dentry_name_sz, - dentry_type, - dentry_colour, - dentry_did_left, - dentry_did_right, - dentry_did_root, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - dentry_start_sid, - dentry_stream_sz, - 0 - ) - - dentry_name = '\x00'.join('Workbook\x00') + '\x00' - dentry_name_sz = len(dentry_name) - dentry_name_pad = '\x00'*(64 - dentry_name_sz) - dentry_type = 0x02 # user stream - dentry_colour = 0x01 # black - dentry_did_left = -1 - dentry_did_right = -1 - dentry_did_root = -1 - dentry_start_sid = 0 - dentry_stream_sz = self.book_stream_len - - self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L', - dentry_name + dentry_name_pad, - dentry_name_sz, - dentry_type, - dentry_colour, - dentry_did_left, - dentry_did_right, - dentry_did_root, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - dentry_start_sid, - dentry_stream_sz, - 0 - ) - - # padding - dentry_name = '' - dentry_name_sz = len(dentry_name) - dentry_name_pad = '\x00'*(64 - dentry_name_sz) - dentry_type = 0x00 # empty - dentry_colour = 0x01 # black - dentry_did_left = -1 - dentry_did_right = -1 - dentry_did_root = -1 - dentry_start_sid = -2 - dentry_stream_sz = 0 - - self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L', - dentry_name + dentry_name_pad, - dentry_name_sz, - dentry_type, - dentry_colour, - dentry_did_left, - dentry_did_right, - dentry_did_root, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - dentry_start_sid, - dentry_stream_sz, - 0 - ) * 2 - - def __build_sat(self): - # Build SAT - book_sect_count = self.book_stream_len >> 9 - dir_sect_count = len(self.dir_stream) >> 9 - - total_sect_count = book_sect_count + dir_sect_count - SAT_sect_count = 0 - MSAT_sect_count = 0 - SAT_sect_count_limit = 109 - while total_sect_count > 128*SAT_sect_count or SAT_sect_count > SAT_sect_count_limit: - SAT_sect_count += 1 - total_sect_count += 1 - if SAT_sect_count > SAT_sect_count_limit: - MSAT_sect_count += 1 - total_sect_count += 1 - SAT_sect_count_limit += 127 - - - SAT = [self.SID_FREE_SECTOR]*128*SAT_sect_count - - sect = 0 - while sect < book_sect_count - 1: - self.book_stream_sect.append(sect) - SAT[sect] = sect + 1 - sect += 1 - self.book_stream_sect.append(sect) - SAT[sect] = self.SID_END_OF_CHAIN - sect += 1 - - while sect < book_sect_count + MSAT_sect_count: - self.MSAT_sect_2nd.append(sect) - SAT[sect] = self.SID_USED_BY_MSAT - sect += 1 - - while sect < book_sect_count + MSAT_sect_count + SAT_sect_count: - self.SAT_sect.append(sect) - SAT[sect] = self.SID_USED_BY_SAT - sect += 1 - - while sect < book_sect_count + MSAT_sect_count + SAT_sect_count + dir_sect_count - 1: - self.dir_stream_sect.append(sect) - SAT[sect] = sect + 1 - sect += 1 - self.dir_stream_sect.append(sect) - SAT[sect] = self.SID_END_OF_CHAIN - sect += 1 - - self.packed_SAT = struct.pack('<%dl' % (SAT_sect_count*128), *SAT) - - MSAT_1st = [self.SID_FREE_SECTOR]*109 - for i, SAT_sect_num in zip(range(0, 109), self.SAT_sect): - MSAT_1st[i] = SAT_sect_num - self.packed_MSAT_1st = struct.pack('<109l', *MSAT_1st) - - MSAT_2nd = [self.SID_FREE_SECTOR]*128*MSAT_sect_count - if MSAT_sect_count > 0: - MSAT_2nd[- 1] = self.SID_END_OF_CHAIN - - i = 109 - msat_sect = 0 - sid_num = 0 - while i < SAT_sect_count: - if (sid_num + 1) % 128 == 0: - #print 'link: ', - msat_sect += 1 - if msat_sect < len(self.MSAT_sect_2nd): - MSAT_2nd[sid_num] = self.MSAT_sect_2nd[msat_sect] - else: - #print 'sid: ', - MSAT_2nd[sid_num] = self.SAT_sect[i] - i += 1 - #print sid_num, MSAT_2nd[sid_num] - sid_num += 1 - - self.packed_MSAT_2nd = struct.pack('<%dl' % (MSAT_sect_count*128), *MSAT_2nd) - - #print vars() - #print zip(range(0, sect), SAT) - #print self.book_stream_sect - #print self.MSAT_sect_2nd - #print MSAT_2nd - #print self.SAT_sect - #print self.dir_stream_sect - - - def __build_header(self): - doc_magic = '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1' - file_uid = '\x00'*16 - rev_num = '\x3E\x00' - ver_num = '\x03\x00' - byte_order = '\xFE\xFF' - log_sect_size = struct.pack('<H', 9) - log_short_sect_size = struct.pack('<H', 6) - not_used0 = '\x00'*10 - total_sat_sectors = struct.pack('<L', len(self.SAT_sect)) - dir_start_sid = struct.pack('<l', self.dir_stream_sect[0]) - not_used1 = '\x00'*4 - min_stream_size = struct.pack('<L', 0x1000) - ssat_start_sid = struct.pack('<l', -2) - total_ssat_sectors = struct.pack('<L', 0) - - if len(self.MSAT_sect_2nd) == 0: - msat_start_sid = struct.pack('<l', -2) - else: - msat_start_sid = struct.pack('<l', self.MSAT_sect_2nd[0]) - - total_msat_sectors = struct.pack('<L', len(self.MSAT_sect_2nd)) - - self.header = ''.join([ doc_magic, - file_uid, - rev_num, - ver_num, - byte_order, - log_sect_size, - log_short_sect_size, - not_used0, - total_sat_sectors, - dir_start_sid, - not_used1, - min_stream_size, - ssat_start_sid, - total_ssat_sectors, - msat_start_sid, - total_msat_sectors - ]) - - - def save(self, file_name_or_filelike_obj, stream): - # 1. Align stream on 0x1000 boundary (and therefore on sector boundary) - padding = '\x00' * (0x1000 - (len(stream) % 0x1000)) - self.book_stream_len = len(stream) + len(padding) - - self.__build_directory() - self.__build_sat() - self.__build_header() - - f = file_name_or_filelike_obj - we_own_it = not hasattr(f, 'write') - if we_own_it: - f = open(file_name_or_filelike_obj, 'wb') - f.write(self.header) - f.write(self.packed_MSAT_1st) - f.write(stream) - f.write(padding) - f.write(self.packed_MSAT_2nd) - f.write(self.packed_SAT) - f.write(self.dir_stream) - if we_own_it: - f.close() diff --git a/tablib/packages/xlwt/ExcelFormula.py b/tablib/packages/xlwt/ExcelFormula.py deleted file mode 100644 index 698d970..0000000 --- a/tablib/packages/xlwt/ExcelFormula.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: windows-1252 -*- - -import ExcelFormulaParser, ExcelFormulaLexer -import struct -from antlr import ANTLRException - - -class Formula(object): - __slots__ = ["__init__", "__s", "__parser", "__sheet_refs", "__xcall_refs"] - - - def __init__(self, s): - try: - self.__s = s - lexer = ExcelFormulaLexer.Lexer(s) - self.__parser = ExcelFormulaParser.Parser(lexer) - self.__parser.formula() - self.__sheet_refs = self.__parser.sheet_references - self.__xcall_refs = self.__parser.xcall_references - except ANTLRException, e: - # print e - raise ExcelFormulaParser.FormulaParseException, "can't parse formula " + s - - def get_references(self): - return self.__sheet_refs, self.__xcall_refs - - def patch_references(self, patches): - for offset, idx in patches: - self.__parser.rpn = self.__parser.rpn[:offset] + struct.pack('<H', idx) + self.__parser.rpn[offset+2:] - - def text(self): - return self.__s - - def rpn(self): - ''' - Offset Size Contents - 0 2 Size of the following formula data (sz) - 2 sz Formula data (RPN token array) - [2+sz] var. (optional) Additional data for specific tokens - - ''' - return struct.pack("<H", len(self.__parser.rpn)) + self.__parser.rpn - diff --git a/tablib/packages/xlwt/ExcelFormulaLexer.py b/tablib/packages/xlwt/ExcelFormulaLexer.py deleted file mode 100644 index 5004d8e..0000000 --- a/tablib/packages/xlwt/ExcelFormulaLexer.py +++ /dev/null @@ -1,128 +0,0 @@ -# -*- coding: windows-1252 -*- - -import sys -from antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException -import struct -import ExcelFormulaParser -from re import compile as recompile, match, UNICODE, IGNORECASE, VERBOSE - - -int_const_pattern = r"\d+\b" -flt_const_pattern = r""" - (?: - (?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc - | - (?: \d+ \. ) # 1. 12. 123. etc - ) - # followed by optional exponent part - (?: [Ee] [+-]? \d+ ) ? - """ -str_const_pattern = r'"(?:[^"]|"")*"' -#range2d_pattern = recompile(r"\$?[A-I]?[A-Z]\$?\d+:\$?[A-I]?[A-Z]\$?\d+" -ref2d_r1c1_pattern = r"[Rr]0*[1-9][0-9]*[Cc]0*[1-9][0-9]*" -ref2d_pattern = r"\$?[A-I]?[A-Z]\$?0*[1-9][0-9]*" -true_pattern = r"TRUE\b" -false_pattern = r"FALSE\b" -if_pattern = r"IF\b" -choose_pattern = r"CHOOSE\b" -name_pattern = r"\w[\.\w]*" -quotename_pattern = r"'(?:[^']|'')*'" #### It's essential that this bracket be non-grouping. -ne_pattern = r"<>" -ge_pattern = r">=" -le_pattern = r"<=" - -pattern_type_tuples = ( - (flt_const_pattern, ExcelFormulaParser.NUM_CONST), - (int_const_pattern, ExcelFormulaParser.INT_CONST), - (str_const_pattern, ExcelFormulaParser.STR_CONST), -# (range2d_pattern , ExcelFormulaParser.RANGE2D), - (ref2d_r1c1_pattern, ExcelFormulaParser.REF2D_R1C1), - (ref2d_pattern , ExcelFormulaParser.REF2D), - (true_pattern , ExcelFormulaParser.TRUE_CONST), - (false_pattern , ExcelFormulaParser.FALSE_CONST), - (if_pattern , ExcelFormulaParser.FUNC_IF), - (choose_pattern , ExcelFormulaParser.FUNC_CHOOSE), - (name_pattern , ExcelFormulaParser.NAME), - (quotename_pattern, ExcelFormulaParser.QUOTENAME), - (ne_pattern, ExcelFormulaParser.NE), - (ge_pattern, ExcelFormulaParser.GE), - (le_pattern, ExcelFormulaParser.LE), -) - -_re = recompile( - '(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')', - VERBOSE+IGNORECASE) - -_toktype = [None] + [i[1] for i in pattern_type_tuples] -# need dummy at start because re.MatchObject.lastindex counts from 1 - -single_char_lookup = { - '=': ExcelFormulaParser.EQ, - '<': ExcelFormulaParser.LT, - '>': ExcelFormulaParser.GT, - '+': ExcelFormulaParser.ADD, - '-': ExcelFormulaParser.SUB, - '*': ExcelFormulaParser.MUL, - '/': ExcelFormulaParser.DIV, - ':': ExcelFormulaParser.COLON, - ';': ExcelFormulaParser.SEMICOLON, - ',': ExcelFormulaParser.COMMA, - '(': ExcelFormulaParser.LP, - ')': ExcelFormulaParser.RP, - '&': ExcelFormulaParser.CONCAT, - '%': ExcelFormulaParser.PERCENT, - '^': ExcelFormulaParser.POWER, - '!': ExcelFormulaParser.BANG, - } - -class Lexer(TokenStream): - def __init__(self, text): - self._text = text[:] - self._pos = 0 - self._line = 0 - - def isEOF(self): - return len(self._text) <= self._pos - - def curr_ch(self): - return self._text[self._pos] - - def next_ch(self, n = 1): - self._pos += n - - def is_whitespace(self): - return self.curr_ch() in " \t\n\r\f\v" - - def match_pattern(self): - m = _re.match(self._text, self._pos) - if not m: - return None - self._pos = m.end(0) - return Tok(type = _toktype[m.lastindex], text = m.group(0), col = m.start(0) + 1) - - def nextToken(self): - # skip whitespace - while not self.isEOF() and self.is_whitespace(): - self.next_ch() - if self.isEOF(): - return Tok(type = EOF) - # first, try to match token with 2 or more chars - t = self.match_pattern() - if t: - return t - # second, we want 1-char tokens - te = self.curr_ch() - try: - ty = single_char_lookup[te] - except KeyError: - raise TokenStreamException( - "Unexpected char %r in column %u." % (self.curr_ch(), self._pos)) - self.next_ch() - return Tok(type=ty, text=te, col=self._pos) - -if __name__ == '__main__': - try: - for t in Lexer(""" 1.23 456 "abcd" R2C2 a1 iv65536 true false if choose a_name 'qname' <> >= <= """): - print t - except TokenStreamException, e: - print "error:", e diff --git a/tablib/packages/xlwt/ExcelFormulaParser.py b/tablib/packages/xlwt/ExcelFormulaParser.py deleted file mode 100644 index 000a8a0..0000000 --- a/tablib/packages/xlwt/ExcelFormulaParser.py +++ /dev/null @@ -1,677 +0,0 @@ -### $ANTLR 2.7.7 (20060930): "xlwt/excel-formula.g" -> "ExcelFormulaParser.py"$ -### import antlr and other modules .. -import sys -import antlr - -version = sys.version.split()[0] -if version < '2.2.1': - False = 0 -if version < '2.3': - True = not False -### header action >>> -import struct -import Utils -from UnicodeUtils import upack1 -from ExcelMagic import * - -_RVAdelta = {"R": 0, "V": 0x20, "A": 0x40} -_RVAdeltaRef = {"R": 0, "V": 0x20, "A": 0x40, "D": 0x20} -_RVAdeltaArea = {"R": 0, "V": 0x20, "A": 0x40, "D": 0} - - -class FormulaParseException(Exception): - """ - An exception indicating that a Formula could not be successfully parsed. - """ -### header action <<< -### preamble action>>> - -### preamble action <<< - -### import antlr.Token -from antlr import Token -### >>>The Known Token Types <<< -SKIP = antlr.SKIP -INVALID_TYPE = antlr.INVALID_TYPE -EOF_TYPE = antlr.EOF_TYPE -EOF = antlr.EOF -NULL_TREE_LOOKAHEAD = antlr.NULL_TREE_LOOKAHEAD -MIN_USER_TYPE = antlr.MIN_USER_TYPE -TRUE_CONST = 4 -FALSE_CONST = 5 -STR_CONST = 6 -NUM_CONST = 7 -INT_CONST = 8 -FUNC_IF = 9 -FUNC_CHOOSE = 10 -NAME = 11 -QUOTENAME = 12 -EQ = 13 -NE = 14 -GT = 15 -LT = 16 -GE = 17 -LE = 18 -ADD = 19 -SUB = 20 -MUL = 21 -DIV = 22 -POWER = 23 -PERCENT = 24 -LP = 25 -RP = 26 -LB = 27 -RB = 28 -COLON = 29 -COMMA = 30 -SEMICOLON = 31 -REF2D = 32 -REF2D_R1C1 = 33 -BANG = 34 -CONCAT = 35 - -class Parser(antlr.LLkParser): - ### user action >>> - ### user action <<< - - def __init__(self, *args, **kwargs): - antlr.LLkParser.__init__(self, *args, **kwargs) - self.tokenNames = _tokenNames - ### __init__ header action >>> - self.rpn = "" - self.sheet_references = [] - self.xcall_references = [] - ### __init__ header action <<< - - def formula(self): - - pass - self.expr("V") - - def expr(self, - arg_type - ): - - pass - self.prec0_expr(arg_type) - while True: - if ((self.LA(1) >= EQ and self.LA(1) <= LE)): - pass - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [EQ]: - pass - self.match(EQ) - op = struct.pack('B', ptgEQ) - elif la1 and la1 in [NE]: - pass - self.match(NE) - op = struct.pack('B', ptgNE) - elif la1 and la1 in [GT]: - pass - self.match(GT) - op = struct.pack('B', ptgGT) - elif la1 and la1 in [LT]: - pass - self.match(LT) - op = struct.pack('B', ptgLT) - elif la1 and la1 in [GE]: - pass - self.match(GE) - op = struct.pack('B', ptgGE) - elif la1 and la1 in [LE]: - pass - self.match(LE) - op = struct.pack('B', ptgLE) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.prec0_expr(arg_type) - self.rpn += op - else: - break - - - def prec0_expr(self, - arg_type - ): - - pass - self.prec1_expr(arg_type) - while True: - if (self.LA(1)==CONCAT): - pass - pass - self.match(CONCAT) - op = struct.pack('B', ptgConcat) - self.prec1_expr(arg_type) - self.rpn += op - else: - break - - - def prec1_expr(self, - arg_type - ): - - pass - self.prec2_expr(arg_type) - while True: - if (self.LA(1)==ADD or self.LA(1)==SUB): - pass - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [ADD]: - pass - self.match(ADD) - op = struct.pack('B', ptgAdd) - elif la1 and la1 in [SUB]: - pass - self.match(SUB) - op = struct.pack('B', ptgSub) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.prec2_expr(arg_type) - self.rpn += op; - # print "**prec1_expr4 %s" % arg_type - else: - break - - - def prec2_expr(self, - arg_type - ): - - pass - self.prec3_expr(arg_type) - while True: - if (self.LA(1)==MUL or self.LA(1)==DIV): - pass - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [MUL]: - pass - self.match(MUL) - op = struct.pack('B', ptgMul) - elif la1 and la1 in [DIV]: - pass - self.match(DIV) - op = struct.pack('B', ptgDiv) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.prec3_expr(arg_type) - self.rpn += op - else: - break - - - def prec3_expr(self, - arg_type - ): - - pass - self.prec4_expr(arg_type) - while True: - if (self.LA(1)==POWER): - pass - pass - self.match(POWER) - op = struct.pack('B', ptgPower) - self.prec4_expr(arg_type) - self.rpn += op - else: - break - - - def prec4_expr(self, - arg_type - ): - - pass - self.prec5_expr(arg_type) - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [PERCENT]: - pass - self.match(PERCENT) - self.rpn += struct.pack('B', ptgPercent) - elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,RP,COMMA,SEMICOLON,CONCAT]: - pass - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - - def prec5_expr(self, - arg_type - ): - - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,LP,REF2D]: - pass - self.primary(arg_type) - elif la1 and la1 in [SUB]: - pass - self.match(SUB) - self.primary(arg_type) - self.rpn += struct.pack('B', ptgUminus) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - - def primary(self, - arg_type - ): - - str_tok = None - int_tok = None - num_tok = None - ref2d_tok = None - ref2d1_tok = None - ref2d2_tok = None - ref3d_ref2d = None - ref3d_ref2d2 = None - name_tok = None - func_tok = None - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [TRUE_CONST]: - pass - self.match(TRUE_CONST) - self.rpn += struct.pack("2B", ptgBool, 1) - elif la1 and la1 in [FALSE_CONST]: - pass - self.match(FALSE_CONST) - self.rpn += struct.pack("2B", ptgBool, 0) - elif la1 and la1 in [STR_CONST]: - pass - str_tok = self.LT(1) - self.match(STR_CONST) - self.rpn += struct.pack("B", ptgStr) + upack1(str_tok.text[1:-1].replace("\"\"", "\"")) - elif la1 and la1 in [NUM_CONST]: - pass - num_tok = self.LT(1) - self.match(NUM_CONST) - self.rpn += struct.pack("<Bd", ptgNum, float(num_tok.text)) - elif la1 and la1 in [FUNC_IF]: - pass - self.match(FUNC_IF) - self.match(LP) - self.expr("V") - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [SEMICOLON]: - pass - self.match(SEMICOLON) - elif la1 and la1 in [COMMA]: - pass - self.match(COMMA) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.rpn += struct.pack("<BBH", ptgAttr, 0x02, 0) # tAttrIf - pos0 = len(self.rpn) - 2 - self.expr(arg_type) - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [SEMICOLON]: - pass - self.match(SEMICOLON) - elif la1 and la1 in [COMMA]: - pass - self.match(COMMA) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 0) # tAttrSkip - pos1 = len(self.rpn) - 2 - self.rpn = self.rpn[:pos0] + struct.pack("<H", pos1-pos0) + self.rpn[pos0+2:] - self.expr(arg_type) - self.match(RP) - self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 3) # tAttrSkip - self.rpn += struct.pack("<BBH", ptgFuncVarR, 3, 1) # 3 = nargs, 1 = IF func - pos2 = len(self.rpn) - self.rpn = self.rpn[:pos1] + struct.pack("<H", pos2-(pos1+2)-1) + self.rpn[pos1+2:] - elif la1 and la1 in [FUNC_CHOOSE]: - pass - self.match(FUNC_CHOOSE) - arg_type = "R" - rpn_chunks = [] - self.match(LP) - self.expr("V") - rpn_start = len(self.rpn) - ref_markers = [len(self.sheet_references)] - while True: - if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON): - pass - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [SEMICOLON]: - pass - self.match(SEMICOLON) - elif la1 and la1 in [COMMA]: - pass - self.match(COMMA) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - mark = len(self.rpn) - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]: - pass - self.expr(arg_type) - elif la1 and la1 in [RP,COMMA,SEMICOLON]: - pass - self.rpn += struct.pack("B", ptgMissArg) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - rpn_chunks.append(self.rpn[mark:]) - ref_markers.append(len(self.sheet_references)) - else: - break - - self.match(RP) - self.rpn = self.rpn[:rpn_start] - nc = len(rpn_chunks) - chunklens = [len(chunk) for chunk in rpn_chunks] - skiplens = [0] * nc - skiplens[-1] = 3 - for ic in xrange(nc-1, 0, -1): - skiplens[ic-1] = skiplens[ic] + chunklens[ic] + 4 - jump_pos = [2 * nc + 2] - for ic in xrange(nc): - jump_pos.append(jump_pos[-1] + chunklens[ic] + 4) - chunk_shift = 2 * nc + 6 # size of tAttrChoose - for ic in xrange(nc): - for refx in xrange(ref_markers[ic], ref_markers[ic+1]): - ref = self.sheet_references[refx] - self.sheet_references[refx] = (ref[0], ref[1], ref[2] + chunk_shift) - chunk_shift += 4 # size of tAttrSkip - choose_rpn = [] - choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x04, nc)) # 0x04 is tAttrChoose - choose_rpn.append(struct.pack("<%dH" % (nc+1), *jump_pos)) - for ic in xrange(nc): - choose_rpn.append(rpn_chunks[ic]) - choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x08, skiplens[ic])) # 0x08 is tAttrSkip - choose_rpn.append(struct.pack("<BBH", ptgFuncVarV, nc+1, 100)) # 100 is CHOOSE fn - self.rpn += "".join(choose_rpn) - elif la1 and la1 in [LP]: - pass - self.match(LP) - self.expr(arg_type) - self.match(RP) - self.rpn += struct.pack("B", ptgParen) - else: - if (self.LA(1)==INT_CONST) and (_tokenSet_0.member(self.LA(2))): - pass - int_tok = self.LT(1) - self.match(INT_CONST) - # print "**int_const", int_tok.text - int_value = int(int_tok.text) - if int_value <= 65535: - self.rpn += struct.pack("<BH", ptgInt, int_value) - else: - self.rpn += struct.pack("<Bd", ptgNum, float(int_value)) - elif (self.LA(1)==REF2D) and (_tokenSet_0.member(self.LA(2))): - pass - ref2d_tok = self.LT(1) - self.match(REF2D) - # print "**ref2d %s %s" % (ref2d_tok.text, arg_type) - r, c = Utils.cell_to_packed_rowcol(ref2d_tok.text) - ptg = ptgRefR + _RVAdeltaRef[arg_type] - self.rpn += struct.pack("<B2H", ptg, r, c) - elif (self.LA(1)==REF2D) and (self.LA(2)==COLON): - pass - ref2d1_tok = self.LT(1) - self.match(REF2D) - self.match(COLON) - ref2d2_tok = self.LT(1) - self.match(REF2D) - r1, c1 = Utils.cell_to_packed_rowcol(ref2d1_tok.text) - r2, c2 = Utils.cell_to_packed_rowcol(ref2d2_tok.text) - ptg = ptgAreaR + _RVAdeltaArea[arg_type] - self.rpn += struct.pack("<B4H", ptg, r1, r2, c1, c2) - elif (self.LA(1)==INT_CONST or self.LA(1)==NAME or self.LA(1)==QUOTENAME) and (self.LA(2)==COLON or self.LA(2)==BANG): - pass - sheet1=self.sheet() - sheet2 = sheet1 - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [COLON]: - pass - self.match(COLON) - sheet2=self.sheet() - elif la1 and la1 in [BANG]: - pass - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.match(BANG) - ref3d_ref2d = self.LT(1) - self.match(REF2D) - ptg = ptgRef3dR + _RVAdeltaRef[arg_type] - rpn_ref2d = "" - r1, c1 = Utils.cell_to_packed_rowcol(ref3d_ref2d.text) - rpn_ref2d = struct.pack("<3H", 0x0000, r1, c1) - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [COLON]: - pass - self.match(COLON) - ref3d_ref2d2 = self.LT(1) - self.match(REF2D) - ptg = ptgArea3dR + _RVAdeltaArea[arg_type] - r2, c2 = Utils.cell_to_packed_rowcol(ref3d_ref2d2.text) - rpn_ref2d = struct.pack("<5H", 0x0000, r1, r2, c1, c2) - elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,PERCENT,RP,COMMA,SEMICOLON,CONCAT]: - pass - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - self.rpn += struct.pack("<B", ptg) - self.sheet_references.append((sheet1, sheet2, len(self.rpn))) - self.rpn += rpn_ref2d - elif (self.LA(1)==NAME) and (_tokenSet_0.member(self.LA(2))): - pass - name_tok = self.LT(1) - self.match(NAME) - raise Exception("[formula] found unexpected NAME token (%r)" % name_tok.txt) - # #### TODO: handle references to defined names here - elif (self.LA(1)==NAME) and (self.LA(2)==LP): - pass - func_tok = self.LT(1) - self.match(NAME) - func_toku = func_tok.text.upper() - if func_toku in all_funcs_by_name: - (opcode, - min_argc, - max_argc, - func_type, - arg_type_str) = all_funcs_by_name[func_toku] - arg_type_list = list(arg_type_str) - else: - raise Exception("[formula] unknown function (%s)" % func_tok.text) - # print "**func_tok1 %s %s" % (func_toku, func_type) - xcall = opcode < 0 - if xcall: - # The name of the add-in function is passed as the 1st arg - # of the hidden XCALL function - self.xcall_references.append((func_toku, len(self.rpn) + 1)) - self.rpn += struct.pack("<BHHH", - ptgNameXR, - 0xadde, # ##PATCHME## index to REF entry in EXTERNSHEET record - 0xefbe, # ##PATCHME## one-based index to EXTERNNAME record - 0x0000) # unused - self.match(LP) - arg_count=self.expr_list(arg_type_list, min_argc, max_argc) - self.match(RP) - if arg_count > max_argc or arg_count < min_argc: - raise Exception, "%d parameters for function: %s" % (arg_count, func_tok.text) - if xcall: - func_ptg = ptgFuncVarR + _RVAdelta[func_type] - self.rpn += struct.pack("<2BH", func_ptg, arg_count + 1, 255) # 255 is magic XCALL function - elif min_argc == max_argc: - func_ptg = ptgFuncR + _RVAdelta[func_type] - self.rpn += struct.pack("<BH", func_ptg, opcode) - elif arg_count == 1 and func_tok.text.upper() == "SUM": - self.rpn += struct.pack("<BBH", ptgAttr, 0x10, 0) # tAttrSum - else: - func_ptg = ptgFuncVarR + _RVAdelta[func_type] - self.rpn += struct.pack("<2BH", func_ptg, arg_count, opcode) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - - def sheet(self): - ref = None - - sheet_ref_name = None - sheet_ref_int = None - sheet_ref_quote = None - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [NAME]: - pass - sheet_ref_name = self.LT(1) - self.match(NAME) - ref = sheet_ref_name.text - elif la1 and la1 in [INT_CONST]: - pass - sheet_ref_int = self.LT(1) - self.match(INT_CONST) - ref = sheet_ref_int.text - elif la1 and la1 in [QUOTENAME]: - pass - sheet_ref_quote = self.LT(1) - self.match(QUOTENAME) - ref = sheet_ref_quote.text[1:-1].replace("''", "'") - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - return ref - - def expr_list(self, - arg_type_list, min_argc, max_argc - ): - arg_cnt = None - - arg_cnt = 0 - arg_type = arg_type_list[arg_cnt] - # print "**expr_list1[%d] req=%s" % (arg_cnt, arg_type) - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]: - pass - self.expr(arg_type) - arg_cnt += 1 - while True: - if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON): - pass - if arg_cnt < len(arg_type_list): - arg_type = arg_type_list[arg_cnt] - else: - arg_type = arg_type_list[-1] - if arg_type == "+": - arg_type = arg_type_list[-2] - # print "**expr_list2[%d] req=%s" % (arg_cnt, arg_type) - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [SEMICOLON]: - pass - self.match(SEMICOLON) - elif la1 and la1 in [COMMA]: - pass - self.match(COMMA) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - la1 = self.LA(1) - if False: - pass - elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]: - pass - self.expr(arg_type) - elif la1 and la1 in [RP,COMMA,SEMICOLON]: - pass - self.rpn += struct.pack("B", ptgMissArg) - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - arg_cnt += 1 - else: - break - - elif la1 and la1 in [RP]: - pass - else: - raise antlr.NoViableAltException(self.LT(1), self.getFilename()) - - return arg_cnt - - -_tokenNames = [ - "<0>", - "EOF", - "<2>", - "NULL_TREE_LOOKAHEAD", - "TRUE_CONST", - "FALSE_CONST", - "STR_CONST", - "NUM_CONST", - "INT_CONST", - "FUNC_IF", - "FUNC_CHOOSE", - "NAME", - "QUOTENAME", - "EQ", - "NE", - "GT", - "LT", - "GE", - "LE", - "ADD", - "SUB", - "MUL", - "DIV", - "POWER", - "PERCENT", - "LP", - "RP", - "LB", - "RB", - "COLON", - "COMMA", - "SEMICOLON", - "REF2D", - "REF2D_R1C1", - "BANG", - "CONCAT" -] - - -### generate bit set -def mk_tokenSet_0(): - ### var1 - data = [ 37681618946L, 0L] - return data -_tokenSet_0 = antlr.BitSet(mk_tokenSet_0()) - diff --git a/tablib/packages/xlwt/ExcelMagic.py b/tablib/packages/xlwt/ExcelMagic.py deleted file mode 100644 index a49ae1f..0000000 --- a/tablib/packages/xlwt/ExcelMagic.py +++ /dev/null @@ -1,862 +0,0 @@ -# -*- coding: ascii -*- -""" -lots of Excel Magic Numbers -""" - -# Boundaries BIFF8+ - -MAX_ROW = 65536 -MAX_COL = 256 - - -biff_records = { - 0x0000: "DIMENSIONS", - 0x0001: "BLANK", - 0x0002: "INTEGER", - 0x0003: "NUMBER", - 0x0004: "LABEL", - 0x0005: "BOOLERR", - 0x0006: "FORMULA", - 0x0007: "STRING", - 0x0008: "ROW", - 0x0009: "BOF", - 0x000A: "EOF", - 0x000B: "INDEX", - 0x000C: "CALCCOUNT", - 0x000D: "CALCMODE", - 0x000E: "PRECISION", - 0x000F: "REFMODE", - 0x0010: "DELTA", - 0x0011: "ITERATION", - 0x0012: "PROTECT", - 0x0013: "PASSWORD", - 0x0014: "HEADER", - 0x0015: "FOOTER", - 0x0016: "EXTERNCOUNT", - 0x0017: "EXTERNSHEET", - 0x0018: "NAME", - 0x0019: "WINDOWPROTECT", - 0x001A: "VERTICALPAGEBREAKS", - 0x001B: "HORIZONTALPAGEBREAKS", - 0x001C: "NOTE", - 0x001D: "SELECTION", - 0x001E: "FORMAT", - 0x001F: "FORMATCOUNT", - 0x0020: "COLUMNDEFAULT", - 0x0021: "ARRAY", - 0x0022: "1904", - 0x0023: "EXTERNNAME", - 0x0024: "COLWIDTH", - 0x0025: "DEFAULTROWHEIGHT", - 0x0026: "LEFTMARGIN", - 0x0027: "RIGHTMARGIN", - 0x0028: "TOPMARGIN", - 0x0029: "BOTTOMMARGIN", - 0x002A: "PRINTHEADERS", - 0x002B: "PRINTGRIDLINES", - 0x002F: "FILEPASS", - 0x0031: "FONT", - 0x0036: "TABLE", - 0x003C: "CONTINUE", - 0x003D: "WINDOW1", - 0x003E: "WINDOW2", - 0x0040: "BACKUP", - 0x0041: "PANE", - 0x0042: "CODEPAGE", - 0x0043: "XF", - 0x0044: "IXFE", - 0x0045: "EFONT", - 0x004D: "PLS", - 0x0050: "DCON", - 0x0051: "DCONREF", - 0x0053: "DCONNAME", - 0x0055: "DEFCOLWIDTH", - 0x0056: "BUILTINFMTCNT", - 0x0059: "XCT", - 0x005A: "CRN", - 0x005B: "FILESHARING", - 0x005C: "WRITEACCESS", - 0x005D: "OBJ", - 0x005E: "UNCALCED", - 0x005F: "SAFERECALC", - 0x0060: "TEMPLATE", - 0x0063: "OBJPROTECT", - 0x007D: "COLINFO", - 0x007E: "RK", - 0x007F: "IMDATA", - 0x0080: "GUTS", - 0x0081: "WSBOOL", - 0x0082: "GRIDSET", - 0x0083: "HCENTER", - 0x0084: "VCENTER", - 0x0085: "BOUNDSHEET", - 0x0086: "WRITEPROT", - 0x0087: "ADDIN", - 0x0088: "EDG", - 0x0089: "PUB", - 0x008C: "COUNTRY", - 0x008D: "HIDEOBJ", - 0x008E: "BUNDLESOFFSET", - 0x008F: "BUNDLEHEADER", - 0x0090: "SORT", - 0x0091: "SUB", - 0x0092: "PALETTE", - 0x0093: "STYLE", - 0x0094: "LHRECORD", - 0x0095: "LHNGRAPH", - 0x0096: "SOUND", - 0x0098: "LPR", - 0x0099: "STANDARDWIDTH", - 0x009A: "FNGROUPNAME", - 0x009B: "FILTERMODE", - 0x009C: "FNGROUPCOUNT", - 0x009D: "AUTOFILTERINFO", - 0x009E: "AUTOFILTER", - 0x00A0: "SCL", - 0x00A1: "SETUP", - 0x00A9: "COORDLIST", - 0x00AB: "GCW", - 0x00AE: "SCENMAN", - 0x00AF: "SCENARIO", - 0x00B0: "SXVIEW", - 0x00B1: "SXVD", - 0x00B2: "SXVI", - 0x00B4: "SXIVD", - 0x00B5: "SXLI", - 0x00B6: "SXPI", - 0x00B8: "DOCROUTE", - 0x00B9: "RECIPNAME", - 0x00BC: "SHRFMLA", - 0x00BD: "MULRK", - 0x00BE: "MULBLANK", - 0x00C1: "MMS", - 0x00C2: "ADDMENU", - 0x00C3: "DELMENU", - 0x00C5: "SXDI", - 0x00C6: "SXDB", - 0x00C7: "SXFIELD", - 0x00C8: "SXINDEXLIST", - 0x00C9: "SXDOUBLE", - 0x00CD: "SXSTRING", - 0x00CE: "SXDATETIME", - 0x00D0: "SXTBL", - 0x00D1: "SXTBRGITEM", - 0x00D2: "SXTBPG", - 0x00D3: "OBPROJ", - 0x00D5: "SXIDSTM", - 0x00D6: "RSTRING", - 0x00D7: "DBCELL", - 0x00DA: "BOOKBOOL", - 0x00DC: "SXEXT|PARAMQRY", - 0x00DD: "SCENPROTECT", - 0x00DE: "OLESIZE", - 0x00DF: "UDDESC", - 0x00E0: "XF", - 0x00E1: "INTERFACEHDR", - 0x00E2: "INTERFACEEND", - 0x00E3: "SXVS", - 0x00E5: "MERGEDCELLS", - 0x00E9: "BITMAP", - 0x00EB: "MSODRAWINGGROUP", - 0x00EC: "MSODRAWING", - 0x00ED: "MSODRAWINGSELECTION", - 0x00F0: "SXRULE", - 0x00F1: "SXEX", - 0x00F2: "SXFILT", - 0x00F6: "SXNAME", - 0x00F7: "SXSELECT", - 0x00F8: "SXPAIR", - 0x00F9: "SXFMLA", - 0x00FB: "SXFORMAT", - 0x00FC: "SST", - 0x00FD: "LABELSST", - 0x00FF: "EXTSST", - 0x0100: "SXVDEX", - 0x0103: "SXFORMULA", - 0x0122: "SXDBEX", - 0x0137: "CHTRINSERT", - 0x0138: "CHTRINFO", - 0x013B: "CHTRCELLCONTENT", - 0x013D: "TABID", - 0x0140: "CHTRMOVERANGE", - 0x014D: "CHTRINSERTTAB", - 0x015F: "LABELRANGES", - 0x0160: "USESELFS", - 0x0161: "DSF", - 0x0162: "XL5MODIFY", - 0x0196: "CHTRHEADER", - 0x01A9: "USERBVIEW", - 0x01AA: "USERSVIEWBEGIN", - 0x01AB: "USERSVIEWEND", - 0x01AD: "QSI", - 0x01AE: "SUPBOOK", - 0x01AF: "PROT4REV", - 0x01B0: "CONDFMT", - 0x01B1: "CF", - 0x01B2: "DVAL", - 0x01B5: "DCONBIN", - 0x01B6: "TXO", - 0x01B7: "REFRESHALL", - 0x01B8: "HLINK", - 0x01BA: "CODENAME", - 0x01BB: "SXFDBTYPE", - 0x01BC: "PROT4REVPASS", - 0x01BE: "DV", - 0x01C0: "XL9FILE", - 0x01C1: "RECALCID", - 0x0200: "DIMENSIONS", - 0x0201: "BLANK", - 0x0203: "NUMBER", - 0x0204: "LABEL", - 0x0205: "BOOLERR", - 0x0206: "FORMULA", - 0x0207: "STRING", - 0x0208: "ROW", - 0x0209: "BOF", - 0x020B: "INDEX", - 0x0218: "NAME", - 0x0221: "ARRAY", - 0x0223: "EXTERNNAME", - 0x0225: "DEFAULTROWHEIGHT", - 0x0231: "FONT", - 0x0236: "TABLE", - 0x023E: "WINDOW2", - 0x0243: "XF", - 0x027E: "RK", - 0x0293: "STYLE", - 0x0406: "FORMULA", - 0x0409: "BOF", - 0x041E: "FORMAT", - 0x0443: "XF", - 0x04BC: "SHRFMLA", - 0x0800: "SCREENTIP", - 0x0803: "WEBQRYSETTINGS", - 0x0804: "WEBQRYTABLES", - 0x0809: "BOF", - 0x0862: "SHEETLAYOUT", - 0x0867: "SHEETPROTECTION", - 0x1001: "UNITS", - 0x1002: "ChartChart", - 0x1003: "ChartSeries", - 0x1006: "ChartDataformat", - 0x1007: "ChartLineformat", - 0x1009: "ChartMarkerformat", - 0x100A: "ChartAreaformat", - 0x100B: "ChartPieformat", - 0x100C: "ChartAttachedlabel", - 0x100D: "ChartSeriestext", - 0x1014: "ChartChartformat", - 0x1015: "ChartLegend", - 0x1016: "ChartSerieslist", - 0x1017: "ChartBar", - 0x1018: "ChartLine", - 0x1019: "ChartPie", - 0x101A: "ChartArea", - 0x101B: "ChartScatter", - 0x101C: "ChartChartline", - 0x101D: "ChartAxis", - 0x101E: "ChartTick", - 0x101F: "ChartValuerange", - 0x1020: "ChartCatserrange", - 0x1021: "ChartAxislineformat", - 0x1022: "ChartFormatlink", - 0x1024: "ChartDefaulttext", - 0x1025: "ChartText", - 0x1026: "ChartFontx", - 0x1027: "ChartObjectLink", - 0x1032: "ChartFrame", - 0x1033: "BEGIN", - 0x1034: "END", - 0x1035: "ChartPlotarea", - 0x103A: "Chart3D", - 0x103C: "ChartPicf", - 0x103D: "ChartDropbar", - 0x103E: "ChartRadar", - 0x103F: "ChartSurface", - 0x1040: "ChartRadararea", - 0x1041: "ChartAxisparent", - 0x1043: "ChartLegendxn", - 0x1044: "ChartShtprops", - 0x1045: "ChartSertocrt", - 0x1046: "ChartAxesused", - 0x1048: "ChartSbaseref", - 0x104A: "ChartSerparent", - 0x104B: "ChartSerauxtrend", - 0x104E: "ChartIfmt", - 0x104F: "ChartPos", - 0x1050: "ChartAlruns", - 0x1051: "ChartAI", - 0x105B: "ChartSerauxerrbar", - 0x105D: "ChartSerfmt", - 0x105F: "Chart3DDataFormat", - 0x1060: "ChartFbi", - 0x1061: "ChartBoppop", - 0x1062: "ChartAxcext", - 0x1063: "ChartDat", - 0x1064: "ChartPlotgrowth", - 0x1065: "ChartSiindex", - 0x1066: "ChartGelframe", - 0x1067: "ChartBoppcustom", - 0xFFFF: "" -} - - -all_funcs_by_name = { - # Includes Analysis ToolPak aka ATP aka add-in aka xcall functions, - # distinguished by -ve opcode. - # name: (opcode, min # args, max # args, func return type, func arg types) - # + in func arg types means more of the same. - 'ABS' : ( 24, 1, 1, 'V', 'V'), - 'ACCRINT' : ( -1, 6, 7, 'V', 'VVVVVVV'), - 'ACCRINTM' : ( -1, 3, 5, 'V', 'VVVVV'), - 'ACOS' : ( 99, 1, 1, 'V', 'V'), - 'ACOSH' : (233, 1, 1, 'V', 'V'), - 'ADDRESS' : (219, 2, 5, 'V', 'VVVVV'), - 'AMORDEGRC' : ( -1, 7, 7, 'V', 'VVVVVVV'), - 'AMORLINC' : ( -1, 7, 7, 'V', 'VVVVVVV'), - 'AND' : ( 36, 1, 30, 'V', 'D+'), - 'AREAS' : ( 75, 1, 1, 'V', 'R'), - 'ASC' : (214, 1, 1, 'V', 'V'), - 'ASIN' : ( 98, 1, 1, 'V', 'V'), - 'ASINH' : (232, 1, 1, 'V', 'V'), - 'ATAN' : ( 18, 1, 1, 'V', 'V'), - 'ATAN2' : ( 97, 2, 2, 'V', 'VV'), - 'ATANH' : (234, 1, 1, 'V', 'V'), - 'AVEDEV' : (269, 1, 30, 'V', 'D+'), - 'AVERAGE' : ( 5, 1, 30, 'V', 'D+'), - 'AVERAGEA' : (361, 1, 30, 'V', 'D+'), - 'BAHTTEXT' : (368, 1, 1, 'V', 'V'), - 'BESSELI' : ( -1, 2, 2, 'V', 'VV'), - 'BESSELJ' : ( -1, 2, 2, 'V', 'VV'), - 'BESSELK' : ( -1, 2, 2, 'V', 'VV'), - 'BESSELY' : ( -1, 2, 2, 'V', 'VV'), - 'BETADIST' : (270, 3, 5, 'V', 'VVVVV'), - 'BETAINV' : (272, 3, 5, 'V', 'VVVVV'), - 'BIN2DEC' : ( -1, 1, 1, 'V', 'V'), - 'BIN2HEX' : ( -1, 1, 2, 'V', 'VV'), - 'BIN2OCT' : ( -1, 1, 2, 'V', 'VV'), - 'BINOMDIST' : (273, 4, 4, 'V', 'VVVV'), - 'CEILING' : (288, 2, 2, 'V', 'VV'), - 'CELL' : (125, 1, 2, 'V', 'VR'), - 'CHAR' : (111, 1, 1, 'V', 'V'), - 'CHIDIST' : (274, 2, 2, 'V', 'VV'), - 'CHIINV' : (275, 2, 2, 'V', 'VV'), - 'CHITEST' : (306, 2, 2, 'V', 'AA'), - 'CHOOSE' : (100, 2, 30, 'R', 'VR+'), - 'CLEAN' : (162, 1, 1, 'V', 'V'), - 'CODE' : (121, 1, 1, 'V', 'V'), - 'COLUMN' : ( 9, 0, 1, 'V', 'R'), - 'COLUMNS' : ( 77, 1, 1, 'V', 'R'), - 'COMBIN' : (276, 2, 2, 'V', 'VV'), - 'COMPLEX' : ( -1, 2, 3, 'V', 'VVV'), - 'CONCATENATE' : (336, 1, 30, 'V', 'V+'), - 'CONFIDENCE' : (277, 3, 3, 'V', 'VVV'), - 'CONVERT' : ( -1, 3, 3, 'V', 'VVV'), - 'CORREL' : (307, 2, 2, 'V', 'AA'), - 'COS' : ( 16, 1, 1, 'V', 'V'), - 'COSH' : (230, 1, 1, 'V', 'V'), - 'COUNT' : ( 0, 1, 30, 'V', 'D+'), - 'COUNTA' : (169, 1, 30, 'V', 'D+'), - 'COUNTBLANK' : (347, 1, 1, 'V', 'R'), - 'COUNTIF' : (346, 2, 2, 'V', 'RV'), - 'COUPDAYBS' : ( -1, 3, 5, 'V', 'VVVVV'), - 'COUPDAYS' : ( -1, 3, 5, 'V', 'VVVVV'), - 'COUPDAYSNC' : ( -1, 3, 5, 'V', 'VVVVV'), - 'COUPNCD' : ( -1, 3, 5, 'V', 'VVVVV'), - 'COUPNUM' : ( -1, 3, 5, 'V', 'VVVVV'), - 'COUPPCD' : ( -1, 3, 5, 'V', 'VVVVV'), - 'COVAR' : (308, 2, 2, 'V', 'AA'), - 'CRITBINOM' : (278, 3, 3, 'V', 'VVV'), - 'CUMIPMT' : ( -1, 6, 6, 'V', 'VVVVVV'), - 'CUMPRINC' : ( -1, 6, 6, 'V', 'VVVVVV'), - 'DATE' : ( 65, 3, 3, 'V', 'VVV'), - 'DATEDIF' : (351, 3, 3, 'V', 'VVV'), - 'DATEVALUE' : (140, 1, 1, 'V', 'V'), - 'DAVERAGE' : ( 42, 3, 3, 'V', 'RRR'), - 'DAY' : ( 67, 1, 1, 'V', 'V'), - 'DAYS360' : (220, 2, 3, 'V', 'VVV'), - 'DB' : (247, 4, 5, 'V', 'VVVVV'), - 'DBCS' : (215, 1, 1, 'V', 'V'), - 'DCOUNT' : ( 40, 3, 3, 'V', 'RRR'), - 'DCOUNTA' : (199, 3, 3, 'V', 'RRR'), - 'DDB' : (144, 4, 5, 'V', 'VVVVV'), - 'DEC2BIN' : ( -1, 1, 2, 'V', 'VV'), - 'DEC2HEX' : ( -1, 1, 2, 'V', 'VV'), - 'DEC2OCT' : ( -1, 1, 2, 'V', 'VV'), - 'DEGREES' : (343, 1, 1, 'V', 'V'), - 'DELTA' : ( -1, 1, 2, 'V', 'VV'), - 'DEVSQ' : (318, 1, 30, 'V', 'D+'), - 'DGET' : (235, 3, 3, 'V', 'RRR'), - 'DISC' : ( -1, 4, 5, 'V', 'VVVVV'), - 'DMAX' : ( 44, 3, 3, 'V', 'RRR'), - 'DMIN' : ( 43, 3, 3, 'V', 'RRR'), - 'DOLLAR' : ( 13, 1, 2, 'V', 'VV'), - 'DOLLARDE' : ( -1, 2, 2, 'V', 'VV'), - 'DOLLARFR' : ( -1, 2, 2, 'V', 'VV'), - 'DPRODUCT' : (189, 3, 3, 'V', 'RRR'), - 'DSTDEV' : ( 45, 3, 3, 'V', 'RRR'), - 'DSTDEVP' : (195, 3, 3, 'V', 'RRR'), - 'DSUM' : ( 41, 3, 3, 'V', 'RRR'), - 'DURATION' : ( -1, 5, 6, 'V', 'VVVVVV'), - 'DVAR' : ( 47, 3, 3, 'V', 'RRR'), - 'DVARP' : (196, 3, 3, 'V', 'RRR'), - 'EDATE' : ( -1, 2, 2, 'V', 'VV'), - 'EFFECT' : ( -1, 2, 2, 'V', 'VV'), - 'EOMONTH' : ( -1, 1, 2, 'V', 'VV'), - 'ERF' : ( -1, 1, 2, 'V', 'VV'), - 'ERFC' : ( -1, 1, 1, 'V', 'V'), - 'ERROR.TYPE' : (261, 1, 1, 'V', 'V'), - 'EVEN' : (279, 1, 1, 'V', 'V'), - 'EXACT' : (117, 2, 2, 'V', 'VV'), - 'EXP' : ( 21, 1, 1, 'V', 'V'), - 'EXPONDIST' : (280, 3, 3, 'V', 'VVV'), - 'FACT' : (184, 1, 1, 'V', 'V'), - 'FACTDOUBLE' : ( -1, 1, 1, 'V', 'V'), - 'FALSE' : ( 35, 0, 0, 'V', '-'), - 'FDIST' : (281, 3, 3, 'V', 'VVV'), - 'FIND' : (124, 2, 3, 'V', 'VVV'), - 'FINDB' : (205, 2, 3, 'V', 'VVV'), - 'FINV' : (282, 3, 3, 'V', 'VVV'), - 'FISHER' : (283, 1, 1, 'V', 'V'), - 'FISHERINV' : (284, 1, 1, 'V', 'V'), - 'FIXED' : ( 14, 2, 3, 'V', 'VVV'), - 'FLOOR' : (285, 2, 2, 'V', 'VV'), - 'FORECAST' : (309, 3, 3, 'V', 'VAA'), - 'FREQUENCY' : (252, 2, 2, 'A', 'RR'), - 'FTEST' : (310, 2, 2, 'V', 'AA'), - 'FV' : ( 57, 3, 5, 'V', 'VVVVV'), - 'FVSCHEDULE' : ( -1, 2, 2, 'V', 'VA'), - 'GAMMADIST' : (286, 4, 4, 'V', 'VVVV'), - 'GAMMAINV' : (287, 3, 3, 'V', 'VVV'), - 'GAMMALN' : (271, 1, 1, 'V', 'V'), - 'GCD' : ( -1, 1, 29, 'V', 'V+'), - 'GEOMEAN' : (319, 1, 30, 'V', 'D+'), - 'GESTEP' : ( -1, 1, 2, 'V', 'VV'), - 'GETPIVOTDATA': (358, 2, 30, 'A', 'VAV+'), - 'GROWTH' : ( 52, 1, 4, 'A', 'RRRV'), - 'HARMEAN' : (320, 1, 30, 'V', 'D+'), - 'HEX2BIN' : ( -1, 1, 2, 'V', 'VV'), - 'HEX2DEC' : ( -1, 1, 1, 'V', 'V'), - 'HEX2OCT' : ( -1, 1, 2, 'V', 'VV'), - 'HLOOKUP' : (101, 3, 4, 'V', 'VRRV'), - 'HOUR' : ( 71, 1, 1, 'V', 'V'), - 'HYPERLINK' : (359, 1, 2, 'V', 'VV'), - 'HYPGEOMDIST' : (289, 4, 4, 'V', 'VVVV'), - 'IF' : ( 1, 2, 3, 'R', 'VRR'), - 'IMABS' : ( -1, 1, 1, 'V', 'V'), - 'IMAGINARY' : ( -1, 1, 1, 'V', 'V'), - 'IMARGUMENT' : ( -1, 1, 1, 'V', 'V'), - 'IMCONJUGATE' : ( -1, 1, 1, 'V', 'V'), - 'IMCOS' : ( -1, 1, 1, 'V', 'V'), - 'IMDIV' : ( -1, 2, 2, 'V', 'VV'), - 'IMEXP' : ( -1, 1, 1, 'V', 'V'), - 'IMLN' : ( -1, 1, 1, 'V', 'V'), - 'IMLOG10' : ( -1, 1, 1, 'V', 'V'), - 'IMLOG2' : ( -1, 1, 1, 'V', 'V'), - 'IMPOWER' : ( -1, 2, 2, 'V', 'VV'), - 'IMPRODUCT' : ( -1, 2, 2, 'V', 'VV'), - 'IMREAL' : ( -1, 1, 1, 'V', 'V'), - 'IMSIN' : ( -1, 1, 1, 'V', 'V'), - 'IMSQRT' : ( -1, 1, 1, 'V', 'V'), - 'IMSUB' : ( -1, 2, 2, 'V', 'VV'), - 'IMSUM' : ( -1, 1, 29, 'V', 'V+'), - 'INDEX' : ( 29, 2, 4, 'R', 'RVVV'), - 'INDIRECT' : (148, 1, 2, 'R', 'VV'), - 'INFO' : (244, 1, 1, 'V', 'V'), - 'INT' : ( 25, 1, 1, 'V', 'V'), - 'INTERCEPT' : (311, 2, 2, 'V', 'AA'), - 'INTRATE' : ( -1, 4, 5, 'V', 'VVVVV'), - 'IPMT' : (167, 4, 6, 'V', 'VVVVVV'), - 'IRR' : ( 62, 1, 2, 'V', 'RV'), - 'ISBLANK' : (129, 1, 1, 'V', 'V'), - 'ISERR' : (126, 1, 1, 'V', 'V'), - 'ISERROR' : ( 3, 1, 1, 'V', 'V'), - 'ISEVEN' : ( -1, 1, 1, 'V', 'V'), - 'ISLOGICAL' : (198, 1, 1, 'V', 'V'), - 'ISNA' : ( 2, 1, 1, 'V', 'V'), - 'ISNONTEXT' : (190, 1, 1, 'V', 'V'), - 'ISNUMBER' : (128, 1, 1, 'V', 'V'), - 'ISODD' : ( -1, 1, 1, 'V', 'V'), - 'ISPMT' : (350, 4, 4, 'V', 'VVVV'), - 'ISREF' : (105, 1, 1, 'V', 'R'), - 'ISTEXT' : (127, 1, 1, 'V', 'V'), - 'KURT' : (322, 1, 30, 'V', 'D+'), - 'LARGE' : (325, 2, 2, 'V', 'RV'), - 'LCM' : ( -1, 1, 29, 'V', 'V+'), - 'LEFT' : (115, 1, 2, 'V', 'VV'), - 'LEFTB' : (208, 1, 2, 'V', 'VV'), - 'LEN' : ( 32, 1, 1, 'V', 'V'), - 'LENB' : (211, 1, 1, 'V', 'V'), - 'LINEST' : ( 49, 1, 4, 'A', 'RRVV'), - 'LN' : ( 22, 1, 1, 'V', 'V'), - 'LOG' : (109, 1, 2, 'V', 'VV'), - 'LOG10' : ( 23, 1, 1, 'V', 'V'), - 'LOGEST' : ( 51, 1, 4, 'A', 'RRVV'), - 'LOGINV' : (291, 3, 3, 'V', 'VVV'), - 'LOGNORMDIST' : (290, 3, 3, 'V', 'VVV'), - 'LOOKUP' : ( 28, 2, 3, 'V', 'VRR'), - 'LOWER' : (112, 1, 1, 'V', 'V'), - 'MATCH' : ( 64, 2, 3, 'V', 'VRR'), - 'MAX' : ( 7, 1, 30, 'V', 'D+'), - 'MAXA' : (362, 1, 30, 'V', 'D+'), - 'MDETERM' : (163, 1, 1, 'V', 'A'), - 'MDURATION' : ( -1, 5, 6, 'V', 'VVVVVV'), - 'MEDIAN' : (227, 1, 30, 'V', 'D+'), - 'MID' : ( 31, 3, 3, 'V', 'VVV'), - 'MIDB' : (210, 3, 3, 'V', 'VVV'), - 'MIN' : ( 6, 1, 30, 'V', 'D+'), - 'MINA' : (363, 1, 30, 'V', 'D+'), - 'MINUTE' : ( 72, 1, 1, 'V', 'V'), - 'MINVERSE' : (164, 1, 1, 'A', 'A'), - 'MIRR' : ( 61, 3, 3, 'V', 'RVV'), - 'MMULT' : (165, 2, 2, 'A', 'AA'), - 'MOD' : ( 39, 2, 2, 'V', 'VV'), - 'MODE' : (330, 1, 30, 'V', 'A+'), ################ weird ################# - 'MONTH' : ( 68, 1, 1, 'V', 'V'), - 'MROUND' : ( -1, 2, 2, 'V', 'VV'), - 'MULTINOMIAL' : ( -1, 1, 29, 'V', 'V+'), - 'N' : (131, 1, 1, 'V', 'R'), - 'NA' : ( 10, 0, 0, 'V', '-'), - 'NEGBINOMDIST': (292, 3, 3, 'V', 'VVV'), - 'NETWORKDAYS' : ( -1, 2, 3, 'V', 'VVR'), - 'NOMINAL' : ( -1, 2, 2, 'V', 'VV'), - 'NORMDIST' : (293, 4, 4, 'V', 'VVVV'), - 'NORMINV' : (295, 3, 3, 'V', 'VVV'), - 'NORMSDIST' : (294, 1, 1, 'V', 'V'), - 'NORMSINV' : (296, 1, 1, 'V', 'V'), - 'NOT' : ( 38, 1, 1, 'V', 'V'), - 'NOW' : ( 74, 0, 0, 'V', '-'), - 'NPER' : ( 58, 3, 5, 'V', 'VVVVV'), - 'NPV' : ( 11, 2, 30, 'V', 'VD+'), - 'OCT2BIN' : ( -1, 1, 2, 'V', 'VV'), - 'OCT2DEC' : ( -1, 1, 1, 'V', 'V'), - 'OCT2HEX' : ( -1, 1, 2, 'V', 'VV'), - 'ODD' : (298, 1, 1, 'V', 'V'), - 'ODDFPRICE' : ( -1, 9, 9, 'V', 'VVVVVVVVV'), - 'ODDFYIELD' : ( -1, 9, 9, 'V', 'VVVVVVVVV'), - 'ODDLPRICE' : ( -1, 8, 8, 'V', 'VVVVVVVV'), - 'ODDLYIELD' : ( -1, 8, 8, 'V', 'VVVVVVVV'), - 'OFFSET' : ( 78, 3, 5, 'R', 'RVVVV'), - 'OR' : ( 37, 1, 30, 'V', 'D+'), - 'PEARSON' : (312, 2, 2, 'V', 'AA'), - 'PERCENTILE' : (328, 2, 2, 'V', 'RV'), - 'PERCENTRANK' : (329, 2, 3, 'V', 'RVV'), - 'PERMUT' : (299, 2, 2, 'V', 'VV'), - 'PHONETIC' : (360, 1, 1, 'V', 'R'), - 'PI' : ( 19, 0, 0, 'V', '-'), - 'PMT' : ( 59, 3, 5, 'V', 'VVVVV'), - 'POISSON' : (300, 3, 3, 'V', 'VVV'), - 'POWER' : (337, 2, 2, 'V', 'VV'), - 'PPMT' : (168, 4, 6, 'V', 'VVVVVV'), - 'PRICE' : ( -1, 6, 7, 'V', 'VVVVVVV'), - 'PRICEDISC' : ( -1, 4, 5, 'V', 'VVVVV'), - 'PRICEMAT' : ( -1, 5, 6, 'V', 'VVVVVV'), - 'PROB' : (317, 3, 4, 'V', 'AAVV'), - 'PRODUCT' : (183, 1, 30, 'V', 'D+'), - 'PROPER' : (114, 1, 1, 'V', 'V'), - 'PV' : ( 56, 3, 5, 'V', 'VVVVV'), - 'QUARTILE' : (327, 2, 2, 'V', 'RV'), - 'QUOTIENT' : ( -1, 2, 2, 'V', 'VV'), - 'RADIANS' : (342, 1, 1, 'V', 'V'), - 'RAND' : ( 63, 0, 0, 'V', '-'), - 'RANDBETWEEN' : ( -1, 2, 2, 'V', 'VV'), - 'RANK' : (216, 2, 3, 'V', 'VRV'), - 'RATE' : ( 60, 3, 6, 'V', 'VVVVVV'), - 'RECEIVED' : ( -1, 4, 5, 'V', 'VVVVV'), - 'REPLACE' : (119, 4, 4, 'V', 'VVVV'), - 'REPLACEB' : (207, 4, 4, 'V', 'VVVV'), - 'REPT' : ( 30, 2, 2, 'V', 'VV'), - 'RIGHT' : (116, 1, 2, 'V', 'VV'), - 'RIGHTB' : (209, 1, 2, 'V', 'VV'), - 'ROMAN' : (354, 1, 2, 'V', 'VV'), - 'ROUND' : ( 27, 2, 2, 'V', 'VV'), - 'ROUNDDOWN' : (213, 2, 2, 'V', 'VV'), - 'ROUNDUP' : (212, 2, 2, 'V', 'VV'), - 'ROW' : ( 8, 0, 1, 'V', 'R'), - 'ROWS' : ( 76, 1, 1, 'V', 'R'), - 'RSQ' : (313, 2, 2, 'V', 'AA'), - 'RTD' : (379, 3, 30, 'A', 'VVV+'), - 'SEARCH' : ( 82, 2, 3, 'V', 'VVV'), - 'SEARCHB' : (206, 2, 3, 'V', 'VVV'), - 'SECOND' : ( 73, 1, 1, 'V', 'V'), - 'SERIESSUM' : ( -1, 4, 4, 'V', 'VVVA'), - 'SIGN' : ( 26, 1, 1, 'V', 'V'), - 'SIN' : ( 15, 1, 1, 'V', 'V'), - 'SINH' : (229, 1, 1, 'V', 'V'), - 'SKEW' : (323, 1, 30, 'V', 'D+'), - 'SLN' : (142, 3, 3, 'V', 'VVV'), - 'SLOPE' : (315, 2, 2, 'V', 'AA'), - 'SMALL' : (326, 2, 2, 'V', 'RV'), - 'SQRT' : ( 20, 1, 1, 'V', 'V'), - 'SQRTPI' : ( -1, 1, 1, 'V', 'V'), - 'STANDARDIZE' : (297, 3, 3, 'V', 'VVV'), - 'STDEV' : ( 12, 1, 30, 'V', 'D+'), - 'STDEVA' : (366, 1, 30, 'V', 'D+'), - 'STDEVP' : (193, 1, 30, 'V', 'D+'), - 'STDEVPA' : (364, 1, 30, 'V', 'D+'), - 'STEYX' : (314, 2, 2, 'V', 'AA'), - 'SUBSTITUTE' : (120, 3, 4, 'V', 'VVVV'), - 'SUBTOTAL' : (344, 2, 30, 'V', 'VR+'), - 'SUM' : ( 4, 1, 30, 'V', 'D+'), - 'SUMIF' : (345, 2, 3, 'V', 'RVR'), - 'SUMPRODUCT' : (228, 1, 30, 'V', 'A+'), - 'SUMSQ' : (321, 1, 30, 'V', 'D+'), - 'SUMX2MY2' : (304, 2, 2, 'V', 'AA'), - 'SUMX2PY2' : (305, 2, 2, 'V', 'AA'), - 'SUMXMY2' : (303, 2, 2, 'V', 'AA'), - 'SYD' : (143, 4, 4, 'V', 'VVVV'), - 'T' : (130, 1, 1, 'V', 'R'), - 'TAN' : ( 17, 1, 1, 'V', 'V'), - 'TANH' : (231, 1, 1, 'V', 'V'), - 'TBILLEQ' : ( -1, 3, 3, 'V', 'VVV'), - 'TBILLPRICE' : ( -1, 3, 3, 'V', 'VVV'), - 'TBILLYIELD' : ( -1, 3, 3, 'V', 'VVV'), - 'TDIST' : (301, 3, 3, 'V', 'VVV'), - 'TEXT' : ( 48, 2, 2, 'V', 'VV'), - 'TIME' : ( 66, 3, 3, 'V', 'VVV'), - 'TIMEVALUE' : (141, 1, 1, 'V', 'V'), - 'TINV' : (332, 2, 2, 'V', 'VV'), - 'TODAY' : (221, 0, 0, 'V', '-'), - 'TRANSPOSE' : ( 83, 1, 1, 'A', 'A'), - 'TREND' : ( 50, 1, 4, 'A', 'RRRV'), - 'TRIM' : (118, 1, 1, 'V', 'V'), - 'TRIMMEAN' : (331, 2, 2, 'V', 'RV'), - 'TRUE' : ( 34, 0, 0, 'V', '-'), - 'TRUNC' : (197, 1, 2, 'V', 'VV'), - 'TTEST' : (316, 4, 4, 'V', 'AAVV'), - 'TYPE' : ( 86, 1, 1, 'V', 'V'), - 'UPPER' : (113, 1, 1, 'V', 'V'), - 'USDOLLAR' : (204, 1, 2, 'V', 'VV'), - 'VALUE' : ( 33, 1, 1, 'V', 'V'), - 'VAR' : ( 46, 1, 30, 'V', 'D+'), - 'VARA' : (367, 1, 30, 'V', 'D+'), - 'VARP' : (194, 1, 30, 'V', 'D+'), - 'VARPA' : (365, 1, 30, 'V', 'D+'), - 'VDB' : (222, 5, 7, 'V', 'VVVVVVV'), - 'VLOOKUP' : (102, 3, 4, 'V', 'VRRV'), - 'WEEKDAY' : ( 70, 1, 2, 'V', 'VV'), - 'WEEKNUM' : ( -1, 1, 2, 'V', 'VV'), - 'WEIBULL' : (302, 4, 4, 'V', 'VVVV'), - 'WORKDAY' : ( -1, 2, 3, 'V', 'VVR'), - 'XIRR' : ( -1, 2, 3, 'V', 'AAV'), - 'XNPV' : ( -1, 3, 3, 'V', 'VAA'), - 'YEAR' : ( 69, 1, 1, 'V', 'V'), - 'YEARFRAC' : ( -1, 2, 3, 'V', 'VVV'), - 'YIELD' : ( -1, 6, 7, 'V', 'VVVVVVV'), - 'YIELDDISC' : ( -1, 4, 5, 'V', 'VVVVV'), - 'YIELDMAT' : ( -1, 5, 6, 'V', 'VVVVVV'), - 'ZTEST' : (324, 2, 3, 'V', 'RVV'), - } - -# Formulas Parse things - -ptgExp = 0x01 -ptgTbl = 0x02 -ptgAdd = 0x03 -ptgSub = 0x04 -ptgMul = 0x05 -ptgDiv = 0x06 -ptgPower = 0x07 -ptgConcat = 0x08 -ptgLT = 0x09 -ptgLE = 0x0a -ptgEQ = 0x0b -ptgGE = 0x0c -ptgGT = 0x0d -ptgNE = 0x0e -ptgIsect = 0x0f -ptgUnion = 0x10 -ptgRange = 0x11 -ptgUplus = 0x12 -ptgUminus = 0x13 -ptgPercent = 0x14 -ptgParen = 0x15 -ptgMissArg = 0x16 -ptgStr = 0x17 -ptgExtend = 0x18 -ptgAttr = 0x19 -ptgSheet = 0x1a -ptgEndSheet = 0x1b -ptgErr = 0x1c -ptgBool = 0x1d -ptgInt = 0x1e -ptgNum = 0x1f - -ptgArrayR = 0x20 -ptgFuncR = 0x21 -ptgFuncVarR = 0x22 -ptgNameR = 0x23 -ptgRefR = 0x24 -ptgAreaR = 0x25 -ptgMemAreaR = 0x26 -ptgMemErrR = 0x27 -ptgMemNoMemR = 0x28 -ptgMemFuncR = 0x29 -ptgRefErrR = 0x2a -ptgAreaErrR = 0x2b -ptgRefNR = 0x2c -ptgAreaNR = 0x2d -ptgMemAreaNR = 0x2e -ptgMemNoMemNR = 0x2f -ptgNameXR = 0x39 -ptgRef3dR = 0x3a -ptgArea3dR = 0x3b -ptgRefErr3dR = 0x3c -ptgAreaErr3dR = 0x3d - -ptgArrayV = 0x40 -ptgFuncV = 0x41 -ptgFuncVarV = 0x42 -ptgNameV = 0x43 -ptgRefV = 0x44 -ptgAreaV = 0x45 -ptgMemAreaV = 0x46 -ptgMemErrV = 0x47 -ptgMemNoMemV = 0x48 -ptgMemFuncV = 0x49 -ptgRefErrV = 0x4a -ptgAreaErrV = 0x4b -ptgRefNV = 0x4c -ptgAreaNV = 0x4d -ptgMemAreaNV = 0x4e -ptgMemNoMemNV = 0x4f -ptgFuncCEV = 0x58 -ptgNameXV = 0x59 -ptgRef3dV = 0x5a -ptgArea3dV = 0x5b -ptgRefErr3dV = 0x5c -ptgAreaErr3dV = 0x5d - -ptgArrayA = 0x60 -ptgFuncA = 0x61 -ptgFuncVarA = 0x62 -ptgNameA = 0x63 -ptgRefA = 0x64 -ptgAreaA = 0x65 -ptgMemAreaA = 0x66 -ptgMemErrA = 0x67 -ptgMemNoMemA = 0x68 -ptgMemFuncA = 0x69 -ptgRefErrA = 0x6a -ptgAreaErrA = 0x6b -ptgRefNA = 0x6c -ptgAreaNA = 0x6d -ptgMemAreaNA = 0x6e -ptgMemNoMemNA = 0x6f -ptgFuncCEA = 0x78 -ptgNameXA = 0x79 -ptgRef3dA = 0x7a -ptgArea3dA = 0x7b -ptgRefErr3dA = 0x7c -ptgAreaErr3dA = 0x7d - - -PtgNames = { - ptgExp : "ptgExp", - ptgTbl : "ptgTbl", - ptgAdd : "ptgAdd", - ptgSub : "ptgSub", - ptgMul : "ptgMul", - ptgDiv : "ptgDiv", - ptgPower : "ptgPower", - ptgConcat : "ptgConcat", - ptgLT : "ptgLT", - ptgLE : "ptgLE", - ptgEQ : "ptgEQ", - ptgGE : "ptgGE", - ptgGT : "ptgGT", - ptgNE : "ptgNE", - ptgIsect : "ptgIsect", - ptgUnion : "ptgUnion", - ptgRange : "ptgRange", - ptgUplus : "ptgUplus", - ptgUminus : "ptgUminus", - ptgPercent : "ptgPercent", - ptgParen : "ptgParen", - ptgMissArg : "ptgMissArg", - ptgStr : "ptgStr", - ptgExtend : "ptgExtend", - ptgAttr : "ptgAttr", - ptgSheet : "ptgSheet", - ptgEndSheet : "ptgEndSheet", - ptgErr : "ptgErr", - ptgBool : "ptgBool", - ptgInt : "ptgInt", - ptgNum : "ptgNum", - ptgArrayR : "ptgArrayR", - ptgFuncR : "ptgFuncR", - ptgFuncVarR : "ptgFuncVarR", - ptgNameR : "ptgNameR", - ptgRefR : "ptgRefR", - ptgAreaR : "ptgAreaR", - ptgMemAreaR : "ptgMemAreaR", - ptgMemErrR : "ptgMemErrR", - ptgMemNoMemR : "ptgMemNoMemR", - ptgMemFuncR : "ptgMemFuncR", - ptgRefErrR : "ptgRefErrR", - ptgAreaErrR : "ptgAreaErrR", - ptgRefNR : "ptgRefNR", - ptgAreaNR : "ptgAreaNR", - ptgMemAreaNR : "ptgMemAreaNR", - ptgMemNoMemNR : "ptgMemNoMemNR", - ptgNameXR : "ptgNameXR", - ptgRef3dR : "ptgRef3dR", - ptgArea3dR : "ptgArea3dR", - ptgRefErr3dR : "ptgRefErr3dR", - ptgAreaErr3dR : "ptgAreaErr3dR", - ptgArrayV : "ptgArrayV", - ptgFuncV : "ptgFuncV", - ptgFuncVarV : "ptgFuncVarV", - ptgNameV : "ptgNameV", - ptgRefV : "ptgRefV", - ptgAreaV : "ptgAreaV", - ptgMemAreaV : "ptgMemAreaV", - ptgMemErrV : "ptgMemErrV", - ptgMemNoMemV : "ptgMemNoMemV", - ptgMemFuncV : "ptgMemFuncV", - ptgRefErrV : "ptgRefErrV", - ptgAreaErrV : "ptgAreaErrV", - ptgRefNV : "ptgRefNV", - ptgAreaNV : "ptgAreaNV", - ptgMemAreaNV : "ptgMemAreaNV", - ptgMemNoMemNV : "ptgMemNoMemNV", - ptgFuncCEV : "ptgFuncCEV", - ptgNameXV : "ptgNameXV", - ptgRef3dV : "ptgRef3dV", - ptgArea3dV : "ptgArea3dV", - ptgRefErr3dV : "ptgRefErr3dV", - ptgAreaErr3dV : "ptgAreaErr3dV", - ptgArrayA : "ptgArrayA", - ptgFuncA : "ptgFuncA", - ptgFuncVarA : "ptgFuncVarA", - ptgNameA : "ptgNameA", - ptgRefA : "ptgRefA", - ptgAreaA : "ptgAreaA", - ptgMemAreaA : "ptgMemAreaA", - ptgMemErrA : "ptgMemErrA", - ptgMemNoMemA : "ptgMemNoMemA", - ptgMemFuncA : "ptgMemFuncA", - ptgRefErrA : "ptgRefErrA", - ptgAreaErrA : "ptgAreaErrA", - ptgRefNA : "ptgRefNA", - ptgAreaNA : "ptgAreaNA", - ptgMemAreaNA : "ptgMemAreaNA", - ptgMemNoMemNA : "ptgMemNoMemNA", - ptgFuncCEA : "ptgFuncCEA", - ptgNameXA : "ptgNameXA", - ptgRef3dA : "ptgRef3dA", - ptgArea3dA : "ptgArea3dA", - ptgRefErr3dA : "ptgRefErr3dA", - ptgAreaErr3dA : "ptgAreaErr3dA" -} - - -error_msg_by_code = { - 0x00: u"#NULL!", # intersection of two cell ranges is empty - 0x07: u"#DIV/0!", # division by zero - 0x0F: u"#VALUE!", # wrong type of operand - 0x17: u"#REF!", # illegal or deleted cell reference - 0x1D: u"#NAME?", # wrong function or range name - 0x24: u"#NUM!", # value range overflow - 0x2A: u"#N/A!" # argument or function not available -} diff --git a/tablib/packages/xlwt/Formatting.py b/tablib/packages/xlwt/Formatting.py deleted file mode 100644 index 76b8e8f..0000000 --- a/tablib/packages/xlwt/Formatting.py +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/env python -''' -The XF record is able to store explicit cell formatting attributes or the -attributes of a cell style. Explicit formatting includes the reference to -a cell style XF record. This allows to extend a defined cell style with -some explicit attributes. The formatting attributes are divided into -6 groups: - -Group Attributes -------------------------------------- -Number format Number format index (index to FORMAT record) -Font Font index (index to FONT record) -Alignment Horizontal and vertical alignment, text wrap, indentation, - orientation/rotation, text direction -Border Border line styles and colours -Background Background area style and colours -Protection Cell locked, formula hidden - -For each group a flag in the cell XF record specifies whether to use the -attributes contained in that XF record or in the referenced style -XF record. In style XF records, these flags specify whether the attributes -will overwrite explicit cell formatting when the style is applied to -a cell. Changing a cell style (without applying this style to a cell) will -change all cells which already use that style and do not contain explicit -cell attributes for the changed style attributes. If a cell XF record does -not contain explicit attributes in a group (if the attribute group flag -is not set), it repeats the attributes of its style XF record. - -''' - -import BIFFRecords - -class Font(object): - - ESCAPEMENT_NONE = 0x00 - ESCAPEMENT_SUPERSCRIPT = 0x01 - ESCAPEMENT_SUBSCRIPT = 0x02 - - UNDERLINE_NONE = 0x00 - UNDERLINE_SINGLE = 0x01 - UNDERLINE_SINGLE_ACC = 0x21 - UNDERLINE_DOUBLE = 0x02 - UNDERLINE_DOUBLE_ACC = 0x22 - - FAMILY_NONE = 0x00 - FAMILY_ROMAN = 0x01 - FAMILY_SWISS = 0x02 - FAMILY_MODERN = 0x03 - FAMILY_SCRIPT = 0x04 - FAMILY_DECORATIVE = 0x05 - - CHARSET_ANSI_LATIN = 0x00 - CHARSET_SYS_DEFAULT = 0x01 - CHARSET_SYMBOL = 0x02 - CHARSET_APPLE_ROMAN = 0x4D - CHARSET_ANSI_JAP_SHIFT_JIS = 0x80 - CHARSET_ANSI_KOR_HANGUL = 0x81 - CHARSET_ANSI_KOR_JOHAB = 0x82 - CHARSET_ANSI_CHINESE_GBK = 0x86 - CHARSET_ANSI_CHINESE_BIG5 = 0x88 - CHARSET_ANSI_GREEK = 0xA1 - CHARSET_ANSI_TURKISH = 0xA2 - CHARSET_ANSI_VIETNAMESE = 0xA3 - CHARSET_ANSI_HEBREW = 0xB1 - CHARSET_ANSI_ARABIC = 0xB2 - CHARSET_ANSI_BALTIC = 0xBA - CHARSET_ANSI_CYRILLIC = 0xCC - CHARSET_ANSI_THAI = 0xDE - CHARSET_ANSI_LATIN_II = 0xEE - CHARSET_OEM_LATIN_I = 0xFF - - def __init__(self): - # twip = 1/20 of a point = 1/1440 of a inch - # usually resolution == 96 pixels per 1 inch - # (rarely 120 pixels per 1 inch or another one) - - self.height = 0x00C8 # 200: this is font with height 10 points - self.italic = False - self.struck_out = False - self.outline = False - self.shadow = False - self.colour_index = 0x7FFF - self.bold = False - self._weight = 0x0190 # 0x02BC gives bold font - self.escapement = self.ESCAPEMENT_NONE - self.underline = self.UNDERLINE_NONE - self.family = self.FAMILY_NONE - self.charset = self.CHARSET_SYS_DEFAULT - self.name = 'Arial' - - def get_biff_record(self): - height = self.height - - options = 0x00 - if self.bold: - options |= 0x01 - self._weight = 0x02BC - if self.italic: - options |= 0x02 - if self.underline != self.UNDERLINE_NONE: - options |= 0x04 - if self.struck_out: - options |= 0x08 - if self.outline: - options |= 0x010 - if self.shadow: - options |= 0x020 - - colour_index = self.colour_index - weight = self._weight - escapement = self.escapement - underline = self.underline - family = self.family - charset = self.charset - name = self.name - - return BIFFRecords.FontRecord(height, options, colour_index, weight, escapement, - underline, family, charset, - name) - - def _search_key(self): - return ( - self.height, - self.italic, - self.struck_out, - self.outline, - self.shadow, - self.colour_index, - self.bold, - self._weight, - self.escapement, - self.underline, - self.family, - self.charset, - self.name, - ) - -class Alignment(object): - HORZ_GENERAL = 0x00 - HORZ_LEFT = 0x01 - HORZ_CENTER = 0x02 - HORZ_RIGHT = 0x03 - HORZ_FILLED = 0x04 - HORZ_JUSTIFIED = 0x05 # BIFF4-BIFF8X - HORZ_CENTER_ACROSS_SEL = 0x06 # Centred across selection (BIFF4-BIFF8X) - HORZ_DISTRIBUTED = 0x07 # Distributed (BIFF8X) - - VERT_TOP = 0x00 - VERT_CENTER = 0x01 - VERT_BOTTOM = 0x02 - VERT_JUSTIFIED = 0x03 # Justified (BIFF5-BIFF8X) - VERT_DISTRIBUTED = 0x04 # Distributed (BIFF8X) - - DIRECTION_GENERAL = 0x00 # BIFF8X - DIRECTION_LR = 0x01 - DIRECTION_RL = 0x02 - - ORIENTATION_NOT_ROTATED = 0x00 - ORIENTATION_STACKED = 0x01 - ORIENTATION_90_CC = 0x02 - ORIENTATION_90_CW = 0x03 - - ROTATION_0_ANGLE = 0x00 - ROTATION_STACKED = 0xFF - - WRAP_AT_RIGHT = 0x01 - NOT_WRAP_AT_RIGHT = 0x00 - - SHRINK_TO_FIT = 0x01 - NOT_SHRINK_TO_FIT = 0x00 - - def __init__(self): - self.horz = self.HORZ_GENERAL - self.vert = self.VERT_BOTTOM - self.dire = self.DIRECTION_GENERAL - self.orie = self.ORIENTATION_NOT_ROTATED - self.rota = self.ROTATION_0_ANGLE - self.wrap = self.NOT_WRAP_AT_RIGHT - self.shri = self.NOT_SHRINK_TO_FIT - self.inde = 0 - self.merg = 0 - - def _search_key(self): - return ( - self.horz, self.vert, self.dire, self.orie, self.rota, - self.wrap, self.shri, self.inde, self.merg, - ) - -class Borders(object): - NO_LINE = 0x00 - THIN = 0x01 - MEDIUM = 0x02 - DASHED = 0x03 - DOTTED = 0x04 - THICK = 0x05 - DOUBLE = 0x06 - HAIR = 0x07 - #The following for BIFF8 - MEDIUM_DASHED = 0x08 - THIN_DASH_DOTTED = 0x09 - MEDIUM_DASH_DOTTED = 0x0A - THIN_DASH_DOT_DOTTED = 0x0B - MEDIUM_DASH_DOT_DOTTED = 0x0C - SLANTED_MEDIUM_DASH_DOTTED = 0x0D - - NEED_DIAG1 = 0x01 - NEED_DIAG2 = 0x01 - NO_NEED_DIAG1 = 0x00 - NO_NEED_DIAG2 = 0x00 - - def __init__(self): - self.left = self.NO_LINE - self.right = self.NO_LINE - self.top = self.NO_LINE - self.bottom = self.NO_LINE - self.diag = self.NO_LINE - - self.left_colour = 0x40 - self.right_colour = 0x40 - self.top_colour = 0x40 - self.bottom_colour = 0x40 - self.diag_colour = 0x40 - - self.need_diag1 = self.NO_NEED_DIAG1 - self.need_diag2 = self.NO_NEED_DIAG2 - - def _search_key(self): - return ( - self.left, self.right, self.top, self.bottom, self.diag, - self.left_colour, self.right_colour, self.top_colour, - self.bottom_colour, self.diag_colour, - self.need_diag1, self.need_diag2, - ) - -class Pattern(object): - # patterns 0x00 - 0x12 - NO_PATTERN = 0x00 - SOLID_PATTERN = 0x01 - - def __init__(self): - self.pattern = self.NO_PATTERN - self.pattern_fore_colour = 0x40 - self.pattern_back_colour = 0x41 - - def _search_key(self): - return ( - self.pattern, - self.pattern_fore_colour, - self.pattern_back_colour, - ) - -class Protection(object): - def __init__(self): - self.cell_locked = 1 - self.formula_hidden = 0 - - def _search_key(self): - return ( - self.cell_locked, - self.formula_hidden, - ) diff --git a/tablib/packages/xlwt/Row.py b/tablib/packages/xlwt/Row.py deleted file mode 100644 index a834ea1..0000000 --- a/tablib/packages/xlwt/Row.py +++ /dev/null @@ -1,253 +0,0 @@ -# -*- coding: windows-1252 -*- - -import BIFFRecords -import Style -from Cell import StrCell, BlankCell, NumberCell, FormulaCell, MulBlankCell, BooleanCell, ErrorCell, \ - _get_cells_biff_data_mul -import ExcelFormula -import datetime as dt -try: - from decimal import Decimal -except ImportError: - # Python 2.3: decimal not supported; create dummy Decimal class - class Decimal(object): - pass - - -class Row(object): - __slots__ = [# private variables - "__idx", - "__parent", - "__parent_wb", - "__cells", - "__min_col_idx", - "__max_col_idx", - "__xf_index", - "__has_default_xf_index", - "__height_in_pixels", - # public variables - "height", - "has_default_height", - "height_mismatch", - "level", - "collapse", - "hidden", - "space_above", - "space_below"] - - def __init__(self, rowx, parent_sheet): - if not (isinstance(rowx, int) and 0 <= rowx <= 65535): - raise ValueError("row index (%r) not an int in range(65536)" % rowx) - self.__idx = rowx - self.__parent = parent_sheet - self.__parent_wb = parent_sheet.get_parent() - self.__cells = {} - self.__min_col_idx = 0 - self.__max_col_idx = 0 - self.__xf_index = 0x0F - self.__has_default_xf_index = 0 - self.__height_in_pixels = 0x11 - - self.height = 0x00FF - self.has_default_height = 0x00 - self.height_mismatch = 0 - self.level = 0 - self.collapse = 0 - self.hidden = 0 - self.space_above = 0 - self.space_below = 0 - - - def __adjust_height(self, style): - twips = style.font.height - points = float(twips)/20.0 - # Cell height in pixels can be calcuted by following approx. formula: - # cell height in pixels = font height in points * 83/50 + 2/5 - # It works when screen resolution is 96 dpi - pix = int(round(points*83.0/50.0 + 2.0/5.0)) - if pix > self.__height_in_pixels: - self.__height_in_pixels = pix - - - def __adjust_bound_col_idx(self, *args): - for arg in args: - iarg = int(arg) - if not ((0 <= iarg <= 255) and arg == iarg): - raise ValueError("column index (%r) not an int in range(256)" % arg) - sheet = self.__parent - if iarg < self.__min_col_idx: - self.__min_col_idx = iarg - if iarg > self.__max_col_idx: - self.__max_col_idx = iarg - if iarg < sheet.first_used_col: - sheet.first_used_col = iarg - if iarg > sheet.last_used_col: - sheet.last_used_col = iarg - - def __excel_date_dt(self, date): - if isinstance(date, dt.date) and (not isinstance(date, dt.datetime)): - epoch = dt.date(1899, 12, 31) - elif isinstance(date, dt.time): - date = dt.datetime.combine(dt.datetime(1900, 1, 1), date) - epoch = dt.datetime(1900, 1, 1, 0, 0, 0) - else: - epoch = dt.datetime(1899, 12, 31, 0, 0, 0) - delta = date - epoch - xldate = delta.days + float(delta.seconds) / (24*60*60) - # Add a day for Excel's missing leap day in 1900 - if xldate > 59: - xldate += 1 - return xldate - - def get_height_in_pixels(self): - return self.__height_in_pixels - - - def set_style(self, style): - self.__adjust_height(style) - self.__xf_index = self.__parent_wb.add_style(style) - self.__has_default_xf_index = 1 - - - def get_xf_index(self): - return self.__xf_index - - - def get_cells_count(self): - return len(self.__cells) - - - def get_min_col(self): - return self.__min_col_idx - - - def get_max_col(self): - return self.__max_col_idx - - - def get_row_biff_data(self): - height_options = (self.height & 0x07FFF) - height_options |= (self.has_default_height & 0x01) << 15 - - options = (self.level & 0x07) << 0 - options |= (self.collapse & 0x01) << 4 - options |= (self.hidden & 0x01) << 5 - options |= (self.height_mismatch & 0x01) << 6 - options |= (self.__has_default_xf_index & 0x01) << 7 - options |= (0x01 & 0x01) << 8 - options |= (self.__xf_index & 0x0FFF) << 16 - options |= (self.space_above & 1) << 28 - options |= (self.space_below & 1) << 29 - - return BIFFRecords.RowRecord(self.__idx, self.__min_col_idx, - self.__max_col_idx, height_options, options).get() - - def insert_cell(self, col_index, cell_obj): - if col_index in self.__cells: - if not self.__parent._cell_overwrite_ok: - msg = "Attempt to overwrite cell: sheetname=%r rowx=%d colx=%d" \ - % (self.__parent.name, self.__idx, col_index) - raise Exception(msg) - prev_cell_obj = self.__cells[col_index] - sst_idx = getattr(prev_cell_obj, 'sst_idx', None) - if sst_idx is not None: - self.__parent_wb.del_str(sst_idx) - self.__cells[col_index] = cell_obj - - def insert_mulcells(self, colx1, colx2, cell_obj): - self.insert_cell(colx1, cell_obj) - for col_index in xrange(colx1+1, colx2+1): - self.insert_cell(col_index, None) - - def get_cells_biff_data(self): - cell_items = [item for item in self.__cells.iteritems() if item[1] is not None] - cell_items.sort() # in column order - return _get_cells_biff_data_mul(self.__idx, cell_items) - # previously: - # return ''.join([cell.get_biff_data() for colx, cell in cell_items]) - - def get_index(self): - return self.__idx - - def set_cell_text(self, colx, value, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.insert_cell(colx, StrCell(self.__idx, colx, xf_index, self.__parent_wb.add_str(value))) - - def set_cell_blank(self, colx, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.insert_cell(colx, BlankCell(self.__idx, colx, xf_index)) - - def set_cell_mulblanks(self, first_colx, last_colx, style=Style.default_style): - assert 0 <= first_colx <= last_colx <= 255 - self.__adjust_height(style) - self.__adjust_bound_col_idx(first_colx, last_colx) - xf_index = self.__parent_wb.add_style(style) - # ncols = last_colx - first_colx + 1 - self.insert_mulcells(first_colx, last_colx, MulBlankCell(self.__idx, first_colx, last_colx, xf_index)) - - def set_cell_number(self, colx, number, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.insert_cell(colx, NumberCell(self.__idx, colx, xf_index, number)) - - def set_cell_date(self, colx, datetime_obj, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.insert_cell(colx, - NumberCell(self.__idx, colx, xf_index, self.__excel_date_dt(datetime_obj))) - - def set_cell_formula(self, colx, formula, style=Style.default_style, calc_flags=0): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.__parent_wb.add_sheet_reference(formula) - self.insert_cell(colx, FormulaCell(self.__idx, colx, xf_index, formula, calc_flags=0)) - - def set_cell_boolean(self, colx, value, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.insert_cell(colx, BooleanCell(self.__idx, colx, xf_index, bool(value))) - - def set_cell_error(self, colx, error_string_or_code, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(colx) - xf_index = self.__parent_wb.add_style(style) - self.insert_cell(colx, ErrorCell(self.__idx, colx, xf_index, error_string_or_code)) - - def write(self, col, label, style=Style.default_style): - self.__adjust_height(style) - self.__adjust_bound_col_idx(col) - style_index = self.__parent_wb.add_style(style) - if isinstance(label, basestring): - if len(label) > 0: - self.insert_cell(col, - StrCell(self.__idx, col, style_index, self.__parent_wb.add_str(label)) - ) - else: - self.insert_cell(col, BlankCell(self.__idx, col, style_index)) - elif isinstance(label, bool): # bool is subclass of int; test bool first - self.insert_cell(col, BooleanCell(self.__idx, col, style_index, label)) - elif isinstance(label, (float, int, long, Decimal)): - self.insert_cell(col, NumberCell(self.__idx, col, style_index, label)) - elif isinstance(label, (dt.datetime, dt.date, dt.time)): - date_number = self.__excel_date_dt(label) - self.insert_cell(col, NumberCell(self.__idx, col, style_index, date_number)) - elif label is None: - self.insert_cell(col, BlankCell(self.__idx, col, style_index)) - elif isinstance(label, ExcelFormula.Formula): - self.__parent_wb.add_sheet_reference(label) - self.insert_cell(col, FormulaCell(self.__idx, col, style_index, label)) - else: - raise Exception("Unexpected data type %r" % type(label)) - - write_blanks = set_cell_mulblanks - - - diff --git a/tablib/packages/xlwt/Style.py b/tablib/packages/xlwt/Style.py deleted file mode 100644 index bf5fb4c..0000000 --- a/tablib/packages/xlwt/Style.py +++ /dev/null @@ -1,592 +0,0 @@ -# -*- coding: windows-1252 -*- - -import Formatting -from BIFFRecords import * - -FIRST_USER_DEFINED_NUM_FORMAT_IDX = 164 - -class XFStyle(object): - - def __init__(self): - self.num_format_str = 'General' - self.font = Formatting.Font() - self.alignment = Formatting.Alignment() - self.borders = Formatting.Borders() - self.pattern = Formatting.Pattern() - self.protection = Formatting.Protection() - -default_style = XFStyle() - -class StyleCollection(object): - _std_num_fmt_list = [ - 'general', - '0', - '0.00', - '#,##0', - '#,##0.00', - '"$"#,##0_);("$"#,##', - '"$"#,##0_);[Red]("$"#,##', - '"$"#,##0.00_);("$"#,##', - '"$"#,##0.00_);[Red]("$"#,##', - '0%', - '0.00%', - '0.00E+00', - '# ?/?', - '# ??/??', - 'M/D/YY', - 'D-MMM-YY', - 'D-MMM', - 'MMM-YY', - 'h:mm AM/PM', - 'h:mm:ss AM/PM', - 'h:mm', - 'h:mm:ss', - 'M/D/YY h:mm', - '_(#,##0_);(#,##0)', - '_(#,##0_);[Red](#,##0)', - '_(#,##0.00_);(#,##0.00)', - '_(#,##0.00_);[Red](#,##0.00)', - '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)', - '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)', - '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)', - '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)', - 'mm:ss', - '[h]:mm:ss', - 'mm:ss.0', - '##0.0E+0', - '@' - ] - - def __init__(self, style_compression=0): - self.style_compression = style_compression - self.stats = [0, 0, 0, 0, 0, 0] - self._font_id2x = {} - self._font_x2id = {} - self._font_val2x = {} - - for x in (0, 1, 2, 3, 5): # The font with index 4 is omitted in all BIFF versions - font = Formatting.Font() - search_key = font._search_key() - self._font_id2x[font] = x - self._font_x2id[x] = font - self._font_val2x[search_key] = x - - self._xf_id2x = {} - self._xf_x2id = {} - self._xf_val2x = {} - - self._num_formats = {} - for fmtidx, fmtstr in zip(range(0, 23), StyleCollection._std_num_fmt_list[0:23]): - self._num_formats[fmtstr] = fmtidx - for fmtidx, fmtstr in zip(range(37, 50), StyleCollection._std_num_fmt_list[23:]): - self._num_formats[fmtstr] = fmtidx - - self.default_style = XFStyle() - self._default_xf = self._add_style(self.default_style)[0] - - def add(self, style): - if style == None: - return 0x10 - return self._add_style(style)[1] - - def _add_style(self, style): - num_format_str = style.num_format_str - if num_format_str in self._num_formats: - num_format_idx = self._num_formats[num_format_str] - else: - num_format_idx = ( - FIRST_USER_DEFINED_NUM_FORMAT_IDX - + len(self._num_formats) - - len(StyleCollection._std_num_fmt_list) - ) - self._num_formats[num_format_str] = num_format_idx - - font = style.font - if font in self._font_id2x: - font_idx = self._font_id2x[font] - self.stats[0] += 1 - elif self.style_compression: - search_key = font._search_key() - font_idx = self._font_val2x.get(search_key) - if font_idx is not None: - self._font_id2x[font] = font_idx - self.stats[1] += 1 - else: - font_idx = len(self._font_x2id) + 1 # Why plus 1? Font 4 is missing - self._font_id2x[font] = font_idx - self._font_val2x[search_key] = font_idx - self._font_x2id[font_idx] = font - self.stats[2] += 1 - else: - font_idx = len(self._font_id2x) + 1 - self._font_id2x[font] = font_idx - self.stats[2] += 1 - - gof = (style.alignment, style.borders, style.pattern, style.protection) - xf = (font_idx, num_format_idx) + gof - if xf in self._xf_id2x: - xf_index = self._xf_id2x[xf] - self.stats[3] += 1 - elif self.style_compression == 2: - xf_key = (font_idx, num_format_idx) + tuple([obj._search_key() for obj in gof]) - xf_index = self._xf_val2x.get(xf_key) - if xf_index is not None: - self._xf_id2x[xf] = xf_index - self.stats[4] += 1 - else: - xf_index = 0x10 + len(self._xf_x2id) - self._xf_id2x[xf] = xf_index - self._xf_val2x[xf_key] = xf_index - self._xf_x2id[xf_index] = xf - self.stats[5] += 1 - else: - xf_index = 0x10 + len(self._xf_id2x) - self._xf_id2x[xf] = xf_index - self.stats[5] += 1 - - if xf_index >= 0xFFF: - # 12 bits allowed, 0xFFF is a sentinel value - raise ValueError("More than 4094 XFs (styles)") - - return xf, xf_index - - def get_biff_data(self): - result = '' - result += self._all_fonts() - result += self._all_num_formats() - result += self._all_cell_styles() - result += self._all_styles() - return result - - def _all_fonts(self): - result = '' - if self.style_compression: - alist = self._font_x2id.items() - else: - alist = [(x, o) for o, x in self._font_id2x.items()] - alist.sort() - for font_idx, font in alist: - result += font.get_biff_record().get() - return result - - def _all_num_formats(self): - result = '' - alist = [ - (v, k) - for k, v in self._num_formats.items() - if v >= FIRST_USER_DEFINED_NUM_FORMAT_IDX - ] - alist.sort() - for fmtidx, fmtstr in alist: - result += NumberFormatRecord(fmtidx, fmtstr).get() - return result - - def _all_cell_styles(self): - result = '' - for i in range(0, 16): - result += XFRecord(self._default_xf, 'style').get() - if self.style_compression == 2: - alist = self._xf_x2id.items() - else: - alist = [(x, o) for o, x in self._xf_id2x.items()] - alist.sort() - for xf_idx, xf in alist: - result += XFRecord(xf).get() - return result - - def _all_styles(self): - return StyleRecord().get() - -# easyxf and its supporting objects ################################### - -class EasyXFException(Exception): - pass - -class EasyXFCallerError(EasyXFException): - pass - -class EasyXFAuthorError(EasyXFException): - pass - -class IntULim(object): - # If astring represents a valid unsigned integer ('123', '0xabcd', etc) - # and it is <= limit, return the int value; otherwise return None. - - def __init__(self, limit): - self.limit = limit - - def __call__(self, astring): - try: - value = int(astring, 0) - except ValueError: - return None - if not 0 <= value <= self.limit: - return None - return value - -bool_map = { - # Text values for all Boolean attributes - '1': 1, 'yes': 1, 'true': 1, 'on': 1, - '0': 0, 'no': 0, 'false': 0, 'off': 0, - } - -border_line_map = { - # Text values for these borders attributes: - # left, right, top, bottom and diag - 'no_line': 0x00, - 'thin': 0x01, - 'medium': 0x02, - 'dashed': 0x03, - 'dotted': 0x04, - 'thick': 0x05, - 'double': 0x06, - 'hair': 0x07, - 'medium_dashed': 0x08, - 'thin_dash_dotted': 0x09, - 'medium_dash_dotted': 0x0a, - 'thin_dash_dot_dotted': 0x0b, - 'medium_dash_dot_dotted': 0x0c, - 'slanted_medium_dash_dotted': 0x0d, - } - -charset_map = { - # Text values for font.charset - 'ansi_latin': 0x00, - 'sys_default': 0x01, - 'symbol': 0x02, - 'apple_roman': 0x4d, - 'ansi_jap_shift_jis': 0x80, - 'ansi_kor_hangul': 0x81, - 'ansi_kor_johab': 0x82, - 'ansi_chinese_gbk': 0x86, - 'ansi_chinese_big5': 0x88, - 'ansi_greek': 0xa1, - 'ansi_turkish': 0xa2, - 'ansi_vietnamese': 0xa3, - 'ansi_hebrew': 0xb1, - 'ansi_arabic': 0xb2, - 'ansi_baltic': 0xba, - 'ansi_cyrillic': 0xcc, - 'ansi_thai': 0xde, - 'ansi_latin_ii': 0xee, - 'oem_latin_i': 0xff, - } - - -# Text values for colour indices. "grey" is a synonym of "gray". -# The names are those given by Microsoft Excel 2003 to the colours -# in the default palette. There is no great correspondence with -# any W3C name-to-RGB mapping. -_colour_map_text = """\ -aqua 0x31 -black 0x08 -blue 0x0C -blue_gray 0x36 -bright_green 0x0B -brown 0x3C -coral 0x1D -cyan_ega 0x0F -dark_blue 0x12 -dark_blue_ega 0x12 -dark_green 0x3A -dark_green_ega 0x11 -dark_purple 0x1C -dark_red 0x10 -dark_red_ega 0x10 -dark_teal 0x38 -dark_yellow 0x13 -gold 0x33 -gray_ega 0x17 -gray25 0x16 -gray40 0x37 -gray50 0x17 -gray80 0x3F -green 0x11 -ice_blue 0x1F -indigo 0x3E -ivory 0x1A -lavender 0x2E -light_blue 0x30 -light_green 0x2A -light_orange 0x34 -light_turquoise 0x29 -light_yellow 0x2B -lime 0x32 -magenta_ega 0x0E -ocean_blue 0x1E -olive_ega 0x13 -olive_green 0x3B -orange 0x35 -pale_blue 0x2C -periwinkle 0x18 -pink 0x0E -plum 0x3D -purple_ega 0x14 -red 0x0A -rose 0x2D -sea_green 0x39 -silver_ega 0x16 -sky_blue 0x28 -tan 0x2F -teal 0x15 -teal_ega 0x15 -turquoise 0x0F -violet 0x14 -white 0x09 -yellow 0x0D""" - -colour_map = {} -for _line in _colour_map_text.splitlines(): - _name, _num = _line.split() - _num = int(_num, 0) - colour_map[_name] = _num - if 'gray' in _name: - colour_map[_name.replace('gray', 'grey')] = _num -del _colour_map_text, _line, _name, _num - - -pattern_map = { - # Text values for pattern.pattern - # xlwt/doc/pattern_examples.xls showcases all of these patterns. - 'no_fill': 0, - 'none': 0, - 'solid': 1, - 'solid_fill': 1, - 'solid_pattern': 1, - 'fine_dots': 2, - 'alt_bars': 3, - 'sparse_dots': 4, - 'thick_horz_bands': 5, - 'thick_vert_bands': 6, - 'thick_backward_diag': 7, - 'thick_forward_diag': 8, - 'big_spots': 9, - 'bricks': 10, - 'thin_horz_bands': 11, - 'thin_vert_bands': 12, - 'thin_backward_diag': 13, - 'thin_forward_diag': 14, - 'squares': 15, - 'diamonds': 16, - } - -def any_str_func(s): - return s.strip() - -def colour_index_func(s, maxval=0x7F): - try: - value = int(s, 0) - except ValueError: - return None - if not (0 <= value <= maxval): - return None - return value - -colour_index_func_7 = colour_index_func - -def colour_index_func_15(s): - return colour_index_func(s, maxval=0x7FFF) - -def rotation_func(s): - try: - value = int(s, 0) - except ValueError: - return None - if not (-90 <= value <= 90): - raise EasyXFCallerError("rotation %d: should be -90 to +90 degrees" % value) - if value < 0: - value = 90 - value # encode as 91 to 180 (clockwise) - return value - -xf_dict = { - 'align': 'alignment', # synonym - 'alignment': { - 'dire': { - 'general': 0, - 'lr': 1, - 'rl': 2, - }, - 'direction': 'dire', - 'horiz': 'horz', - 'horizontal': 'horz', - 'horz': { - 'general': 0, - 'left': 1, - 'center': 2, - 'centre': 2, # "align: horiz centre" means xf.alignment.horz is set to 2 - 'right': 3, - 'filled': 4, - 'justified': 5, - 'center_across_selection': 6, - 'centre_across_selection': 6, - 'distributed': 7, - }, - 'inde': IntULim(15), # restriction: 0 <= value <= 15 - 'indent': 'inde', - 'rota': [{'stacked': 255, 'none': 0, }, rotation_func], - 'rotation': 'rota', - 'shri': bool_map, - 'shrink': 'shri', - 'shrink_to_fit': 'shri', - 'vert': { - 'top': 0, - 'center': 1, - 'centre': 1, - 'bottom': 2, - 'justified': 3, - 'distributed': 4, - }, - 'vertical': 'vert', - 'wrap': bool_map, - }, - 'border': 'borders', - 'borders': { - 'left': [border_line_map, IntULim(0x0d)], - 'right': [border_line_map, IntULim(0x0d)], - 'top': [border_line_map, IntULim(0x0d)], - 'bottom': [border_line_map, IntULim(0x0d)], - 'diag': [border_line_map, IntULim(0x0d)], - 'top_colour': [colour_map, colour_index_func_7], - 'bottom_colour': [colour_map, colour_index_func_7], - 'left_colour': [colour_map, colour_index_func_7], - 'right_colour': [colour_map, colour_index_func_7], - 'diag_colour': [colour_map, colour_index_func_7], - 'top_color': 'top_colour', - 'bottom_color': 'bottom_colour', - 'left_color': 'left_colour', - 'right_color': 'right_colour', - 'diag_color': 'diag-colour', - 'need_diag_1': bool_map, - 'need_diag_2': bool_map, - }, - 'font': { - 'bold': bool_map, - 'charset': charset_map, - 'color': 'colour_index', - 'color_index': 'colour_index', - 'colour': 'colour_index', - 'colour_index': [colour_map, colour_index_func_15], - 'escapement': {'none': 0, 'superscript': 1, 'subscript': 2}, - 'family': {'none': 0, 'roman': 1, 'swiss': 2, 'modern': 3, 'script': 4, 'decorative': 5, }, - 'height': IntULim(0xFFFF), # practical limits are much narrower e.g. 160 to 1440 (8pt to 72pt) - 'italic': bool_map, - 'name': any_str_func, - 'outline': bool_map, - 'shadow': bool_map, - 'struck_out': bool_map, - 'underline': [bool_map, {'none': 0, 'single': 1, 'single_acc': 0x21, 'double': 2, 'double_acc': 0x22, }], - }, - 'pattern': { - 'back_color': 'pattern_back_colour', - 'back_colour': 'pattern_back_colour', - 'fore_color': 'pattern_fore_colour', - 'fore_colour': 'pattern_fore_colour', - 'pattern': [pattern_map, IntULim(16)], - 'pattern_back_color': 'pattern_back_colour', - 'pattern_back_colour': [colour_map, colour_index_func_7], - 'pattern_fore_color': 'pattern_fore_colour', - 'pattern_fore_colour': [colour_map, colour_index_func_7], - }, - 'protection': { - 'cell_locked' : bool_map, - 'formula_hidden': bool_map, - }, - } - -def _esplit(s, split_char, esc_char="\\"): - escaped = False - olist = [''] - for c in s: - if escaped: - olist[-1] += c - escaped = False - elif c == esc_char: - escaped = True - elif c == split_char: - olist.append('') - else: - olist[-1] += c - return olist - -def _parse_strg_to_obj(strg, obj, parse_dict, - field_sep=",", line_sep=";", intro_sep=":", esc_char="\\", debug=False): - for line in _esplit(strg, line_sep, esc_char): - line = line.strip() - if not line: - break - split_line = _esplit(line, intro_sep, esc_char) - if len(split_line) != 2: - raise EasyXFCallerError('line %r should have exactly 1 "%c"' % (line, intro_sep)) - section, item_str = split_line - section = section.strip().lower() - for counter in range(2): - result = parse_dict.get(section) - if result is None: - raise EasyXFCallerError('section %r is unknown' % section) - if isinstance(result, dict): - break - if not isinstance(result, str): - raise EasyXFAuthorError( - 'section %r should map to dict or str object; found %r' % (section, type(result))) - # synonym - old_section = section - section = result - else: - raise EasyXFAuthorError('Attempt to define synonym of synonym (%r: %r)' % (old_section, result)) - section_dict = result - section_obj = getattr(obj, section, None) - if section_obj is None: - raise EasyXFAuthorError('instance of %s class has no attribute named %s' % (obj.__class__.__name__, section)) - for kv_str in _esplit(item_str, field_sep, esc_char): - guff = kv_str.split() - if not guff: - continue - k = guff[0].lower().replace('-', '_') - v = ' '.join(guff[1:]) - if not v: - raise EasyXFCallerError("no value supplied for %s.%s" % (section, k)) - for counter in xrange(2): - result = section_dict.get(k) - if result is None: - raise EasyXFCallerError('%s.%s is not a known attribute' % (section, k)) - if not isinstance(result, basestring): - break - # synonym - old_k = k - k = result - else: - raise EasyXFAuthorError('Attempt to define synonym of synonym (%r: %r)' % (old_k, result)) - value_info = result - if not isinstance(value_info, list): - value_info = [value_info] - for value_rule in value_info: - if isinstance(value_rule, dict): - # dict maps strings to integer field values - vl = v.lower().replace('-', '_') - if vl in value_rule: - value = value_rule[vl] - break - elif callable(value_rule): - value = value_rule(v) - if value is not None: - break - else: - raise EasyXFAuthorError("unknown value rule for attribute %r: %r" % (k, value_rule)) - else: - raise EasyXFCallerError("unexpected value %r for %s.%s" % (v, section, k)) - try: - orig = getattr(section_obj, k) - except AttributeError: - raise EasyXFAuthorError('%s.%s in dictionary but not in supplied object' % (section, k)) - if debug: print "+++ %s.%s = %r # %s; was %r" % (section, k, value, v, orig) - setattr(section_obj, k, value) - -def easyxf(strg_to_parse="", num_format_str=None, - field_sep=",", line_sep=";", intro_sep=":", esc_char="\\", debug=False): - xfobj = XFStyle() - if num_format_str is not None: - xfobj.num_format_str = num_format_str - if strg_to_parse: - _parse_strg_to_obj(strg_to_parse, xfobj, xf_dict, - field_sep=field_sep, line_sep=line_sep, intro_sep=intro_sep, esc_char=esc_char, debug=debug) - return xfobj diff --git a/tablib/packages/xlwt/UnicodeUtils.py b/tablib/packages/xlwt/UnicodeUtils.py deleted file mode 100644 index 630c259..0000000 --- a/tablib/packages/xlwt/UnicodeUtils.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: windows-1252 -*- - -''' -From BIFF8 on, strings are always stored using UTF-16LE text encoding. The -character array is a sequence of 16-bit values4. Additionally it is -possible to use a compressed format, which omits the high bytes of all -characters, if they are all zero. - -The following tables describe the standard format of the entire string, but -in many records the strings differ from this format. This will be mentioned -separately. It is possible (but not required) to store Rich-Text formatting -information and Asian phonetic information inside a Unicode string. This -results in four different ways to store a string. The character array -is not zero-terminated. - -The string consists of the character count (as usual an 8-bit value or -a 16-bit value), option flags, the character array and optional formatting -information. If the string is empty, sometimes the option flags field will -not occur. This is mentioned at the respective place. - -Offset Size Contents -0 1 or 2 Length of the string (character count, ln) -1 or 2 1 Option flags: - Bit Mask Contents - 0 01H Character compression (ccompr): - 0 = Compressed (8-bit characters) - 1 = Uncompressed (16-bit characters) - 2 04H Asian phonetic settings (phonetic): - 0 = Does not contain Asian phonetic settings - 1 = Contains Asian phonetic settings - 3 08H Rich-Text settings (richtext): - 0 = Does not contain Rich-Text settings - 1 = Contains Rich-Text settings -[2 or 3] 2 (optional, only if richtext=1) Number of Rich-Text formatting runs (rt) -[var.] 4 (optional, only if phonetic=1) Size of Asian phonetic settings block (in bytes, sz) -var. ln or - 2·ln Character array (8-bit characters or 16-bit characters, dependent on ccompr) -[var.] 4·rt (optional, only if richtext=1) List of rt formatting runs -[var.] sz (optional, only if phonetic=1) Asian Phonetic Settings Block -''' - - -from struct import pack - -def upack2(s, encoding='ascii'): - # If not unicode, make it so. - if isinstance(s, unicode): - us = s - else: - us = unicode(s, encoding) - # Limit is based on number of content characters - # (not on number of bytes in packed result) - len_us = len(us) - if len_us > 65535: - raise Exception('String longer than 65535 characters') - try: - encs = us.encode('latin1') - # Success here means all chars are in U+0000 to U+00FF - # inclusive, meaning that we can use "compressed format". - flag = 0 - except UnicodeEncodeError: - encs = us.encode('utf_16_le') - flag = 1 - return pack('<HB', len_us, flag) + encs - -def upack1(s, encoding='ascii'): - # Same as upack2(), but with a one-byte length field. - if isinstance(s, unicode): - us = s - else: - us = unicode(s, encoding) - len_us = len(us) - if len_us > 255: - raise Exception('String longer than 255 characters') - try: - encs = us.encode('latin1') - flag = 0 - except UnicodeEncodeError: - encs = us.encode('utf_16_le') - flag = 1 - return pack('<BB', len_us, flag) + encs diff --git a/tablib/packages/xlwt/Utils.py b/tablib/packages/xlwt/Utils.py deleted file mode 100644 index 19e8d21..0000000 --- a/tablib/packages/xlwt/Utils.py +++ /dev/null @@ -1,196 +0,0 @@ -# pyXLWriter: A library for generating Excel Spreadsheets -# Copyright (c) 2004 Evgeny Filatov <fufff@users.sourceforge.net> -# Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel) -# -# This library is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -# General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this library; if not, write to the Free Software Foundation, -# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#---------------------------------------------------------------------------- -# This module was written/ported from PERL Spreadsheet::WriteExcel module -# The author of the PERL Spreadsheet::WriteExcel module is John McNamara -# <jmcnamara@cpan.org> -#---------------------------------------------------------------------------- -# See the README.txt distributed with pyXLWriter for more details. - -# Portions are (C) Roman V. Kiseliov, 2005 - - -# Utilities for work with reference to cells and with sheetnames - - -__rev_id__ = """$Id: Utils.py 3844 2009-05-20 01:02:54Z sjmachin $""" - -import re -from struct import pack -from ExcelMagic import MAX_ROW, MAX_COL - - -_re_cell_ex = re.compile(r"(\$?)([A-I]?[A-Z])(\$?)(\d+)", re.IGNORECASE) -_re_row_range = re.compile(r"\$?(\d+):\$?(\d+)") -_re_col_range = re.compile(r"\$?([A-I]?[A-Z]):\$?([A-I]?[A-Z])", re.IGNORECASE) -_re_cell_range = re.compile(r"\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)", re.IGNORECASE) -_re_cell_ref = re.compile(r"\$?([A-I]?[A-Z]\$?\d+)", re.IGNORECASE) - - -def col_by_name(colname): - """ - """ - col = 0 - pow = 1 - for i in xrange(len(colname)-1, -1, -1): - ch = colname[i] - col += (ord(ch) - ord('A') + 1) * pow - pow *= 26 - return col - 1 - - -def cell_to_rowcol(cell): - """Convert an Excel cell reference string in A1 notation - to numeric row/col notation. - - Returns: row, col, row_abs, col_abs - - """ - m = _re_cell_ex.match(cell) - if not m: - raise Exception("Ill-formed single_cell reference: %s" % cell) - col_abs, col, row_abs, row = m.groups() - row_abs = bool(row_abs) - col_abs = bool(col_abs) - row = int(row) - 1 - col = col_by_name(col.upper()) - return row, col, row_abs, col_abs - - -def cell_to_rowcol2(cell): - """Convert an Excel cell reference string in A1 notation - to numeric row/col notation. - - Returns: row, col - - """ - m = _re_cell_ex.match(cell) - if not m: - raise Exception("Error in cell format") - col_abs, col, row_abs, row = m.groups() - # Convert base26 column string to number - # All your Base are belong to us. - row = int(row) - 1 - col = col_by_name(col.upper()) - return row, col - - -def rowcol_to_cell(row, col, row_abs=False, col_abs=False): - """Convert numeric row/col notation to an Excel cell reference string in - A1 notation. - - """ - assert 0 <= row < MAX_ROW # MAX_ROW counts from 1 - assert 0 <= col < MAX_COL # MAX_COL counts from 1 - d = col // 26 - m = col % 26 - chr1 = "" # Most significant character in AA1 - if row_abs: - row_abs = '$' - else: - row_abs = '' - if col_abs: - col_abs = '$' - else: - col_abs = '' - if d > 0: - chr1 = chr(ord('A') + d - 1) - chr2 = chr(ord('A') + m) - # Zero index to 1-index - return col_abs + chr1 + chr2 + row_abs + str(row + 1) - -def rowcol_pair_to_cellrange(row1, col1, row2, col2, - row1_abs=False, col1_abs=False, row2_abs=False, col2_abs=False): - """Convert two (row,column) pairs - into a cell range string in A1:B2 notation. - - Returns: cell range string - """ - assert row1 <= row2 - assert col1 <= col2 - return ( - rowcol_to_cell(row1, col1, row1_abs, col1_abs) - + ":" - + rowcol_to_cell(row2, col2, row2_abs, col2_abs) - ) - -def cellrange_to_rowcol_pair(cellrange): - """Convert cell range string in A1 notation to numeric row/col - pair. - - Returns: row1, col1, row2, col2 - - """ - cellrange = cellrange.upper() - # Convert a row range: '1:3' - res = _re_row_range.match(cellrange) - if res: - row1 = int(res.group(1)) - 1 - col1 = 0 - row2 = int(res.group(2)) - 1 - col2 = -1 - return row1, col1, row2, col2 - # Convert a column range: 'A:A' or 'B:G'. - # A range such as A:A is equivalent to A1:A16384, so add rows as required - res = _re_col_range.match(cellrange) - if res: - col1 = col_by_name(res.group(1).upper()) - row1 = 0 - col2 = col_by_name(res.group(2).upper()) - row2 = -1 - return row1, col1, row2, col2 - # Convert a cell range: 'A1:B7' - res = _re_cell_range.match(cellrange) - if res: - row1, col1 = cell_to_rowcol2(res.group(1)) - row2, col2 = cell_to_rowcol2(res.group(2)) - return row1, col1, row2, col2 - # Convert a cell reference: 'A1' or 'AD2000' - res = _re_cell_ref.match(cellrange) - if res: - row1, col1 = cell_to_rowcol2(res.group(1)) - return row1, col1, row1, col1 - raise Exception("Unknown cell reference %s" % (cell)) - - -def cell_to_packed_rowcol(cell): - """ pack row and column into the required 4 byte format """ - row, col, row_abs, col_abs = cell_to_rowcol(cell) - if col >= MAX_COL: - raise Exception("Column %s greater than IV in formula" % cell) - if row >= MAX_ROW: # this for BIFF8. for BIFF7 available 2^14 - raise Exception("Row %s greater than %d in formula" % (cell, MAX_ROW)) - col |= int(not row_abs) << 15 - col |= int(not col_abs) << 14 - return row, col - -# === sheetname functions === - -def valid_sheet_name(sheet_name): - if sheet_name == u"" or sheet_name[0] == u"'" or len(sheet_name) > 31: - return False - for c in sheet_name: - if c in u"[]:\\?/*\x00": - return False - return True - -def quote_sheet_name(unquoted_sheet_name): - if not valid_sheet_name(unquoted_sheet_name): - raise Exception( - 'attempt to quote an invalid worksheet name %r' % unquoted_sheet_name) - return u"'" + unquoted_sheet_name.replace(u"'", u"''") + u"'" diff --git a/tablib/packages/xlwt/Workbook.py b/tablib/packages/xlwt/Workbook.py deleted file mode 100644 index b24282b..0000000 --- a/tablib/packages/xlwt/Workbook.py +++ /dev/null @@ -1,636 +0,0 @@ -# -*- coding: windows-1252 -*- -''' -Record Order in BIFF8 - Workbook Globals Substream - BOF Type = workbook globals - Interface Header - MMS - Interface End - WRITEACCESS - CODEPAGE - DSF - TABID - FNGROUPCOUNT - Workbook Protection Block - WINDOWPROTECT - PROTECT - PASSWORD - PROT4REV - PROT4REVPASS - BACKUP - HIDEOBJ - WINDOW1 - DATEMODE - PRECISION - REFRESHALL - BOOKBOOL - FONT + - FORMAT * - XF + - STYLE + - ? PALETTE - USESELFS - - BOUNDSHEET + - - COUNTRY - ? Link Table - SST - ExtSST - EOF -''' - -import BIFFRecords -import Style - -class Workbook(object): - - ################################################################# - ## Constructor - ################################################################# - def __init__(self, encoding='ascii', style_compression=0): - self.encoding = encoding - self.__owner = 'None' - self.__country_code = None # 0x07 is Russia :-) - self.__wnd_protect = 0 - self.__obj_protect = 0 - self.__protect = 0 - self.__backup_on_save = 0 - # for WINDOW1 record - self.__hpos_twips = 0x01E0 - self.__vpos_twips = 0x005A - self.__width_twips = 0x3FCF - self.__height_twips = 0x2A4E - - self.__active_sheet = 0 - self.__first_tab_index = 0 - self.__selected_tabs = 0x01 - self.__tab_width_twips = 0x0258 - - self.__wnd_hidden = 0 - self.__wnd_mini = 0 - self.__hscroll_visible = 1 - self.__vscroll_visible = 1 - self.__tabs_visible = 1 - - self.__styles = Style.StyleCollection(style_compression) - - self.__dates_1904 = 0 - self.__use_cell_values = 1 - - self.__sst = BIFFRecords.SharedStringTable(self.encoding) - - self.__worksheets = [] - self.__worksheet_idx_from_name = {} - self.__sheet_refs = {} - self._supbook_xref = {} - self._xcall_xref = {} - self._ownbook_supbookx = None - self._ownbook_supbook_ref = None - self._xcall_supbookx = None - self._xcall_supbook_ref = None - - - - ################################################################# - ## Properties, "getters", "setters" - ################################################################# - - def get_style_stats(self): - return self.__styles.stats[:] - - def set_owner(self, value): - self.__owner = value - - def get_owner(self): - return self.__owner - - owner = property(get_owner, set_owner) - - ################################################################# - - def set_country_code(self, value): - self.__country_code = value - - def get_country_code(self): - return self.__country_code - - country_code = property(get_country_code, set_country_code) - - ################################################################# - - def set_wnd_protect(self, value): - self.__wnd_protect = int(value) - - def get_wnd_protect(self): - return bool(self.__wnd_protect) - - wnd_protect = property(get_wnd_protect, set_wnd_protect) - - ################################################################# - - def set_obj_protect(self, value): - self.__obj_protect = int(value) - - def get_obj_protect(self): - return bool(self.__obj_protect) - - obj_protect = property(get_obj_protect, set_obj_protect) - - ################################################################# - - def set_protect(self, value): - self.__protect = int(value) - - def get_protect(self): - return bool(self.__protect) - - protect = property(get_protect, set_protect) - - ################################################################# - - def set_backup_on_save(self, value): - self.__backup_on_save = int(value) - - def get_backup_on_save(self): - return bool(self.__backup_on_save) - - backup_on_save = property(get_backup_on_save, set_backup_on_save) - - ################################################################# - - def set_hpos(self, value): - self.__hpos_twips = value & 0xFFFF - - def get_hpos(self): - return self.__hpos_twips - - hpos = property(get_hpos, set_hpos) - - ################################################################# - - def set_vpos(self, value): - self.__vpos_twips = value & 0xFFFF - - def get_vpos(self): - return self.__vpos_twips - - vpos = property(get_vpos, set_vpos) - - ################################################################# - - def set_width(self, value): - self.__width_twips = value & 0xFFFF - - def get_width(self): - return self.__width_twips - - width = property(get_width, set_width) - - ################################################################# - - def set_height(self, value): - self.__height_twips = value & 0xFFFF - - def get_height(self): - return self.__height_twips - - height = property(get_height, set_height) - - ################################################################# - - def set_active_sheet(self, value): - self.__active_sheet = value & 0xFFFF - self.__first_tab_index = self.__active_sheet - - def get_active_sheet(self): - return self.__active_sheet - - active_sheet = property(get_active_sheet, set_active_sheet) - - ################################################################# - - def set_tab_width(self, value): - self.__tab_width_twips = value & 0xFFFF - - def get_tab_width(self): - return self.__tab_width_twips - - tab_width = property(get_tab_width, set_tab_width) - - ################################################################# - - def set_wnd_visible(self, value): - self.__wnd_hidden = int(not value) - - def get_wnd_visible(self): - return not bool(self.__wnd_hidden) - - wnd_visible = property(get_wnd_visible, set_wnd_visible) - - ################################################################# - - def set_wnd_mini(self, value): - self.__wnd_mini = int(value) - - def get_wnd_mini(self): - return bool(self.__wnd_mini) - - wnd_mini = property(get_wnd_mini, set_wnd_mini) - - ################################################################# - - def set_hscroll_visible(self, value): - self.__hscroll_visible = int(value) - - def get_hscroll_visible(self): - return bool(self.__hscroll_visible) - - hscroll_visible = property(get_hscroll_visible, set_hscroll_visible) - - ################################################################# - - def set_vscroll_visible(self, value): - self.__vscroll_visible = int(value) - - def get_vscroll_visible(self): - return bool(self.__vscroll_visible) - - vscroll_visible = property(get_vscroll_visible, set_vscroll_visible) - - ################################################################# - - def set_tabs_visible(self, value): - self.__tabs_visible = int(value) - - def get_tabs_visible(self): - return bool(self.__tabs_visible) - - tabs_visible = property(get_tabs_visible, set_tabs_visible) - - ################################################################# - - def set_dates_1904(self, value): - self.__dates_1904 = int(value) - - def get_dates_1904(self): - return bool(self.__dates_1904) - - dates_1904 = property(get_dates_1904, set_dates_1904) - - ################################################################# - - def set_use_cell_values(self, value): - self.__use_cell_values = int(value) - - def get_use_cell_values(self): - return bool(self.__use_cell_values) - - use_cell_values = property(get_use_cell_values, set_use_cell_values) - - ################################################################# - - def get_default_style(self): - return self.__styles.default_style - - default_style = property(get_default_style) - - ################################################################## - ## Methods - ################################################################## - - def add_style(self, style): - return self.__styles.add(style) - - def add_str(self, s): - return self.__sst.add_str(s) - - def del_str(self, sst_idx): - self.__sst.del_str(sst_idx) - - def str_index(self, s): - return self.__sst.str_index(s) - - def add_sheet(self, sheetname, cell_overwrite_ok=False): - import Worksheet, Utils - if not isinstance(sheetname, unicode): - sheetname = sheetname.decode(self.encoding) - if not Utils.valid_sheet_name(sheetname): - raise Exception("invalid worksheet name %r" % sheetname) - lower_name = sheetname.lower() - if lower_name in self.__worksheet_idx_from_name: - raise Exception("duplicate worksheet name %r" % sheetname) - self.__worksheet_idx_from_name[lower_name] = len(self.__worksheets) - self.__worksheets.append(Worksheet.Worksheet(sheetname, self, cell_overwrite_ok)) - return self.__worksheets[-1] - - def get_sheet(self, sheetnum): - return self.__worksheets[sheetnum] - - def raise_bad_sheetname(self, sheetname): - raise Exception("Formula: unknown sheet name %s" % sheetname) - - def convert_sheetindex(self, strg_ref, n_sheets): - idx = int(strg_ref) - if 0 <= idx < n_sheets: - return idx - msg = "Formula: sheet index (%s) >= number of sheets (%d)" % (strg_ref, n_sheets) - raise Exception(msg) - - def _get_supbook_index(self, tag): - if tag in self._supbook_xref: - return self._supbook_xref[tag] - self._supbook_xref[tag] = idx = len(self._supbook_xref) - return idx - - def setup_ownbook(self): - self._ownbook_supbookx = self._get_supbook_index(('ownbook', 0)) - self._ownbook_supbook_ref = None - reference = (self._ownbook_supbookx, 0xFFFE, 0xFFFE) - if reference in self.__sheet_refs: - raise Exception("can't happen") - self.__sheet_refs[reference] = self._ownbook_supbook_ref = len(self.__sheet_refs) - - def setup_xcall(self): - self._xcall_supbookx = self._get_supbook_index(('xcall', 0)) - self._xcall_supbook_ref = None - reference = (self._xcall_supbookx, 0xFFFE, 0xFFFE) - if reference in self.__sheet_refs: - raise Exception("can't happen") - self.__sheet_refs[reference] = self._xcall_supbook_ref = len(self.__sheet_refs) - - def add_sheet_reference(self, formula): - patches = [] - n_sheets = len(self.__worksheets) - sheet_refs, xcall_refs = formula.get_references() - - for ref0, ref1, offset in sheet_refs: - if not ref0.isdigit(): - try: - ref0n = self.__worksheet_idx_from_name[ref0.lower()] - except KeyError: - self.raise_bad_sheetname(ref0) - else: - ref0n = self.convert_sheetindex(ref0, n_sheets) - if ref1 == ref0: - ref1n = ref0n - elif not ref1.isdigit(): - try: - ref1n = self.__worksheet_idx_from_name[ref1.lower()] - except KeyError: - self.raise_bad_sheetname(ref1) - else: - ref1n = self.convert_sheetindex(ref1, n_sheets) - if ref1n < ref0n: - msg = "Formula: sheets out of order; %r:%r -> (%d, %d)" \ - % (ref0, ref1, ref0n, ref1n) - raise Exception(msg) - if self._ownbook_supbookx is None: - self.setup_ownbook() - reference = (self._ownbook_supbookx, ref0n, ref1n) - if reference in self.__sheet_refs: - patches.append((offset, self.__sheet_refs[reference])) - else: - nrefs = len(self.__sheet_refs) - if nrefs > 65535: - raise Exception('More than 65536 inter-sheet references') - self.__sheet_refs[reference] = nrefs - patches.append((offset, nrefs)) - - for funcname, offset in xcall_refs: - if self._ownbook_supbookx is None: - self.setup_ownbook() - if self._xcall_supbookx is None: - self.setup_xcall() - # print funcname, self._supbook_xref - patches.append((offset, self._xcall_supbook_ref)) - if not isinstance(funcname, unicode): - funcname = funcname.decode(self.encoding) - if funcname in self._xcall_xref: - idx = self._xcall_xref[funcname] - else: - self._xcall_xref[funcname] = idx = len(self._xcall_xref) - patches.append((offset + 2, idx + 1)) - - formula.patch_references(patches) - - ################################################################## - ## BIFF records generation - ################################################################## - - def __bof_rec(self): - return BIFFRecords.Biff8BOFRecord(BIFFRecords.Biff8BOFRecord.BOOK_GLOBAL).get() - - def __eof_rec(self): - return BIFFRecords.EOFRecord().get() - - def __intf_hdr_rec(self): - return BIFFRecords.InteraceHdrRecord().get() - - def __intf_end_rec(self): - return BIFFRecords.InteraceEndRecord().get() - - def __intf_mms_rec(self): - return BIFFRecords.MMSRecord().get() - - def __write_access_rec(self): - return BIFFRecords.WriteAccessRecord(self.__owner).get() - - def __wnd_protect_rec(self): - return BIFFRecords.WindowProtectRecord(self.__wnd_protect).get() - - def __obj_protect_rec(self): - return BIFFRecords.ObjectProtectRecord(self.__obj_protect).get() - - def __protect_rec(self): - return BIFFRecords.ProtectRecord(self.__protect).get() - - def __password_rec(self): - return BIFFRecords.PasswordRecord().get() - - def __prot4rev_rec(self): - return BIFFRecords.Prot4RevRecord().get() - - def __prot4rev_pass_rec(self): - return BIFFRecords.Prot4RevPassRecord().get() - - def __backup_rec(self): - return BIFFRecords.BackupRecord(self.__backup_on_save).get() - - def __hide_obj_rec(self): - return BIFFRecords.HideObjRecord().get() - - def __window1_rec(self): - flags = 0 - flags |= (self.__wnd_hidden) << 0 - flags |= (self.__wnd_mini) << 1 - flags |= (self.__hscroll_visible) << 3 - flags |= (self.__vscroll_visible) << 4 - flags |= (self.__tabs_visible) << 5 - - return BIFFRecords.Window1Record(self.__hpos_twips, self.__vpos_twips, - self.__width_twips, self.__height_twips, - flags, - self.__active_sheet, self.__first_tab_index, - self.__selected_tabs, self.__tab_width_twips).get() - - def __codepage_rec(self): - return BIFFRecords.CodepageBiff8Record().get() - - def __country_rec(self): - if not self.__country_code: - return '' - return BIFFRecords.CountryRecord(self.__country_code, self.__country_code).get() - - def __dsf_rec(self): - return BIFFRecords.DSFRecord().get() - - def __tabid_rec(self): - return BIFFRecords.TabIDRecord(len(self.__worksheets)).get() - - def __fngroupcount_rec(self): - return BIFFRecords.FnGroupCountRecord().get() - - def __datemode_rec(self): - return BIFFRecords.DateModeRecord(self.__dates_1904).get() - - def __precision_rec(self): - return BIFFRecords.PrecisionRecord(self.__use_cell_values).get() - - def __refresh_all_rec(self): - return BIFFRecords.RefreshAllRecord().get() - - def __bookbool_rec(self): - return BIFFRecords.BookBoolRecord().get() - - def __all_fonts_num_formats_xf_styles_rec(self): - return self.__styles.get_biff_data() - - def __palette_rec(self): - result = '' - return result - - def __useselfs_rec(self): - return BIFFRecords.UseSelfsRecord().get() - - def __boundsheets_rec(self, data_len_before, data_len_after, sheet_biff_lens): - # ................................. - # BOUNDSEHEET0 - # BOUNDSEHEET1 - # BOUNDSEHEET2 - # .................................. - # WORKSHEET0 - # WORKSHEET1 - # WORKSHEET2 - boundsheets_len = 0 - for sheet in self.__worksheets: - boundsheets_len += len(BIFFRecords.BoundSheetRecord( - 0x00L, sheet.visibility, sheet.name, self.encoding - ).get()) - - start = data_len_before + boundsheets_len + data_len_after - - result = '' - for sheet_biff_len, sheet in zip(sheet_biff_lens, self.__worksheets): - result += BIFFRecords.BoundSheetRecord( - start, sheet.visibility, sheet.name, self.encoding - ).get() - start += sheet_biff_len - return result - - def __all_links_rec(self): - pieces = [] - temp = [(idx, tag) for tag, idx in self._supbook_xref.items()] - temp.sort() - for idx, tag in temp: - stype, snum = tag - if stype == 'ownbook': - rec = BIFFRecords.InternalReferenceSupBookRecord(len(self.__worksheets)).get() - pieces.append(rec) - elif stype == 'xcall': - rec = BIFFRecords.XcallSupBookRecord().get() - pieces.append(rec) - temp = [(idx, name) for name, idx in self._xcall_xref.items()] - temp.sort() - for idx, name in temp: - rec = BIFFRecords.ExternnameRecord( - options=0, index=0, name=name, fmla='\x02\x00\x1c\x17').get() - pieces.append(rec) - else: - raise Exception('unknown supbook stype %r' % stype) - if len(self.__sheet_refs) > 0: - # get references in index order - temp = [(idx, ref) for ref, idx in self.__sheet_refs.items()] - temp.sort() - temp = [ref for idx, ref in temp] - externsheet_record = BIFFRecords.ExternSheetRecord(temp).get() - pieces.append(externsheet_record) - return ''.join(pieces) - - def __sst_rec(self): - return self.__sst.get_biff_record() - - def __ext_sst_rec(self, abs_stream_pos): - return '' - #return BIFFRecords.ExtSSTRecord(abs_stream_pos, self.sst_record.str_placement, - #self.sst_record.portions_len).get() - - def get_biff_data(self): - before = '' - before += self.__bof_rec() - before += self.__intf_hdr_rec() - before += self.__intf_mms_rec() - before += self.__intf_end_rec() - before += self.__write_access_rec() - before += self.__codepage_rec() - before += self.__dsf_rec() - before += self.__tabid_rec() - before += self.__fngroupcount_rec() - before += self.__wnd_protect_rec() - before += self.__protect_rec() - before += self.__obj_protect_rec() - before += self.__password_rec() - before += self.__prot4rev_rec() - before += self.__prot4rev_pass_rec() - before += self.__backup_rec() - before += self.__hide_obj_rec() - before += self.__window1_rec() - before += self.__datemode_rec() - before += self.__precision_rec() - before += self.__refresh_all_rec() - before += self.__bookbool_rec() - before += self.__all_fonts_num_formats_xf_styles_rec() - before += self.__palette_rec() - before += self.__useselfs_rec() - - country = self.__country_rec() - all_links = self.__all_links_rec() - - shared_str_table = self.__sst_rec() - after = country + all_links + shared_str_table - - ext_sst = self.__ext_sst_rec(0) # need fake cause we need calc stream pos - eof = self.__eof_rec() - - self.__worksheets[self.__active_sheet].selected = True - sheets = '' - sheet_biff_lens = [] - for sheet in self.__worksheets: - data = sheet.get_biff_data() - sheets += data - sheet_biff_lens.append(len(data)) - - bundlesheets = self.__boundsheets_rec(len(before), len(after)+len(ext_sst)+len(eof), sheet_biff_lens) - - sst_stream_pos = len(before) + len(bundlesheets) + len(country) + len(all_links) - ext_sst = self.__ext_sst_rec(sst_stream_pos) - - return before + bundlesheets + after + ext_sst + eof + sheets - - def save(self, filename): - import CompoundDoc - - doc = CompoundDoc.XlsDoc() - doc.save(filename, self.get_biff_data()) - - diff --git a/tablib/packages/xlwt/Worksheet.py b/tablib/packages/xlwt/Worksheet.py deleted file mode 100644 index ff36f1d..0000000 --- a/tablib/packages/xlwt/Worksheet.py +++ /dev/null @@ -1,1297 +0,0 @@ -# -*- coding: windows-1252 -*- -''' - BOF - UNCALCED - INDEX - Calculation Settings Block - PRINTHEADERS - PRINTGRIDLINES - GRIDSET - GUTS - DEFAULTROWHEIGHT - WSBOOL - Page Settings Block - Worksheet Protection Block - DEFCOLWIDTH - COLINFO - SORT - DIMENSIONS - Row Blocks - WINDOW2 - SCL - PANE - SELECTION - STANDARDWIDTH - MERGEDCELLS - LABELRANGES - PHONETIC - Conditional Formatting Table - Hyperlink Table - Data Validity Table - SHEETLAYOUT (BIFF8X only) - SHEETPROTECTION (BIFF8X only) - RANGEPROTECTION (BIFF8X only) - EOF -''' - -import BIFFRecords -import Bitmap -import Formatting -import Style -import tempfile - - -class Worksheet(object): - from Workbook import Workbook - - ################################################################# - ## Constructor - ################################################################# - def __init__(self, sheetname, parent_book, cell_overwrite_ok=False): - import Row - self.Row = Row.Row - - import Column - self.Column = Column.Column - - self.__name = sheetname - self.__parent = parent_book - self._cell_overwrite_ok = cell_overwrite_ok - - self.__rows = {} - self.__cols = {} - self.__merged_ranges = [] - self.__bmp_rec = '' - - self.__show_formulas = 0 - self.__show_grid = 1 - self.__show_headers = 1 - self.__panes_frozen = 0 - ### self.__show_empty_as_zero = 1 ### deprecated with extreme prejudice 2009-05-19 - self.show_zero_values = 1 - self.__auto_colour_grid = 1 - self.__cols_right_to_left = 0 - self.__show_outline = 1 - self.__remove_splits = 0 - self.__selected = 0 - # RED HERRING ALERT: "sheet_visible" is a clone of the "selected" attribute. - # Typically a workbook created by the Excel UI will have one sheet - # (the sheet that was selected when the user saved it) - # with both bits set to 1, and all other sheets will have both - # bits set to 0. The true visibility of the sheet is found in the "visibility" - # attribute obtained from the BOUNDSHEET record. - self.__sheet_visible = 0 - self.__page_preview = 0 - - self.__first_visible_row = 0 - self.__first_visible_col = 0 - self.__grid_colour = 0x40 - self.__preview_magn = 60 # percent - self.__normal_magn = 100 # percent - - self.visibility = 0 # from/to BOUNDSHEET record. - - self.__vert_split_pos = None - self.__horz_split_pos = None - self.__vert_split_first_visible = None - self.__horz_split_first_visible = None - self.__split_active_pane = None - - self.__row_gut_width = 0 - self.__col_gut_height = 0 - - self.__show_auto_page_breaks = 1 - self.__dialogue_sheet = 0 - self.__auto_style_outline = 0 - self.__outline_below = 0 - self.__outline_right = 0 - self.__fit_num_pages = 0 - self.__show_row_outline = 1 - self.__show_col_outline = 1 - self.__alt_expr_eval = 0 - self.__alt_formula_entries = 0 - - self.__row_default_height = 0x00FF - self.row_default_height_mismatch = 0 - self.row_default_hidden = 0 - self.row_default_space_above = 0 - self.row_default_space_below = 0 - - self.__col_default_width = 0x0008 - - self.__calc_mode = 1 - self.__calc_count = 0x0064 - self.__RC_ref_mode = 1 - self.__iterations_on = 0 - self.__delta = 0.001 - self.__save_recalc = 0 - - self.__print_headers = 0 - self.__print_grid = 0 - self.__grid_set = 1 - self.__vert_page_breaks = [] - self.__horz_page_breaks = [] - self.__header_str = '&P' - self.__footer_str = '&F' - self.__print_centered_vert = 0 - self.__print_centered_horz = 1 - self.__left_margin = 0.3 #0.5 - self.__right_margin = 0.3 #0.5 - self.__top_margin = 0.61 #1.0 - self.__bottom_margin = 0.37 #1.0 - self.__paper_size_code = 9 # A4 - self.__print_scaling = 100 - self.__start_page_number = 1 - self.__fit_width_to_pages = 1 - self.__fit_height_to_pages = 1 - self.__print_in_rows = 1 - self.__portrait = 1 - self.__print_not_colour = 0 - self.__print_draft = 0 - self.__print_notes = 0 - self.__print_notes_at_end = 0 - self.__print_omit_errors = 0 - self.__print_hres = 0x012C # 300 dpi - self.__print_vres = 0x012C # 300 dpi - self.__header_margin = 0.1 - self.__footer_margin = 0.1 - self.__copies_num = 1 - - self.__wnd_protect = 0 - self.__obj_protect = 0 - self.__protect = 0 - self.__scen_protect = 0 - self.__password = '' - - self.last_used_row = 0 - self.first_used_row = 65535 - self.last_used_col = 0 - self.first_used_col = 255 - self.row_tempfile = None - self.__flushed_rows = {} - self.__row_visible_levels = 0 - - ################################################################# - ## Properties, "getters", "setters" - ################################################################# - - def set_name(self, value): - self.__name = value - - def get_name(self): - return self.__name - - name = property(get_name, set_name) - - ################################################################# - - def get_parent(self): - return self.__parent - - parent = property(get_parent) - - ################################################################# - - def get_rows(self): - return self.__rows - - rows = property(get_rows) - - ################################################################# - - def get_cols(self): - return self.__cols - - cols = property(get_cols) - - ################################################################# - - def get_merged_ranges(self): - return self.__merged_ranges - - merged_ranges = property(get_merged_ranges) - - ################################################################# - - def get_bmp_rec(self): - return self.__bmp_rec - - bmp_rec = property(get_bmp_rec) - - ################################################################# - - def set_show_formulas(self, value): - self.__show_formulas = int(value) - - def get_show_formulas(self): - return bool(self.__show_formulas) - - show_formulas = property(get_show_formulas, set_show_formulas) - - ################################################################# - - def set_show_grid(self, value): - self.__show_grid = int(value) - - def get_show_grid(self): - return bool(self.__show_grid) - - show_grid = property(get_show_grid, set_show_grid) - - ################################################################# - - def set_show_headers(self, value): - self.__show_headers = int(value) - - def get_show_headers(self): - return bool(self.__show_headers) - - show_headers = property(get_show_headers, set_show_headers) - - ################################################################# - - def set_panes_frozen(self, value): - self.__panes_frozen = int(value) - - def get_panes_frozen(self): - return bool(self.__panes_frozen) - - panes_frozen = property(get_panes_frozen, set_panes_frozen) - - ################################################################# - - ### def set_show_empty_as_zero(self, value): - ### self.__show_empty_as_zero = int(value) - - ### def get_show_empty_as_zero(self): - ### return bool(self.__show_empty_as_zero) - - ### show_empty_as_zero = property(get_show_empty_as_zero, set_show_empty_as_zero) - - ################################################################# - - def set_auto_colour_grid(self, value): - self.__auto_colour_grid = int(value) - - def get_auto_colour_grid(self): - return bool(self.__auto_colour_grid) - - auto_colour_grid = property(get_auto_colour_grid, set_auto_colour_grid) - - ################################################################# - - def set_cols_right_to_left(self, value): - self.__cols_right_to_left = int(value) - - def get_cols_right_to_left(self): - return bool(self.__cols_right_to_left) - - cols_right_to_left = property(get_cols_right_to_left, set_cols_right_to_left) - - ################################################################# - - def set_show_outline(self, value): - self.__show_outline = int(value) - - def get_show_outline(self): - return bool(self.__show_outline) - - show_outline = property(get_show_outline, set_show_outline) - - ################################################################# - - def set_remove_splits(self, value): - self.__remove_splits = int(value) - - def get_remove_splits(self): - return bool(self.__remove_splits) - - remove_splits = property(get_remove_splits, set_remove_splits) - - ################################################################# - - def set_selected(self, value): - self.__selected = int(value) - - def get_selected(self): - return bool(self.__selected) - - selected = property(get_selected, set_selected) - - ################################################################# - - def set_sheet_visible(self, value): - self.__sheet_visible = int(value) - - def get_sheet_visible(self): - return bool(self.__sheet_visible) - - sheet_visible = property(get_sheet_visible, set_sheet_visible) - - ################################################################# - - def set_page_preview(self, value): - self.__page_preview = int(value) - - def get_page_preview(self): - return bool(self.__page_preview) - - page_preview = property(get_page_preview, set_page_preview) - - ################################################################# - - def set_first_visible_row(self, value): - self.__first_visible_row = value - - def get_first_visible_row(self): - return self.__first_visible_row - - first_visible_row = property(get_first_visible_row, set_first_visible_row) - - ################################################################# - - def set_first_visible_col(self, value): - self.__first_visible_col = value - - def get_first_visible_col(self): - return self.__first_visible_col - - first_visible_col = property(get_first_visible_col, set_first_visible_col) - - ################################################################# - - def set_grid_colour(self, value): - self.__grid_colour = value - - def get_grid_colour(self): - return self.__grid_colour - - grid_colour = property(get_grid_colour, set_grid_colour) - - ################################################################# - - def set_preview_magn(self, value): - self.__preview_magn = value - - def get_preview_magn(self): - return self.__preview_magn - - preview_magn = property(get_preview_magn, set_preview_magn) - - ################################################################# - - def set_normal_magn(self, value): - self.__normal_magn = value - - def get_normal_magn(self): - return self.__normal_magn - - normal_magn = property(get_normal_magn, set_normal_magn) - - ################################################################# - - def set_vert_split_pos(self, value): - self.__vert_split_pos = abs(value) - - def get_vert_split_pos(self): - return self.__vert_split_pos - - vert_split_pos = property(get_vert_split_pos, set_vert_split_pos) - - ################################################################# - - def set_horz_split_pos(self, value): - self.__horz_split_pos = abs(value) - - def get_horz_split_pos(self): - return self.__horz_split_pos - - horz_split_pos = property(get_horz_split_pos, set_horz_split_pos) - - ################################################################# - - def set_vert_split_first_visible(self, value): - self.__vert_split_first_visible = abs(value) - - def get_vert_split_first_visible(self): - return self.__vert_split_first_visible - - vert_split_first_visible = property(get_vert_split_first_visible, set_vert_split_first_visible) - - ################################################################# - - def set_horz_split_first_visible(self, value): - self.__horz_split_first_visible = abs(value) - - def get_horz_split_first_visible(self): - return self.__horz_split_first_visible - - horz_split_first_visible = property(get_horz_split_first_visible, set_horz_split_first_visible) - - ################################################################# - - #def set_split_active_pane(self, value): - # self.__split_active_pane = abs(value) & 0x03 - # - #def get_split_active_pane(self): - # return self.__split_active_pane - # - #split_active_pane = property(get_split_active_pane, set_split_active_pane) - - ################################################################# - - #def set_row_gut_width(self, value): - # self.__row_gut_width = value - # - #def get_row_gut_width(self): - # return self.__row_gut_width - # - #row_gut_width = property(get_row_gut_width, set_row_gut_width) - # - ################################################################# - # - #def set_col_gut_height(self, value): - # self.__col_gut_height = value - # - #def get_col_gut_height(self): - # return self.__col_gut_height - # - #col_gut_height = property(get_col_gut_height, set_col_gut_height) - # - ################################################################# - - def set_show_auto_page_breaks(self, value): - self.__show_auto_page_breaks = int(value) - - def get_show_auto_page_breaks(self): - return bool(self.__show_auto_page_breaks) - - show_auto_page_breaks = property(get_show_auto_page_breaks, set_show_auto_page_breaks) - - ################################################################# - - def set_dialogue_sheet(self, value): - self.__dialogue_sheet = int(value) - - def get_dialogue_sheet(self): - return bool(self.__dialogue_sheet) - - dialogue_sheet = property(get_dialogue_sheet, set_dialogue_sheet) - - ################################################################# - - def set_auto_style_outline(self, value): - self.__auto_style_outline = int(value) - - def get_auto_style_outline(self): - return bool(self.__auto_style_outline) - - auto_style_outline = property(get_auto_style_outline, set_auto_style_outline) - - ################################################################# - - def set_outline_below(self, value): - self.__outline_below = int(value) - - def get_outline_below(self): - return bool(self.__outline_below) - - outline_below = property(get_outline_below, set_outline_below) - - ################################################################# - - def set_outline_right(self, value): - self.__outline_right = int(value) - - def get_outline_right(self): - return bool(self.__outline_right) - - outline_right = property(get_outline_right, set_outline_right) - - ################################################################# - - def set_fit_num_pages(self, value): - self.__fit_num_pages = value - - def get_fit_num_pages(self): - return self.__fit_num_pages - - fit_num_pages = property(get_fit_num_pages, set_fit_num_pages) - - ################################################################# - - def set_show_row_outline(self, value): - self.__show_row_outline = int(value) - - def get_show_row_outline(self): - return bool(self.__show_row_outline) - - show_row_outline = property(get_show_row_outline, set_show_row_outline) - - ################################################################# - - def set_show_col_outline(self, value): - self.__show_col_outline = int(value) - - def get_show_col_outline(self): - return bool(self.__show_col_outline) - - show_col_outline = property(get_show_col_outline, set_show_col_outline) - - ################################################################# - - def set_alt_expr_eval(self, value): - self.__alt_expr_eval = int(value) - - def get_alt_expr_eval(self): - return bool(self.__alt_expr_eval) - - alt_expr_eval = property(get_alt_expr_eval, set_alt_expr_eval) - - ################################################################# - - def set_alt_formula_entries(self, value): - self.__alt_formula_entries = int(value) - - def get_alt_formula_entries(self): - return bool(self.__alt_formula_entries) - - alt_formula_entries = property(get_alt_formula_entries, set_alt_formula_entries) - - ################################################################# - - def set_row_default_height(self, value): - self.__row_default_height = value - - def get_row_default_height(self): - return self.__row_default_height - - row_default_height = property(get_row_default_height, set_row_default_height) - - ################################################################# - - def set_col_default_width(self, value): - self.__col_default_width = value - - def get_col_default_width(self): - return self.__col_default_width - - col_default_width = property(get_col_default_width, set_col_default_width) - - ################################################################# - - def set_calc_mode(self, value): - self.__calc_mode = value & 0x03 - - def get_calc_mode(self): - return self.__calc_mode - - calc_mode = property(get_calc_mode, set_calc_mode) - - ################################################################# - - def set_calc_count(self, value): - self.__calc_count = value - - def get_calc_count(self): - return self.__calc_count - - calc_count = property(get_calc_count, set_calc_count) - - ################################################################# - - def set_RC_ref_mode(self, value): - self.__RC_ref_mode = int(value) - - def get_RC_ref_mode(self): - return bool(self.__RC_ref_mode) - - RC_ref_mode = property(get_RC_ref_mode, set_RC_ref_mode) - - ################################################################# - - def set_iterations_on(self, value): - self.__iterations_on = int(value) - - def get_iterations_on(self): - return bool(self.__iterations_on) - - iterations_on = property(get_iterations_on, set_iterations_on) - - ################################################################# - - def set_delta(self, value): - self.__delta = value - - def get_delta(self): - return self.__delta - - delta = property(get_delta, set_delta) - - ################################################################# - - def set_save_recalc(self, value): - self.__save_recalc = int(value) - - def get_save_recalc(self): - return bool(self.__save_recalc) - - save_recalc = property(get_save_recalc, set_save_recalc) - - ################################################################# - - def set_print_headers(self, value): - self.__print_headers = int(value) - - def get_print_headers(self): - return bool(self.__print_headers) - - print_headers = property(get_print_headers, set_print_headers) - - ################################################################# - - def set_print_grid(self, value): - self.__print_grid = int(value) - - def get_print_grid(self): - return bool(self.__print_grid) - - print_grid = property(get_print_grid, set_print_grid) - - ################################################################# - # - #def set_grid_set(self, value): - # self.__grid_set = int(value) - # - #def get_grid_set(self): - # return bool(self.__grid_set) - # - #grid_set = property(get_grid_set, set_grid_set) - # - ################################################################# - - def set_vert_page_breaks(self, value): - self.__vert_page_breaks = value - - def get_vert_page_breaks(self): - return self.__vert_page_breaks - - vert_page_breaks = property(get_vert_page_breaks, set_vert_page_breaks) - - ################################################################# - - def set_horz_page_breaks(self, value): - self.__horz_page_breaks = value - - def get_horz_page_breaks(self): - return self.__horz_page_breaks - - horz_page_breaks = property(get_horz_page_breaks, set_horz_page_breaks) - - ################################################################# - - def set_header_str(self, value): - if isinstance(value, str): - value = unicode(value, self.__parent.encoding) - self.__header_str = value - - def get_header_str(self): - return self.__header_str - - header_str = property(get_header_str, set_header_str) - - ################################################################# - - def set_footer_str(self, value): - if isinstance(value, str): - value = unicode(value, self.__parent.encoding) - self.__footer_str = value - - def get_footer_str(self): - return self.__footer_str - - footer_str = property(get_footer_str, set_footer_str) - - ################################################################# - - def set_print_centered_vert(self, value): - self.__print_centered_vert = int(value) - - def get_print_centered_vert(self): - return bool(self.__print_centered_vert) - - print_centered_vert = property(get_print_centered_vert, set_print_centered_vert) - - ################################################################# - - def set_print_centered_horz(self, value): - self.__print_centered_horz = int(value) - - def get_print_centered_horz(self): - return bool(self.__print_centered_horz) - - print_centered_horz = property(get_print_centered_horz, set_print_centered_horz) - - ################################################################# - - def set_left_margin(self, value): - self.__left_margin = value - - def get_left_margin(self): - return self.__left_margin - - left_margin = property(get_left_margin, set_left_margin) - - ################################################################# - - def set_right_margin(self, value): - self.__right_margin = value - - def get_right_margin(self): - return self.__right_margin - - right_margin = property(get_right_margin, set_right_margin) - - ################################################################# - - def set_top_margin(self, value): - self.__top_margin = value - - def get_top_margin(self): - return self.__top_margin - - top_margin = property(get_top_margin, set_top_margin) - - ################################################################# - - def set_bottom_margin(self, value): - self.__bottom_margin = value - - def get_bottom_margin(self): - return self.__bottom_margin - - bottom_margin = property(get_bottom_margin, set_bottom_margin) - - ################################################################# - - def set_paper_size_code(self, value): - self.__paper_size_code = value - - def get_paper_size_code(self): - return self.__paper_size_code - - paper_size_code = property(get_paper_size_code, set_paper_size_code) - - ################################################################# - - def set_print_scaling(self, value): - self.__print_scaling = value - - def get_print_scaling(self): - return self.__print_scaling - - print_scaling = property(get_print_scaling, set_print_scaling) - - ################################################################# - - def set_start_page_number(self, value): - self.__start_page_number = value - - def get_start_page_number(self): - return self.__start_page_number - - start_page_number = property(get_start_page_number, set_start_page_number) - - ################################################################# - - def set_fit_width_to_pages(self, value): - self.__fit_width_to_pages = value - - def get_fit_width_to_pages(self): - return self.__fit_width_to_pages - - fit_width_to_pages = property(get_fit_width_to_pages, set_fit_width_to_pages) - - ################################################################# - - def set_fit_height_to_pages(self, value): - self.__fit_height_to_pages = value - - def get_fit_height_to_pages(self): - return self.__fit_height_to_pages - - fit_height_to_pages = property(get_fit_height_to_pages, set_fit_height_to_pages) - - ################################################################# - - def set_print_in_rows(self, value): - self.__print_in_rows = int(value) - - def get_print_in_rows(self): - return bool(self.__print_in_rows) - - print_in_rows = property(get_print_in_rows, set_print_in_rows) - - ################################################################# - - def set_portrait(self, value): - self.__portrait = int(value) - - def get_portrait(self): - return bool(self.__portrait) - - portrait = property(get_portrait, set_portrait) - - ################################################################# - - def set_print_colour(self, value): - self.__print_not_colour = int(not value) - - def get_print_colour(self): - return not bool(self.__print_not_colour) - - print_colour = property(get_print_colour, set_print_colour) - - ################################################################# - - def set_print_draft(self, value): - self.__print_draft = int(value) - - def get_print_draft(self): - return bool(self.__print_draft) - - print_draft = property(get_print_draft, set_print_draft) - - ################################################################# - - def set_print_notes(self, value): - self.__print_notes = int(value) - - def get_print_notes(self): - return bool(self.__print_notes) - - print_notes = property(get_print_notes, set_print_notes) - - ################################################################# - - def set_print_notes_at_end(self, value): - self.__print_notes_at_end = int(value) - - def get_print_notes_at_end(self): - return bool(self.__print_notes_at_end) - - print_notes_at_end = property(get_print_notes_at_end, set_print_notes_at_end) - - ################################################################# - - def set_print_omit_errors(self, value): - self.__print_omit_errors = int(value) - - def get_print_omit_errors(self): - return bool(self.__print_omit_errors) - - print_omit_errors = property(get_print_omit_errors, set_print_omit_errors) - - ################################################################# - - def set_print_hres(self, value): - self.__print_hres = value - - def get_print_hres(self): - return self.__print_hres - - print_hres = property(get_print_hres, set_print_hres) - - ################################################################# - - def set_print_vres(self, value): - self.__print_vres = value - - def get_print_vres(self): - return self.__print_vres - - print_vres = property(get_print_vres, set_print_vres) - - ################################################################# - - def set_header_margin(self, value): - self.__header_margin = value - - def get_header_margin(self): - return self.__header_margin - - header_margin = property(get_header_margin, set_header_margin) - - ################################################################# - - def set_footer_margin(self, value): - self.__footer_margin = value - - def get_footer_margin(self): - return self.__footer_margin - - footer_margin = property(get_footer_margin, set_footer_margin) - - ################################################################# - - def set_copies_num(self, value): - self.__copies_num = value - - def get_copies_num(self): - return self.__copies_num - - copies_num = property(get_copies_num, set_copies_num) - - ################################################################## - - def set_wnd_protect(self, value): - self.__wnd_protect = int(value) - - def get_wnd_protect(self): - return bool(self.__wnd_protect) - - wnd_protect = property(get_wnd_protect, set_wnd_protect) - - ################################################################# - - def set_obj_protect(self, value): - self.__obj_protect = int(value) - - def get_obj_protect(self): - return bool(self.__obj_protect) - - obj_protect = property(get_obj_protect, set_obj_protect) - - ################################################################# - - def set_protect(self, value): - self.__protect = int(value) - - def get_protect(self): - return bool(self.__protect) - - protect = property(get_protect, set_protect) - - ################################################################# - - def set_scen_protect(self, value): - self.__scen_protect = int(value) - - def get_scen_protect(self): - return bool(self.__scen_protect) - - scen_protect = property(get_scen_protect, set_scen_protect) - - ################################################################# - - def set_password(self, value): - self.__password = value - - def get_password(self): - return self.__password - - password = property(get_password, set_password) - - ################################################################## - ## Methods - ################################################################## - - def get_parent(self): - return self.__parent - - def write(self, r, c, label="", style=Style.default_style): - self.row(r).write(c, label, style) - - def merge(self, r1, r2, c1, c2, style=Style.default_style): - # Stand-alone merge of previously written cells. - # Problems: (1) style to be used should be existing style of - # the top-left cell, not an arg. - # (2) should ensure that any previous data value in - # non-top-left cells is nobbled. - # Note: if a cell is set by a data record then later - # is referenced by a [MUL]BLANK record, Excel will blank - # out the cell on the screen, but OOo & Gnu will not - # blank it out. Need to do something better than writing - # multiple records. In the meantime, avoid this method and use - # write_merge() instead. - if c2 > c1: - self.row(r1).write_blanks(c1 + 1, c2, style) - for r in range(r1+1, r2+1): - self.row(r).write_blanks(c1, c2, style) - self.__merged_ranges.append((r1, r2, c1, c2)) - - def write_merge(self, r1, r2, c1, c2, label="", style=Style.default_style): - assert 0 <= c1 <= c2 <= 255 - assert 0 <= r1 <= r2 <= 65535 - self.write(r1, c1, label, style) - if c2 > c1: - self.row(r1).write_blanks(c1 + 1, c2, style) # skip (r1, c1) - for r in range(r1+1, r2+1): - self.row(r).write_blanks(c1, c2, style) - self.__merged_ranges.append((r1, r2, c1, c2)) - - def insert_bitmap(self, filename, row, col, x = 0, y = 0, scale_x = 1, scale_y = 1): - bmp = Bitmap.ImDataBmpRecord(filename) - obj = Bitmap.ObjBmpRecord(row, col, self, bmp, x, y, scale_x, scale_y) - - self.__bmp_rec += obj.get() + bmp.get() - - def col(self, indx): - if indx not in self.__cols: - self.__cols[indx] = self.Column(indx, self) - return self.__cols[indx] - - def row(self, indx): - if indx not in self.__rows: - if indx in self.__flushed_rows: - raise Exception("Attempt to reuse row index %d of sheet %r after flushing" % (indx, self.__name)) - self.__rows[indx] = self.Row(indx, self) - if indx > self.last_used_row: - self.last_used_row = indx - if indx < self.first_used_row: - self.first_used_row = indx - return self.__rows[indx] - - def row_height(self, row): # in pixels - if row in self.__rows: - return self.__rows[row].get_height_in_pixels() - else: - return 17 - - def col_width(self, col): # in pixels - if col in self.__cols: - return self.__cols[col].width_in_pixels() - else: - return 64 - - - ################################################################## - ## BIFF records generation - ################################################################## - - def __bof_rec(self): - return BIFFRecords.Biff8BOFRecord(BIFFRecords.Biff8BOFRecord.WORKSHEET).get() - - def __update_row_visible_levels(self): - if self.__rows: - temp = max([self.__rows[r].level for r in self.__rows]) + 1 - self.__row_visible_levels = max(temp, self.__row_visible_levels) - - def __guts_rec(self): - self.__update_row_visible_levels() - col_visible_levels = 0 - if len(self.__cols) != 0: - col_visible_levels = max([self.__cols[c].level for c in self.__cols]) + 1 - return BIFFRecords.GutsRecord( - self.__row_gut_width, self.__col_gut_height, self.__row_visible_levels, col_visible_levels).get() - - def __defaultrowheight_rec(self): - options = 0x0000 - options |= (self.row_default_height_mismatch & 1) << 0 - options |= (self.row_default_hidden & 1) << 1 - options |= (self.row_default_space_above & 1) << 2 - options |= (self.row_default_space_below & 1) << 3 - defht = self.__row_default_height - return BIFFRecords.DefaultRowHeightRecord(options, defht).get() - - def __wsbool_rec(self): - options = 0x00 - options |= (self.__show_auto_page_breaks & 0x01) << 0 - options |= (self.__dialogue_sheet & 0x01) << 4 - options |= (self.__auto_style_outline & 0x01) << 5 - options |= (self.__outline_below & 0x01) << 6 - options |= (self.__outline_right & 0x01) << 7 - options |= (self.__fit_num_pages & 0x01) << 8 - options |= (self.__show_row_outline & 0x01) << 10 - options |= (self.__show_col_outline & 0x01) << 11 - options |= (self.__alt_expr_eval & 0x01) << 14 - options |= (self.__alt_formula_entries & 0x01) << 15 - - return BIFFRecords.WSBoolRecord(options).get() - - def __eof_rec(self): - return BIFFRecords.EOFRecord().get() - - def __colinfo_rec(self): - result = '' - for col in self.__cols: - result += self.__cols[col].get_biff_record() - return result - - def __dimensions_rec(self): - return BIFFRecords.DimensionsRecord( - self.first_used_row, self.last_used_row, - self.first_used_col, self.last_used_col - ).get() - - def __window2_rec(self): - # Appends SCL record. - options = 0 - options |= (self.__show_formulas & 0x01) << 0 - options |= (self.__show_grid & 0x01) << 1 - options |= (self.__show_headers & 0x01) << 2 - options |= (self.__panes_frozen & 0x01) << 3 - options |= (self.show_zero_values & 0x01) << 4 - options |= (self.__auto_colour_grid & 0x01) << 5 - options |= (self.__cols_right_to_left & 0x01) << 6 - options |= (self.__show_outline & 0x01) << 7 - options |= (self.__remove_splits & 0x01) << 8 - options |= (self.__selected & 0x01) << 9 - options |= (self.__sheet_visible & 0x01) << 10 - options |= (self.__page_preview & 0x01) << 11 - if self.__page_preview: - scl_magn = self.__preview_magn - else: - scl_magn = self.__normal_magn - return BIFFRecords.Window2Record( - options, self.__first_visible_row, self.__first_visible_col, - self.__grid_colour, - self.__preview_magn, self.__normal_magn, scl_magn).get() - - def __panes_rec(self): - if self.__vert_split_pos is None and self.__horz_split_pos is None: - return "" - - if self.__vert_split_pos is None: - self.__vert_split_pos = 0 - if self.__horz_split_pos is None: - self.__horz_split_pos = 0 - - if self.__panes_frozen: - if self.__vert_split_first_visible is None: - self.__vert_split_first_visible = self.__vert_split_pos - if self.__horz_split_first_visible is None: - self.__horz_split_first_visible = self.__horz_split_pos - else: - if self.__vert_split_first_visible is None: - self.__vert_split_first_visible = 0 - if self.__horz_split_first_visible is None: - self.__horz_split_first_visible = 0 - # inspired by pyXLWriter - self.__horz_split_pos = 20*self.__horz_split_pos + 255 - self.__vert_split_pos = 113.879*self.__vert_split_pos + 390 - - if self.__vert_split_pos > 0 and self.__horz_split_pos > 0: - self.__split_active_pane = 0 - elif self.__vert_split_pos > 0 and self.__horz_split_pos == 0: - self.__split_active_pane = 1 - elif self.__vert_split_pos == 0 and self.__horz_split_pos > 0: - self.__split_active_pane = 2 - else: - self.__split_active_pane = 3 - - result = BIFFRecords.PanesRecord(self.__vert_split_pos, - self.__horz_split_pos, - self.__horz_split_first_visible, - self.__vert_split_first_visible, - self.__split_active_pane).get() - return result - - def __row_blocks_rec(self): - result = [] - for row in self.__rows.itervalues(): - result.append(row.get_row_biff_data()) - result.append(row.get_cells_biff_data()) - return ''.join(result) - - def __merged_rec(self): - return BIFFRecords.MergedCellsRecord(self.__merged_ranges).get() - - def __bitmaps_rec(self): - return self.__bmp_rec - - def __calc_settings_rec(self): - result = '' - result += BIFFRecords.CalcModeRecord(self.__calc_mode & 0x01).get() - result += BIFFRecords.CalcCountRecord(self.__calc_count & 0xFFFF).get() - result += BIFFRecords.RefModeRecord(self.__RC_ref_mode & 0x01).get() - result += BIFFRecords.IterationRecord(self.__iterations_on & 0x01).get() - result += BIFFRecords.DeltaRecord(self.__delta).get() - result += BIFFRecords.SaveRecalcRecord(self.__save_recalc & 0x01).get() - return result - - def __print_settings_rec(self): - result = '' - result += BIFFRecords.PrintHeadersRecord(self.__print_headers).get() - result += BIFFRecords.PrintGridLinesRecord(self.__print_grid).get() - result += BIFFRecords.GridSetRecord(self.__grid_set).get() - result += BIFFRecords.HorizontalPageBreaksRecord(self.__horz_page_breaks).get() - result += BIFFRecords.VerticalPageBreaksRecord(self.__vert_page_breaks).get() - result += BIFFRecords.HeaderRecord(self.__header_str).get() - result += BIFFRecords.FooterRecord(self.__footer_str).get() - result += BIFFRecords.HCenterRecord(self.__print_centered_horz).get() - result += BIFFRecords.VCenterRecord(self.__print_centered_vert).get() - result += BIFFRecords.LeftMarginRecord(self.__left_margin).get() - result += BIFFRecords.RightMarginRecord(self.__right_margin).get() - result += BIFFRecords.TopMarginRecord(self.__top_margin).get() - result += BIFFRecords.BottomMarginRecord(self.__bottom_margin).get() - - setup_page_options = (self.__print_in_rows & 0x01) << 0 - setup_page_options |= (self.__portrait & 0x01) << 1 - setup_page_options |= (0x00 & 0x01) << 2 - setup_page_options |= (self.__print_not_colour & 0x01) << 3 - setup_page_options |= (self.__print_draft & 0x01) << 4 - setup_page_options |= (self.__print_notes & 0x01) << 5 - setup_page_options |= (0x00 & 0x01) << 6 - setup_page_options |= (0x01 & 0x01) << 7 - setup_page_options |= (self.__print_notes_at_end & 0x01) << 9 - setup_page_options |= (self.__print_omit_errors & 0x03) << 10 - - result += BIFFRecords.SetupPageRecord(self.__paper_size_code, - self.__print_scaling, - self.__start_page_number, - self.__fit_width_to_pages, - self.__fit_height_to_pages, - setup_page_options, - self.__print_hres, - self.__print_vres, - self.__header_margin, - self.__footer_margin, - self.__copies_num).get() - return result - - def __protection_rec(self): - result = '' - result += BIFFRecords.ProtectRecord(self.__protect).get() - result += BIFFRecords.ScenProtectRecord(self.__scen_protect).get() - result += BIFFRecords.WindowProtectRecord(self.__wnd_protect).get() - result += BIFFRecords.ObjectProtectRecord(self.__obj_protect).get() - result += BIFFRecords.PasswordRecord(self.__password).get() - return result - - def get_biff_data(self): - result = [ - self.__bof_rec(), - self.__calc_settings_rec(), - self.__guts_rec(), - self.__defaultrowheight_rec(), - self.__wsbool_rec(), - self.__colinfo_rec(), - self.__dimensions_rec(), - self.__print_settings_rec(), - self.__protection_rec(), - ] - if self.row_tempfile: - self.row_tempfile.flush() - self.row_tempfile.seek(0) - result.append(self.row_tempfile.read()) - result.extend([ - self.__row_blocks_rec(), - self.__merged_rec(), - self.__bitmaps_rec(), - self.__window2_rec(), - self.__panes_rec(), - self.__eof_rec(), - ]) - return ''.join(result) - - def flush_row_data(self): - if self.row_tempfile is None: - self.row_tempfile = tempfile.TemporaryFile() - self.row_tempfile.write(self.__row_blocks_rec()) - for rowx in self.__rows: - self.__flushed_rows[rowx] = 1 - self.__update_row_visible_levels() - self.__rows = {} - - diff --git a/tablib/packages/xlwt/__init__.py b/tablib/packages/xlwt/__init__.py deleted file mode 100644 index cb65687..0000000 --- a/tablib/packages/xlwt/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: windows-1252 -*- - -__VERSION__ = '0.7.2' - -import sys - -from Workbook import Workbook -from Worksheet import Worksheet -from Row import Row -from Column import Column -from Formatting import Font, Alignment, Borders, Pattern, Protection -from Style import XFStyle, easyxf -from ExcelFormula import * diff --git a/tablib/packages/xlwt/antlr.py b/tablib/packages/xlwt/antlr.py deleted file mode 100644 index aaad447..0000000 --- a/tablib/packages/xlwt/antlr.py +++ /dev/null @@ -1,2874 +0,0 @@ -## This file is part of PyANTLR. See LICENSE.txt for license -## details..........Copyright (C) Wolfgang Haefelinger, 2004. - -## This file was copied for use with xlwt from the 2.7.7 ANTLR distribution. Yes, it -## says 2.7.5 below. The 2.7.5 distribution version didn't have a -## version in it. - -## Here is the contents of the ANTLR 2.7.7 LICENSE.txt referred to above. - -# SOFTWARE RIGHTS -# -# ANTLR 1989-2006 Developed by Terence Parr -# Partially supported by University of San Francisco & jGuru.com -# -# We reserve no legal rights to the ANTLR--it is fully in the -# public domain. An individual or company may do whatever -# they wish with source code distributed with ANTLR or the -# code generated by ANTLR, including the incorporation of -# ANTLR, or its output, into commerical software. -# -# We encourage users to develop software with ANTLR. However, -# we do ask that credit is given to us for developing -# ANTLR. By "credit", we mean that if you use ANTLR or -# incorporate any source code into one of your programs -# (commercial product, research project, or otherwise) that -# you acknowledge this fact somewhere in the documentation, -# research report, etc... If you like ANTLR and have -# developed a nice tool with the output, please mention that -# you developed it using ANTLR. In addition, we ask that the -# headers remain intact in our source code. As long as these -# guidelines are kept, we expect to continue enhancing this -# system and expect to make other tools available as they are -# completed. -# -# The primary ANTLR guy: -# -# Terence Parr -# parrt@cs.usfca.edu -# parrt@antlr.org - -## End of contents of the ANTLR 2.7.7 LICENSE.txt ######################## - -## get sys module -import sys - -version = sys.version.split()[0] -if version < '2.2.1': - False = 0 -if version < '2.3': - True = not False - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### global symbols ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -### ANTLR Standard Tokens -SKIP = -1 -INVALID_TYPE = 0 -EOF_TYPE = 1 -EOF = 1 -NULL_TREE_LOOKAHEAD = 3 -MIN_USER_TYPE = 4 - -### ANTLR's EOF Symbol -EOF_CHAR = '' - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### general functions ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -## Version should be automatically derived from configure.in. For now, -## we need to bump it ourselfs. Don't remove the <version> tags. -## <version> -def version(): - r = { - 'major' : '2', - 'minor' : '7', - 'micro' : '5', - 'patch' : '' , - 'version': '2.7.5' - } - return r -## </version> - -def error(fmt,*args): - if fmt: - print "error: ", fmt % tuple(args) - -def ifelse(cond,_then,_else): - if cond : - r = _then - else: - r = _else - return r - -def is_string_type(x): - # return (isinstance(x,str) or isinstance(x,unicode)) - # Simplify; xlwt doesn't support Python < 2.3 - return isinstance(basestring) - -def assert_string_type(x): - assert is_string_type(x) - pass - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### ANTLR Exceptions ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class ANTLRException(Exception): - - def __init__(self, *args): - Exception.__init__(self, *args) - - -class RecognitionException(ANTLRException): - - def __init__(self, *args): - ANTLRException.__init__(self, *args) - self.fileName = None - self.line = -1 - self.column = -1 - if len(args) >= 2: - self.fileName = args[1] - if len(args) >= 3: - self.line = args[2] - if len(args) >= 4: - self.column = args[3] - - def __str__(self): - buf = [''] - if self.fileName: - buf.append(self.fileName + ":") - if self.line != -1: - if not self.fileName: - buf.append("line ") - buf.append(str(self.line)) - if self.column != -1: - buf.append(":" + str(self.column)) - buf.append(":") - buf.append(" ") - return str('').join(buf) - - __repr__ = __str__ - - -class NoViableAltException(RecognitionException): - - def __init__(self, *args): - RecognitionException.__init__(self, *args) - self.token = None - self.node = None - if isinstance(args[0],AST): - self.node = args[0] - elif isinstance(args[0],Token): - self.token = args[0] - else: - raise TypeError("NoViableAltException requires Token or AST argument") - - def __str__(self): - if self.token: - line = self.token.getLine() - col = self.token.getColumn() - text = self.token.getText() - return "unexpected symbol at line %s (column %s): \"%s\"" % (line,col,text) - if self.node == ASTNULL: - return "unexpected end of subtree" - assert self.node - ### hackish, we assume that an AST contains method getText - return "unexpected node: %s" % (self.node.getText()) - - __repr__ = __str__ - - -class NoViableAltForCharException(RecognitionException): - - def __init__(self, *args): - self.foundChar = None - if len(args) == 2: - self.foundChar = args[0] - scanner = args[1] - RecognitionException.__init__(self, "NoViableAlt", - scanner.getFilename(), - scanner.getLine(), - scanner.getColumn()) - elif len(args) == 4: - self.foundChar = args[0] - fileName = args[1] - line = args[2] - column = args[3] - RecognitionException.__init__(self, "NoViableAlt", - fileName, line, column) - else: - RecognitionException.__init__(self, "NoViableAlt", - '', -1, -1) - - def __str__(self): - mesg = "unexpected char: " - if self.foundChar >= ' ' and self.foundChar <= '~': - mesg += "'" + self.foundChar + "'" - elif self.foundChar: - mesg += "0x" + hex(ord(self.foundChar)).upper()[2:] - else: - mesg += "<None>" - return mesg - - __repr__ = __str__ - - -class SemanticException(RecognitionException): - - def __init__(self, *args): - RecognitionException.__init__(self, *args) - - -class MismatchedCharException(RecognitionException): - - NONE = 0 - CHAR = 1 - NOT_CHAR = 2 - RANGE = 3 - NOT_RANGE = 4 - SET = 5 - NOT_SET = 6 - - def __init__(self, *args): - self.args = args - if len(args) == 5: - # Expected range / not range - if args[3]: - self.mismatchType = MismatchedCharException.NOT_RANGE - else: - self.mismatchType = MismatchedCharException.RANGE - self.foundChar = args[0] - self.expecting = args[1] - self.upper = args[2] - self.scanner = args[4] - RecognitionException.__init__(self, "Mismatched char range", - self.scanner.getFilename(), - self.scanner.getLine(), - self.scanner.getColumn()) - elif len(args) == 4 and is_string_type(args[1]): - # Expected char / not char - if args[2]: - self.mismatchType = MismatchedCharException.NOT_CHAR - else: - self.mismatchType = MismatchedCharException.CHAR - self.foundChar = args[0] - self.expecting = args[1] - self.scanner = args[3] - RecognitionException.__init__(self, "Mismatched char", - self.scanner.getFilename(), - self.scanner.getLine(), - self.scanner.getColumn()) - elif len(args) == 4 and isinstance(args[1], BitSet): - # Expected BitSet / not BitSet - if args[2]: - self.mismatchType = MismatchedCharException.NOT_SET - else: - self.mismatchType = MismatchedCharException.SET - self.foundChar = args[0] - self.set = args[1] - self.scanner = args[3] - RecognitionException.__init__(self, "Mismatched char set", - self.scanner.getFilename(), - self.scanner.getLine(), - self.scanner.getColumn()) - else: - self.mismatchType = MismatchedCharException.NONE - RecognitionException.__init__(self, "Mismatched char") - - ## Append a char to the msg buffer. If special, - # then show escaped version - # - def appendCharName(self, sb, c): - if not c or c == 65535: - # 65535 = (char) -1 = EOF - sb.append("'<EOF>'") - elif c == '\n': - sb.append("'\\n'") - elif c == '\r': - sb.append("'\\r'"); - elif c == '\t': - sb.append("'\\t'") - else: - sb.append('\'' + c + '\'') - - ## - # Returns an error message with line number/column information - # - def __str__(self): - sb = [''] - sb.append(RecognitionException.__str__(self)) - - if self.mismatchType == MismatchedCharException.CHAR: - sb.append("expecting ") - self.appendCharName(sb, self.expecting) - sb.append(", found ") - self.appendCharName(sb, self.foundChar) - elif self.mismatchType == MismatchedCharException.NOT_CHAR: - sb.append("expecting anything but '") - self.appendCharName(sb, self.expecting) - sb.append("'; got it anyway") - elif self.mismatchType in [MismatchedCharException.RANGE, MismatchedCharException.NOT_RANGE]: - sb.append("expecting char ") - if self.mismatchType == MismatchedCharException.NOT_RANGE: - sb.append("NOT ") - sb.append("in range: ") - appendCharName(sb, self.expecting) - sb.append("..") - appendCharName(sb, self.upper) - sb.append(", found ") - appendCharName(sb, self.foundChar) - elif self.mismatchType in [MismatchedCharException.SET, MismatchedCharException.NOT_SET]: - sb.append("expecting ") - if self.mismatchType == MismatchedCharException.NOT_SET: - sb.append("NOT ") - sb.append("one of (") - for i in range(len(self.set)): - self.appendCharName(sb, self.set[i]) - sb.append("), found ") - self.appendCharName(sb, self.foundChar) - - return str().join(sb).strip() - - __repr__ = __str__ - - -class MismatchedTokenException(RecognitionException): - - NONE = 0 - TOKEN = 1 - NOT_TOKEN = 2 - RANGE = 3 - NOT_RANGE = 4 - SET = 5 - NOT_SET = 6 - - def __init__(self, *args): - self.args = args - self.tokenNames = [] - self.token = None - self.tokenText = '' - self.node = None - if len(args) == 6: - # Expected range / not range - if args[3]: - self.mismatchType = MismatchedTokenException.NOT_RANGE - else: - self.mismatchType = MismatchedTokenException.RANGE - self.tokenNames = args[0] - self.expecting = args[2] - self.upper = args[3] - self.fileName = args[5] - - elif len(args) == 4 and isinstance(args[2], int): - # Expected token / not token - if args[3]: - self.mismatchType = MismatchedTokenException.NOT_TOKEN - else: - self.mismatchType = MismatchedTokenException.TOKEN - self.tokenNames = args[0] - self.expecting = args[2] - - elif len(args) == 4 and isinstance(args[2], BitSet): - # Expected BitSet / not BitSet - if args[3]: - self.mismatchType = MismatchedTokenException.NOT_SET - else: - self.mismatchType = MismatchedTokenException.SET - self.tokenNames = args[0] - self.set = args[2] - - else: - self.mismatchType = MismatchedTokenException.NONE - RecognitionException.__init__(self, "Mismatched Token: expecting any AST node", "<AST>", -1, -1) - - if len(args) >= 2: - if isinstance(args[1],Token): - self.token = args[1] - self.tokenText = self.token.getText() - RecognitionException.__init__(self, "Mismatched Token", - self.fileName, - self.token.getLine(), - self.token.getColumn()) - elif isinstance(args[1],AST): - self.node = args[1] - self.tokenText = str(self.node) - RecognitionException.__init__(self, "Mismatched Token", - "<AST>", - self.node.getLine(), - self.node.getColumn()) - else: - self.tokenText = "<empty tree>" - RecognitionException.__init__(self, "Mismatched Token", - "<AST>", -1, -1) - - def appendTokenName(self, sb, tokenType): - if tokenType == INVALID_TYPE: - sb.append("<Set of tokens>") - elif tokenType < 0 or tokenType >= len(self.tokenNames): - sb.append("<" + str(tokenType) + ">") - else: - sb.append(self.tokenNames[tokenType]) - - ## - # Returns an error message with line number/column information - # - def __str__(self): - sb = [''] - sb.append(RecognitionException.__str__(self)) - - if self.mismatchType == MismatchedTokenException.TOKEN: - sb.append("expecting ") - self.appendTokenName(sb, self.expecting) - sb.append(", found " + self.tokenText) - elif self.mismatchType == MismatchedTokenException.NOT_TOKEN: - sb.append("expecting anything but '") - self.appendTokenName(sb, self.expecting) - sb.append("'; got it anyway") - elif self.mismatchType in [MismatchedTokenException.RANGE, MismatchedTokenException.NOT_RANGE]: - sb.append("expecting token ") - if self.mismatchType == MismatchedTokenException.NOT_RANGE: - sb.append("NOT ") - sb.append("in range: ") - appendTokenName(sb, self.expecting) - sb.append("..") - appendTokenName(sb, self.upper) - sb.append(", found " + self.tokenText) - elif self.mismatchType in [MismatchedTokenException.SET, MismatchedTokenException.NOT_SET]: - sb.append("expecting ") - if self.mismatchType == MismatchedTokenException.NOT_SET: - sb.append("NOT ") - sb.append("one of (") - for i in range(len(self.set)): - self.appendTokenName(sb, self.set[i]) - sb.append("), found " + self.tokenText) - - return str().join(sb).strip() - - __repr__ = __str__ - - -class TokenStreamException(ANTLRException): - - def __init__(self, *args): - ANTLRException.__init__(self, *args) - - -# Wraps an Exception in a TokenStreamException -class TokenStreamIOException(TokenStreamException): - - def __init__(self, *args): - if args and isinstance(args[0], Exception): - io = args[0] - TokenStreamException.__init__(self, str(io)) - self.io = io - else: - TokenStreamException.__init__(self, *args) - self.io = self - - -# Wraps a RecognitionException in a TokenStreamException -class TokenStreamRecognitionException(TokenStreamException): - - def __init__(self, *args): - if args and isinstance(args[0], RecognitionException): - recog = args[0] - TokenStreamException.__init__(self, str(recog)) - self.recog = recog - else: - raise TypeError("TokenStreamRecognitionException requires RecognitionException argument") - - def __str__(self): - return str(self.recog) - - __repr__ = __str__ - - -class TokenStreamRetryException(TokenStreamException): - - def __init__(self, *args): - TokenStreamException.__init__(self, *args) - - -class CharStreamException(ANTLRException): - - def __init__(self, *args): - ANTLRException.__init__(self, *args) - - -# Wraps an Exception in a CharStreamException -class CharStreamIOException(CharStreamException): - - def __init__(self, *args): - if args and isinstance(args[0], Exception): - io = args[0] - CharStreamException.__init__(self, str(io)) - self.io = io - else: - CharStreamException.__init__(self, *args) - self.io = self - - -class TryAgain(Exception): - pass - - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### Token ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class Token(object): - SKIP = -1 - INVALID_TYPE = 0 - EOF_TYPE = 1 - EOF = 1 - NULL_TREE_LOOKAHEAD = 3 - MIN_USER_TYPE = 4 - - def __init__(self,**argv): - try: - self.type = argv['type'] - except: - self.type = INVALID_TYPE - try: - self.text = argv['text'] - except: - self.text = "<no text>" - - def isEOF(self): - return (self.type == EOF_TYPE) - - def getColumn(self): - return 0 - - def getLine(self): - return 0 - - def getFilename(self): - return None - - def setFilename(self,name): - return self - - def getText(self): - return "<no text>" - - def setText(self,text): - if is_string_type(text): - pass - else: - raise TypeError("Token.setText requires string argument") - return self - - def setColumn(self,column): - return self - - def setLine(self,line): - return self - - def getType(self): - return self.type - - def setType(self,type): - if isinstance(type,int): - self.type = type - else: - raise TypeError("Token.setType requires integer argument") - return self - - def toString(self): - ## not optimal - type_ = self.type - if type_ == 3: - tval = 'NULL_TREE_LOOKAHEAD' - elif type_ == 1: - tval = 'EOF_TYPE' - elif type_ == 0: - tval = 'INVALID_TYPE' - elif type_ == -1: - tval = 'SKIP' - else: - tval = type_ - return '["%s",<%s>]' % (self.getText(),tval) - - __str__ = toString - __repr__ = toString - -### static attribute .. -Token.badToken = Token( type=INVALID_TYPE, text="<no text>") - -if __name__ == "__main__": - print "testing .." - T = Token.badToken - print T - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CommonToken ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class CommonToken(Token): - - def __init__(self,**argv): - Token.__init__(self,**argv) - self.line = 0 - self.col = 0 - try: - self.line = argv['line'] - except: - pass - try: - self.col = argv['col'] - except: - pass - - def getLine(self): - return self.line - - def getText(self): - return self.text - - def getColumn(self): - return self.col - - def setLine(self,line): - self.line = line - return self - - def setText(self,text): - self.text = text - return self - - def setColumn(self,col): - self.col = col - return self - - def toString(self): - ## not optimal - type_ = self.type - if type_ == 3: - tval = 'NULL_TREE_LOOKAHEAD' - elif type_ == 1: - tval = 'EOF_TYPE' - elif type_ == 0: - tval = 'INVALID_TYPE' - elif type_ == -1: - tval = 'SKIP' - else: - tval = type_ - d = { - 'text' : self.text, - 'type' : tval, - 'line' : self.line, - 'colm' : self.col - } - - fmt = '["%(text)s",<%(type)s>,line=%(line)s,col=%(colm)s]' - return fmt % d - - __str__ = toString - __repr__ = toString - - -if __name__ == '__main__' : - T = CommonToken() - print T - T = CommonToken(col=15,line=1,text="some text", type=5) - print T - T = CommonToken() - T.setLine(1).setColumn(15).setText("some text").setType(5) - print T - print T.getLine() - print T.getColumn() - print T.getText() - print T.getType() - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CommonHiddenStreamToken ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class CommonHiddenStreamToken(CommonToken): - def __init__(self,*args): - CommonToken.__init__(self,*args) - self.hiddenBefore = None - self.hiddenAfter = None - - def getHiddenAfter(self): - return self.hiddenAfter - - def getHiddenBefore(self): - return self.hiddenBefore - - def setHiddenAfter(self,t): - self.hiddenAfter = t - - def setHiddenBefore(self, t): - self.hiddenBefore = t - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### Queue ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -## Shall be a circular buffer on tokens .. -class Queue(object): - - def __init__(self): - self.buffer = [] # empty list - - def append(self,item): - self.buffer.append(item) - - def elementAt(self,index): - return self.buffer[index] - - def reset(self): - self.buffer = [] - - def removeFirst(self): - self.buffer.pop(0) - - def length(self): - return len(self.buffer) - - def __str__(self): - return str(self.buffer) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### InputBuffer ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class InputBuffer(object): - def __init__(self): - self.nMarkers = 0 - self.markerOffset = 0 - self.numToConsume = 0 - self.queue = Queue() - - def __str__(self): - return "(%s,%s,%s,%s)" % ( - self.nMarkers, - self.markerOffset, - self.numToConsume, - self.queue) - - def __repr__(self): - return str(self) - - def commit(self): - self.nMarkers -= 1 - - def consume(self) : - self.numToConsume += 1 - - ## probably better to return a list of items - ## because of unicode. Or return a unicode - ## string .. - def getLAChars(self) : - i = self.markerOffset - n = self.queue.length() - s = '' - while i<n: - s += self.queue.elementAt(i) - return s - - ## probably better to return a list of items - ## because of unicode chars - def getMarkedChars(self) : - s = '' - i = 0 - n = self.markerOffset - while i<n: - s += self.queue.elementAt(i) - return s - - def isMarked(self) : - return self.nMarkers != 0 - - def fill(self,k): - ### abstract method - raise NotImplementedError() - - def LA(self,k) : - self.fill(k) - return self.queue.elementAt(self.markerOffset + k - 1) - - def mark(self) : - self.syncConsume() - self.nMarkers += 1 - return self.markerOffset - - def rewind(self,mark) : - self.syncConsume() - self.markerOffset = mark - self.nMarkers -= 1 - - def reset(self) : - self.nMarkers = 0 - self.markerOffset = 0 - self.numToConsume = 0 - self.queue.reset() - - def syncConsume(self) : - while self.numToConsume > 0: - if self.nMarkers > 0: - # guess mode -- leave leading characters and bump offset. - self.markerOffset += 1 - else: - # normal mode -- remove first character - self.queue.removeFirst() - self.numToConsume -= 1 - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CharBuffer ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class CharBuffer(InputBuffer): - def __init__(self,reader): - ##assert isinstance(reader,file) - super(CharBuffer,self).__init__() - ## a reader is supposed to be anything that has - ## a method 'read(int)'. - self.input = reader - - def __str__(self): - base = super(CharBuffer,self).__str__() - return "CharBuffer{%s,%s" % (base,str(input)) - - def fill(self,amount): - try: - self.syncConsume() - while self.queue.length() < (amount + self.markerOffset) : - ## retrieve just one char - what happend at end - ## of input? - c = self.input.read(1) - ### python's behaviour is to return the empty string on - ### EOF, ie. no exception whatsoever is thrown. An empty - ### python string has the nice feature that it is of - ### type 'str' and "not ''" would return true. Contrary, - ### one can't do this: '' in 'abc'. This should return - ### false, but all we get is then a TypeError as an - ### empty string is not a character. - - ### Let's assure then that we have either seen a - ### character or an empty string (EOF). - assert len(c) == 0 or len(c) == 1 - - ### And it shall be of type string (ASCII or UNICODE). - assert is_string_type(c) - - ### Just append EOF char to buffer. Note that buffer may - ### contain then just more than one EOF char .. - - ### use unicode chars instead of ASCII .. - self.queue.append(c) - except Exception,e: - raise CharStreamIOException(e) - ##except: # (mk) Cannot happen ... - ##error ("unexpected exception caught ..") - ##assert 0 - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### LexerSharedInputState ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class LexerSharedInputState(object): - def __init__(self,ibuf): - assert isinstance(ibuf,InputBuffer) - self.input = ibuf - self.column = 1 - self.line = 1 - self.tokenStartColumn = 1 - self.tokenStartLine = 1 - self.guessing = 0 - self.filename = None - - def reset(self): - self.column = 1 - self.line = 1 - self.tokenStartColumn = 1 - self.tokenStartLine = 1 - self.guessing = 0 - self.filename = None - self.input.reset() - - def LA(self,k): - return self.input.LA(k) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TokenStream ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TokenStream(object): - def nextToken(self): - pass - - def __iter__(self): - return TokenStreamIterator(self) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TokenStreamIterator ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TokenStreamIterator(object): - def __init__(self,inst): - if isinstance(inst,TokenStream): - self.inst = inst - return - raise TypeError("TokenStreamIterator requires TokenStream object") - - def next(self): - assert self.inst - item = self.inst.nextToken() - if not item or item.isEOF(): - raise StopIteration() - return item - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TokenStreamSelector ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TokenStreamSelector(TokenStream): - - def __init__(self): - self._input = None - self._stmap = {} - self._stack = [] - - def addInputStream(self,stream,key): - self._stmap[key] = stream - - def getCurrentStream(self): - return self._input - - def getStream(self,sname): - try: - stream = self._stmap[sname] - except: - raise ValueError("TokenStream " + sname + " not found"); - return stream; - - def nextToken(self): - while 1: - try: - return self._input.nextToken() - except TokenStreamRetryException,r: - ### just retry "forever" - pass - - def pop(self): - stream = self._stack.pop(); - self.select(stream); - return stream; - - def push(self,arg): - self._stack.append(self._input); - self.select(arg) - - def retry(self): - raise TokenStreamRetryException() - - def select(self,arg): - if isinstance(arg,TokenStream): - self._input = arg - return - if is_string_type(arg): - self._input = self.getStream(arg) - return - raise TypeError("TokenStreamSelector.select requires " + - "TokenStream or string argument") - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TokenStreamBasicFilter ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TokenStreamBasicFilter(TokenStream): - - def __init__(self,input): - - self.input = input; - self.discardMask = BitSet() - - def discard(self,arg): - if isinstance(arg,int): - self.discardMask.add(arg) - return - if isinstance(arg,BitSet): - self.discardMark = arg - return - raise TypeError("TokenStreamBasicFilter.discard requires" + - "integer or BitSet argument") - - def nextToken(self): - tok = self.input.nextToken() - while tok and self.discardMask.member(tok.getType()): - tok = self.input.nextToken() - return tok - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TokenStreamHiddenTokenFilter ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TokenStreamHiddenTokenFilter(TokenStreamBasicFilter): - - def __init__(self,input): - TokenStreamBasicFilter.__init__(self,input) - self.hideMask = BitSet() - self.nextMonitoredToken = None - self.lastHiddenToken = None - self.firstHidden = None - - def consume(self): - self.nextMonitoredToken = self.input.nextToken() - - def consumeFirst(self): - self.consume() - - p = None; - while self.hideMask.member(self.LA(1).getType()) or \ - self.discardMask.member(self.LA(1).getType()): - if self.hideMask.member(self.LA(1).getType()): - if not p: - p = self.LA(1) - else: - p.setHiddenAfter(self.LA(1)) - self.LA(1).setHiddenBefore(p) - p = self.LA(1) - self.lastHiddenToken = p - if not self.firstHidden: - self.firstHidden = p - self.consume() - - def getDiscardMask(self): - return self.discardMask - - def getHiddenAfter(self,t): - return t.getHiddenAfter() - - def getHiddenBefore(self,t): - return t.getHiddenBefore() - - def getHideMask(self): - return self.hideMask - - def getInitialHiddenToken(self): - return self.firstHidden - - def hide(self,m): - if isinstance(m,int): - self.hideMask.add(m) - return - if isinstance(m.BitMask): - self.hideMask = m - return - - def LA(self,i): - return self.nextMonitoredToken - - def nextToken(self): - if not self.LA(1): - self.consumeFirst() - - monitored = self.LA(1) - - monitored.setHiddenBefore(self.lastHiddenToken) - self.lastHiddenToken = None - - self.consume() - p = monitored - - while self.hideMask.member(self.LA(1).getType()) or \ - self.discardMask.member(self.LA(1).getType()): - if self.hideMask.member(self.LA(1).getType()): - p.setHiddenAfter(self.LA(1)) - if p != monitored: - self.LA(1).setHiddenBefore(p) - p = self.lastHiddenToken = self.LA(1) - self.consume() - return monitored - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### StringBuffer ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class StringBuffer: - def __init__(self,string=None): - if string: - self.text = list(string) - else: - self.text = [] - - def setLength(self,sz): - if not sz : - self.text = [] - return - assert sz>0 - if sz >= self.length(): - return - ### just reset to empty buffer - self.text = self.text[0:sz] - - def length(self): - return len(self.text) - - def append(self,c): - self.text.append(c) - - ### return buffer as string. Arg 'a' is used as index - ## into the buffer and 2nd argument shall be the length. - ## If 2nd args is absent, we return chars till end of - ## buffer starting with 'a'. - def getString(self,a=None,length=None): - if not a : - a = 0 - assert a>=0 - if a>= len(self.text) : - return "" - - if not length: - ## no second argument - L = self.text[a:] - else: - assert (a+length) <= len(self.text) - b = a + length - L = self.text[a:b] - s = "" - for x in L : s += x - return s - - toString = getString ## alias - - def __str__(self): - return str(self.text) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### Reader ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -## When reading Japanese chars, it happens that a stream returns a -## 'char' of length 2. This looks like a bug in the appropriate -## codecs - but I'm rather unsure about this. Anyway, if this is -## the case, I'm going to split this string into a list of chars -## and put them on hold, ie. on a buffer. Next time when called -## we read from buffer until buffer is empty. -## wh: nov, 25th -> problem does not appear in Python 2.4.0.c1. - -class Reader(object): - def __init__(self,stream): - self.cin = stream - self.buf = [] - - def read(self,num): - assert num==1 - - if len(self.buf): - return self.buf.pop() - - ## Read a char - this may return a string. - ## Is this a bug in codecs/Python? - c = self.cin.read(1) - - if not c or len(c)==1: - return c - - L = list(c) - L.reverse() - for x in L: - self.buf.append(x) - - ## read one char .. - return self.read(1) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CharScanner ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class CharScanner(TokenStream): - ## class members - NO_CHAR = 0 - EOF_CHAR = '' ### EOF shall be the empty string. - - def __init__(self, *argv, **kwargs): - super(CharScanner, self).__init__() - self.saveConsumedInput = True - self.tokenClass = None - self.caseSensitive = True - self.caseSensitiveLiterals = True - self.literals = None - self.tabsize = 8 - self._returnToken = None - self.commitToPath = False - self.traceDepth = 0 - self.text = StringBuffer() - self.hashString = hash(self) - self.setTokenObjectClass(CommonToken) - self.setInput(*argv) - - def __iter__(self): - return CharScannerIterator(self) - - def setInput(self,*argv): - ## case 1: - ## if there's no arg we default to read from - ## standard input - if not argv: - import sys - self.setInput(sys.stdin) - return - - ## get 1st argument - arg1 = argv[0] - - ## case 2: - ## if arg1 is a string, we assume it's a file name - ## and open a stream using 2nd argument as open - ## mode. If there's no 2nd argument we fall back to - ## mode '+rb'. - if is_string_type(arg1): - f = open(arg1,"rb") - self.setInput(f) - self.setFilename(arg1) - return - - ## case 3: - ## if arg1 is a file we wrap it by a char buffer ( - ## some additional checks?? No, can't do this in - ## general). - if isinstance(arg1,file): - self.setInput(CharBuffer(arg1)) - return - - ## case 4: - ## if arg1 is of type SharedLexerInputState we use - ## argument as is. - if isinstance(arg1,LexerSharedInputState): - self.inputState = arg1 - return - - ## case 5: - ## check whether argument type is of type input - ## buffer. If so create a SharedLexerInputState and - ## go ahead. - if isinstance(arg1,InputBuffer): - self.setInput(LexerSharedInputState(arg1)) - return - - ## case 6: - ## check whether argument type has a method read(int) - ## If so create CharBuffer ... - try: - if arg1.read: - rd = Reader(arg1) - cb = CharBuffer(rd) - ss = LexerSharedInputState(cb) - self.inputState = ss - return - except: - pass - - ## case 7: - ## raise wrong argument exception - raise TypeError(argv) - - def setTabSize(self,size) : - self.tabsize = size - - def getTabSize(self) : - return self.tabsize - - def setCaseSensitive(self,t) : - self.caseSensitive = t - - def setCommitToPath(self,commit) : - self.commitToPath = commit - - def setFilename(self,f) : - self.inputState.filename = f - - def setLine(self,line) : - self.inputState.line = line - - def setText(self,s) : - self.resetText() - self.text.append(s) - - def getCaseSensitive(self) : - return self.caseSensitive - - def getCaseSensitiveLiterals(self) : - return self.caseSensitiveLiterals - - def getColumn(self) : - return self.inputState.column - - def setColumn(self,c) : - self.inputState.column = c - - def getCommitToPath(self) : - return self.commitToPath - - def getFilename(self) : - return self.inputState.filename - - def getInputBuffer(self) : - return self.inputState.input - - def getInputState(self) : - return self.inputState - - def setInputState(self,state) : - assert isinstance(state,LexerSharedInputState) - self.inputState = state - - def getLine(self) : - return self.inputState.line - - def getText(self) : - return str(self.text) - - def getTokenObject(self) : - return self._returnToken - - def LA(self,i) : - c = self.inputState.input.LA(i) - if not self.caseSensitive: - ### E0006 - c = c.__class__.lower(c) - return c - - def makeToken(self,type) : - try: - ## dynamically load a class - assert self.tokenClass - tok = self.tokenClass() - tok.setType(type) - tok.setColumn(self.inputState.tokenStartColumn) - tok.setLine(self.inputState.tokenStartLine) - return tok - except: - self.panic("unable to create new token") - return Token.badToken - - def mark(self) : - return self.inputState.input.mark() - - def _match_bitset(self,b) : - if b.member(self.LA(1)): - self.consume() - else: - raise MismatchedCharException(self.LA(1), b, False, self) - - def _match_string(self,s) : - for c in s: - if self.LA(1) == c: - self.consume() - else: - raise MismatchedCharException(self.LA(1), c, False, self) - - def match(self,item): - if is_string_type(item): - return self._match_string(item) - else: - return self._match_bitset(item) - - def matchNot(self,c) : - if self.LA(1) != c: - self.consume() - else: - raise MismatchedCharException(self.LA(1), c, True, self) - - def matchRange(self,c1,c2) : - if self.LA(1) < c1 or self.LA(1) > c2 : - raise MismatchedCharException(self.LA(1), c1, c2, False, self) - else: - self.consume() - - def newline(self) : - self.inputState.line += 1 - self.inputState.column = 1 - - def tab(self) : - c = self.getColumn() - nc = ( ((c-1)/self.tabsize) + 1) * self.tabsize + 1 - self.setColumn(nc) - - def panic(self,s='') : - print "CharScanner: panic: " + s - sys.exit(1) - - def reportError(self,ex) : - print ex - - def reportError(self,s) : - if not self.getFilename(): - print "error: " + str(s) - else: - print self.getFilename() + ": error: " + str(s) - - def reportWarning(self,s) : - if not self.getFilename(): - print "warning: " + str(s) - else: - print self.getFilename() + ": warning: " + str(s) - - def resetText(self) : - self.text.setLength(0) - self.inputState.tokenStartColumn = self.inputState.column - self.inputState.tokenStartLine = self.inputState.line - - def rewind(self,pos) : - self.inputState.input.rewind(pos) - - def setTokenObjectClass(self,cl): - self.tokenClass = cl - - def testForLiteral(self,token): - if not token: - return - assert isinstance(token,Token) - - _type = token.getType() - - ## special tokens can't be literals - if _type in [SKIP,INVALID_TYPE,EOF_TYPE,NULL_TREE_LOOKAHEAD] : - return - - _text = token.getText() - if not _text: - return - - assert is_string_type(_text) - _type = self.testLiteralsTable(_text,_type) - token.setType(_type) - return _type - - def testLiteralsTable(self,*args): - if is_string_type(args[0]): - s = args[0] - i = args[1] - else: - s = self.text.getString() - i = args[0] - - ## check whether integer has been given - if not isinstance(i,int): - assert isinstance(i,int) - - ## check whether we have a dict - assert isinstance(self.literals,dict) - try: - ## E0010 - if not self.caseSensitiveLiterals: - s = s.__class__.lower(s) - i = self.literals[s] - except: - pass - return i - - def toLower(self,c): - return c.__class__.lower() - - def traceIndent(self): - print ' ' * self.traceDepth - - def traceIn(self,rname): - self.traceDepth += 1 - self.traceIndent() - print "> lexer %s c== %s" % (rname,self.LA(1)) - - def traceOut(self,rname): - self.traceIndent() - print "< lexer %s c== %s" % (rname,self.LA(1)) - self.traceDepth -= 1 - - def uponEOF(self): - pass - - def append(self,c): - if self.saveConsumedInput : - self.text.append(c) - - def commit(self): - self.inputState.input.commit() - - def consume(self): - if not self.inputState.guessing: - c = self.LA(1) - if self.caseSensitive: - self.append(c) - else: - # use input.LA(), not LA(), to get original case - # CharScanner.LA() would toLower it. - c = self.inputState.input.LA(1) - self.append(c) - - if c and c in "\t": - self.tab() - else: - self.inputState.column += 1 - self.inputState.input.consume() - - ## Consume chars until one matches the given char - def consumeUntil_char(self,c): - while self.LA(1) != EOF_CHAR and self.LA(1) != c: - self.consume() - - ## Consume chars until one matches the given set - def consumeUntil_bitset(self,bitset): - while self.LA(1) != EOF_CHAR and not self.set.member(self.LA(1)): - self.consume() - - ### If symbol seen is EOF then generate and set token, otherwise - ### throw exception. - def default(self,la1): - if not la1 : - self.uponEOF() - self._returnToken = self.makeToken(EOF_TYPE) - else: - self.raise_NoViableAlt(la1) - - def filterdefault(self,la1,*args): - if not la1: - self.uponEOF() - self._returnToken = self.makeToken(EOF_TYPE) - return - - if not args: - self.consume() - raise TryAgain() - else: - ### apply filter object - self.commit(); - try: - func=args[0] - args=args[1:] - apply(func,args) - except RecognitionException, e: - ## catastrophic failure - self.reportError(e); - self.consume(); - raise TryAgain() - - def raise_NoViableAlt(self,la1=None): - if not la1: la1 = self.LA(1) - fname = self.getFilename() - line = self.getLine() - col = self.getColumn() - raise NoViableAltForCharException(la1,fname,line,col) - - def set_return_token(self,_create,_token,_ttype,_offset): - if _create and not _token and (not _ttype == SKIP): - string = self.text.getString(_offset) - _token = self.makeToken(_ttype) - _token.setText(string) - self._returnToken = _token - return _token - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CharScannerIterator ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class CharScannerIterator: - - def __init__(self,inst): - if isinstance(inst,CharScanner): - self.inst = inst - return - raise TypeError("CharScannerIterator requires CharScanner object") - - def next(self): - assert self.inst - item = self.inst.nextToken() - if not item or item.isEOF(): - raise StopIteration() - return item - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### BitSet ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -### I'm assuming here that a long is 64bits. It appears however, that -### a long is of any size. That means we can use a single long as the -### bitset (!), ie. Python would do almost all the work (TBD). - -class BitSet(object): - BITS = 64 - NIBBLE = 4 - LOG_BITS = 6 - MOD_MASK = BITS -1 - - def __init__(self,data=None): - if not data: - BitSet.__init__(self,[long(0)]) - return - if isinstance(data,int): - BitSet.__init__(self,[long(data)]) - return - if isinstance(data,long): - BitSet.__init__(self,[data]) - return - if not isinstance(data,list): - raise TypeError("BitSet requires integer, long, or " + - "list argument") - for x in data: - if not isinstance(x,long): - raise TypeError(self,"List argument item is " + - "not a long: %s" % (x)) - self.data = data - - def __str__(self): - bits = len(self.data) * BitSet.BITS - s = "" - for i in xrange(0,bits): - if self.at(i): - s += "1" - else: - s += "o" - if not ((i+1) % 10): - s += '|%s|' % (i+1) - return s - - def __repr__(self): - return str(self) - - def member(self,item): - if not item: - return False - - if isinstance(item,int): - return self.at(item) - - if not is_string_type(item): - raise TypeError(self,"char or unichar expected: %s" % (item)) - - ## char is a (unicode) string with at most lenght 1, ie. - ## a char. - - if len(item) != 1: - raise TypeError(self,"char expected: %s" % (item)) - - ### handle ASCII/UNICODE char - num = ord(item) - - ### check whether position num is in bitset - return self.at(num) - - def wordNumber(self,bit): - return bit >> BitSet.LOG_BITS - - def bitMask(self,bit): - pos = bit & BitSet.MOD_MASK ## bit mod BITS - return (1L << pos) - - def set(self,bit,on=True): - # grow bitset as required (use with care!) - i = self.wordNumber(bit) - mask = self.bitMask(bit) - if i>=len(self.data): - d = i - len(self.data) + 1 - for x in xrange(0,d): - self.data.append(0L) - assert len(self.data) == i+1 - if on: - self.data[i] |= mask - else: - self.data[i] &= (~mask) - - ### make add an alias for set - add = set - - def off(self,bit,off=True): - self.set(bit,not off) - - def at(self,bit): - i = self.wordNumber(bit) - v = self.data[i] - m = self.bitMask(bit) - return v & m - - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### some further funcs ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -def illegalarg_ex(func): - raise ValueError( - "%s is only valid if parser is built for debugging" % - (func.func_name)) - -def runtime_ex(func): - raise RuntimeException( - "%s is only valid if parser is built for debugging" % - (func.func_name)) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TokenBuffer ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TokenBuffer(object): - def __init__(self,stream): - self.input = stream - self.nMarkers = 0 - self.markerOffset = 0 - self.numToConsume = 0 - self.queue = Queue() - - def reset(self) : - self.nMarkers = 0 - self.markerOffset = 0 - self.numToConsume = 0 - self.queue.reset() - - def consume(self) : - self.numToConsume += 1 - - def fill(self, amount): - self.syncConsume() - while self.queue.length() < (amount + self.markerOffset): - self.queue.append(self.input.nextToken()) - - def getInput(self): - return self.input - - def LA(self,k) : - self.fill(k) - return self.queue.elementAt(self.markerOffset + k - 1).type - - def LT(self,k) : - self.fill(k) - return self.queue.elementAt(self.markerOffset + k - 1) - - def mark(self) : - self.syncConsume() - self.nMarkers += 1 - return self.markerOffset - - def rewind(self,mark) : - self.syncConsume() - self.markerOffset = mark - self.nMarkers -= 1 - - def syncConsume(self) : - while self.numToConsume > 0: - if self.nMarkers > 0: - # guess mode -- leave leading characters and bump offset. - self.markerOffset += 1 - else: - # normal mode -- remove first character - self.queue.removeFirst() - self.numToConsume -= 1 - - def __str__(self): - return "(%s,%s,%s,%s,%s)" % ( - self.input, - self.nMarkers, - self.markerOffset, - self.numToConsume, - self.queue) - - def __repr__(self): - return str(self) - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### ParserSharedInputState ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class ParserSharedInputState(object): - - def __init__(self): - self.input = None - self.reset() - - def reset(self): - self.guessing = 0 - self.filename = None - if self.input: - self.input.reset() - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### Parser ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class Parser(object): - - def __init__(self, *args, **kwargs): - self.tokenNames = None - self.returnAST = None - self.astFactory = None - self.tokenTypeToASTClassMap = {} - self.ignoreInvalidDebugCalls = False - self.traceDepth = 0 - if not args: - self.inputState = ParserSharedInputState() - return - arg0 = args[0] - assert isinstance(arg0,ParserSharedInputState) - self.inputState = arg0 - return - - def getTokenTypeToASTClassMap(self): - return self.tokenTypeToASTClassMap - - - def addMessageListener(self, l): - if not self.ignoreInvalidDebugCalls: - illegalarg_ex(addMessageListener) - - def addParserListener(self,l) : - if (not self.ignoreInvalidDebugCalls) : - illegalarg_ex(addParserListener) - - def addParserMatchListener(self, l) : - if (not self.ignoreInvalidDebugCalls) : - illegalarg_ex(addParserMatchListener) - - def addParserTokenListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - illegalarg_ex(addParserTokenListener) - - def addSemanticPredicateListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - illegalarg_ex(addSemanticPredicateListener) - - def addSyntacticPredicateListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - illegalarg_ex(addSyntacticPredicateListener) - - def addTraceListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - illegalarg_ex(addTraceListener) - - def consume(self): - raise NotImplementedError() - - def _consumeUntil_type(self,tokenType): - while self.LA(1) != EOF_TYPE and self.LA(1) != tokenType: - self.consume() - - def _consumeUntil_bitset(self, set): - while self.LA(1) != EOF_TYPE and not set.member(self.LA(1)): - self.consume() - - def consumeUntil(self,arg): - if isinstance(arg,int): - self._consumeUntil_type(arg) - else: - self._consumeUntil_bitset(arg) - - def defaultDebuggingSetup(self): - pass - - def getAST(self) : - return self.returnAST - - def getASTFactory(self) : - return self.astFactory - - def getFilename(self) : - return self.inputState.filename - - def getInputState(self) : - return self.inputState - - def setInputState(self, state) : - self.inputState = state - - def getTokenName(self,num) : - return self.tokenNames[num] - - def getTokenNames(self) : - return self.tokenNames - - def isDebugMode(self) : - return self.false - - def LA(self, i): - raise NotImplementedError() - - def LT(self, i): - raise NotImplementedError() - - def mark(self): - return self.inputState.input.mark() - - def _match_int(self,t): - if (self.LA(1) != t): - raise MismatchedTokenException( - self.tokenNames, self.LT(1), t, False, self.getFilename()) - else: - self.consume() - - def _match_set(self, b): - if (not b.member(self.LA(1))): - raise MismatchedTokenException( - self.tokenNames,self.LT(1), b, False, self.getFilename()) - else: - self.consume() - - def match(self,set) : - if isinstance(set,int): - self._match_int(set) - return - if isinstance(set,BitSet): - self._match_set(set) - return - raise TypeError("Parser.match requires integer ot BitSet argument") - - def matchNot(self,t): - if self.LA(1) == t: - raise MismatchedTokenException( - tokenNames, self.LT(1), t, True, self.getFilename()) - else: - self.consume() - - def removeMessageListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeMessageListener) - - def removeParserListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeParserListener) - - def removeParserMatchListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeParserMatchListener) - - def removeParserTokenListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeParserTokenListener) - - def removeSemanticPredicateListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeSemanticPredicateListener) - - def removeSyntacticPredicateListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeSyntacticPredicateListener) - - def removeTraceListener(self, l) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(removeTraceListener) - - def reportError(self,x) : - fmt = "syntax error:" - f = self.getFilename() - if f: - fmt = ("%s:" % f) + fmt - if isinstance(x,Token): - line = x.getColumn() - col = x.getLine() - text = x.getText() - fmt = fmt + 'unexpected symbol at line %s (column %s) : "%s"' - print >>sys.stderr, fmt % (line,col,text) - else: - print >>sys.stderr, fmt,str(x) - - def reportWarning(self,s): - f = self.getFilename() - if f: - print "%s:warning: %s" % (f,str(x)) - else: - print "warning: %s" % (str(x)) - - def rewind(self, pos) : - self.inputState.input.rewind(pos) - - def setASTFactory(self, f) : - self.astFactory = f - - def setASTNodeClass(self, cl) : - self.astFactory.setASTNodeType(cl) - - def setASTNodeType(self, nodeType) : - self.setASTNodeClass(nodeType) - - def setDebugMode(self, debugMode) : - if (not self.ignoreInvalidDebugCalls): - runtime_ex(setDebugMode) - - def setFilename(self, f) : - self.inputState.filename = f - - def setIgnoreInvalidDebugCalls(self, value) : - self.ignoreInvalidDebugCalls = value - - def setTokenBuffer(self, t) : - self.inputState.input = t - - def traceIndent(self): - print " " * self.traceDepth - - def traceIn(self,rname): - self.traceDepth += 1 - self.trace("> ", rname) - - def traceOut(self,rname): - self.trace("< ", rname) - self.traceDepth -= 1 - - ### wh: moved from ASTFactory to Parser - def addASTChild(self,currentAST, child): - if not child: - return - if not currentAST.root: - currentAST.root = child - elif not currentAST.child: - currentAST.root.setFirstChild(child) - else: - currentAST.child.setNextSibling(child) - currentAST.child = child - currentAST.advanceChildToEnd() - - ### wh: moved from ASTFactory to Parser - def makeASTRoot(self,currentAST,root) : - if root: - ### Add the current root as a child of new root - root.addChild(currentAST.root) - ### The new current child is the last sibling of the old root - currentAST.child = currentAST.root - currentAST.advanceChildToEnd() - ### Set the new root - currentAST.root = root - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### LLkParser ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class LLkParser(Parser): - - def __init__(self, *args, **kwargs): - try: - arg1 = args[0] - except: - arg1 = 1 - - if isinstance(arg1,int): - super(LLkParser,self).__init__() - self.k = arg1 - return - - if isinstance(arg1,ParserSharedInputState): - super(LLkParser,self).__init__(arg1) - self.set_k(1,*args) - return - - if isinstance(arg1,TokenBuffer): - super(LLkParser,self).__init__() - self.setTokenBuffer(arg1) - self.set_k(1,*args) - return - - if isinstance(arg1,TokenStream): - super(LLkParser,self).__init__() - tokenBuf = TokenBuffer(arg1) - self.setTokenBuffer(tokenBuf) - self.set_k(1,*args) - return - - ### unknown argument - raise TypeError("LLkParser requires integer, " + - "ParserSharedInputStream or TokenStream argument") - - def consume(self): - self.inputState.input.consume() - - def LA(self,i): - return self.inputState.input.LA(i) - - def LT(self,i): - return self.inputState.input.LT(i) - - def set_k(self,index,*args): - try: - self.k = args[index] - except: - self.k = 1 - - def trace(self,ee,rname): - print type(self) - self.traceIndent() - guess = "" - if self.inputState.guessing > 0: - guess = " [guessing]" - print(ee + rname + guess) - for i in xrange(1,self.k+1): - if i != 1: - print(", ") - if self.LT(i) : - v = self.LT(i).getText() - else: - v = "null" - print "LA(%s) == %s" % (i,v) - print("\n") - - def traceIn(self,rname): - self.traceDepth += 1; - self.trace("> ", rname); - - def traceOut(self,rname): - self.trace("< ", rname); - self.traceDepth -= 1; - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TreeParserSharedInputState ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TreeParserSharedInputState(object): - def __init__(self): - self.guessing = 0 - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### TreeParser ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class TreeParser(object): - - def __init__(self, *args, **kwargs): - self.inputState = TreeParserSharedInputState() - self._retTree = None - self.tokenNames = [] - self.returnAST = None - self.astFactory = ASTFactory() - self.traceDepth = 0 - - def getAST(self): - return self.returnAST - - def getASTFactory(self): - return self.astFactory - - def getTokenName(self,num) : - return self.tokenNames[num] - - def getTokenNames(self): - return self.tokenNames - - def match(self,t,set) : - assert isinstance(set,int) or isinstance(set,BitSet) - if not t or t == ASTNULL: - raise MismatchedTokenException(self.getTokenNames(), t,set, False) - - if isinstance(set,int) and t.getType() != set: - raise MismatchedTokenException(self.getTokenNames(), t,set, False) - - if isinstance(set,BitSet) and not set.member(t.getType): - raise MismatchedTokenException(self.getTokenNames(), t,set, False) - - def matchNot(self,t, ttype) : - if not t or (t == ASTNULL) or (t.getType() == ttype): - raise MismatchedTokenException(getTokenNames(), t, ttype, True) - - def reportError(self,ex): - print >>sys.stderr,"error:",ex - - def reportWarning(self, s): - print "warning:",s - - def setASTFactory(self,f): - self.astFactory = f - - def setASTNodeType(self,nodeType): - self.setASTNodeClass(nodeType) - - def setASTNodeClass(self,nodeType): - self.astFactory.setASTNodeType(nodeType) - - def traceIndent(self): - print " " * self.traceDepth - - def traceIn(self,rname,t): - self.traceDepth += 1 - self.traceIndent() - print("> " + rname + "(" + - ifelse(t,str(t),"null") + ")" + - ifelse(self.inputState.guessing>0,"[guessing]","")) - - def traceOut(self,rname,t): - self.traceIndent() - print("< " + rname + "(" + - ifelse(t,str(t),"null") + ")" + - ifelse(self.inputState.guessing>0,"[guessing]","")) - self.traceDepth -= 1 - - ### wh: moved from ASTFactory to TreeParser - def addASTChild(self,currentAST, child): - if not child: - return - if not currentAST.root: - currentAST.root = child - elif not currentAST.child: - currentAST.root.setFirstChild(child) - else: - currentAST.child.setNextSibling(child) - currentAST.child = child - currentAST.advanceChildToEnd() - - ### wh: moved from ASTFactory to TreeParser - def makeASTRoot(self,currentAST,root): - if root: - ### Add the current root as a child of new root - root.addChild(currentAST.root) - ### The new current child is the last sibling of the old root - currentAST.child = currentAST.root - currentAST.advanceChildToEnd() - ### Set the new root - currentAST.root = root - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### funcs to work on trees ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -def rightmost(ast): - if ast: - while(ast.right): - ast = ast.right - return ast - -def cmptree(s,t,partial): - while(s and t): - ### as a quick optimization, check roots first. - if not s.equals(t): - return False - - ### if roots match, do full list match test on children. - if not cmptree(s.getFirstChild(),t.getFirstChild(),partial): - return False - - s = s.getNextSibling() - t = t.getNextSibling() - - r = ifelse(partial,not t,not s and not t) - return r - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### AST ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class AST(object): - def __init__(self): - pass - - def addChild(self, c): - pass - - def equals(self, t): - return False - - def equalsList(self, t): - return False - - def equalsListPartial(self, t): - return False - - def equalsTree(self, t): - return False - - def equalsTreePartial(self, t): - return False - - def findAll(self, tree): - return None - - def findAllPartial(self, subtree): - return None - - def getFirstChild(self): - return self - - def getNextSibling(self): - return self - - def getText(self): - return "" - - def getType(self): - return INVALID_TYPE - - def getLine(self): - return 0 - - def getColumn(self): - return 0 - - def getNumberOfChildren(self): - return 0 - - def initialize(self, t, txt): - pass - - def initialize(self, t): - pass - - def setFirstChild(self, c): - pass - - def setNextSibling(self, n): - pass - - def setText(self, text): - pass - - def setType(self, ttype): - pass - - def toString(self): - self.getText() - - __str__ = toString - - def toStringList(self): - return self.getText() - - def toStringTree(self): - return self.getText() - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### ASTNULLType ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -### There is only one instance of this class **/ -class ASTNULLType(AST): - def __init__(self): - AST.__init__(self) - pass - - def getText(self): - return "<ASTNULL>" - - def getType(self): - return NULL_TREE_LOOKAHEAD - - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### BaseAST ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class BaseAST(AST): - - verboseStringConversion = False - tokenNames = None - - def __init__(self): - self.down = None ## kid - self.right = None ## sibling - - def addChild(self,node): - if node: - t = rightmost(self.down) - if t: - t.right = node - else: - assert not self.down - self.down = node - - def getNumberOfChildren(self): - t = self.down - n = 0 - while t: - n += 1 - t = t.right - return n - - def doWorkForFindAll(self,v,target,partialMatch): - sibling = self - - while sibling: - c1 = partialMatch and sibling.equalsTreePartial(target) - if c1: - v.append(sibling) - else: - c2 = not partialMatch and sibling.equalsTree(target) - if c2: - v.append(sibling) - - ### regardless of match or not, check any children for matches - if sibling.getFirstChild(): - sibling.getFirstChild().doWorkForFindAll(v,target,partialMatch) - - sibling = sibling.getNextSibling() - - ### Is node t equal to 'self' in terms of token type and text? - def equals(self,t): - if not t: - return False - return self.getText() == t.getText() and self.getType() == t.getType() - - ### Is t an exact structural and equals() match of this tree. The - ### 'self' reference is considered the start of a sibling list. - ### - def equalsList(self, t): - return cmptree(self, t, partial=False) - - ### Is 't' a subtree of this list? - ### The siblings of the root are NOT ignored. - ### - def equalsListPartial(self,t): - return cmptree(self,t,partial=True) - - ### Is tree rooted at 'self' equal to 't'? The siblings - ### of 'self' are ignored. - ### - def equalsTree(self, t): - return self.equals(t) and \ - cmptree(self.getFirstChild(), t.getFirstChild(), partial=False) - - ### Is 't' a subtree of the tree rooted at 'self'? The siblings - ### of 'self' are ignored. - ### - def equalsTreePartial(self, t): - if not t: - return True - return self.equals(t) and cmptree( - self.getFirstChild(), t.getFirstChild(), partial=True) - - ### Walk the tree looking for all exact subtree matches. Return - ### an ASTEnumerator that lets the caller walk the list - ### of subtree roots found herein. - def findAll(self,target): - roots = [] - - ### the empty tree cannot result in an enumeration - if not target: - return None - # find all matches recursively - self.doWorkForFindAll(roots, target, False) - return roots - - ### Walk the tree looking for all subtrees. Return - ### an ASTEnumerator that lets the caller walk the list - ### of subtree roots found herein. - def findAllPartial(self,sub): - roots = [] - - ### the empty tree cannot result in an enumeration - if not sub: - return None - - self.doWorkForFindAll(roots, sub, True) ### find all matches recursively - return roots - - ### Get the first child of this node None if not children - def getFirstChild(self): - return self.down - - ### Get the next sibling in line after this one - def getNextSibling(self): - return self.right - - ### Get the token text for this node - def getText(self): - return "" - - ### Get the token type for this node - def getType(self): - return 0 - - def getLine(self): - return 0 - - def getColumn(self): - return 0 - - ### Remove all children */ - def removeChildren(self): - self.down = None - - def setFirstChild(self,c): - self.down = c - - def setNextSibling(self, n): - self.right = n - - ### Set the token text for this node - def setText(self, text): - pass - - ### Set the token type for this node - def setType(self, ttype): - pass - - ### static - def setVerboseStringConversion(verbose,names): - verboseStringConversion = verbose - tokenNames = names - setVerboseStringConversion = staticmethod(setVerboseStringConversion) - - ### Return an array of strings that maps token ID to it's text. - ## @since 2.7.3 - def getTokenNames(): - return tokenNames - - def toString(self): - return self.getText() - - ### return tree as lisp string - sibling included - def toStringList(self): - ts = self.toStringTree() - sib = self.getNextSibling() - if sib: - ts += sib.toStringList() - return ts - - __str__ = toStringList - - ### return tree as string - siblings ignored - def toStringTree(self): - ts = "" - kid = self.getFirstChild() - if kid: - ts += " (" - ts += " " + self.toString() - if kid: - ts += kid.toStringList() - ts += " )" - return ts - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CommonAST ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -### Common AST node implementation -class CommonAST(BaseAST): - def __init__(self,token=None): - super(CommonAST,self).__init__() - self.ttype = INVALID_TYPE - self.text = "<no text>" - self.line = 0 - self.column= 0 - self.initialize(token) - #assert self.text - - ### Get the token text for this node - def getText(self): - return self.text - - ### Get the token type for this node - def getType(self): - return self.ttype - - ### Get the line for this node - def getLine(self): - return self.line - - ### Get the column for this node - def getColumn(self): - return self.column - - def initialize(self,*args): - if not args: - return - - arg0 = args[0] - - if isinstance(arg0,int): - arg1 = args[1] - self.setType(arg0) - self.setText(arg1) - return - - if isinstance(arg0,AST) or isinstance(arg0,Token): - self.setText(arg0.getText()) - self.setType(arg0.getType()) - self.line = arg0.getLine() - self.column = arg0.getColumn() - return - - ### Set the token text for this node - def setText(self,text_): - assert is_string_type(text_) - self.text = text_ - - ### Set the token type for this node - def setType(self,ttype_): - assert isinstance(ttype_,int) - self.ttype = ttype_ - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### CommonASTWithHiddenTokens ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class CommonASTWithHiddenTokens(CommonAST): - - def __init__(self,*args): - CommonAST.__init__(self,*args) - self.hiddenBefore = None - self.hiddenAfter = None - - def getHiddenAfter(self): - return self.hiddenAfter - - def getHiddenBefore(self): - return self.hiddenBefore - - def initialize(self,*args): - CommonAST.initialize(self,*args) - if args and isinstance(args[0],Token): - assert isinstance(args[0],CommonHiddenStreamToken) - self.hiddenBefore = args[0].getHiddenBefore() - self.hiddenAfter = args[0].getHiddenAfter() - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### ASTPair ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class ASTPair(object): - def __init__(self): - self.root = None ### current root of tree - self.child = None ### current child to which siblings are added - - ### Make sure that child is the last sibling */ - def advanceChildToEnd(self): - if self.child: - while self.child.getNextSibling(): - self.child = self.child.getNextSibling() - - ### Copy an ASTPair. Don't call it clone() because we want type-safety */ - def copy(self): - tmp = ASTPair() - tmp.root = self.root - tmp.child = self.child - return tmp - - def toString(self): - r = ifelse(not root,"null",self.root.getText()) - c = ifelse(not child,"null",self.child.getText()) - return "[%s,%s]" % (r,c) - - __str__ = toString - __repr__ = toString - - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### ASTFactory ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class ASTFactory(object): - def __init__(self,table=None): - self._class = None - self._classmap = ifelse(table,table,None) - - def create(self,*args): - if not args: - return self.create(INVALID_TYPE) - - arg0 = args[0] - arg1 = None - arg2 = None - - try: - arg1 = args[1] - arg2 = args[2] - except: - pass - - # ctor(int) - if isinstance(arg0,int) and not arg2: - ### get class for 'self' type - c = self.getASTNodeType(arg0) - t = self.create(c) - if t: - t.initialize(arg0, ifelse(arg1,arg1,"")) - return t - - # ctor(int,something) - if isinstance(arg0,int) and arg2: - t = self.create(arg2) - if t: - t.initialize(arg0,arg1) - return t - - # ctor(AST) - if isinstance(arg0,AST): - t = self.create(arg0.getType()) - if t: - t.initialize(arg0) - return t - - # ctor(token) - if isinstance(arg0,Token) and not arg1: - ttype = arg0.getType() - assert isinstance(ttype,int) - t = self.create(ttype) - if t: - t.initialize(arg0) - return t - - # ctor(token,class) - if isinstance(arg0,Token) and arg1: - assert isinstance(arg1,type) - assert issubclass(arg1,AST) - # this creates instance of 'arg1' using 'arg0' as - # argument. Wow, that's magic! - t = arg1(arg0) - assert t and isinstance(t,AST) - return t - - # ctor(class) - if isinstance(arg0,type): - ### next statement creates instance of type (!) - t = arg0() - assert isinstance(t,AST) - return t - - - def setASTNodeClass(self,className=None): - if not className: - return - assert isinstance(className,type) - assert issubclass(className,AST) - self._class = className - - ### kind of misnomer - use setASTNodeClass instead. - setASTNodeType = setASTNodeClass - - def getASTNodeClass(self): - return self._class - - - - def getTokenTypeToASTClassMap(self): - return self._classmap - - def setTokenTypeToASTClassMap(self,amap): - self._classmap = amap - - def error(self, e): - import sys - print >> sys.stderr, e - - def setTokenTypeASTNodeType(self, tokenType, className): - """ - Specify a mapping between a token type and a (AST) class. - """ - if not self._classmap: - self._classmap = {} - - if not className: - try: - del self._classmap[tokenType] - except: - pass - else: - ### here we should also perform actions to ensure that - ### a. class can be loaded - ### b. class is a subclass of AST - ### - assert isinstance(className,type) - assert issubclass(className,AST) ## a & b - ### enter the class - self._classmap[tokenType] = className - - def getASTNodeType(self,tokenType): - """ - For a given token type return the AST node type. First we - lookup a mapping table, second we try _class - and finally we resolve to "antlr.CommonAST". - """ - - # first - if self._classmap: - try: - c = self._classmap[tokenType] - if c: - return c - except: - pass - # second - if self._class: - return self._class - - # default - return CommonAST - - ### methods that have been moved to file scope - just listed - ### here to be somewhat consistent with original API - def dup(self,t): - return antlr.dup(t,self) - - def dupList(self,t): - return antlr.dupList(t,self) - - def dupTree(self,t): - return antlr.dupTree(t,self) - - ### methods moved to other classes - ### 1. makeASTRoot -> Parser - ### 2. addASTChild -> Parser - - ### non-standard: create alias for longish method name - maptype = setTokenTypeASTNodeType - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### ASTVisitor ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -class ASTVisitor(object): - def __init__(self,*args): - pass - - def visit(self,ast): - pass - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### -### static methods and variables ### -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx### - -ASTNULL = ASTNULLType() - -### wh: moved from ASTFactory as there's nothing ASTFactory-specific -### in this method. -def make(*nodes): - if not nodes: - return None - - for i in xrange(0,len(nodes)): - node = nodes[i] - if node: - assert isinstance(node,AST) - - root = nodes[0] - tail = None - if root: - root.setFirstChild(None) - - for i in xrange(1,len(nodes)): - if not nodes[i]: - continue - if not root: - root = tail = nodes[i] - elif not tail: - root.setFirstChild(nodes[i]) - tail = root.getFirstChild() - else: - tail.setNextSibling(nodes[i]) - tail = tail.getNextSibling() - - ### Chase tail to last sibling - while tail.getNextSibling(): - tail = tail.getNextSibling() - return root - -def dup(t,factory): - if not t: - return None - - if factory: - dup_t = factory.create(t.__class__) - else: - raise TypeError("dup function requires ASTFactory argument") - dup_t.initialize(t) - return dup_t - -def dupList(t,factory): - result = dupTree(t,factory) - nt = result - while t: - ## for each sibling of the root - t = t.getNextSibling() - nt.setNextSibling(dupTree(t,factory)) - nt = nt.getNextSibling() - return result - -def dupTree(t,factory): - result = dup(t,factory) - if t: - result.setFirstChild(dupList(t.getFirstChild(),factory)) - return result - -###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -### $Id: antlr.py 3750 2009-02-13 00:13:04Z sjmachin $ - -# Local Variables: *** -# mode: python *** -# py-indent-offset: 4 *** -# End: *** diff --git a/tablib/packages/xlwt/doc/xlwt.html b/tablib/packages/xlwt/doc/xlwt.html deleted file mode 100644 index 6efb698..0000000 --- a/tablib/packages/xlwt/doc/xlwt.html +++ /dev/null @@ -1,199 +0,0 @@ -<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'> -<html> -<head> -<meta http-equiv='Content-Type' content='text/html; charset=us-ascii' /> -<title>The xlwt Module</title> -</head> -<body> -<h1>The xlwt Module</h1> -<p /><p><b>A Python package for generating Microsoft Excel ™ spreadsheet files. -</b></p> - -<h2>General information</h2> - -<h3>State of Documentation</h3> - -<p> -This documentation is currently incomplete. There may be methods and -classes not included and any item marked with a <em -style="color:red;">[NC]</em> is not complete and may have further -parameters, methods, attributes and functionality that are not -documented. In these cases, you'll have to refer to the source if the -documentation provided is insufficient. -</p> - -</p> - -<h2>Module Contents <em style="color:red;">[NC]</em></h2> -<dl> - <dt><b>easyxf</b> (function)</dt> - <dd> - <p> - This function is used to create and configure XFStyle objects - for use with (for example) the Worksheet.write method. - </p> - <dl> - <dt><i>strg_to_parse</i></dt> - <dd> - <p> - A string to be parsed to obtain attribute values for Alignment, Borders, Font, - Pattern and Protection objects. Refer to the examples - in the file .../examples/xlwt_easyxf_simple_demo.py and to the xf_dict - dictionary in Style.py. Various synonyms including color/colour, center/centre and gray/grey - are allowed. Case is irrelevant (except maybe in font names). '-' may be used instead - of '_'.<br /> - Example: "font: bold on; align: wrap on, vert centre, horiz center" - </p> - </dd> - <dt><i>num_format_str</i></dt> - <dd> - <p> - To get the "number format string" of an existing cell whose format you want to reproduce, - select the cell and click on Format/Cells/Number/Custom. Otherwise, refer to Excel help.<br /> - Examples: "#,##0.00", "dd/mm/yyyy" - </p> - </dd> - <dt>Returns:</dt> - <dd> - An object of the XFstyle class - </dd> - </dl> - <br /> - - </dd> - - <dt><b>Workbook</b> (class) [<a href='#xlwt.Workbook-class'>#</a>]</dt> - <dd> - <p>The class to instantiate to create a workbook</p> - <p>For more information about this class, see <a href='#xlwt.Workbook-class'><i>The Workbook Class</i></a>.</p> - </dd> - <dt><b>Worksheet</b> (class) [<a href='#xlwt.Worksheet-class'>#</a>]</dt> - <dd> - <p>A class to represent the contents of a sheet in a workbook.</p> - <p>For more information about this class, see <a href='#xlwt.Worksheet-class'><i>The Worksheet Class</i></a>.</p> - </dd> -</dl> - -<h2><a id='xlwt.Workbook-class' name='xlwt.Workbook-class'>The Workbook Class</a><em style="color:red;">[NC]</em></h2> -<dl> -<dt><b>Workbook(encoding='ascii',style_compression=0)</b> (class) [<a href='#xlwt.Workbook-class'>#</a>]</dt> -<dd> - <p> - This is a class representing a workbook and all its contents. - When creating Excel files with xlwt, you will normally start by - instantiating an object of this class. - </p> - <dl> - <dt><i>encoding</i></dt> - <dd> - <em style="color:red;">[NC]</em> - </dd> - <dt><i>style_compression</i></dt> - <dd> - <em style="color:red;">[NC]</em> - </dd> - <dt>Returns:</dt> - <dd> - An object of the <a href="#xlwt.Workbook-class">Workbook</a> class - </dd> - </dl> - <br /> -</dd> -<dt><a id='xlwt.Workbook.add_sheet-method' name='xlwt.Workbook.add_sheet-method'><b>add_sheet(sheetname)</b></a> [<a href='#xlwt.Workbook.add_sheet-method'>#</a>]</dt> -<dd> - <p> - This method is used to create Worksheets in a Workbook. - </p> - <dl> - <dt><i>sheetname</i></dt> - <dd> - The name to use for this sheet, as it will appear in the tabs at - the bottom of the Excel application. - </dd> - <dt>Returns:</dt> - <dd> - An object of the <a href="#xlwt.Worksheet-class">Worksheet</a> class - </dd> - </dl> - <br /> -</dd> -<dt><a id='xlwt.Workbook.save-method' name='xlwt.Workbook.save-method'><b>save(filename_or_stream)</b></a> [<a href='#xlwt.Workbook.save-method'>#</a>]</dt> -<dd> - <p> - This method is used to save Workbook to a file in native Excel format. - </p> - <dl> - <dt><i>filename_or_stream</i></dt> - <dd> - <p> - This can be a string containing a filename of the file, in which case - the excel file is saved to disk using the name provided. - </p> - <p> - It can also be a stream object with a write method, such as a - StringIO, in which case the data for the excel file is written - to the stream. - </p> - </dd> - </dl> - <br /> -</dd> -</dl> - -<h2><a id='xlwt.Worksheet-class' name='xlwt.Worksheet-class'>The Worksheet Class</a><em style="color:red;">[NC]</em></h2> -<dl> -<dt><b>Worksheet(sheetname, parent_book)</b> (class) [<a href='#xlwt.Worksheet-class'>#</a>]</dt> -<dd> - <p> - This is a class representing the contents of a sheet in a workbook. - </p> - <p> - WARNING: You don't normally create instances of this class - yourself. They are returned from calls to <a href="#xlwt.Workbook.add_sheet-method">Workbook.add_sheet</a> - </p> -</dd> -<dt><a id='xlwt.Worksheet.write-method' -name='xlwt.Worksheet.write-method'><b>write(r, c, label="", style=Style.default_style)</b></a> [<a href='#xlwt.Worksheet.write-method'>#</a>]</dt> -<dd> - <p> - This method is used to write a cell to a Worksheet.. - </p> - <dl> - <dt><i>r</i></dt> - <dd> - The zero-relative number of the row in the worksheet to which the cell should be written. - </dd> - <dt><i>c</i></dt> - <dd> - The zero-relative number of the column in the worksheet to which the cell should be written. - </dd> - <dt><i>label</i></dt> - <dd> - The data value to be written. - An int, long, or decimal.Decimal instance is converted to float. - A unicode instance is written as is. - A str instance is converted to unicode using the encoding (default: 'ascii') specified - when the Workbook instance was created. - A datetime.datetime, datetime.date, or datetime.time instance is converted into Excel date format - (a float representing the number of days since (typically) 1899-12-31T00:00:00, - under the pretence that 1900 was a leap year). - A bool instance will show up as TRUE or FALSE in Excel. - None causes the cell to be blank -- no data, only formatting. - An xlwt.Formula instance causes an Excel formula to be written. - <em style="color:red;">[NC]</em> - </dd> - <dt><i>style</i></dt> - <dd> - A style -- also known as an XF (extended format) -- is an XFStyle object, which encapsulates - the formatting applied to the cell and its contents. XFStyle objects are best set up using the - <i>easyxf</i> function. They may also be set up by setting attributes in - Alignment, Borders, Pattern, Font and Protection objects - then setting those objects and a format string as attributes of an XFStyle object. - <em style="color:red;">[NC]</em> - </dd> - </dl> - <br /> -</dd> -</dl> - -</body></html> diff --git a/tablib/packages/xlwt/examples/big-16Mb.py b/tablib/packages/xlwt/examples/big-16Mb.py deleted file mode 100644 index 91db123..0000000 --- a/tablib/packages/xlwt/examples/big-16Mb.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# tries stress SST, SAT and MSAT - -from time import * -from xlwt.Workbook import * -from xlwt.Style import * - -style = XFStyle() - -wb = Workbook() -ws0 = wb.add_sheet('0') - -colcount = 200 + 1 -rowcount = 6000 + 1 - -t0 = time() -print "\nstart: %s" % ctime(t0) - -print "Filling..." -for col in xrange(colcount): - print "[%d]" % col, - for row in xrange(rowcount): - #ws0.write(row, col, "BIG(%d, %d)" % (row, col)) - ws0.write(row, col, "BIG") - -t1 = time() - t0 -print "\nsince starting elapsed %.2f s" % (t1) - -print "Storing..." -wb.save('big-16Mb.xls') - -t2 = time() - t0 -print "since starting elapsed %.2f s" % (t2) - - diff --git a/tablib/packages/xlwt/examples/big-35Mb.py b/tablib/packages/xlwt/examples/big-35Mb.py deleted file mode 100644 index 74be5a7..0000000 --- a/tablib/packages/xlwt/examples/big-35Mb.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# tries stress SST, SAT and MSAT - -from time import * -from xlwt import * - -style = XFStyle() - -wb = Workbook() -ws0 = wb.add_sheet('0') - -colcount = 200 + 1 -rowcount = 6000 + 1 - -t0 = time() -print "\nstart: %s" % ctime(t0) - -print "Filling..." -for col in xrange(colcount): - print "[%d]" % col, - for row in xrange(rowcount): - ws0.write(row, col, "BIG(%d, %d)" % (row, col)) - #ws0.write(row, col, "BIG") - -t1 = time() - t0 -print "\nsince starting elapsed %.2f s" % (t1) - -print "Storing..." -wb.save('big-35Mb.xls') - -t2 = time() - t0 -print "since starting elapsed %.2f s" % (t2) - - diff --git a/tablib/packages/xlwt/examples/blanks.py b/tablib/packages/xlwt/examples/blanks.py deleted file mode 100644 index 056a3ec..0000000 --- a/tablib/packages/xlwt/examples/blanks.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -font0 = Font() -font0.name = 'Times New Roman' -font0.struck_out = True -font0.bold = True - -style0 = XFStyle() -style0.font = font0 - - -wb = Workbook() -ws0 = wb.add_sheet('0') - -ws0.write(1, 1, 'Test', style0) - -for i in range(0, 0x53): - borders = Borders() - borders.left = i - borders.right = i - borders.top = i - borders.bottom = i - - style = XFStyle() - style.borders = borders - - ws0.write(i, 2, '', style) - ws0.write(i, 3, hex(i), style0) - -ws0.write_merge(5, 8, 6, 10, "") - -wb.save('blanks.xls') diff --git a/tablib/packages/xlwt/examples/col_width.py b/tablib/packages/xlwt/examples/col_width.py deleted file mode 100644 index 6e6cb33..0000000 --- a/tablib/packages/xlwt/examples/col_width.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman -__rev_id__ = """$Id: col_width.py 3315 2008-03-14 14:44:52Z chris $""" - - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('Hey, Dude') - -for i in range(6, 80): - fnt = Font() - fnt.height = i*20 - style = XFStyle() - style.font = fnt - ws.write(1, i, 'Test') - ws.col(i).width = 0x0d00 + i -w.save('col_width.xls') diff --git a/tablib/packages/xlwt/examples/country.py b/tablib/packages/xlwt/examples/country.py deleted file mode 100644 index cb26e29..0000000 --- a/tablib/packages/xlwt/examples/country.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1252 -*- -# Copyright (C) 2007 John Machin - -from xlwt import * - -w = Workbook() -w.country_code = 61 -ws = w.add_sheet('AU') -w.save('country.xls') diff --git a/tablib/packages/xlwt/examples/dates.py b/tablib/packages/xlwt/examples/dates.py deleted file mode 100644 index 389b93b..0000000 --- a/tablib/packages/xlwt/examples/dates.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * -from datetime import datetime - -w = Workbook() -ws = w.add_sheet('Hey, Dude') - -fmts = [ - 'M/D/YY', - 'D-MMM-YY', - 'D-MMM', - 'MMM-YY', - 'h:mm AM/PM', - 'h:mm:ss AM/PM', - 'h:mm', - 'h:mm:ss', - 'M/D/YY h:mm', - 'mm:ss', - '[h]:mm:ss', - 'mm:ss.0', -] - -i = 0 -for fmt in fmts: - ws.write(i, 0, fmt) - - style = XFStyle() - style.num_format_str = fmt - - ws.write(i, 4, datetime.now(), style) - - i += 1 - -w.save('dates.xls') diff --git a/tablib/packages/xlwt/examples/format.py b/tablib/packages/xlwt/examples/format.py deleted file mode 100644 index fd49e0a..0000000 --- a/tablib/packages/xlwt/examples/format.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -font0 = Font() -font0.name = 'Times New Roman' -font0.struck_out = True -font0.bold = True - -style0 = XFStyle() -style0.font = font0 - - -wb = Workbook() -ws0 = wb.add_sheet('0') - -ws0.write(1, 1, 'Test', style0) - -for i in range(0, 0x53): - fnt = Font() - fnt.name = 'Arial' - fnt.colour_index = i - fnt.outline = True - - borders = Borders() - borders.left = i - - style = XFStyle() - style.font = fnt - style.borders = borders - - ws0.write(i, 2, 'colour', style) - ws0.write(i, 3, hex(i), style0) - - -wb.save('format.xls') diff --git a/tablib/packages/xlwt/examples/formula_names.py b/tablib/packages/xlwt/examples/formula_names.py deleted file mode 100644 index f0354bc..0000000 --- a/tablib/packages/xlwt/examples/formula_names.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * -from xlwt.ExcelFormulaParser import FormulaParseException - -w = Workbook() -ws = w.add_sheet('F') - -## This example is a little silly since the formula building is -## so simplistic that it often fails because the generated text -## has the wrong number of parameters for the function being -## tested. - -i = 0 -succeed_count = 0 -fail_count = 0 -for n in sorted(ExcelMagic.std_func_by_name): - ws.write(i, 0, n) - text = n + "($A$1)" - try: - formula = Formula(text) - except FormulaParseException,e: - print "Could not parse %r: %s" % (text,e.args[0]) - fail_count += 1 - else: - ws.write(i, 3, formula) - succeed_count += 1 - i += 1 - -w.save('formula_names.xls') - -print "succeeded with %i functions, failed with %i" % (succeed_count,fail_count) diff --git a/tablib/packages/xlwt/examples/formulas.py b/tablib/packages/xlwt/examples/formulas.py deleted file mode 100644 index b89f5f5..0000000 --- a/tablib/packages/xlwt/examples/formulas.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('F') - -ws.write(0, 0, Formula("-(1+1)")) -ws.write(1, 0, Formula("-(1+1)/(-2-2)")) -ws.write(2, 0, Formula("-(134.8780789+1)")) -ws.write(3, 0, Formula("-(134.8780789e-10+1)")) -ws.write(4, 0, Formula("-1/(1+1)+9344")) - -ws.write(0, 1, Formula("-(1+1)")) -ws.write(1, 1, Formula("-(1+1)/(-2-2)")) -ws.write(2, 1, Formula("-(134.8780789+1)")) -ws.write(3, 1, Formula("-(134.8780789e-10+1)")) -ws.write(4, 1, Formula("-1/(1+1)+9344")) - -ws.write(0, 2, Formula("A1*B1")) -ws.write(1, 2, Formula("A2*B2")) -ws.write(2, 2, Formula("A3*B3")) -ws.write(3, 2, Formula("A4*B4*sin(pi()/4)")) -ws.write(4, 2, Formula("A5%*B5*pi()/1000")) - -############## -## NOTE: parameters are separated by semicolon!!! -############## - - -ws.write(5, 2, Formula("C1+C2+C3+C4+C5/(C1+C2+C3+C4/(C1+C2+C3+C4/(C1+C2+C3+C4)+C5)+C5)-20.3e-2")) -ws.write(5, 3, Formula("C1^2")) -ws.write(6, 2, Formula("SUM(C1;C2;;;;;C3;;;C4)")) -ws.write(6, 3, Formula("SUM($A$1:$C$5)")) - -ws.write(7, 0, Formula('"lkjljllkllkl"')) -ws.write(7, 1, Formula('"yuyiyiyiyi"')) -ws.write(7, 2, Formula('A8 & B8 & A8')) -ws.write(8, 2, Formula('now()')) - -ws.write(10, 2, Formula('TRUE')) -ws.write(11, 2, Formula('FALSE')) -ws.write(12, 3, Formula('IF(A1>A2;3;"hkjhjkhk")')) - -w.save('formulas.xls') diff --git a/tablib/packages/xlwt/examples/hyperlinks.py b/tablib/packages/xlwt/examples/hyperlinks.py deleted file mode 100644 index 8de611b..0000000 --- a/tablib/packages/xlwt/examples/hyperlinks.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -f = Font() -f.height = 20*72 -f.name = 'Verdana' -f.bold = True -f.underline = Font.UNDERLINE_DOUBLE -f.colour_index = 4 - -h_style = XFStyle() -h_style.font = f - -w = Workbook() -ws = w.add_sheet('F') - -############## -## NOTE: parameters are separated by semicolon!!! -############## - -n = "HYPERLINK" -ws.write_merge(1, 1, 1, 10, Formula(n + '("http://www.irs.gov/pub/irs-pdf/f1000.pdf";"f1000.pdf")'), h_style) -ws.write_merge(2, 2, 2, 25, Formula(n + '("mailto:roman.kiseliov@gmail.com?subject=pyExcelerator-feedback&Body=Hello,%20Roman!";"pyExcelerator-feedback")'), h_style) - -w.save("hyperlinks.xls") diff --git a/tablib/packages/xlwt/examples/image.py b/tablib/packages/xlwt/examples/image.py deleted file mode 100644 index f926b8d..0000000 --- a/tablib/packages/xlwt/examples/image.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('Image') -ws.insert_bitmap('python.bmp', 2, 2) -ws.insert_bitmap('python.bmp', 10, 2) - -w.save('image.xls') diff --git a/tablib/packages/xlwt/examples/merged.py b/tablib/packages/xlwt/examples/merged.py deleted file mode 100644 index f7f9c57..0000000 --- a/tablib/packages/xlwt/examples/merged.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -fnt = Font() -fnt.name = 'Arial' -fnt.colour_index = 4 -fnt.bold = True - -borders = Borders() -borders.left = 6 -borders.right = 6 -borders.top = 6 -borders.bottom = 6 - -al = Alignment() -al.horz = Alignment.HORZ_CENTER -al.vert = Alignment.VERT_CENTER - -style = XFStyle() -style.font = fnt -style.borders = borders -style.alignment = al - - -wb = Workbook() -ws0 = wb.add_sheet('sheet0') -ws1 = wb.add_sheet('sheet1') -ws2 = wb.add_sheet('sheet2') - -for i in range(0, 0x200, 2): - ws0.write_merge(i, i+1, 1, 5, 'test %d' % i, style) - ws1.write_merge(i, i, 1, 7, 'test %d' % i, style) - ws2.write_merge(i, i+1, 1, 7 + (i%10), 'test %d' % i, style) - - -wb.save('merged.xls') diff --git a/tablib/packages/xlwt/examples/merged0.py b/tablib/packages/xlwt/examples/merged0.py deleted file mode 100644 index 93496c6..0000000 --- a/tablib/packages/xlwt/examples/merged0.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -wb = Workbook() -ws0 = wb.add_sheet('sheet0') - - -fnt = Font() -fnt.name = 'Arial' -fnt.colour_index = 4 -fnt.bold = True - -borders = Borders() -borders.left = 6 -borders.right = 6 -borders.top = 6 -borders.bottom = 6 - -style = XFStyle() -style.font = fnt -style.borders = borders - -ws0.write_merge(3, 3, 1, 5, 'test1', style) -ws0.write_merge(4, 10, 1, 5, 'test2', style) -ws0.col(1).width = 0x0d00 - -wb.save('merged0.xls') diff --git a/tablib/packages/xlwt/examples/merged1.py b/tablib/packages/xlwt/examples/merged1.py deleted file mode 100644 index 813530b..0000000 --- a/tablib/packages/xlwt/examples/merged1.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -wb = Workbook() -ws0 = wb.add_sheet('sheet0') - -fnt1 = Font() -fnt1.name = 'Verdana' -fnt1.bold = True -fnt1.height = 18*0x14 - -pat1 = Pattern() -pat1.pattern = Pattern.SOLID_PATTERN -pat1.pattern_fore_colour = 0x16 - -brd1 = Borders() -brd1.left = 0x06 -brd1.right = 0x06 -brd1.top = 0x06 -brd1.bottom = 0x06 - -fnt2 = Font() -fnt2.name = 'Verdana' -fnt2.bold = True -fnt2.height = 14*0x14 - -brd2 = Borders() -brd2.left = 0x01 -brd2.right = 0x01 -brd2.top = 0x01 -brd2.bottom = 0x01 - -pat2 = Pattern() -pat2.pattern = Pattern.SOLID_PATTERN -pat2.pattern_fore_colour = 0x01F - -fnt3 = Font() -fnt3.name = 'Verdana' -fnt3.bold = True -fnt3.italic = True -fnt3.height = 12*0x14 - -brd3 = Borders() -brd3.left = 0x07 -brd3.right = 0x07 -brd3.top = 0x07 -brd3.bottom = 0x07 - -fnt4 = Font() - -al1 = Alignment() -al1.horz = Alignment.HORZ_CENTER -al1.vert = Alignment.VERT_CENTER - -al2 = Alignment() -al2.horz = Alignment.HORZ_RIGHT -al2.vert = Alignment.VERT_CENTER - -al3 = Alignment() -al3.horz = Alignment.HORZ_LEFT -al3.vert = Alignment.VERT_CENTER - -style1 = XFStyle() -style1.font = fnt1 -style1.alignment = al1 -style1.pattern = pat1 -style1.borders = brd1 - -style2 = XFStyle() -style2.font = fnt2 -style2.alignment = al1 -style2.pattern = pat2 -style2.borders = brd2 - -style3 = XFStyle() -style3.font = fnt3 -style3.alignment = al1 -style3.pattern = pat2 -style3.borders = brd3 - -price_style = XFStyle() -price_style.font = fnt4 -price_style.alignment = al2 -price_style.borders = brd3 -price_style.num_format_str = '_(#,##0.00_) "money"' - -ware_style = XFStyle() -ware_style.font = fnt4 -ware_style.alignment = al3 -ware_style.borders = brd3 - - -ws0.merge(3, 3, 1, 5, style1) -ws0.merge(4, 10, 1, 6, style2) -ws0.merge(14, 16, 1, 7, style3) -ws0.col(1).width = 0x0d00 - - -wb.save('merged1.xls') diff --git a/tablib/packages/xlwt/examples/mini.py b/tablib/packages/xlwt/examples/mini.py deleted file mode 100644 index 61bb30c..0000000 --- a/tablib/packages/xlwt/examples/mini.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('xlwt was here') -w.save('mini.xls') diff --git a/tablib/packages/xlwt/examples/num_formats.py b/tablib/packages/xlwt/examples/num_formats.py deleted file mode 100644 index 3a56f6c..0000000 --- a/tablib/packages/xlwt/examples/num_formats.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('Hey, Dude') - -fmts = [ - 'general', - '0', - '0.00', - '#,##0', - '#,##0.00', - '"$"#,##0_);("$"#,##', - '"$"#,##0_);[Red]("$"#,##', - '"$"#,##0.00_);("$"#,##', - '"$"#,##0.00_);[Red]("$"#,##', - '0%', - '0.00%', - '0.00E+00', - '# ?/?', - '# ??/??', - 'M/D/YY', - 'D-MMM-YY', - 'D-MMM', - 'MMM-YY', - 'h:mm AM/PM', - 'h:mm:ss AM/PM', - 'h:mm', - 'h:mm:ss', - 'M/D/YY h:mm', - '_(#,##0_);(#,##0)', - '_(#,##0_);[Red](#,##0)', - '_(#,##0.00_);(#,##0.00)', - '_(#,##0.00_);[Red](#,##0.00)', - '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)', - '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)', - '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)', - '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)', - 'mm:ss', - '[h]:mm:ss', - 'mm:ss.0', - '##0.0E+0', - '@' -] - -i = 0 -for fmt in fmts: - ws.write(i, 0, fmt) - - style = XFStyle() - style.num_format_str = fmt - - ws.write(i, 4, -1278.9078, style) - - i += 1 - -w.save('num_formats.xls') diff --git a/tablib/packages/xlwt/examples/numbers.py b/tablib/packages/xlwt/examples/numbers.py deleted file mode 100644 index 524d9fc..0000000 --- a/tablib/packages/xlwt/examples/numbers.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('Hey, Dude') - -ws.write(0, 0, 1) -ws.write(1, 0, 1.23) -ws.write(2, 0, 12345678) -ws.write(3, 0, 123456.78) - -ws.write(0, 1, -1) -ws.write(1, 1, -1.23) -ws.write(2, 1, -12345678) -ws.write(3, 1, -123456.78) - -ws.write(0, 2, -17867868678687.0) -ws.write(1, 2, -1.23e-5) -ws.write(2, 2, -12345678.90780980) -ws.write(3, 2, -123456.78) - -w.save('numbers.xls') diff --git a/tablib/packages/xlwt/examples/outline.py b/tablib/packages/xlwt/examples/outline.py deleted file mode 100644 index 45b8df9..0000000 --- a/tablib/packages/xlwt/examples/outline.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -fnt = Font() -fnt.name = 'Arial' -fnt.colour_index = 4 -fnt.bold = True - -borders = Borders() -borders.left = 6 -borders.right = 6 -borders.top = 6 -borders.bottom = 6 - -style = XFStyle() -style.font = fnt -style.borders = borders - -wb = Workbook() - -ws0 = wb.add_sheet('Rows Outline') - -ws0.write_merge(1, 1, 1, 5, 'test 1', style) -ws0.write_merge(2, 2, 1, 4, 'test 1', style) -ws0.write_merge(3, 3, 1, 3, 'test 2', style) -ws0.write_merge(4, 4, 1, 4, 'test 1', style) -ws0.write_merge(5, 5, 1, 4, 'test 3', style) -ws0.write_merge(6, 6, 1, 5, 'test 1', style) -ws0.write_merge(7, 7, 1, 5, 'test 4', style) -ws0.write_merge(8, 8, 1, 4, 'test 1', style) -ws0.write_merge(9, 9, 1, 3, 'test 5', style) - -ws0.row(1).level = 1 -ws0.row(2).level = 1 -ws0.row(3).level = 2 -ws0.row(4).level = 2 -ws0.row(5).level = 2 -ws0.row(6).level = 2 -ws0.row(7).level = 2 -ws0.row(8).level = 1 -ws0.row(9).level = 1 - - -ws1 = wb.add_sheet('Columns Outline') - -ws1.write_merge(1, 1, 1, 5, 'test 1', style) -ws1.write_merge(2, 2, 1, 4, 'test 1', style) -ws1.write_merge(3, 3, 1, 3, 'test 2', style) -ws1.write_merge(4, 4, 1, 4, 'test 1', style) -ws1.write_merge(5, 5, 1, 4, 'test 3', style) -ws1.write_merge(6, 6, 1, 5, 'test 1', style) -ws1.write_merge(7, 7, 1, 5, 'test 4', style) -ws1.write_merge(8, 8, 1, 4, 'test 1', style) -ws1.write_merge(9, 9, 1, 3, 'test 5', style) - -ws1.col(1).level = 1 -ws1.col(2).level = 1 -ws1.col(3).level = 2 -ws1.col(4).level = 2 -ws1.col(5).level = 2 -ws1.col(6).level = 2 -ws1.col(7).level = 2 -ws1.col(8).level = 1 -ws1.col(9).level = 1 - - -ws2 = wb.add_sheet('Rows and Columns Outline') - -ws2.write_merge(1, 1, 1, 5, 'test 1', style) -ws2.write_merge(2, 2, 1, 4, 'test 1', style) -ws2.write_merge(3, 3, 1, 3, 'test 2', style) -ws2.write_merge(4, 4, 1, 4, 'test 1', style) -ws2.write_merge(5, 5, 1, 4, 'test 3', style) -ws2.write_merge(6, 6, 1, 5, 'test 1', style) -ws2.write_merge(7, 7, 1, 5, 'test 4', style) -ws2.write_merge(8, 8, 1, 4, 'test 1', style) -ws2.write_merge(9, 9, 1, 3, 'test 5', style) - -ws2.row(1).level = 1 -ws2.row(2).level = 1 -ws2.row(3).level = 2 -ws2.row(4).level = 2 -ws2.row(5).level = 2 -ws2.row(6).level = 2 -ws2.row(7).level = 2 -ws2.row(8).level = 1 -ws2.row(9).level = 1 - -ws2.write_merge(1, 1, 1, 5, 'test 1', style) -ws2.write_merge(2, 2, 1, 4, 'test 1', style) -ws2.write_merge(3, 3, 1, 3, 'test 2', style) -ws2.write_merge(4, 4, 1, 4, 'test 1', style) -ws2.write_merge(5, 5, 1, 4, 'test 3', style) -ws2.write_merge(6, 6, 1, 5, 'test 1', style) -ws2.write_merge(7, 7, 1, 5, 'test 4', style) -ws2.write_merge(8, 8, 1, 4, 'test 1', style) -ws2.write_merge(9, 9, 1, 3, 'test 5', style) - -ws2.col(1).level = 1 -ws2.col(2).level = 1 -ws2.col(3).level = 2 -ws2.col(4).level = 2 -ws2.col(5).level = 2 -ws2.col(6).level = 2 -ws2.col(7).level = 2 -ws2.col(8).level = 1 -ws2.col(9).level = 1 - - -wb.save('outline.xls') diff --git a/tablib/packages/xlwt/examples/panes.py b/tablib/packages/xlwt/examples/panes.py deleted file mode 100644 index 9fd83b0..0000000 --- a/tablib/packages/xlwt/examples/panes.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws1 = w.add_sheet('sheet 1') -ws2 = w.add_sheet('sheet 2') -ws3 = w.add_sheet('sheet 3') -ws4 = w.add_sheet('sheet 4') -ws5 = w.add_sheet('sheet 5') -ws6 = w.add_sheet('sheet 6') - -for i in range(0x100): - ws1.write(i/0x10, i%0x10, i) - -for i in range(0x100): - ws2.write(i/0x10, i%0x10, i) - -for i in range(0x100): - ws3.write(i/0x10, i%0x10, i) - -for i in range(0x100): - ws4.write(i/0x10, i%0x10, i) - -for i in range(0x100): - ws5.write(i/0x10, i%0x10, i) - -for i in range(0x100): - ws6.write(i/0x10, i%0x10, i) - -ws1.panes_frozen = True -ws1.horz_split_pos = 2 - -ws2.panes_frozen = True -ws2.vert_split_pos = 2 - -ws3.panes_frozen = True -ws3.horz_split_pos = 1 -ws3.vert_split_pos = 1 - -ws4.panes_frozen = False -ws4.horz_split_pos = 12 -ws4.horz_split_first_visible = 2 - -ws5.panes_frozen = False -ws5.vert_split_pos = 40 -ws4.vert_split_first_visible = 2 - -ws6.panes_frozen = False -ws6.horz_split_pos = 12 -ws4.horz_split_first_visible = 2 -ws6.vert_split_pos = 40 -ws4.vert_split_first_visible = 2 - -w.save('panes.xls') - diff --git a/tablib/packages/xlwt/examples/parse-fmla.py b/tablib/packages/xlwt/examples/parse-fmla.py deleted file mode 100644 index 06f68eb..0000000 --- a/tablib/packages/xlwt/examples/parse-fmla.py +++ /dev/null @@ -1,12 +0,0 @@ -from xlwt import ExcelFormulaParser, ExcelFormula -import sys - -f = ExcelFormula.Formula( -""" -((1.80 + 2.898 * 1)/(1.80 + 2.898))* -AVERAGE((1.80 + 2.898 * 1)/(1.80 + 2.898); - (1.80 + 2.898 * 1)/(1.80 + 2.898); - (1.80 + 2.898 * 1)/(1.80 + 2.898)) + -SIN(PI()/4)""") - -#for t in f.rpn(): -# print "%15s %15s" % (ExcelFormulaParser.PtgNames[t[0]], t[1]) diff --git a/tablib/packages/xlwt/examples/protection.py b/tablib/packages/xlwt/examples/protection.py deleted file mode 100644 index db54cb0..0000000 --- a/tablib/packages/xlwt/examples/protection.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -fnt = Font() -fnt.name = 'Arial' -fnt.colour_index = 4 -fnt.bold = True - -borders = Borders() -borders.left = 6 -borders.right = 6 -borders.top = 6 -borders.bottom = 6 - -style = XFStyle() -style.font = fnt -style.borders = borders - -wb = Workbook() - -ws0 = wb.add_sheet('Rows Outline') - -ws0.write_merge(1, 1, 1, 5, 'test 1', style) -ws0.write_merge(2, 2, 1, 4, 'test 1', style) -ws0.write_merge(3, 3, 1, 3, 'test 2', style) -ws0.write_merge(4, 4, 1, 4, 'test 1', style) -ws0.write_merge(5, 5, 1, 4, 'test 3', style) -ws0.write_merge(6, 6, 1, 5, 'test 1', style) -ws0.write_merge(7, 7, 1, 5, 'test 4', style) -ws0.write_merge(8, 8, 1, 4, 'test 1', style) -ws0.write_merge(9, 9, 1, 3, 'test 5', style) - -ws0.row(1).level = 1 -ws0.row(2).level = 1 -ws0.row(3).level = 2 -ws0.row(4).level = 2 -ws0.row(5).level = 2 -ws0.row(6).level = 2 -ws0.row(7).level = 2 -ws0.row(8).level = 1 -ws0.row(9).level = 1 - - -ws1 = wb.add_sheet('Columns Outline') - -ws1.write_merge(1, 1, 1, 5, 'test 1', style) -ws1.write_merge(2, 2, 1, 4, 'test 1', style) -ws1.write_merge(3, 3, 1, 3, 'test 2', style) -ws1.write_merge(4, 4, 1, 4, 'test 1', style) -ws1.write_merge(5, 5, 1, 4, 'test 3', style) -ws1.write_merge(6, 6, 1, 5, 'test 1', style) -ws1.write_merge(7, 7, 1, 5, 'test 4', style) -ws1.write_merge(8, 8, 1, 4, 'test 1', style) -ws1.write_merge(9, 9, 1, 3, 'test 5', style) - -ws1.col(1).level = 1 -ws1.col(2).level = 1 -ws1.col(3).level = 2 -ws1.col(4).level = 2 -ws1.col(5).level = 2 -ws1.col(6).level = 2 -ws1.col(7).level = 2 -ws1.col(8).level = 1 -ws1.col(9).level = 1 - - -ws2 = wb.add_sheet('Rows and Columns Outline') - -ws2.write_merge(1, 1, 1, 5, 'test 1', style) -ws2.write_merge(2, 2, 1, 4, 'test 1', style) -ws2.write_merge(3, 3, 1, 3, 'test 2', style) -ws2.write_merge(4, 4, 1, 4, 'test 1', style) -ws2.write_merge(5, 5, 1, 4, 'test 3', style) -ws2.write_merge(6, 6, 1, 5, 'test 1', style) -ws2.write_merge(7, 7, 1, 5, 'test 4', style) -ws2.write_merge(8, 8, 1, 4, 'test 1', style) -ws2.write_merge(9, 9, 1, 3, 'test 5', style) - -ws2.row(1).level = 1 -ws2.row(2).level = 1 -ws2.row(3).level = 2 -ws2.row(4).level = 2 -ws2.row(5).level = 2 -ws2.row(6).level = 2 -ws2.row(7).level = 2 -ws2.row(8).level = 1 -ws2.row(9).level = 1 - -ws2.col(1).level = 1 -ws2.col(2).level = 1 -ws2.col(3).level = 2 -ws2.col(4).level = 2 -ws2.col(5).level = 2 -ws2.col(6).level = 2 -ws2.col(7).level = 2 -ws2.col(8).level = 1 -ws2.col(9).level = 1 - - -ws0.protect = True -ws0.wnd_protect = True -ws0.obj_protect = True -ws0.scen_protect = True -ws0.password = "123456" - -ws1.protect = True -ws1.wnd_protect = True -ws1.obj_protect = True -ws1.scen_protect = True -ws1.password = "abcdefghij" - -ws2.protect = True -ws2.wnd_protect = True -ws2.obj_protect = True -ws2.scen_protect = True -ws2.password = "ok" - -wb.protect = True -wb.wnd_protect = True -wb.obj_protect = True -wb.save('protection.xls') diff --git a/tablib/packages/xlwt/examples/python.bmp b/tablib/packages/xlwt/examples/python.bmp Binary files differdeleted file mode 100644 index bd1ba3f..0000000 --- a/tablib/packages/xlwt/examples/python.bmp +++ /dev/null diff --git a/tablib/packages/xlwt/examples/row_styles.py b/tablib/packages/xlwt/examples/row_styles.py deleted file mode 100644 index dd6d494..0000000 --- a/tablib/packages/xlwt/examples/row_styles.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws = w.add_sheet('Hey, Dude') - -for i in range(6, 80): - fnt = Font() - fnt.height = i*20 - style = XFStyle() - style.font = fnt - ws.write(i, 1, 'Test') - ws.row(i).set_style(style) -w.save('row_styles.xls') diff --git a/tablib/packages/xlwt/examples/row_styles_empty.py b/tablib/packages/xlwt/examples/row_styles_empty.py deleted file mode 100644 index cf6a65c..0000000 --- a/tablib/packages/xlwt/examples/row_styles_empty.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman -__rev_id__ = """$Id: row_styles_empty.py 3309 2008-03-14 11:04:30Z chris $""" - - -from pyExcelerator import * - -w = Workbook() -ws = w.add_sheet('Hey, Dude') - -for i in range(6, 80): - fnt = Font() - fnt.height = i*20 - style = XFStyle() - style.font = fnt - ws.row(i).set_style(style) -w.save('row_styles_empty.xls') diff --git a/tablib/packages/xlwt/examples/simple.py b/tablib/packages/xlwt/examples/simple.py deleted file mode 100644 index 44f7622..0000000 --- a/tablib/packages/xlwt/examples/simple.py +++ /dev/null @@ -1,24 +0,0 @@ -import xlwt -from datetime import datetime - -font0 = xlwt.Font() -font0.name = 'Times New Roman' -font0.colour_index = 2 -font0.bold = True - -style0 = xlwt.XFStyle() -style0.font = font0 - -style1 = xlwt.XFStyle() -style1.num_format_str = 'D-MMM-YY' - -wb = xlwt.Workbook() -ws = wb.add_sheet('A Test Sheet') - -ws.write(0, 0, 'Test', style0) -ws.write(1, 0, datetime.now(), style1) -ws.write(2, 0, 1) -ws.write(2, 1, 1) -ws.write(2, 2, xlwt.Formula("A3+B3")) - -wb.save('example.xls') diff --git a/tablib/packages/xlwt/examples/sst.py b/tablib/packages/xlwt/examples/sst.py deleted file mode 100644 index b91c2f5..0000000 --- a/tablib/packages/xlwt/examples/sst.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -font0 = Formatting.Font() -font0.name = 'Arial' -font1 = Formatting.Font() -font1.name = 'Arial Cyr' -font2 = Formatting.Font() -font2.name = 'Times New Roman' -font3 = Formatting.Font() -font3.name = 'Courier New Cyr' - -num_format0 = '0.00000' -num_format1 = '0.000000' -num_format2 = '0.0000000' -num_format3 = '0.00000000' - -st0 = XFStyle() -st1 = XFStyle() -st2 = XFStyle() -st3 = XFStyle() -st4 = XFStyle() - -st0.font = font0 -st0.num_format = num_format0 - -st1.font = font1 -st1.num_format = num_format1 - -st2.font = font2 -st2.num_format = num_format2 - -st3.font = font3 -st3.num_format = num_format3 - -wb = Workbook() - -wb.add_style(st0) -wb.add_style(st1) -wb.add_style(st2) -wb.add_style(st3) - -ws0 = wb.add_sheet('0') -ws0.write(0, 0, 'Olya'*0x4000, st0) - -#for i in range(0, 0x10): -# ws0.write(i, 2, ('%d'%i)*0x4000, st1) - -wb.save('sst.xls') diff --git a/tablib/packages/xlwt/examples/unicode0.py b/tablib/packages/xlwt/examples/unicode0.py deleted file mode 100644 index 3651ec9..0000000 --- a/tablib/packages/xlwt/examples/unicode0.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -import xlwt - -# Strings passed to (for example) Worksheet.write can be unicode objects, -# or str (8-bit) objects, which are then decoded into unicode. -# The encoding to be used defaults to 'ascii'. This can be overridden -# when the Workbook instance is created: - -book = xlwt.Workbook(encoding='cp1251') -sheet = book.add_sheet('cp1251-demo') -sheet.write(0, 0, '\xce\xeb\xff') -book.save('unicode0.xls') diff --git a/tablib/packages/xlwt/examples/unicode1.py b/tablib/packages/xlwt/examples/unicode1.py deleted file mode 100644 index 90e99cc..0000000 --- a/tablib/packages/xlwt/examples/unicode1.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws1 = w.add_sheet(u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER BETA}\N{GREEK SMALL LETTER GAMMA}') - -ws1.write(0, 0, u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER BETA}\N{GREEK SMALL LETTER GAMMA}') -ws1.write(1, 1, u'\N{GREEK SMALL LETTER DELTA}x = 1 + \N{GREEK SMALL LETTER DELTA}') - -ws1.write(2,0, u'A\u2262\u0391.') # RFC2152 example -ws1.write(3,0, u'Hi Mom -\u263a-!') # RFC2152 example -ws1.write(4,0, u'\u65E5\u672C\u8A9E') # RFC2152 example -ws1.write(5,0, u'Item 3 is \u00a31.') # RFC2152 example -ws1.write(8,0, u'\N{INTEGRAL}') # RFC2152 example - -w.add_sheet(u'A\u2262\u0391.') # RFC2152 example -w.add_sheet(u'Hi Mom -\u263a-!') # RFC2152 example -one_more_ws = w.add_sheet(u'\u65E5\u672C\u8A9E') # RFC2152 example -w.add_sheet(u'Item 3 is \u00a31.') # RFC2152 example - -one_more_ws.write(0, 0, u'\u2665\u2665') - -w.add_sheet(u'\N{GREEK SMALL LETTER ETA WITH TONOS}') -w.save('unicode1.xls') - diff --git a/tablib/packages/xlwt/examples/unicode2.py b/tablib/packages/xlwt/examples/unicode2.py deleted file mode 100644 index 18904b0..0000000 --- a/tablib/packages/xlwt/examples/unicode2.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python -# -*- coding: windows-1251 -*- -# Copyright (C) 2005 Kiseliov Roman - -from xlwt import * - -w = Workbook() -ws1 = w.add_sheet(u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER BETA}\N{GREEK SMALL LETTER GAMMA}\u2665\u041e\u041b\u042f\u2665') - -fnt = Font() -fnt.height = 26*20 -style = XFStyle() -style.font = fnt - -for i in range(0x10000): - ws1.write(i/0x10, i%0x10, unichr(i), style) - -w.save('unicode2.xls') - diff --git a/tablib/packages/xlwt/examples/wsprops.py b/tablib/packages/xlwt/examples/wsprops.py deleted file mode 100644 index adc5a04..0000000 --- a/tablib/packages/xlwt/examples/wsprops.py +++ /dev/null @@ -1,155 +0,0 @@ -props = \ -[ - 'name', - 'parent', - 'rows', - 'cols', - 'merged_ranges', - 'bmp_rec', - 'show_formulas', - 'show_grid', - 'show_headers', - 'panes_frozen', - 'show_empty_as_zero', - 'auto_colour_grid', - 'cols_right_to_left', - 'show_outline', - 'remove_splits', - 'selected', - 'hidden', - 'page_preview', - 'first_visible_row', - 'first_visible_col', - 'grid_colour', - 'preview_magn', - 'normal_magn', - 'row_gut_width', - 'col_gut_height', - 'show_auto_page_breaks', - 'dialogue_sheet', - 'auto_style_outline', - 'outline_below', - 'outline_right', - 'fit_num_pages', - 'show_row_outline', - 'show_col_outline', - 'alt_expr_eval', - 'alt_formula_entries', - 'row_default_height', - 'col_default_width', - 'calc_mode', - 'calc_count', - 'RC_ref_mode', - 'iterations_on', - 'delta', - 'save_recalc', - 'print_headers', - 'print_grid', - 'grid_set', - 'vert_page_breaks', - 'horz_page_breaks', - 'header_str', - 'footer_str', - 'print_centered_vert', - 'print_centered_horz', - 'left_margin', - 'right_margin', - 'top_margin', - 'bottom_margin', - 'paper_size_code', - 'print_scaling', - 'start_page_number', - 'fit_width_to_pages', - 'fit_height_to_pages', - 'print_in_rows', - 'portrait', - 'print_not_colour', - 'print_draft', - 'print_notes', - 'print_notes_at_end', - 'print_omit_errors', - 'print_hres', - 'print_vres', - 'header_margin', - 'footer_margin', - 'copies_num', -] - -from xlwt import * - -wb = Workbook() -ws = wb.add_sheet('sheet') - -print ws.name -print ws.parent -print ws.rows -print ws.cols -print ws.merged_ranges -print ws.bmp_rec -print ws.show_formulas -print ws.show_grid -print ws.show_headers -print ws.panes_frozen -print ws.show_empty_as_zero -print ws.auto_colour_grid -print ws.cols_right_to_left -print ws.show_outline -print ws.remove_splits -print ws.selected -# print ws.hidden -print ws.page_preview -print ws.first_visible_row -print ws.first_visible_col -print ws.grid_colour -print ws.preview_magn -print ws.normal_magn -#print ws.row_gut_width -#print ws.col_gut_height -print ws.show_auto_page_breaks -print ws.dialogue_sheet -print ws.auto_style_outline -print ws.outline_below -print ws.outline_right -print ws.fit_num_pages -print ws.show_row_outline -print ws.show_col_outline -print ws.alt_expr_eval -print ws.alt_formula_entries -print ws.row_default_height -print ws.col_default_width -print ws.calc_mode -print ws.calc_count -print ws.RC_ref_mode -print ws.iterations_on -print ws.delta -print ws.save_recalc -print ws.print_headers -print ws.print_grid -#print ws.grid_set -print ws.vert_page_breaks -print ws.horz_page_breaks -print ws.header_str -print ws.footer_str -print ws.print_centered_vert -print ws.print_centered_horz -print ws.left_margin -print ws.right_margin -print ws.top_margin -print ws.bottom_margin -print ws.paper_size_code -print ws.print_scaling -print ws.start_page_number -print ws.fit_width_to_pages -print ws.fit_height_to_pages -print ws.print_in_rows -print ws.portrait -print ws.print_colour -print ws.print_draft -print ws.print_notes -print ws.print_notes_at_end -print ws.print_omit_errors -print ws.print_hres -print ws.print_vres -print ws.header_margin -print ws.footer_margin -print ws.copies_num diff --git a/tablib/packages/xlwt/examples/xlwt_easyxf_simple_demo.py b/tablib/packages/xlwt/examples/xlwt_easyxf_simple_demo.py deleted file mode 100644 index 2afa69f..0000000 --- a/tablib/packages/xlwt/examples/xlwt_easyxf_simple_demo.py +++ /dev/null @@ -1,46 +0,0 @@ - -# Write an XLS file with a single worksheet, containing -# a heading row and some rows of data. - -import xlwt -import datetime -ezxf = xlwt.easyxf - -def write_xls(file_name, sheet_name, headings, data, heading_xf, data_xfs): - book = xlwt.Workbook() - sheet = book.add_sheet(sheet_name) - rowx = 0 - for colx, value in enumerate(headings): - sheet.write(rowx, colx, value, heading_xf) - sheet.set_panes_frozen(True) # frozen headings instead of split panes - sheet.set_horz_split_pos(rowx+1) # in general, freeze after last heading row - sheet.set_remove_splits(True) # if user does unfreeze, don't leave a split there - for row in data: - rowx += 1 - for colx, value in enumerate(row): - sheet.write(rowx, colx, value, data_xfs[colx]) - book.save(file_name) - -if __name__ == '__main__': - import sys - mkd = datetime.date - hdngs = ['Date', 'Stock Code', 'Quantity', 'Unit Price', 'Value', 'Message'] - kinds = 'date text int price money text'.split() - data = [ - [mkd(2007, 7, 1), 'ABC', 1000, 1.234567, 1234.57, ''], - [mkd(2007, 12, 31), 'XYZ', -100, 4.654321, -465.43, 'Goods returned'], - ] + [ - [mkd(2008, 6, 30), 'PQRCD', 100, 2.345678, 234.57, ''], - ] * 100 - - heading_xf = ezxf('font: bold on; align: wrap on, vert centre, horiz center') - kind_to_xf_map = { - 'date': ezxf(num_format_str='yyyy-mm-dd'), - 'int': ezxf(num_format_str='#,##0'), - 'money': ezxf('font: italic on; pattern: pattern solid, fore-colour grey25', - num_format_str='$#,##0.00'), - 'price': ezxf(num_format_str='#0.000000'), - 'text': ezxf(), - } - data_xfs = [kind_to_xf_map[k] for k in kinds] - write_xls('xlwt_easyxf_simple_demo.xls', 'Demo', hdngs, data, heading_xf, data_xfs) diff --git a/tablib/packages/xlwt/excel-formula.g b/tablib/packages/xlwt/excel-formula.g deleted file mode 100644 index d98d9b9..0000000 --- a/tablib/packages/xlwt/excel-formula.g +++ /dev/null @@ -1,374 +0,0 @@ -header { - import struct - import Utils - from UnicodeUtils import upack1 - from ExcelMagic import * - - _RVAdelta = {"R": 0, "V": 0x20, "A": 0x40} - _RVAdeltaRef = {"R": 0, "V": 0x20, "A": 0x40, "D": 0x20} - _RVAdeltaArea = {"R": 0, "V": 0x20, "A": 0x40, "D": 0} - - - class FormulaParseException(Exception): - """ - An exception indicating that a Formula could not be successfully parsed. - """ -} - -header "ExcelFormulaParser.__init__" { - self.rpn = "" - self.sheet_references = [] - self.xcall_references = [] -} - -options { - language = "Python"; -} - -class ExcelFormulaParser extends Parser; -options { - k = 2; - defaultErrorHandler = false; - buildAST = false; -} - - -tokens { - TRUE_CONST; - FALSE_CONST; - STR_CONST; - NUM_CONST; - INT_CONST; - - FUNC_IF; - FUNC_CHOOSE; - NAME; - QUOTENAME; - - EQ; - NE; - GT; - LT; - GE; - LE; - - ADD; - SUB; - MUL; - DIV; - - POWER; - PERCENT; - - LP; - RP; - - LB; - RB; - - COLON; - COMMA; - SEMICOLON; - REF2D; - REF2D_R1C1; - BANG; -} - -formula - : expr["V"] - ; - -expr[arg_type] - : // {print "\n**expr %s" % arg_type} - prec0_expr[arg_type] - ( - ( - EQ { op = struct.pack('B', ptgEQ) } - | NE { op = struct.pack('B', ptgNE) } - | GT { op = struct.pack('B', ptgGT) } - | LT { op = struct.pack('B', ptgLT) } - | GE { op = struct.pack('B', ptgGE) } - | LE { op = struct.pack('B', ptgLE) } - ) - prec0_expr[arg_type] { self.rpn += op } - )* - ; - -prec0_expr[arg_type] - : prec1_expr[arg_type] - ( - ( - CONCAT { op = struct.pack('B', ptgConcat) } - ) - prec1_expr[arg_type] { self.rpn += op } - )* - ; - -prec1_expr[arg_type] - : // {print "**prec1_expr1 %s" % arg_type} - prec2_expr[arg_type] - // {print "**prec1_expr2 %s" % arg_type} - ( - ( - ADD { op = struct.pack('B', ptgAdd) } - | SUB { op = struct.pack('B', ptgSub) } - ) - // {print "**prec1_expr3 %s" % arg_type} - prec2_expr[arg_type] - { self.rpn += op; - // print "**prec1_expr4 %s" % arg_type - } - )* - ; - - -prec2_expr[arg_type] - : prec3_expr[arg_type] - ( - ( - MUL { op = struct.pack('B', ptgMul) } - | DIV { op = struct.pack('B', ptgDiv) } - ) - prec3_expr[arg_type] { self.rpn += op } - )* - ; - -prec3_expr[arg_type] - : prec4_expr[arg_type] - ( - ( - POWER { op = struct.pack('B', ptgPower) } - ) - prec4_expr[arg_type] { self.rpn += op } - )* - ; - -prec4_expr[arg_type] - : prec5_expr[arg_type] - ( - PERCENT { self.rpn += struct.pack('B', ptgPercent) } - )? - ; - -prec5_expr[arg_type] - : primary[arg_type] - | SUB primary[arg_type] { self.rpn += struct.pack('B', ptgUminus) } - ; - -primary[arg_type] - : TRUE_CONST - { - self.rpn += struct.pack("2B", ptgBool, 1) - } - | FALSE_CONST - { - self.rpn += struct.pack("2B", ptgBool, 0) - } - | str_tok:STR_CONST - { - self.rpn += struct.pack("B", ptgStr) + upack1(str_tok.text[1:-1].replace("\"\"", "\"")) - } - | int_tok:INT_CONST - { - // print "**int_const", int_tok.text - int_value = int(int_tok.text) - if int_value <= 65535: - self.rpn += struct.pack("<BH", ptgInt, int_value) - else: - self.rpn += struct.pack("<Bd", ptgNum, float(int_value)) - } - | num_tok:NUM_CONST - { - self.rpn += struct.pack("<Bd", ptgNum, float(num_tok.text)) - } - | ref2d_tok:REF2D - { - // print "**ref2d %s %s" % (ref2d_tok.text, arg_type) - r, c = Utils.cell_to_packed_rowcol(ref2d_tok.text) - ptg = ptgRefR + _RVAdeltaRef[arg_type] - self.rpn += struct.pack("<B2H", ptg, r, c) - } - | ref2d1_tok:REF2D COLON ref2d2_tok:REF2D - { - r1, c1 = Utils.cell_to_packed_rowcol(ref2d1_tok.text) - r2, c2 = Utils.cell_to_packed_rowcol(ref2d2_tok.text) - ptg = ptgAreaR + _RVAdeltaArea[arg_type] - self.rpn += struct.pack("<B4H", ptg, r1, r2, c1, c2) - } - | sheet1 = sheet - { - sheet2 = sheet1 - } - ( COLON sheet2 = sheet )? BANG ref3d_ref2d: REF2D - { - ptg = ptgRef3dR + _RVAdeltaRef[arg_type] - rpn_ref2d = "" - r1, c1 = Utils.cell_to_packed_rowcol(ref3d_ref2d.text) - rpn_ref2d = struct.pack("<3H", 0x0000, r1, c1) - } - ( COLON ref3d_ref2d2: REF2D - { - ptg = ptgArea3dR + _RVAdeltaArea[arg_type] - r2, c2 = Utils.cell_to_packed_rowcol(ref3d_ref2d2.text) - rpn_ref2d = struct.pack("<5H", 0x0000, r1, r2, c1, c2) - } - )? - { - self.rpn += struct.pack("<B", ptg) - self.sheet_references.append((sheet1, sheet2, len(self.rpn))) - self.rpn += rpn_ref2d - } - | FUNC_IF - LP expr["V"] (SEMICOLON | COMMA) - { - self.rpn += struct.pack("<BBH", ptgAttr, 0x02, 0) // tAttrIf - pos0 = len(self.rpn) - 2 - } - expr[arg_type] (SEMICOLON | COMMA) - { - self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 0) // tAttrSkip - pos1 = len(self.rpn) - 2 - self.rpn = self.rpn[:pos0] + struct.pack("<H", pos1-pos0) + self.rpn[pos0+2:] - } - expr[arg_type] RP - { - self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 3) // tAttrSkip - self.rpn += struct.pack("<BBH", ptgFuncVarR, 3, 1) // 3 = nargs, 1 = IF func - pos2 = len(self.rpn) - self.rpn = self.rpn[:pos1] + struct.pack("<H", pos2-(pos1+2)-1) + self.rpn[pos1+2:] - } - | FUNC_CHOOSE - { - arg_type = "R" - rpn_chunks = [] - } - LP expr["V"] // first argument (the selector) - { - rpn_start = len(self.rpn) - ref_markers = [len(self.sheet_references)] - } - ( - (SEMICOLON | COMMA) - { mark = len(self.rpn) } - ( - expr[arg_type] - | { self.rpn += struct.pack("B", ptgMissArg) } - ) - { - rpn_chunks.append(self.rpn[mark:]) - ref_markers.append(len(self.sheet_references)) - } - )* - RP - { - self.rpn = self.rpn[:rpn_start] - nc = len(rpn_chunks) - chunklens = [len(chunk) for chunk in rpn_chunks] - skiplens = [0] * nc - skiplens[-1] = 3 - for ic in xrange(nc-1, 0, -1): - skiplens[ic-1] = skiplens[ic] + chunklens[ic] + 4 - jump_pos = [2 * nc + 2] - for ic in xrange(nc): - jump_pos.append(jump_pos[-1] + chunklens[ic] + 4) - chunk_shift = 2 * nc + 6 // size of tAttrChoose - for ic in xrange(nc): - for refx in xrange(ref_markers[ic], ref_markers[ic+1]): - ref = self.sheet_references[refx] - self.sheet_references[refx] = (ref[0], ref[1], ref[2] + chunk_shift) - chunk_shift += 4 // size of tAttrSkip - choose_rpn = [] - choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x04, nc)) // 0x04 is tAttrChoose - choose_rpn.append(struct.pack("<%dH" % (nc+1), *jump_pos)) - for ic in xrange(nc): - choose_rpn.append(rpn_chunks[ic]) - choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x08, skiplens[ic])) // 0x08 is tAttrSkip - choose_rpn.append(struct.pack("<BBH", ptgFuncVarV, nc+1, 100)) // 100 is CHOOSE fn - self.rpn += "".join(choose_rpn) - } - | name_tok:NAME - { - raise Exception("[formula] found unexpected NAME token (%r)" % name_tok.txt) - // #### TODO: handle references to defined names here - } - | func_tok:NAME - { - func_toku = func_tok.text.upper() - if func_toku in all_funcs_by_name: - (opcode, - min_argc, - max_argc, - func_type, - arg_type_str) = all_funcs_by_name[func_toku] - arg_type_list = list(arg_type_str) - else: - raise Exception("[formula] unknown function (%s)" % func_tok.text) - // print "**func_tok1 %s %s" % (func_toku, func_type) - xcall = opcode < 0 - if xcall: - // The name of the add-in function is passed as the 1st arg - // of the hidden XCALL function - self.xcall_references.append((func_toku, len(self.rpn) + 1)) - self.rpn += struct.pack("<BHHH", - ptgNameXR, - 0xadde, // ##PATCHME## index to REF entry in EXTERNSHEET record - 0xefbe, // ##PATCHME## one-based index to EXTERNNAME record - 0x0000) // unused - } - LP arg_count = expr_list[arg_type_list, min_argc, max_argc] RP - { - if arg_count > max_argc or arg_count < min_argc: - raise Exception, "%d parameters for function: %s" % (arg_count, func_tok.text) - if xcall: - func_ptg = ptgFuncVarR + _RVAdelta[func_type] - self.rpn += struct.pack("<2BH", func_ptg, arg_count + 1, 255) // 255 is magic XCALL function - elif min_argc == max_argc: - func_ptg = ptgFuncR + _RVAdelta[func_type] - self.rpn += struct.pack("<BH", func_ptg, opcode) - elif arg_count == 1 and func_tok.text.upper() == "SUM": - self.rpn += struct.pack("<BBH", ptgAttr, 0x10, 0) // tAttrSum - else: - func_ptg = ptgFuncVarR + _RVAdelta[func_type] - self.rpn += struct.pack("<2BH", func_ptg, arg_count, opcode) - } - | LP expr[arg_type] RP - { - self.rpn += struct.pack("B", ptgParen) - } - ; - -expr_list[arg_type_list, min_argc, max_argc] returns [arg_cnt] - { - arg_cnt = 0 - arg_type = arg_type_list[arg_cnt] - // print "**expr_list1[%d] req=%s" % (arg_cnt, arg_type) - } - : expr[arg_type] { arg_cnt += 1 } - ( - { - if arg_cnt < len(arg_type_list): - arg_type = arg_type_list[arg_cnt] - else: - arg_type = arg_type_list[-1] - if arg_type == "+": - arg_type = arg_type_list[-2] - // print "**expr_list2[%d] req=%s" % (arg_cnt, arg_type) - } - (SEMICOLON | COMMA) - ( - expr[arg_type] - | { self.rpn += struct.pack("B", ptgMissArg) } - ) - { arg_cnt += 1 } - )* - | - ; - -sheet returns[ref] - : sheet_ref_name: NAME - { ref = sheet_ref_name.text } - | sheet_ref_int: INT_CONST - { ref = sheet_ref_int.text } - | sheet_ref_quote: QUOTENAME - { ref = sheet_ref_quote.text[1:-1].replace("''", "'") } - ; diff --git a/tablib/packages/xlwt3/BIFFRecords.py b/tablib/packages/xlwt3/BIFFRecords.py deleted file mode 100644 index 39a9554..0000000 --- a/tablib/packages/xlwt3/BIFFRecords.py +++ /dev/null @@ -1,2392 +0,0 @@ -from struct import pack -from .UnicodeUtils import upack1, upack2 -import sys - -class SharedStringTable(object): - _SST_ID = 0x00FC - _CONTINUE_ID = 0x003C - - def __init__(self, encoding): - self.encoding = encoding - self._str_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, str): - s = str(s, self.encoding) - self._add_calls += 1 - if s not in self._str_indexes: - idx = len(self._str_indexes) - self._str_indexes[s] = idx - self._tally.append(1) - else: - idx = self._str_indexes[s] - self._tally[idx] += 1 - return idx - - def del_str(self, idx): - # This is called when we are replacing the contents of a string cell. - assert self._tally[idx] > 0 - self._tally[idx] -= 1 - self._add_calls -= 1 - - def str_index(self, s): - return self._str_indexes[s] - - def get_biff_record(self): - self._sst_record = b'' - self._continues = [None, None] - self._current_piece = pack('<II', 0, 0) - data = [(idx, s) for s, idx in list(self._str_indexes.items())] - data.sort() # in index order - for idx, s in data: - if self._tally[idx] == 0: - s = b'' - self._add_to_sst(s) - del data - self._new_piece() - self._continues[0] = pack('<2HII', self._SST_ID, len(self._sst_record), self._add_calls, len(self._str_indexes)) - self._continues[1] = self._sst_record[8:] - self._sst_record = None - self._current_piece = None - result = b''.join(self._continues) - self._continues = None - return result - - - def _add_to_sst(self, s): - u_str = upack2(s, self.encoding) - # (to_py3): added b'...' - is_unicode_str = u_str[2] == b'\x01' - if is_unicode_str: - atom_len = 5 # 2 byte -- len, - # 1 byte -- options, - # 2 byte -- 1st sym - else: - atom_len = 4 # 2 byte -- len, - # 1 byte -- options, - # 1 byte -- 1st sym - - self._save_atom(u_str[0:atom_len]) - self._save_splitted(u_str[atom_len:], is_unicode_str) - - def _new_piece(self): - if self._sst_record == b'': - self._sst_record = self._current_piece - else: - curr_piece_len = len(self._current_piece) - self._continues.append(pack('<2H%ds'%curr_piece_len, self._CONTINUE_ID, curr_piece_len, self._current_piece)) - self._current_piece = b'' - - def _save_atom(self, s): - atom_len = len(s) - free_space = 0x2020 - len(self._current_piece) - if free_space < atom_len: - self._new_piece() - self._current_piece += s - - def _save_splitted(self, s, is_unicode_str): - i = 0 - str_len = len(s) - while i < str_len: - piece_len = len(self._current_piece) - free_space = 0x2020 - piece_len - tail_len = str_len - i - need_more_space = free_space < tail_len - - if not need_more_space: - atom_len = tail_len - else: - if is_unicode_str: - atom_len = free_space & 0xFFFE - else: - atom_len = free_space - - self._current_piece += s[i:i+atom_len] - - if need_more_space: - self._new_piece() - if is_unicode_str: - self._current_piece += b'\x01' # (to_py3): added b'...' - else: - self._current_piece += b'\x00' # (to_py3): added b'...' - - i += atom_len - - -class BiffRecord(object): - - _rec_data = b'' # class attribute; child classes need to set this. - - # Sheer waste. - # def __init__(self): - # self._rec_data = '' - - def get_rec_id(self): - return _REC_ID - - def get_rec_header(self): - return pack('<2H', self._REC_ID, len(self._rec_data)) - - # Not over-ridden by any child classes, never called (except by "get"; see below). - # def get_rec_data(self): - # return self._rec_data - - def get(self): - # data = self.get_rec_data() - data = self._rec_data - - if len(data) > 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('<H', 0x00) - - -class WriteAccessRecord(BiffRecord): - """ - This record is part of the file protection. It contains the name of the - user that has saved the file. The user name is always stored as an - equal-sized string. All unused characters after the name are filled - with space characters. It is not required to write the mentioned string - length. Every other length will be accepted too. - """ - _REC_ID = 0x005C - - def __init__(self, owner): - uowner = owner[0:0x30] - uowner_len = len(uowner) - self._rec_data = pack(bytes('%ds%ds' % (uowner_len, 0x70 - uowner_len), encoding='utf8'), bytes(uowner, encoding='utf8'), b' '*(0x70 - uowner_len)) # (to_py3): added b'...' - # self._rec_data = (b'%ds%ds' % (uowner_len, 0x70 - uowner_len), uowner, b' '*(0x70 - uowner_len)) # (to_py3): added b'...' - - -class DSFRecord(BiffRecord): - """ - This record specifies if the file contains an additional BIFF5/BIFF7 - workbook stream. - Record DSF, BIFF8: - Offset Size Contents - 0 2 0 = Only the BIFF8 Workbook stream is present - 1 = Additional BIFF5/BIFF7 Book stream is in the file - A double stream file can be read by Excel 5.0 and Excel 95, and still - contains all new features added to BIFF8 (which are left out in the - BIFF5/BIFF7 Book stream). - """ - _REC_ID = 0x0161 - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class TabIDRecord(BiffRecord): - _REC_ID = 0x013D - - def __init__(self, sheetcount): - for i in range(sheetcount): - self._rec_data += pack('<H', i+1) - - -class FnGroupCountRecord(BiffRecord): - _REC_ID = 0x009C - - def __init__(self): - self._rec_data = pack('BB', 0x0E, 0x00) - - -class WindowProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It determines - whether the window configuration of this document is protected. Window - protection is not active, if this record is omitted. - """ - _REC_ID = 0x0019 - - def __init__(self, wndprotect): - self._rec_data = pack('<H', wndprotect) - - -class ObjectProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. - It determines whether the objects of the current sheet are protected. - Object protection is not active, if this record is omitted. - """ - _REC_ID = 0x0063 - - - def __init__(self, objprotect): - self._rec_data = pack('<H', objprotect) - - -class ScenProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It - determines whether the scenarios of the current sheet are protected. - Scenario protection is not active, if this record is omitted. - """ - _REC_ID = 0x00DD - - - def __init__(self, scenprotect): - self._rec_data = pack('<H', scenprotect) - - -class ProtectRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It specifies - whether a worksheet or a workbook is protected against modification. - Protection is not active, if this record is omitted. - """ - - _REC_ID = 0x0012 - - def __init__(self, protect): - self._rec_data = pack('<H', protect) - - -class PasswordRecord(BiffRecord): - """ - This record is part of the worksheet/workbook protection. It - stores a 16-bit hash value, calculated from the worksheet or workbook - protection password. - """ - _REC_ID = 0x0013 - def passwd_hash(self, plaintext): - """ - Based on the algorithm provided by Daniel Rentz of OpenOffice. - """ - if plaintext == b"": - return 0 - - passwd_hash = 0x0000 - for i, char in enumerate(plaintext): - c = ord(char) << (i + 1) - low_15 = c & 0x7fff - high_15 = c & 0x7fff << 15 - high_15 = high_15 >> 15 - c = low_15 | high_15 - passwd_hash ^= c - passwd_hash ^= len(plaintext) - passwd_hash ^= 0xCE4B - return passwd_hash - - def __init__(self, passwd = b""): - self._rec_data = pack('<H', self.passwd_hash(passwd)) - - -class Prot4RevRecord(BiffRecord): - _REC_ID = 0x01AF - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class Prot4RevPassRecord(BiffRecord): - _REC_ID = 0x01BC - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class BackupRecord(BiffRecord): - """ - This record contains a Boolean value determining whether Excel makes - a backup of the file while saving. - """ - _REC_ID = 0x0040 - - def __init__(self, backup): - self._rec_data = pack('<H', backup) - -class HideObjRecord(BiffRecord): - """ - This record specifies whether and how to show objects in the workbook. - - Record HIDEOBJ, BIFF3-BIFF8: - Offset Size Contents - 0 2 Viewing mode for objects: - 0 = Show all objects - 1 = Show placeholders - 2 = Do not show objects - """ - _REC_ID = 0x008D - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - - -class RefreshAllRecord(BiffRecord): - """ - """ - - _REC_ID = 0x01B7 - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class BookBoolRecord(BiffRecord): - """ - This record contains a Boolean value determining whether to save values - linked from external workbooks (CRN records and XCT records). In BIFF3 - and BIFF4 this option is stored in the WSBOOL record. - - Record BOOKBOOL, BIFF5-BIFF8: - - Offset Size Contents - 0 2 0 = Save external linked values; - 1 = Do not save external linked values - """ - - _REC_ID = 0x00DA - - def __init__(self): - self._rec_data = pack('<H', 0x00) - - -class CountryRecord(BiffRecord): - """ - This record stores two Windows country identifiers. The first - represents the user interface language of the Excel version that has - saved the file, and the second represents the system regional settings - at the time the file was saved. - - Record COUNTRY, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Windows country identifier of the user interface language of Excel - 2 2 Windows country identifier of the system regional settings - - The following table shows most of the used country identifiers. Most - of these identifiers are equal to the international country calling - codes. - - 1 USA - 2 Canada - 7 Russia - """ - - _REC_ID = 0x008C - - def __init__(self, ui_id, sys_settings_id): - self._rec_data = pack('<2H', ui_id, sys_settings_id) - - -class UseSelfsRecord(BiffRecord): - """ - This record specifies if the formulas in the workbook can use natural - language formulas. This type of formula can refer to cells by its - content or the content of the column or row header cell. - - Record USESELFS, BIFF8: - - Offset Size Contents - 0 2 0 = Do not use natural language formulas - 1 = Use natural language formulas - - """ - - _REC_ID = 0x0160 - - def __init__(self): - self._rec_data = pack('<H', 0x01) - - -class EOFRecord(BiffRecord): - _REC_ID = 0x000A - - def __init__(self): - self._rec_data = b'' - - -class DateModeRecord(BiffRecord): - """ - This record specifies the base date for displaying date values. All - dates are stored as count of days past this base date. In BIFF2-BIFF4 - this record is part of the Calculation Settings Block. - In BIFF5-BIFF8 it is stored in the Workbook Globals Substream. - - Record DATEMODE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Base is 1899-Dec-31 (the cell = 1 represents 1900-Jan-01) - 1 = Base is 1904-Jan-01 (the cell = 1 represents 1904-Jan-02) - """ - _REC_ID = 0x0022 - - def __init__(self, from1904): - if from1904: - self._rec_data = pack('<H', 1) - else: - self._rec_data = pack('<H', 0) - - -class PrecisionRecord(BiffRecord): - """ - This record stores if formulas use the real cell values for calculation - or the values displayed on the screen. In BIFF2- BIFF4 this record - is part of the Calculation Settings Block. In BIFF5-BIFF8 it is stored - in the Workbook Globals Substream. - - Record PRECISION, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Use displayed values; - 1 = Use real cell values - """ - _REC_ID = 0x000E - - def __init__(self, use_real_values): - if use_real_values: - self._rec_data = pack('<H', 1) - else: - self._rec_data = pack('<H', 0) - - -class CodepageBiff8Record(BiffRecord): - """ - This record stores the text encoding used to write byte strings, stored - as MS Windows code page identifier. The CODEPAGE record in BIFF8 always - contains the code page 1200 (UTF-16). Therefore it is not - possible to obtain the encoding used for a protection password (it is - not UTF-16). - - Record CODEPAGE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 Code page identifier used for byte string text encoding: - 016FH = 367 = ASCII - 01B5H = 437 = IBM PC CP-437 (US) - 02D0H = 720 = IBM PC CP-720 (OEM Arabic) - 02E1H = 737 = IBM PC CP-737 (Greek) - 0307H = 775 = IBM PC CP-775 (Baltic) - 0352H = 850 = IBM PC CP-850 (Latin I) - 0354H = 852 = IBM PC CP-852 (Latin II (Central European)) - 0357H = 855 = IBM PC CP-855 (Cyrillic) - 0359H = 857 = IBM PC CP-857 (Turkish) - 035AH = 858 = IBM PC CP-858 (Multilingual Latin I with Euro) - 035CH = 860 = IBM PC CP-860 (Portuguese) - 035DH = 861 = IBM PC CP-861 (Icelandic) - 035EH = 862 = IBM PC CP-862 (Hebrew) - 035FH = 863 = IBM PC CP-863 (Canadian (French)) - 0360H = 864 = IBM PC CP-864 (Arabic) - 0361H = 865 = IBM PC CP-865 (Nordic) - 0362H = 866 = IBM PC CP-866 (Cyrillic (Russian)) - 0365H = 869 = IBM PC CP-869 (Greek (Modern)) - 036AH = 874 = Windows CP-874 (Thai) - 03A4H = 932 = Windows CP-932 (Japanese Shift-JIS) - 03A8H = 936 = Windows CP-936 (Chinese Simplified GBK) - 03B5H = 949 = Windows CP-949 (Korean (Wansung)) - 03B6H = 950 = Windows CP-950 (Chinese Traditional BIG5) - 04B0H = 1200 = UTF-16 (BIFF8) - 04E2H = 1250 = Windows CP-1250 (Latin II) (Central European) - 04E3H = 1251 = Windows CP-1251 (Cyrillic) - 04E4H = 1252 = Windows CP-1252 (Latin I) (BIFF4-BIFF7) - 04E5H = 1253 = Windows CP-1253 (Greek) - 04E6H = 1254 = Windows CP-1254 (Turkish) - 04E7H = 1255 = Windows CP-1255 (Hebrew) - 04E8H = 1256 = Windows CP-1256 (Arabic) - 04E9H = 1257 = Windows CP-1257 (Baltic) - 04EAH = 1258 = Windows CP-1258 (Vietnamese) - 0551H = 1361 = Windows CP-1361 (Korean (Johab)) - 2710H = 10000 = Apple Roman - 8000H = 32768 = Apple Roman - 8001H = 32769 = Windows CP-1252 (Latin I) (BIFF2-BIFF3) - """ - _REC_ID = 0x0042 - UTF_16 = 0x04B0 - - def __init__(self): - self._rec_data = pack('<H', self.UTF_16) - -class Window1Record(BiffRecord): - """ - Offset Size Contents - 0 2 Horizontal position of the document window (in twips = 1/20 of a point) - 2 2 Vertical position of the document window (in twips = 1/20 of a point) - 4 2 Width of the document window (in twips = 1/20 of a point) - 6 2 Height of the document window (in twips = 1/20 of a point) - 8 2 Option flags: - Bits Mask Contents - 0 0001H 0 = Window is visible 1 = Window is hidden - 1 0002H 0 = Window is open 1 = Window is minimised - 3 0008H 0 = Horizontal scroll bar hidden 1 = Horizontal scroll bar visible - 4 0010H 0 = Vertical scroll bar hidden 1 = Vertical scroll bar visible - 5 0020H 0 = Worksheet tab bar hidden 1 = Worksheet tab bar visible - 10 2 Index to active (displayed) worksheet - 12 2 Index of first visible tab in the worksheet tab bar - 14 2 Number of selected worksheets (highlighted in the worksheet tab bar) - 16 2 Width of worksheet tab bar (in 1/1000 of window width). The remaining space is used by the - horizontal scrollbar. - """ - _REC_ID = 0x003D - # flags - - def __init__(self, - hpos_twips, vpos_twips, - width_twips, height_twips, - flags, - active_sheet, - first_tab_index, selected_tabs, tab_width): - self._rec_data = pack('<9H', hpos_twips, vpos_twips, - width_twips, height_twips, - flags, - active_sheet, - first_tab_index, selected_tabs, tab_width) - -class FontRecord(BiffRecord): - """ - WARNING - The font with index 4 is omitted in all BIFF versions. - This means the first four fonts have zero-based indexes, and - the fifth font and all following fonts are referenced with one-based - indexes. - - Offset Size Contents - 0 2 Height of the font (in twips = 1/20 of a point) - 2 2 Option flags: - Bit Mask Contents - 0 0001H 1 = Characters are bold (redundant, see below) - 1 0002H 1 = Characters are italic - 2 0004H 1 = Characters are underlined (redundant, see below) - 3 0008H 1 = Characters are struck out - 0010H 1 = Outline - 0020H 1 = Shadow - 4 2 Colour index - 6 2 Font weight (100-1000). - Standard values are 0190H (400) for normal text and 02BCH - (700) for bold text. - 8 2 Escapement type: - 0000H = None - 0001H = Superscript - 0002H = Subscript - 10 1 Underline type: - 00H = None - 01H = Single - 21H = Single accounting - 02H = Double - 22H = Double accounting - 11 1 Font family: - 00H = None (unknown or don't care) - 01H = Roman (variable width, serifed) - 02H = Swiss (variable width, sans-serifed) - 03H = Modern (fixed width, serifed or sans-serifed) - 04H = Script (cursive) - 05H = Decorative (specialised, i.e. Old English, Fraktur) - 12 1 Character set: - 00H = 0 = ANSI Latin - 01H = 1 = System default - 02H = 2 = Symbol - 4DH = 77 = Apple Roman - 80H = 128 = ANSI Japanese Shift-JIS - 81H = 129 = ANSI Korean (Hangul) - 82H = 130 = ANSI Korean (Johab) - 86H = 134 = ANSI Chinese Simplified GBK - 88H = 136 = ANSI Chinese Traditional BIG5 - A1H = 161 = ANSI Greek - A2H = 162 = ANSI Turkish - A3H = 163 = ANSI Vietnamese - B1H = 177 = ANSI Hebrew - B2H = 178 = ANSI Arabic - BAH = 186 = ANSI Baltic - CCH = 204 = ANSI Cyrillic - DEH = 222 = ANSI Thai - EEH = 238 = ANSI Latin II (Central European) - FFH = 255 = OEM Latin I - 13 1 Not used - 14 var. Font name: - BIFF5/BIFF7: Byte string, 8-bit string length - BIFF8: Unicode string, 8-bit string length - The boldness and underline flags are still set in the options field, - but not used on reading the font. Font weight and underline type - are specified in separate fields instead. - """ - _REC_ID = 0x0031 - - def __init__(self, - height, options, colour_index, weight, escapement, - underline, family, charset, - name): - uname = upack1(name) - uname_len = len(uname) - - self._rec_data = pack('<5H4B%ds' % uname_len, height, options, colour_index, weight, escapement, - underline, family, charset, 0x00, - uname) - -class NumberFormatRecord(BiffRecord): - """ - Record FORMAT, BIFF8: - Offset Size Contents - 0 2 Format index used in other records - 2 var. Number format string (Unicode string, 16-bit string length) - - From BIFF5 on, the built-in number formats will be omitted. The built-in - formats are dependent on the current regional settings of the operating - system. The following table shows which number formats are used by default - in a US-English environment. All indexes from 0 to 163 are reserved for - built-in formats. The first user-defined format starts at 164. - - The built-in number formats, BIFF5-BIFF8 - - Index Type Format string - 0 General General - 1 Decimal 0 - 2 Decimal 0.00 - 3 Decimal #,##0 - 4 Decimal #,##0.00 - 5 Currency "$"#,##0_);("$"#,## - 6 Currency "$"#,##0_);[Red]("$"#,## - 7 Currency "$"#,##0.00_);("$"#,## - 8 Currency "$"#,##0.00_);[Red]("$"#,## - 9 Percent 0% - 10 Percent 0.00% - 11 Scientific 0.00E+00 - 12 Fraction # ?/? - 13 Fraction # ??/?? - 14 Date M/D/YY - 15 Date D-MMM-YY - 16 Date D-MMM - 17 Date MMM-YY - 18 Time h:mm AM/PM - 19 Time h:mm:ss AM/PM - 20 Time h:mm - 21 Time h:mm:ss - 22 Date/Time M/D/YY h:mm - 37 Account _(#,##0_);(#,##0) - 38 Account _(#,##0_);[Red](#,##0) - 39 Account _(#,##0.00_);(#,##0.00) - 40 Account _(#,##0.00_);[Red](#,##0.00) - 41 Currency _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_) - 42 Currency _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) - 43 Currency _("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_) - 44 Currency _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_) - 45 Time mm:ss - 46 Time [h]:mm:ss - 47 Time mm:ss.0 - 48 Scientific ##0.0E+0 - 49 Text @ - """ - _REC_ID = 0x041E - - def __init__(self, idx, fmtstr): - ufmtstr = upack2(fmtstr) - ufmtstr_len = len(ufmtstr) - - self._rec_data = pack('<H%ds' % ufmtstr_len, idx, ufmtstr) - - -class XFRecord(BiffRecord): - """ - XF Substructures - ------------------------------------------------------------------------- - XF_TYPE_PROT XF Type and Cell Protection (3 Bits), BIFF3-BIFF8 - These 3 bits are part of a specific data byte. - Bit Mask Contents - 0 01H 1 = Cell is locked - 1 02H 1 = Formula is hidden - 2 04H 0 = Cell XF; 1 = Style XF - - XF_USED_ATTRIB Attributes Used from Parent Style XF (6 Bits), - BIFF3-BIFF8 Each bit describes the validity of a specific group - of attributes. In cell XFs a cleared bit means the attributes of the - parent style XF are used (but only if the attributes are valid there), - a set bit means the attributes of this XF are used. In style XFs - a cleared bit means the attribute setting is valid, a set bit means the - attribute should be ignored. - Bit Mask Contents - 0 01H Flag for number format - 1 02H Flag for font - 2 04H Flag for horizontal and vertical alignment, text wrap, indentation, orientation, rotation, and - text direction - 3 08H Flag for border lines - 4 10H Flag for background area style - 5 20H Flag for cell protection (cell locked and formula hidden) - - XF_HOR_ALIGN Horizontal Alignment (3 Bits), BIFF2-BIFF8 The horizontal - alignment consists of 3 bits and is part of a specific data byte. - Value Horizontal alignment - 00H General - 01H Left - 02H Centred - 03H Right - 04H Filled - 05H Justified (BIFF4-BIFF8X) - 06H Centred across selection (BIFF4-BIFF8X) - 07H Distributed (BIFF8X) - - XF_VERT_ALIGN Vertical Alignment (2 or 3 Bits), BIFF4-BIFF8 - The vertical alignment consists of 2 bits (BIFF4) or 3 bits (BIFF5-BIFF8) - and is part of a specific data byte. Vertical alignment is not available - in BIFF2 and BIFF3. - Value Vertical alignment - 00H Top - 01H Centred - 02H Bottom - 03H Justified (BIFF5-BIFF8X) - 04H Distributed (BIFF8X) - - XF_ORIENTATION Text Orientation (2 Bits), BIFF4-BIFF7 In the BIFF - versions BIFF4-BIFF7, text can be rotated in steps of 90 degrees - or stacked. The orientation mode consists of 2 bits and is part of - a specific data byte. In BIFF8 a rotation angle occurs instead of these - flags. - Value Text orientation - 00H Not rotated - 01H Letters are stacked top-to-bottom, but not rotated - 02H Text is rotated 90 degrees counterclockwise - 03H Text is rotated 90 degrees clockwise - - XF_ROTATION Text Rotation Angle (1 Byte), BIFF8 - Value Text rotation - 0 Not rotated - 1-90 1 to 90 degrees counterclockwise - 91-180 1 to 90 degrees clockwise - 255 Letters are stacked top-to-bottom, but not rotated - - XF_BORDER_34 Cell Border Style (4 Bytes), BIFF3-BIFF4 Cell borders - contain a line style and a line colour for each line of the border. - Bit Mask Contents - 2-0 00000007H Top line style - 7-3 000000F8H Colour index for top line colour - 10-8 00000700H Left line style - 15-11 0000F800H Colour index for left line colour - 18-16 00070000H Bottom line style - 23-19 00F80000H Colour index for bottom line colour - 26-24 07000000H Right line style - 31-27 F8000000H Colour index for right line colour - - XF_AREA_34 Cell Background Area Style (2 Bytes), BIFF3-BIFF4 A cell - background area style contains an area pattern and a foreground and - background colour. - Bit Mask Contents - 5-0 003FH Fill pattern - 10-6 07C0H Colour index for pattern colour - 15-11 F800H Colour index for pattern background - --------------------------------------------------------------------------------------------- - Record XF, BIFF8: - Offset Size Contents - 0 2 Index to FONT record - 2 2 Index to FORMAT record - 4 2 Bit Mask Contents - 2-0 0007H XF_TYPE_PROT . XF type, cell protection (see above) - 15-4 FFF0H Index to parent style XF (always FFFH in style XFs) - 6 1 Bit Mask Contents - 2-0 07H XF_HOR_ALIGN . Horizontal alignment (see above) - 3 08H 1 = Text is wrapped at right border - 6-4 70H XF_VERT_ALIGN . Vertical alignment (see above) - 7 1 XF_ROTATION: Text rotation angle (see above) - 8 1 Bit Mask Contents - 3-0 0FH Indent level - 4 10H 1 = Shrink content to fit into cell - 5 merge - 7-6 C0H Text direction (BIFF8X only) - 00b = According to context - 01b = Left-to-right - 10b = Right-to-left - 9 1 Bit Mask Contents - 7-2 FCH XF_USED_ATTRIB . Used attributes (see above) - 10 4 Cell border lines and background area: - Bit Mask Contents - 3-0 0000000FH Left line style - 7-4 000000F0H Right line style - 11-8 00000F00H Top line style - 15-12 0000F000H Bottom line style - 22-16 007F0000H Colour index for left line colour - 29-23 3F800000H Colour index for right line colour - 30 40000000H 1 = Diagonal line from top left to right bottom - 31 80000000H 1 = Diagonal line from bottom left to right top - 14 4 Bit Mask Contents - 6-0 0000007FH Colour index for top line colour - 13-7 00003F80H Colour index for bottom line colour - 20-14 001FC000H Colour index for diagonal line colour - 24-21 01E00000H Diagonal line style - 31-26 FC000000H Fill pattern - 18 2 Bit Mask Contents - 6-0 007FH Colour index for pattern colour - 13-7 3F80H Colour index for pattern background - - """ - _REC_ID = 0x00E0 - - def __init__(self, xf, xftype='cell'): - font_xf_idx, fmt_str_xf_idx, alignment, borders, pattern, protection = xf - fnt = pack('<H', font_xf_idx) - fmt = pack('<H', fmt_str_xf_idx) - if xftype == 'cell': - prt = pack('<H', - ((protection.cell_locked & 0x01) << 0) | - ((protection.formula_hidden & 0x01) << 1) - ) - else: - prt = pack('<H', 0xFFF5) - aln = pack('B', - ((alignment.horz & 0x07) << 0) | - ((alignment.wrap & 0x01) << 3) | - ((alignment.vert & 0x07) << 4) - ) - rot = pack('B', alignment.rota) - txt = pack('B', - ((alignment.inde & 0x0F) << 0) | - ((alignment.shri & 0x01) << 4) | - ((alignment.merg & 0x01) << 5) | - ((alignment.dire & 0x03) << 6) - ) - if xftype == 'cell': - used_attr = pack('B', 0xF8) - else: - used_attr = pack('B', 0xF4) - - if borders.left == borders.NO_LINE: - borders.left_colour = 0x00 - if borders.right == borders.NO_LINE: - borders.right_colour = 0x00 - if borders.top == borders.NO_LINE: - borders.top_colour = 0x00 - if borders.bottom == borders.NO_LINE: - borders.bottom_colour = 0x00 - if borders.diag == borders.NO_LINE: - borders.diag_colour = 0x00 - brd1 = pack('<L', - ((borders.left & 0x0F) << 0 ) | - ((borders.right & 0x0F) << 4 ) | - ((borders.top & 0x0F) << 8 ) | - ((borders.bottom & 0x0F) << 12) | - ((borders.left_colour & 0x7F) << 16) | - ((borders.right_colour & 0x7F) << 23) | - ((borders.need_diag1 & 0x01) << 30) | - ((borders.need_diag2 & 0x01) << 31) - ) - brd2 = pack('<L', - ((borders.top_colour & 0x7F) << 0 ) | - ((borders.bottom_colour & 0x7F) << 7 ) | - ((borders.diag_colour & 0x7F) << 14) | - ((borders.diag & 0x0F) << 21) | - ((pattern.pattern & 0x3F) << 26) - ) - pat = pack('<H', - ((pattern.pattern_fore_colour & 0x7F) << 0 ) | - ((pattern.pattern_back_colour & 0x7F) << 7 ) - ) - self._rec_data = fnt + fmt + prt + \ - aln + rot + txt + used_attr + \ - brd1 + brd2 + \ - pat - -class StyleRecord(BiffRecord): - """ - STYLE record for user-defined cell styles, BIFF3-BIFF8: - Offset Size Contents - 0 2 Bit Mask Contents - 11-0 0FFFH Index to style XF record - 15 8000H Always 0 for user-defined styles - 2 var. BIFF2-BIFF7: Non-empty byte string, 8-bit string length - BIFF8: Non-empty Unicode string, 16-bit string length - STYLE record for built-in cell styles, BIFF3-BIFF8: - Offset Size Contents - 0 2 Bit Mask Contents - 11-0 0FFFH Index to style XF record - 15 8000H Always 1 for built-in styles - 2 1 Identifier of the built-in cell style: - 00H = Normal - 01H = RowLevel_lv (see next field) - 02H = ColLevel_lv (see next field) - 03H = Comma - 04H = Currency - 05H = Percent - 06H = Comma [0] (BIFF4-BIFF8) - 07H = Currency [0] (BIFF4-BIFF8) - 08H = Hyperlink (BIFF8) - 09H = Followed Hyperlink (BIFF8) - 3 1 Level for RowLevel or ColLevel style - (zero-based, lv), FFH otherwise - The RowLevel and ColLevel styles specify the formatting of subtotal - cells in a specific outline level. The level is specified by the last - field in the STYLE record. Valid values are 0-6 for the outline levels - 1-7. - """ - _REC_ID = 0x0293 - - def __init__(self): - self._rec_data = pack('<HBB', 0x8000, 0x00, 0xFF) - # TODO: implement user-defined styles??? - - -class PaletteRecord(BiffRecord): - """ - This record contains the definition of all user-defined colours - available for cell and object formatting. - - Record PALETTE, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Number of following colours (nm). Contains 16 in BIFF3-BIFF4 and 56 in BIFF5-BIFF8. - 2 4*nm List of nm RGB colours - - The following table shows how colour indexes are used in other records: - - Colour index Resulting colour or internal list index - 00H Built-in Black (R = 00H, G = 00H, B = 00H) - 01H Built-in White (R = FFH, G = FFH, B = FFH) - 02H Built-in Red (R = FFH, G = 00H, B = 00H) - 03H Built-in Green (R = 00H, G = FFH, B = 00H) - 04H Built-in Blue (R = 00H, G = 00H, B = FFH) - 05H Built-in Yellow (R = FFH, G = FFH, B = 00H) - 06H Built-in Magenta (R = FFH, G = 00H, B = FFH) - 07H Built-in Cyan (R = 00H, G = FFH, B = FFH) - 08H First user-defined colour from the PALETTE record (entry 0 from record colour list) - ......................... - - 17H (BIFF3-BIFF4) Last user-defined colour from the PALETTE record (entry 15 or 55 from record colour list) - 3FH (BIFF5-BIFF8) - - 18H (BIFF3-BIFF4) System window text colour for border lines (used in records XF, CF, and - 40H (BIFF5-BIFF8) WINDOW2 (BIFF8 only)) - - 19H (BIFF3-BIFF4) System window background colour for pattern background (used in records XF, and CF) - 41H (BIFF5-BIFF8) - - 43H System face colour (dialogue background colour) - 4DH System window text colour for chart border lines - 4EH System window background colour for chart areas - 4FH Automatic colour for chart border lines (seems to be always Black) - 50H System ToolTip background colour (used in note objects) - 51H System ToolTip text colour (used in note objects) - 7FFFH System window text colour for fonts (used in records FONT, EFONT, and CF) - - """ - _REC_ID = 0x0092 - - -class BoundSheetRecord(BiffRecord): - """ - This record is located in the workbook globals area and represents - a sheet inside of the workbook. For each sheet a BOUNDSHEET record - is written. It stores the sheet name and a stream offset to the BOF - record within the workbook stream. The record is also known - as BUNDLESHEET. - - Record BOUNDSHEET, BIFF5-BIFF8: - Offset Size Contents - 0 4 Absolute stream position of the BOF record of the sheet represented by this record. This - field is never encrypted in protected files. - 4 1 Visibility: - 00H = Visible - 01H = Hidden - 02H = Strong hidden - 5 1 Sheet type: - 00H = Worksheet - 02H = Chart - 06H = Visual Basic module - 6 var. Sheet name: - BIFF5/BIFF7: Byte string, 8-bit string length - BIFF8: Unicode string, 8-bit string length - """ - _REC_ID = 0x0085 - - def __init__(self, stream_pos, visibility, sheetname, encoding='ascii'): - usheetname = upack1(sheetname, encoding) - uusheetname_len = len(usheetname) - - self._rec_data = pack('<LBB%ds' % uusheetname_len, stream_pos, visibility, 0x00, usheetname) - - -class ContinueRecord(BiffRecord): - """ - Whenever the content of a record exceeds the given limits (see table), - the record must be split. Several CONTINUE records containing the - additional data are added after the parent record. - - BIFF version Maximum data size of a record - BIFF2-BIFF7 2080 bytes (2084 bytes including record header) - BIFF8 8224 bytes (8228 bytes including record header) (0x2020) - - Record CONTINUE, BIFF2-BIFF8: - Offset Size Contents - 0 var. Data continuation of the previous record - - Unicode strings are split in a special way. At the beginning of each - CONTINUE record the option flags byte is repeated. Only the character - size flag will be set in this flags byte, the Rich-Text flag and the - Far-East flag are set to zero. In each CONTINUE record it is possible - that the character size changes from 8-bit characters to 16-bit - characters and vice versa. - - Never a Unicode string is split until and including the first - character. That means, all header fields (string length, option flags, - optional Rich-Text size, and optional Far-East data size) and the first - character of the string have to occur together in the leading record, - or have to be moved completely into the CONTINUE record. Formatting - runs cannot be split between their components (character index and FONT - record index). If a string is split between two formatting runs, the - option flags field will not be repeated in the CONTINUE record. - """ - _REC_ID = 0x003C - - -class SSTRecord(BiffRecord): - """ - This record contains a list of all strings used anywhere in the - workbook. Each string occurs only once. The workbook uses indexes into - the list to reference the strings. - - Record SST, BIFF8: - Offset Size Contents - 0 4 Total number of strings in the workbook (see below) - 4 4 Number of following strings (nm) - 8 var. List of nm Unicode strings, 16-bit string length - - The first field of the SST record counts the total occurrence - of strings in the workbook. For instance, the string AAA is used - 3 times and the string BBB is used 2 times. The first field contains - 5 and the second field contains 2, followed by the two strings. - """ - _REC_ID = 0x00FC - - -class ExtSSTRecord(BiffRecord): - """ - This record occurs in conjunction with the SST record. It is used - by Excel to create a hash table with stream offsets to the SST record - to optimise string search operations. Excel may not shorten this record - if strings are deleted from the shared string table, so the last part - might contain invalid data. The stream indexes in this record divide - the SST into portions containing a constant number of strings. - - Record EXTSST, BIFF8: - - Offset Size Contents - 0 2 Number of strings in a portion, this number is >=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('<H', exsst_str_count_delta) - str_counter = 0 - while str_counter < len(str_placement): - self._rec_data += pack('<IHH', extsst[str_counter][1], extsst[str_counter][0], 0) - str_counter += exsst_str_count_delta - -class DimensionsRecord(BiffRecord): - """ - Record DIMENSIONS, BIFF8: - - Offset Size Contents - 0 4 Index to first used row - 4 4 Index to last used row, increased by 1 - 8 2 Index to first used column - 10 2 Index to last used column, increased by 1 - 12 2 Not used - """ - _REC_ID = 0x0200 - def __init__(self, first_used_row, last_used_row, first_used_col, last_used_col): - if first_used_row > 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, - 0x00) - if scl_magn: - self._scl_rec = pack('<4H', 0x00A0, 4, scl_magn, 100) - else: - self._scl_rec = b'' - - 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 - def __init__(self, px, py, first_row_bottom, first_col_right, active_pane): - self._rec_data = pack('<5H', int(px), int(py), int(first_row_bottom), - int(first_col_right), int(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 = b'' - 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('<H', last_col) - - -class BlankRecord(BiffRecord): - """ - This record represents an empty cell. - - Record BLANK, BIFF5-BIFF8: - - Offset Size Contents - 0 2 Index to row - 2 2 Index to first column (fc) - 4 2 indexes to XF record - """ - _REC_ID = 0x0201 - - def __init__(self, row, col, xf_index): - self._rec_data = pack('<3H', row, col, xf_index) - - -class RKRecord(BiffRecord): - """ - This record represents a cell that contains an RK value (encoded integer or - floating-point value). If a floating-point value cannot be encoded to an RK value, - a NUMBER record will be written. - """ - _REC_ID = 0x027E - - def __init__(self, row, col, xf_index, rk_encoded): - self._rec_data = pack('<3Hi', row, col, xf_index, rk_encoded) - - -class NumberRecord(BiffRecord): - """ - This record represents a cell that contains an IEEE-754 floating-point value. - """ - _REC_ID = 0x0203 - - def __init__(self, row, col, xf_index, number): - self._rec_data = pack('<3Hd', row, col, xf_index, number) - -class BoolErrRecord(BiffRecord): - """ - This record represents a cell that contains a boolean or error value. - """ - _REC_ID = 0x0205 - - def __init__(self, row, col, xf_index, number, is_error): - self._rec_data = pack('<3HBB', row, col, xf_index, number, is_error) - - -class FormulaRecord(BiffRecord): - """ - Offset Size Contents - 0 2 Index to row - 2 2 Index to column - 4 2 Index to XF record - 6 8 Result of the formula - 14 2 Option flags: - Bit Mask Contents - 0 0001H 1 = Recalculate always - 1 0002H 1 = Calculate on open - 3 0008H 1 = Part of a shared formula - 16 4 Not used - 20 var. Formula data (RPN token array) - - """ - _REC_ID = 0x0006 - - def __init__(self, row, col, xf_index, rpn, calc_flags=0): - self._rec_data = pack('<3HQHL', row, col, xf_index, 0xFFFF000000000003, calc_flags & 3, 0) + rpn - - -class GutsRecord(BiffRecord): - """ - This record contains information about the layout of outline symbols. - - Record GUTS, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Width of the area to display row outlines (left of the sheet), in pixel - 2 2 Height of the area to display column outlines (above the sheet), in pixel - 4 2 Number of visible row outline levels (used row levels + 1; or 0, if not used) - 6 2 Number of visible column outline levels (used column levels + 1; or 0, if not used) - - """ - - _REC_ID = 0x0080 - - def __init__(self, row_gut_width, col_gut_height, row_visible_levels, col_visible_levels): - self._rec_data = pack('<4H', row_gut_width, col_gut_height, row_visible_levels, col_visible_levels) - -class WSBoolRecord(BiffRecord): - """ - This record stores a 16 bit value with Boolean options for the current - sheet. From BIFF5 on the "Save external linked values" option is moved - to the record BOOKBOOL. - - Option flags of record WSBOOL, BIFF3-BIFF8: - - Bit Mask Contents - 0 0001H 0 = Do not show automatic page breaks - 1 = Show automatic page breaks - 4 0010H 0 = Standard sheet - 1 = Dialogue sheet (BIFF5-BIFF8) - 5 0020H 0 = No automatic styles in outlines - 1 = Apply automatic styles to outlines - 6 0040H 0 = Outline buttons above outline group - 1 = Outline buttons below outline group - 7 0080H 0 = Outline buttons left of outline group - 1 = Outline buttons right of outline group - 8 0100H 0 = Scale printout in percent - 1 = Fit printout to number of pages - 9 0200H 0 = Save external linked values (BIFF3?BIFF4 only) - 1 = Do not save external linked values (BIFF3?BIFF4 only) - 10 0400H 0 = Do not show row outline symbols - 1 = Show row outline symbols - 11 0800H 0 = Do not show column outline symbols - 1 = Show column outline symbols - 13-12 3000H These flags specify the arrangement of windows. - They are stored in BIFF4 only. - 00 = Arrange windows tiled - 01 = Arrange windows horizontal - 10 = Arrange windows vertical112 = Arrange windows cascaded - The following flags are valid for BIFF4-BIFF8 only: - 14 4000H 0 = Standard expression evaluation - 1 = Alternative expression evaluation - 15 8000H 0 = Standard formula entries - 1 = Alternative formula entries - - """ - _REC_ID = 0x0081 - - def __init__(self, options): - self._rec_data = pack('<H', options) - -class ColInfoRecord(BiffRecord): - """ - This record specifies the width for a given range of columns. - If a column does not have a corresponding COLINFO record, - the width specified in the record STANDARDWIDTH is used. If - this record is also not present, the contents of the record - DEFCOLWIDTH is used instead. - This record also specifies a default XF record to use for - cells in the columns that are not described by any cell record - (which contain the XF index for that cell). Additionally, - the option flags field contains hidden, outline, and collapsed - options applied at the columns. - - Record COLINFO, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Index to first column in the range - 2 2 Index to last column in the range - 4 2 Width of the columns in 1/256 of the width of the zero character, using default font - (first FONT record in the file) - 6 2 Index to XF record for default column formatting - 8 2 Option flags: - Bits Mask Contents - 0 0001H 1 = Columns are hidden - 10-8 0700H Outline level of the columns (0 = no outline) - 12 1000H 1 = Columns are collapsed - 10 2 Not used - - """ - _REC_ID = 0x007D - - def __init__(self, first_col, last_col, width, xf_index, options): - self._rec_data = pack('<6H', first_col, last_col, width, xf_index, options, 0) - -class CalcModeRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It specifies whether to calculate formulas manually, - automatically or automatically except for multiple table operations. - - Record CALCMODE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 FFFFH = automatic except for multiple table operations - 0000H = manually - 0001H = automatically (default) - """ - _REC_ID = 0x000D - - def __init__(self, calc_mode): - self._rec_data = pack('<h', calc_mode) - - -class CalcCountRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. It specifies the maximum - number of times the formulas should be iteratively calculated. This is a fail-safe - against mutually recursive formulas locking up a spreadsheet application. - - Record CALCCOUNT, BIFF2-BIFF8: - - Offset Size Contents - 0 2 Maximum number of iterations allowed in circular references - """ - - _REC_ID = 0x000C - - def __init__(self, calc_count): - self._rec_data = pack('<H', calc_count) - -class RefModeRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It stores which method is used to show cell addresses in formulas. - The “RC†mode uses numeric indexes for rows and columns, - i.e. “R(1)C(-1)â€, or “R1C1:R2C2â€. - The “A1†mode uses characters for columns and numbers for rows, - i.e. “B1â€, or “$A$1:$B$2â€. - - Record REFMODE, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = RC mode; 1 = A1 mode - - """ - _REC_ID = 0x00F - - def __init__(self, ref_mode): - self._rec_data = pack('<H', ref_mode) - -class IterationRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It stores if iterations are allowed while calculating recursive formulas. - - Record ITERATION, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Iterations off; 1 = Iterations on - """ - _REC_ID = 0x011 - - def __init__(self, iterations_on): - self._rec_data = pack('<H', iterations_on) - -class DeltaRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It stores the maximum change of the result to exit an iteration. - - Record DELTA, BIFF2-BIFF8: - - Offset Size Contents - 0 8 Maximum change in iteration - (IEEE 754 floating-point value, - 64bit double precision) - """ - _REC_ID = 0x010 - - def __init__(self, delta): - self._rec_data = pack('<d', delta) - -class SaveRecalcRecord(BiffRecord): - """ - This record is part of the Calculation Settings Block. - It contains the “Recalculate before save†option in - Excel's calculation settings dialogue. - - Record SAVERECALC, BIFF3-BIFF8: - - Offset Size Contents - 0 2 0 = Do not recalculate; - 1 = Recalculate before saving the document - - """ - _REC_ID = 0x05F - - def __init__(self, recalc): - self._rec_data = pack('<H', recalc) - -class PrintHeadersRecord(BiffRecord): - """ - This record stores if the row and column headers - (the areas with row numbers and column letters) will be printed. - - Record PRINTHEADERS, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Do not print row/column headers; - 1 = Print row/column headers - """ - _REC_ID = 0x02A - - def __init__(self, print_headers): - self._rec_data = pack('<H', print_headers) - - -class PrintGridLinesRecord(BiffRecord): - """ - This record stores if sheet grid lines will be printed. - - Record PRINTGRIDLINES, BIFF2-BIFF8: - - Offset Size Contents - 0 2 0 = Do not print sheet grid lines; - 1 = Print sheet grid lines - - """ - _REC_ID = 0x02B - - def __init__(self, print_grid): - self._rec_data = pack('<H', print_grid) - - -class GridSetRecord(BiffRecord): - """ - This record specifies if the option to print sheet grid lines - (record PRINTGRIDLINES) has ever been changed. - - Record GRIDSET, BIFF3-BIFF8: - - Offset Size Contents - 0 2 0 = Print grid lines option never changed - 1 = Print grid lines option changed - """ - _REC_ID = 0x082 - - def __init__(self, print_grid_changed): - self._rec_data = pack('<H', print_grid_changed) - - -class DefaultRowHeightRecord(BiffRecord): - """ - This record specifies the default height and default flags - for rows that do not have a corresponding ROW record. - - Record DEFAULTROWHEIGHT, BIFF3-BIFF8: - - Offset Size Contents - 0 2 Option flags: - Bit Mask Contents - 0 0001H 1 = Row height and default font height do not match - 1 0002H 1 = Row is hidden - 2 0004H 1 = Additional space above the row - 3 0008H 1 = Additional space below the row - 2 2 Default height for unused rows, in twips = 1/20 of a point - - """ - _REC_ID = 0x0225 - - def __init__(self, options, def_height): - self._rec_data = pack('<2H', options, def_height) - - -class DefColWidthRecord(BiffRecord): - """ - This record specifies the default column width for columns that - do not have a specific width set using the record COLINFO or COLWIDTH. - This record has no effect, if a STANDARDWIDTH record is present in the file. - - Record DEFCOLWIDTH, BIFF2-BIFF8: - - Offset Size Contents - 0 2 Column width in characters, using the width of the zero - character from default font (first FONT record in the file) - """ - _REC_ID = 0x0055 - - def __init__(self, def_width): - self._rec_data = pack('<H', options, def_width) - -class HorizontalPageBreaksRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains all - horizontal manual page breaks. - - Record HORIZONTALPAGEBREAKS, BIFF8: - Offset Size Contents - 0 2 Number of following row index structures (nm) - 2 6nm List of nm row index structures. Each row index - structure contains: - Offset Size Contents - 0 2 Index to first row below the page break - 2 2 Index to first column of this page break - 4 2 Index to last column of this page break - - The row indexes in the lists must be ordered ascending. - If in BIFF8 a row contains several page breaks, they must be ordered - ascending by start column index. - """ - _REC_ID = 0x001B - - def __init__(self, breaks_list): - self._rec_data = pack('<H', len(breaks_list)) - for r, c1, c2 in breaks_list: - self._rec_data += pack('<3H', r, c1, c2) - -class VerticalPageBreaksRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains all - vertical manual page breaks. - - Record VERTICALPAGEBREAKS, BIFF8: - Offset Size Contents - 0 2 Number of following column index structures (nm) - 2 6nm List of nm column index structures. Each column index - structure contains: - Offset Size Contents - 0 2 Index to first column following the page - break - 2 2 Index to first row of this page break - 4 2 Index to last row of this page break - - The column indexes in the lists must be ordered ascending. - If in BIFF8 a column contains several page breaks, they must be ordered - ascending by start row index. - """ - _REC_ID = 0x001A - - def __init__(self, breaks_list): - self._rec_data = pack('<H', len(breaks_list)) - for r, c1, c2 in breaks_list: - self._rec_data += pack('<3H', r, c1, c2) - -class HeaderRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It specifies the - page header string for the current worksheet. If this record is not - present or completely empty (record size is 0), the sheet does not - contain a page header. - - Record HEADER for non-empty page header, BIFF2-BIFF8: - Offset Size Contents - 0 var. Page header string - BIFF2-BIFF7: Non-empty byte string, 8bit string - length - BIFF8: Non-empty Unicode string, 16bit string length - The header string may contain special commands, i.e. placeholders for - the page number, current date, or text formatting attributes. These - fields are represented by single letters (exception: font name and - size, see below) with a leading ampersand ("&"). If the ampersand - is part of the regular header text, it will be duplicated ("&&"). The - page header is divided into 3 sections: the left, the centred, and the - right section. Each section is introduced by a special command. All - text and all commands following are part of the selected section. Each - section starts with the text formatting specified in the default font - (first FONT record in the file). Active formatting attributes from - a previous section do not go into the next section. - - The following table shows all available commands: - - Command Contents - && The "&" character itself - &L Start of the left section - &C Start of the centred section - &R Start of the right section - &P Current page number - &N Page count - &D Current date - &T Current time - &A Sheet name (BIFF5-BIFF8) - &F File name without path - &Z File path without file name (BIFF8X) - &G Picture (BIFF8X) - &B Bold on/off (BIFF2-BIFF4) - &I Italic on/off (BIFF2-BIFF4) - &U Underlining on/off - &E Double underlining on/off (BIFF5-BIFF8) - &S Strikeout on/off - &X Superscript on/off (BIFF5-BIFF8) - &Y Subscript on/off (BIFF5-BIFF8) - &"<fontname>" Set new font <fontname> - &"<fontname>,<fontstyle>" - Set new font with specified style <fontstyle>. - The style <fontstyle> 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) - &<fontheight> Set font height in points (<fontheight> 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('<H', is_horz_center) - - -class VCenterRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It specifies if the - sheet is centred vertically when printed. - - Record VCENTER, BIFF3-BIFF8: - - Offset Size Contents - 0 2 0 = Print sheet aligned at top page border - 1 = Print sheet vertically centred - - """ - _REC_ID = 0x0084 - - def __init__(self, is_vert_center): - self._rec_data = pack('<H', is_vert_center) - - -class LeftMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the left - page margin of the current worksheet. - - Record LEFTMARGIN, BIFF2-BIFF8: - - Offset Size Contents - 0 8 Left page margin in inches - (IEEE 754 floating-point value, 64bit double precision) - - """ - _REC_ID = 0x0026 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - - -class RightMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the right - page margin of the current worksheet. - - Offset Size Contents - 0 8 Right page margin in inches - (IEEE 754 floating-point value, 64?bit double precision) - - """ - _REC_ID = 0x0027 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - -class TopMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the top - page margin of the current worksheet. - - Offset Size Contents - 0 8 Top page margin in inches - (IEEE 754 floating-point value, 64?bit double precision) - - """ - _REC_ID = 0x0028 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - - -class BottomMarginRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It contains the bottom - page margin of the current worksheet. - - Offset Size Contents - 0 8 Bottom page margin in inches - (IEEE 754 floating-point value, 64?bit double precision) - - """ - _REC_ID = 0x0029 - - def __init__(self, margin): - self._rec_data = pack('<d', margin) - -class SetupPageRecord(BiffRecord): - """ - This record is part of the Page Settings Block. It stores the page - format settings of the current sheet. The pages may be scaled in - percent or by using an absolute number of pages. This setting is - located in the WSBOOL record. If pages are scaled in percent, - the scaling factor in this record is used, otherwise the "Fit to - pages" values. One of the "Fit to pages" values may be 0. In this case - the sheet is scaled to fit only to the other value. - - Record SETUP, BIFF5-BIFF8: - - Offset Size Contents - 0 2 Paper size (see below) - 2 2 Scaling factor in percent - 4 2 Start page number - 6 2 Fit worksheet width to this number of pages - (0 = use as many as needed) - 8 2 Fit worksheet height to this number of pages - (0 = use as many as needed) - 10 2 Option flags: - Bit Mask Contents - 0 0001H 0 = Print pages in columns - 1 = Print pages in rows - 1 0002H 0 = Landscape - 1 = Portrait - 2 0004H 1 = Paper size, scaling factor, - paper orientation (portrait/landscape), - print resolution and number of copies - are not initialised - 3 0008H 0 = Print coloured - 1 = Print black and white - 4 0010H 0 = Default print quality - 1 = Draft quality - 5 0020H 0 = Do not print cell notes - 1 = Print cell notes - 6 0040H 0 = Paper orientation setting is valid - 1 = Paper orientation setting not - initialised - 7 0080H 0 = Automatic page numbers - 1 = Use start page number - The following flags are valid for BIFF8 only: - 9 0200H 0 = Print notes as displayed - 1 = Print notes at end of sheet - 11-10 0C00H 00 = Print errors as displayed - 01 = Do not print errors - 10 = Print errors as "--" - 11 = Print errors as "#N/A!" - 12 2 Print resolution in dpi - 14 2 Vertical print resolution in dpi - 16 8 Header margin (IEEE 754 floating-point value, - 64bit double precision) - 24 8 Footer margin (IEEE 754 floating-point value, - 64bit double precision) - 32 2 Number of copies to print - - - PAPER TYPES: - - Index Paper type Paper size - 0 Undefined - 1 Letter 8 1/2" x 11" - 2 Letter small 8 1/2" x 11" - 3 Tabloid 11" x 17" - 4 Ledger 17" x 11" - 5 Legal 8 1/2" x 14" - 6 Statement 5 1/2" x 8 1/2" - 7 Executive 7 1/4" x 10 1/2" - 8 A3 297mm x 420mm - 9 A4 210mm x 297mm - 10 A4 small 210mm x 297mm - 11 A5 148mm x 210mm - 12 B4 (JIS) 257mm x 364mm - 13 B5 (JIS) 182mm x 257mm - 14 Folio 8 1/2" x 13" - 15 Quarto 215mm x 275mm - 16 10x14 10" x 14" - 17 11x17 11" x 17" - 18 Note 8 1/2" x 11" - 19 Envelope #9 3 7/8" x 8 7/8" - 20 Envelope #10 4 1/8" x 9 1/2" - 21 Envelope #11 4 1/2" x 10 3/8" - 22 Envelope #12 4 3/4" x 11" - 23 Envelope #14 5" x 11 1/2" - 24 C 17" x 22" - 25 D 22" x 34" - 26 E 34" x 44" - 27 Envelope DL 110mm x 220mm - 28 Envelope C5 162mm x 229mm - 29 Envelope C3 324mm x 458mm - 30 Envelope C4 229mm x 324mm - 31 Envelope C6 114mm x 162mm - 32 Envelope C6/C5 114mm x 229mm - 33 B4 (ISO) 250mm x 353mm - 34 B5 (ISO) 176mm x 250mm - 35 B6 (ISO) 125mm x 176mm - 36 Envelope Italy 110mm x 230mm - 37 Envelope Monarch 3 7/8" x 7 1/2" - 38 63/4 Envelope 3 5/8" x 6 1/2" - 39 US Standard Fanfold 14 7/8" x 11" - 40 German Std. Fanfold 8 1/2" x 12" - 41 German Legal Fanfold 8 1/2" x 13" - 42 B4 (ISO) 250mm x 353mm - 43 Japanese Postcard 100mm x 148mm - 44 9x11 9" x 11" - 45 10x11 10" x 11" - 46 15x11 15" x 11" - 47 Envelope Invite 220mm x 220mm - 48 Undefined - 49 Undefined - 50 Letter Extra 9 1/2" x 12" - 51 Legal Extra 9 1/2" x 15" - 52 Tabloid Extra 11 11/16" x 18" - 53 A4 Extra 235mm x 322mm - 54 Letter Transverse 8 1/2" x 11" - 55 A4 Transverse 210mm x 297mm - 56 Letter Extra Transv. 9 1/2" x 12" - 57 Super A/A4 227mm x 356mm - 58 Super B/A3 305mm x 487mm - 59 Letter Plus 8 1/2" x 12 11/16" - 60 A4 Plus 210mm x 330mm - 61 A5 Transverse 148mm x 210mm - 62 B5 (JIS) Transverse 182mm x 257mm - 63 A3 Extra 322mm x 445mm - 64 A5 Extra 174mm x 235mm - 65 B5 (ISO) Extra 201mm x 276mm - 66 A2 420mm x 594mm - 67 A3 Transverse 297mm x 420mm - 68 A3 Extra Transverse 322mm x 445mm - 69 Dbl. Japanese Postcard 200mm x 148mm - 70 A6 105mm x 148mm - 71 - 72 - 73 - 74 - 75 Letter Rotated 11" x 8 1/2" - 76 A3 Rotated 420mm x 297mm - 77 A4 Rotated 297mm x 210mm - 78 A5 Rotated 210mm x 148mm - 79 B4 (JIS) Rotated 364mm x 257mm - 80 B5 (JIS) Rotated 257mm x 182mm - 81 Japanese Postcard Rot. 148mm x 100mm - 82 Dbl. Jap. Postcard Rot. 148mm x 200mm - 83 A6 Rotated 148mm x 105mm - 84 - 85 - 86 - 87 - 88 B6 (JIS) 128mm x 182mm - 89 B6 (JIS) Rotated 182mm x 128mm - 90 12x11 12" x 11" - - """ - _REC_ID = 0x00A1 - def __init__(self, paper, scaling, start_num, fit_width_to, fit_height_to, - options, - hres, vres, - header_margin, footer_margin, - num_copies): - self._rec_data = pack('<8H2dH', paper, scaling, start_num, - fit_width_to, fit_height_to, \ - options, - hres, vres, - header_margin, footer_margin, - num_copies) - -class NameRecord(BiffRecord): - """ - This record is part of a Link Table. It contains the name and the token - array of an internal defined name. Token arrays of defined names - contain tokens with aberrant token classes. - - Record NAME, BIFF5/BIFF7: - Offset Size Contents - 0 2 Option flags, see below - 2 1 Keyboard shortcut (only for command macro names, see below) - 3 1 Length of the name (character count, ln) - 4 2 Size of the formula data (sz) - 6 2 0 = Global name, otherwise index to EXTERNSHEET record (one-based) - 8 2 0 = Global name, otherwise index to sheet (one-based) - 10 1 Length of menu text (character count, lm) - 11 1 Length of description text (character count, ld) - 12 1 Length of help topic text (character count, lh) - 13 1 Length of status bar text (character count, ls) - 14 ln Character array of the name - 14+ln sz Formula data (RPN token array without size field, 4) - 14+ln+sz lm Character array of menu text - var. ld Character array of description text - var. lh Character array of help topic text - var. ls Character array of status bar text - - Record NAME, BIFF8: - Offset Size Contents - 0 2 Option flags, see below - 2 1 Keyboard shortcut (only for command macro names, see below) - 3 1 Length of the name (character count, ln) - 4 2 Size of the formula data (sz) - 6 2 Not used - 8 2 0 = Global name, otherwise index to sheet (one-based) - 10 1 Length of menu text (character count, lm) - 11 1 Length of description text (character count, ld) - 12 1 Length of help topic text (character count, lh) - 13 1 Length of status bar text (character count, ls) - 14 var. Name (Unicode string without length field, 3.4) - var. sz Formula data (RPN token array without size field, 4) - [var.] var. (optional, only if lm > 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=b'', desc_text=b'', help_text=b'', status_text=b''): - if type(name) == int: - uname = chr(name) - else: - uname = upack1(name)[1:] - uname_len = len(uname) - - #~ self._rec_data = pack('<HBBHHHBBBB%ds%ds' % (uname_len, len(rpn)), options, keyboard_shortcut, uname_len, len(rpn), 0x0000, sheet_index, len(menu_text), len(desc_text), len(help_text), len(status_text), uname, rpn) + menu_text + desc_text + help_text + status_text - self._rec_data = pack('<HBBHHHBBBBB%ds%ds' % (uname_len, len(rpn)), options, keyboard_shortcut, uname_len, len(rpn), 0x0000, sheet_index, 0x00, len(menu_text), len(desc_text), len(help_text), len(status_text), uname, rpn) + menu_text + desc_text + help_text + status_text - -# Excel (both 2003 and 2007) don't like refs -# split over a record boundary, which is what the -# standard BiffRecord.get method does. - -# 8224 max data bytes in a BIFF record -# 6 bytes per ref -# 1370 = floor((8224 - 2) / 6.0) max refs in a record - -_maxRefPerRecord = 1370 - -class ExternSheetRecord(BiffRecord): - """ - In BIFF8 the record stores a list with indexes to SUPBOOK - records (list of REF structures, 6.100). See 5.10.3 for - details about external references in BIFF8. - - Record EXTERNSHEET, BIFF8: - Offset Size Contents - 0 2 Number of following REF structures (nm) - 2 6nm List of nm REF structures. Each REF contains the following data: - Offset Size Contents - 0 2 Index to SUPBOOK record - 2 2 Index to first SUPBOOK sheet - 4 2 Index to last SUPBOOK sheet - """ - _REC_ID = 0x0017 - - def __init__(self, refs): - - # do we always need this ref? or only if there are no refs? - # (I believe that if there are no refs then we should not generate the link table - Ruben) - #refs.insert(0, (0,0,0)) - - self.refs = refs - - def get(self): - res = [] - nrefs = len(self.refs) - for idx in range(0, nrefs, _maxRefPerRecord): - chunk = self.refs[idx:idx+_maxRefPerRecord] - krefs = len(chunk) - if idx: # CONTINUE record - header = pack("<HH", 0x003C, 6 * krefs) - else: # ExternSheetRecord - header = pack("<HHH", self._REC_ID, 6 * krefs + 2, nrefs) - res.append(header) - res.extend([pack("<HHH", *r) for r in chunk]) - return b''.join(res) - -class SupBookRecord(BiffRecord): - """ - This record mainly stores the URL of an external document - and a list of sheet names inside this document. Furthermore - it is used to store DDE and OLE object links, or to indicate - an internal 3D reference or an add-in function. See 5.10.3 - for details about external references in BIFF8. - - """ - _REC_ID = 0x01AE - -class InternalReferenceSupBookRecord(SupBookRecord): - """ - In each file occurs a SUPBOOK that is used for internal 3D - references. It stores the number of sheets of the own document. - - Record SUPBOOK for 3D references, BIFF8: - Offset Size Contents - 0 2 Number of sheets in this document - 2 2 01H 04H (relict of BIFF5/BIFF7, the byte string "<04H>", see 3.9.1) - - """ - - def __init__(self, num_sheets): - self._rec_data = pack('<HBB', num_sheets, 0x01, 0x04) - -class XcallSupBookRecord(SupBookRecord): - """ - Add-in function names are stored in EXTERNNAME records following this record. - - Offset Size Contents - 0 2 0001H - 2 2 01H 3AH (relict of BIFF5, the byte string ':', see EXTERNSHEET record, 5.41) - - """ - - def __init__(self): - self._rec_data = pack('<HBB', 1, 0x01, 0x3A) - - -class ExternnameRecord(BiffRecord): - """ - Record EXTERNNAME for external names and Analysis add-in functions, BIFF5-BIFF8: - Offset Size Contents - 0 2 Option flags (see below) - 2 2 0 for global names, or: - BIFF5: One-based index to EXTERNSHEET record containing the sheet name, - BIFF8: One-based index to sheet list in preceding EXTERNALBOOK record. - 4 2 Not used - 6 var. BIFF5: Name (byte string, 8-bit string length, ?2.5.2). - BIFF8: Name (Unicode string, 8-bit string length, ?2.5.3). - See DEFINEDNAME record (?5.33) for a list of built-in names, if the built-in flag is set - in the option flags above. - var. var. Formula data (RPN token array, ?3) - - Option flags for external names (BIFF5-BIFF8) - Bit Mask Contents - 0 0001H 0 = Standard name; 1 = Built-in name - 1 0002H 0 = Manual link; 1 = Automatic link (DDE links and OLE links only) - 2 0004H 1 = Picture link (DDE links and OLE links only) - 3 0008H 1 = This is the “StdDocumentName†identifier (DDE links only) - 4 0010H 1 = OLE link - 14-5 7FE0H Clipboard format of last successful update (DDE links and OLE links only) - 15 8000H 1 = Iconified picture link (BIFF8 OLE links only) - """ - _REC_ID = 0x0023 - - def __init__(self, options=0, index=0, name=None, fmla=None): - self._rec_data = pack('<HHH', options, index, 0) + upack1(name) + fmla.encode() - diff --git a/tablib/packages/xlwt3/Bitmap.py b/tablib/packages/xlwt3/Bitmap.py deleted file mode 100644 index 5da082b..0000000 --- a/tablib/packages/xlwt3/Bitmap.py +++ /dev/null @@ -1,258 +0,0 @@ -# Portions are Copyright (C) 2005 Roman V. Kiseliov
-# Portions are Copyright (c) 2004 Evgeny Filatov <fufff@users.sourceforge.net>
-# Portions are Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel)
-
-from .BIFFRecords import BiffRecord
-from struct import *
-
-
-def _size_col(sheet, col):
- return sheet.col_width(col)
-
-
-def _size_row(sheet, row):
- return sheet.row_height(row)
-
-
-def _position_image(sheet, row_start, col_start, x1, y1, width, height):
- """Calculate the vertices that define the position of the image as required by
- the OBJ record.
-
- +------------+------------+
- | A | B |
- +-----+------------+------------+
- | |(x1,y1) | |
- | 1 |(A1)._______|______ |
- | | | | |
- | | | | |
- +-----+----| BITMAP |-----+
- | | | | |
- | 2 | |______________. |
- | | | (B2)|
- | | | (x2,y2)|
- +---- +------------+------------+
-
- Example of a bitmap that covers some of the area from cell A1 to cell B2.
-
- Based on the width and height of the bitmap we need to calculate 8 vars:
- col_start, row_start, col_end, row_end, x1, y1, x2, y2.
- The width and height of the cells are also variable and have to be taken into
- account.
- The values of col_start and row_start are passed in from the calling
- function. The values of col_end and row_end are calculated by subtracting
- the width and height of the bitmap from the width and height of the
- underlying cells.
- The vertices are expressed as a percentage of the underlying cell width as
- follows (rhs values are in pixels):
-
- x1 = X / W *1024
- y1 = Y / H *256
- x2 = (X-1) / W *1024
- y2 = (Y-1) / H *256
-
- Where: X is distance from the left side of the underlying cell
- Y is distance from the top of the underlying cell
- W is the width of the cell
- H is the height of the cell
-
- Note: the SDK incorrectly states that the height should be expressed as a
- percentage of 1024.
-
- col_start - Col containing upper left corner of object
- row_start - Row containing top left corner of object
- x1 - Distance to left side of object
- y1 - Distance to top of object
- width - Width of image frame
- height - Height of image frame
-
- """
- # Adjust start column for offsets that are greater than the col width
- while x1 >= _size_col(sheet, col_start):
- x1 -= _size_col(sheet, col_start)
- col_start += 1
- # Adjust start row for offsets that are greater than the row height
- while y1 >= _size_row(sheet, row_start):
- y1 -= _size_row(sheet, row_start)
- row_start += 1
- # Initialise end cell to the same as the start cell
- row_end = row_start # Row containing bottom right corner of object
- col_end = col_start # Col containing lower right corner of object
- width = width + x1 - 1
- height = height + y1 - 1
- # Subtract the underlying cell widths to find the end cell of the image
- while (width >= _size_col(sheet, col_end)):
- width -= _size_col(sheet, col_end)
- col_end += 1
- # Subtract the underlying cell heights to find the end cell of the image
- while (height >= _size_row(sheet, row_end)):
- height -= _size_row(sheet, row_end)
- row_end += 1
- # Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
- # with zero height or width.
- if ((_size_col(sheet, col_start) == 0) or (_size_col(sheet, col_end) == 0)
- or (_size_row(sheet, row_start) == 0) or (_size_row(sheet, row_end) == 0)):
- return
- # Convert the pixel values to the percentage value expected by Excel
- x1 = int(float(x1) / _size_col(sheet, col_start) * 1024)
- y1 = int(float(y1) / _size_row(sheet, row_start) * 256)
- # Distance to right side of object
- x2 = int(float(width) / _size_col(sheet, col_end) * 1024)
- # Distance to bottom of object
- y2 = int(float(height) / _size_row(sheet, row_end) * 256)
- return (col_start, x1, row_start, y1, col_end, x2, row_end, y2)
-
-
-class ObjBmpRecord(BiffRecord):
- _REC_ID = 0x005D # Record identifier
-
- def __init__(self, row, col, sheet, im_data_bmp, x, y, scale_x, scale_y):
- # Scale the frame of the image.
- width = im_data_bmp.width * scale_x
- height = im_data_bmp.height * scale_y
-
- # Calculate the vertices of the image and write the OBJ record
- coordinates = _position_image(sheet, row, col, x, y, width, height)
- # print coordinates
- col_start, x1, row_start, y1, col_end, x2, row_end, y2 = coordinates
-
- """Store the OBJ record that precedes an IMDATA record. This could be generalise
- to support other Excel objects.
-
- """
- cObj = 0x0001 # Count of objects in file (set to 1)
- OT = 0x0008 # Object type. 8 = Picture
- id = 0x0001 # Object ID
- grbit = 0x0614 # Option flags
- colL = col_start # Col containing upper left corner of object
- dxL = x1 # Distance from left side of cell
- rwT = row_start # Row containing top left corner of object
- dyT = y1 # Distance from top of cell
- colR = col_end # Col containing lower right corner of object
- dxR = x2 # Distance from right of cell
- rwB = row_end # Row containing bottom right corner of object
- dyB = y2 # Distance from bottom of cell
- cbMacro = 0x0000 # Length of FMLA structure
- Reserved1 = 0x0000 # Reserved
- Reserved2 = 0x0000 # Reserved
- icvBack = 0x09 # Background colour
- icvFore = 0x09 # Foreground colour
- fls = 0x00 # Fill pattern
- fAuto = 0x00 # Automatic fill
- icv = 0x08 # Line colour
- lns = 0xff # Line style
- lnw = 0x01 # Line weight
- fAutoB = 0x00 # Automatic border
- frs = 0x0000 # Frame style
- cf = 0x0009 # Image format, 9 = bitmap
- Reserved3 = 0x0000 # Reserved
- cbPictFmla = 0x0000 # Length of FMLA structure
- Reserved4 = 0x0000 # Reserved
- grbit2 = 0x0001 # Option flags
- Reserved5 = 0x0000 # Reserved
-
- data = pack("<L", cObj)
- data += pack("<H", OT)
- data += pack("<H", id)
- data += pack("<H", grbit)
- data += pack("<H", colL)
- data += pack("<H", dxL)
- data += pack("<H", rwT)
- data += pack("<H", dyT)
- data += pack("<H", colR)
- data += pack("<H", dxR)
- data += pack("<H", rwB)
- data += pack("<H", dyB)
- data += pack("<H", cbMacro)
- data += pack("<L", Reserved1)
- data += pack("<H", Reserved2)
- data += pack("<B", icvBack)
- data += pack("<B", icvFore)
- data += pack("<B", fls)
- data += pack("<B", fAuto)
- data += pack("<B", icv)
- data += pack("<B", lns)
- data += pack("<B", lnw)
- data += pack("<B", fAutoB)
- data += pack("<H", frs)
- data += pack("<L", cf)
- data += pack("<H", Reserved3)
- data += pack("<H", cbPictFmla)
- data += pack("<H", Reserved4)
- data += pack("<H", grbit2)
- data += pack("<L", Reserved5)
-
- self._rec_data = data
-
-def _process_bitmap(bitmap):
- """Convert a 24 bit bitmap into the modified internal format used by Windows.
- This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
- MSDN library.
-
- """
- # Open file and binmode the data in case the platform needs it.
- fh = open(bitmap, 'rb')
- try:
- # Slurp the file into a string.
- data = fh.read()
- finally:
- fh.close()
- # Check that the file is big enough to be a bitmap.
- if len(data) <= 0x36:
- raise Exception("bitmap doesn't contain enough data.")
- # The first 2 bytes are used to identify the bitmap.
- if (data[:2] != b"BM"):
- raise Exception("bitmap doesn't appear to to be a valid bitmap image.")
- # Remove bitmap data: ID.
- data = data[2:]
- # Read and remove the bitmap size. This is more reliable than reading
- # the data size at offset 0x22.
- #
- size = unpack("<L", data[:4])[0]
- size -= 0x36 # Subtract size of bitmap header.
- size += 0x0C # Add size of BIFF header.
- data = data[4:]
- # Remove bitmap data: reserved, offset, header length.
- data = data[12:]
- # Read and remove the bitmap width and height. Verify the sizes.
- width, height = unpack("<LL", data[:8])
- data = data[8:]
- if (width > 0xFFFF):
- raise Exception("bitmap: largest image width supported is 65k.")
- if (height > 0xFFFF):
- raise Exception("bitmap: largest image height supported is 65k.")
- # Read and remove the bitmap planes and bpp data. Verify them.
- planes, bitcount = unpack("<HH", data[:4])
- data = data[4:]
- if (bitcount != 24):
- raise Exception("bitmap isn't a 24bit true color bitmap.")
- if (planes != 1):
- raise Exception("bitmap: only 1 plane supported in bitmap image.")
- # Read and remove the bitmap compression. Verify compression.
- compression = unpack("<L", data[:4])[0]
- data = data[4:]
- if (compression != 0):
- raise Exception("bitmap: compression not supported in bitmap image.")
- # Remove bitmap data: data size, hres, vres, colours, imp. colours.
- data = data[20:]
- # Add the BITMAPCOREHEADER data
- header = pack("<LHHHH", 0x000c, width, height, 0x01, 0x18)
- data = header + data
- return (width, height, size, data)
-
-
-class ImDataBmpRecord(BiffRecord):
- _REC_ID = 0x007F
-
- def __init__(self, filename):
- """Insert a 24bit bitmap image in a worksheet. The main record required is
- IMDATA but it must be proceeded by a OBJ record to define its position.
-
- """
- BiffRecord.__init__(self)
-
- self.width, self.height, self.size, data = _process_bitmap(filename)
- # Write the IMDATA record to store the bitmap data
- cf = 0x09
- env = 0x01
- lcb = self.size
- self._rec_data = pack("<HHL", cf, env, lcb) + data
diff --git a/tablib/packages/xlwt3/Cell.py b/tablib/packages/xlwt3/Cell.py deleted file mode 100644 index 08a9e42..0000000 --- a/tablib/packages/xlwt3/Cell.py +++ /dev/null @@ -1,233 +0,0 @@ -from struct import unpack, pack
-from . import BIFFRecords
-
-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 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 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
- 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:
- 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):
- return 1, w23
-
- packed100 = pack('<d', temp)
- w01, w23 = unpack('<2i', packed100)
- if not w01 and not(w23 & 3):
- return 1, w23 | 1
-
- 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 = b'' # (to_py3): 'b' binary data
- for j in range(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))
- # (to_py3): 'b' binary data
- 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))
- # (to_py3): 'b' binary data
- 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) # (to_py3): 'b' binary data
diff --git a/tablib/packages/xlwt3/Column.py b/tablib/packages/xlwt3/Column.py deleted file mode 100644 index 4c75a2c..0000000 --- a/tablib/packages/xlwt3/Column.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: windows-1252 -*-
-
-from .BIFFRecords import ColInfoRecord
-
-class Column(object):
- def __init__(self, colx, parent_sheet):
- if not(isinstance(colx, int) and 0 <= colx <= 255):
- raise ValueError("column index (%r) not an int in range(256)" % colx)
- self._index = colx
- self._parent = parent_sheet
- self._parent_wb = parent_sheet.get_parent()
- self._xf_index = 0x0F
-
- self.width = 0x0B92
- self.hidden = 0
- self.level = 0
- self.collapse = 0
-
- def set_style(self, style):
- self._xf_index = self._parent_wb.add_style(style)
-
- def width_in_pixels(self):
- # *** Approximation ****
- return int(round(self.width * 0.0272 + 0.446, 0))
-
- def get_biff_record(self):
- options = (self.hidden & 0x01) << 0
- options |= (self.level & 0x07) << 8
- options |= (self.collapse & 0x01) << 12
-
- return ColInfoRecord(self._index, self._index, self.width, self._xf_index, options).get()
-
-
-
diff --git a/tablib/packages/xlwt3/CompoundDoc.py b/tablib/packages/xlwt3/CompoundDoc.py deleted file mode 100644 index d53726f..0000000 --- a/tablib/packages/xlwt3/CompoundDoc.py +++ /dev/null @@ -1,516 +0,0 @@ -import sys
-import struct
-
-ENCODING = 'utf-16-le'
-
-class Reader:
- def __init__(self, filename, dump = False):
- self.dump = dump
- self.STREAMS = {}
-
- doc = file(filename, 'rb').read()
- self.header, self.data = doc[0:512], doc[512:]
- del doc
-
- self.__build_header()
- self.__build_MSAT()
- self.__build_SAT()
- self.__build_directory()
- self.__build_short_sectors_data()
-
- if len(self.short_sectors_data) > 0:
- self.__build_SSAT()
- else:
- if self.dump and (self.total_ssat_sectors != 0 or self.ssat_start_sid != -2):
- print('NOTE: header says that must be', self.total_ssat_sectors, 'short sectors')
- print('NOTE: starting at', self.ssat_start_sid, 'sector')
- print('NOTE: but file does not contains data in short sectors')
- self.ssat_start_sid = -2
- self.total_ssat_sectors = 0
- self.SSAT = [-2]
-
- for dentry in self.dir_entry_list[1:]:
- (did,
- sz, name,
- t, c,
- did_left, did_right, did_root,
- dentry_start_sid,
- stream_size
- ) = dentry
- stream_data = b''
- if stream_size > 0:
- if stream_size >= self.min_stream_size:
- args = (self.data, self.SAT, dentry_start_sid, self.sect_size)
- else:
- args = (self.short_sectors_data, self.SSAT, dentry_start_sid, self.short_sect_size)
- stream_data = self.get_stream_data(*args)
-
- if name != b'':
- # BAD IDEA: names may be equal. NEED use full paths...
- self.STREAMS[name] = stream_data
-
-
- def __build_header(self):
- self.doc_magic = self.header[0:8]
-
- if self.doc_magic != b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1':
- raise Exception('Not an OLE file.')
-
- self.file_uid = self.header[8:24]
- self.rev_num = self.header[24:26]
- self.ver_num = self.header[26:28]
- self.byte_order = self.header[28:30]
- self.log2_sect_size, = struct.unpack('<H', self.header[30:32])
- self.log2_short_sect_size, = struct.unpack('<H', self.header[32:34])
- self.total_sat_sectors, = struct.unpack('<L', self.header[44:48])
- self.dir_start_sid, = struct.unpack('<l', self.header[48:52])
- self.min_stream_size, = struct.unpack('<L', self.header[56:60])
- self.ssat_start_sid, = struct.unpack('<l', self.header[60:64])
- self.total_ssat_sectors, = struct.unpack('<L', self.header[64:68])
- self.msat_start_sid, = struct.unpack('<l', self.header[68:72])
- self.total_msat_sectors, = struct.unpack('<L', self.header[72:76])
-
- self.sect_size = 1 << self.log2_sect_size
- self.short_sect_size = 1 << self.log2_short_sect_size
-
- if self.dump:
- print('file magic: ')
- print_bin_data(self.doc_magic)
-
- print('file uid: ')
- print_bin_data(self.file_uid)
-
- print('revision number: ')
- print_bin_data(self.rev_num)
-
- print('version number: ')
- print_bin_data(self.ver_num)
-
- print('byte order: ')
- print_bin_data(self.byte_order)
-
- print('sector size :', hex(self.sect_size), self.sect_size)
- #print 'total sectors in file :', hex(self.total_sectors), self.total_sectors
- print('short sector size :', hex(self.short_sect_size), self.short_sect_size)
- print('Total number of sectors used for the SAT :', hex(self.total_sat_sectors), self.total_sat_sectors)
- print('SID of first sector of the directory stream:', hex(self.dir_start_sid), self.dir_start_sid)
- print('Minimum size of a standard stream :', hex(self.min_stream_size), self.min_stream_size)
- print('SID of first sector of the SSAT :', hex(self.ssat_start_sid), self.ssat_start_sid)
- print('Total number of sectors used for the SSAT :', hex(self.total_ssat_sectors), self.total_ssat_sectors)
- print('SID of first additional sector of the MSAT :', hex(self.msat_start_sid), self.msat_start_sid)
- print('Total number of sectors used for the MSAT :', hex(self.total_msat_sectors), self.total_msat_sectors)
-
-
- def __build_MSAT(self):
- self.MSAT = list(struct.unpack('<109l', self.header[76:]))
-
- next = self.msat_start_sid
- while next > 0:
- msat_sector = struct.unpack('<128l', self.data[next*self.sect_size:(next+1)*self.sect_size])
- self.MSAT.extend(msat_sector[:127])
- next = msat_sector[-1]
-
- if self.dump:
- print('MSAT (header part): \n', self.MSAT[:109])
- print('additional MSAT sectors: \n', self.MSAT[109:])
-
-
- def __build_SAT(self):
- sat_stream = b''.join([self.data[i*self.sect_size:(i+1)*self.sect_size] for i in self.MSAT if i >= 0])
-
- sat_sids_count = len(sat_stream) >> 2
- self.SAT = struct.unpack('<%dl' % sat_sids_count, sat_stream) # SIDs tuple
-
- if self.dump:
- print('SAT sid count:\n', sat_sids_count)
- print('SAT content:\n', self.SAT)
-
-
- def __build_SSAT(self):
- ssat_stream = self.get_stream_data(self.data, self.SAT, self.ssat_start_sid, self.sect_size)
-
- ssids_count = len(ssat_stream) >> 2
- self.SSAT = struct.unpack('<%dl' % ssids_count, ssat_stream)
-
- if self.dump:
- print('SSID count:', ssids_count)
- print('SSAT content:\n', self.SSAT)
-
-
- def __build_directory(self):
- dir_stream = self.get_stream_data(self.data, self.SAT, self.dir_start_sid, self.sect_size)
-
- self.dir_entry_list = []
-
- i = 0
- while i < len(dir_stream):
- dentry = dir_stream[i:i+128] # 128 -- dir entry size
- i += 128
-
- did = len(self.dir_entry_list)
- sz, = struct.unpack('<H', dentry[64:66])
- if sz > 0 :
- name = dentry[0:sz-2].decode('utf_16_le', 'replace')
- else:
- name = b''
- t, = struct.unpack('B', dentry[66])
- c, = struct.unpack('B', dentry[67])
- did_left , = struct.unpack('<l', dentry[68:72])
- did_right , = struct.unpack('<l', dentry[72:76])
- did_root , = struct.unpack('<l', dentry[76:80])
- dentry_start_sid , = struct.unpack('<l', dentry[116:120])
- stream_size , = struct.unpack('<L', dentry[120:124])
-
- self.dir_entry_list.extend([(did, sz, name, t, c,
- did_left, did_right, did_root,
- dentry_start_sid, stream_size)])
-
- if self.dump:
- dentry_types = {
- 0x00: 'Empty',
- 0x01: 'User storage',
- 0x02: 'User stream',
- 0x03: 'LockBytes',
- 0x04: 'Property',
- 0x05: 'Root storage'
- }
- node_colours = {
- 0x00: 'Red',
- 0x01: 'Black'
- }
- print('total directory entries:', len(self.dir_entry_list))
-
- for dentry in self.dir_entry_list:
- (did, sz, name, t, c,
- did_left, did_right, did_root,
- dentry_start_sid, stream_size) = dentry
- print('DID', did)
- print('Size of the used area of the character buffer of the name:', sz)
- print('dir entry name:', repr(name))
- print('type of entry:', t, dentry_types[t])
- print('entry colour:', c, node_colours[c])
- print('left child DID :', did_left)
- print('right child DID:', did_right)
- print('root DID :', did_root)
- print('start SID :', dentry_start_sid)
- print('stream size :', stream_size)
- if stream_size == 0:
- print('stream is empty')
- elif stream_size >= self.min_stream_size:
- print('stream stored as normal stream')
- else:
- print('stream stored as short-stream')
-
-
- def __build_short_sectors_data(self):
- (did, sz, name, t, c,
- did_left, did_right, did_root,
- dentry_start_sid, stream_size) = self.dir_entry_list[0]
- assert t == 0x05 # Short-Stream Container Stream (SSCS) resides in Root Storage
- if stream_size == 0:
- self.short_sectors_data = b''
- else:
- self.short_sectors_data = self.get_stream_data(self.data, self.SAT, dentry_start_sid, self.sect_size)
-
-
- def get_stream_data(self, data, SAT, start_sid, sect_size):
- sid = start_sid
- chunks = [(sid, sid)]
- stream_data = b''
-
- while SAT[sid] >= 0:
- next_in_chain = SAT[sid]
- last_chunk_start, last_chunk_finish = chunks[-1]
- if next_in_chain == last_chunk_finish + 1:
- chunks[-1] = last_chunk_start, next_in_chain
- else:
- chunks.extend([(next_in_chain, next_in_chain)])
- sid = next_in_chain
- for s, f in chunks:
- stream_data += data[s*sect_size:(f+1)*sect_size]
- #print chunks
- return stream_data
-
-
-def print_bin_data(data):
- i = 0
- while i < len(data):
- j = 0
- while (i < len(data)) and (j < 16):
- c = b'0x%02X' % ord(data[i])
- sys.stdout.write(c)
- sys.stdout.write(' ')
- i += 1
- j += 1
- print()
- if i == 0:
- print('<NO DATA>')
-
-
-
-# This implementation writes only 'Root Entry', 'Workbook' streams
-# and 2 empty streams for aligning directory stream on sector boundary
-#
-# LAYOUT:
-# 0 header
-# 76 MSAT (1st part: 109 SID)
-# 512 workbook stream
-# ... additional MSAT sectors if streams' size > about 7 Mb == (109*512 * 128)
-# ... SAT
-# ... directory stream
-#
-# NOTE: this layout is "ad hoc". It can be more general. RTFM
-
-class XlsDoc:
- SECTOR_SIZE = 0x0200
- MIN_LIMIT = 0x1000
-
- SID_FREE_SECTOR = -1
- SID_END_OF_CHAIN = -2
- SID_USED_BY_SAT = -3
- SID_USED_BY_MSAT = -4
-
- def __init__(self):
- self.book_stream_sect = []
-
- self.dir_stream = b''
- self.dir_stream_sect = []
-
- self.packed_SAT = b''
- self.SAT_sect = []
-
- self.packed_MSAT_1st = b''
- self.packed_MSAT_2nd = b''
- self.MSAT_sect_2nd = []
-
- self.header = b''
-
- def __build_directory(self): # align on sector boundary
- self.dir_stream = b''
-
- #(to_py3): replaced = b'\x00'.join(b'Root Entry\x00') + b'\x00'
- dentry_name = 'Root Entry\x00'.encode(ENCODING)
- dentry_name_sz = len(dentry_name)
- dentry_name_pad = b'\x00'*(64 - dentry_name_sz)
- dentry_type = 0x05 # root storage
- dentry_colour = 0x01 # black
- dentry_did_left = -1
- dentry_did_right = -1
- dentry_did_root = 1
- dentry_start_sid = -2
- dentry_stream_sz = 0
-
- self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L',
- dentry_name + dentry_name_pad,
- dentry_name_sz,
- dentry_type,
- dentry_colour,
- dentry_did_left,
- dentry_did_right,
- dentry_did_root,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- dentry_start_sid,
- dentry_stream_sz,
- 0
- )
- # (to_py3): replaced = b'\x00'.join(b'Workbook\x00') + b'\x00'
- dentry_name = 'Workbook\x00'.encode(ENCODING)
- dentry_name_sz = len(dentry_name)
- dentry_name_pad = b'\x00'*(64 - dentry_name_sz)
- dentry_type = 0x02 # user stream
- dentry_colour = 0x01 # black
- dentry_did_left = -1
- dentry_did_right = -1
- dentry_did_root = -1
- dentry_start_sid = 0
- dentry_stream_sz = self.book_stream_len
-
- self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L',
- dentry_name + dentry_name_pad,
- dentry_name_sz,
- dentry_type,
- dentry_colour,
- dentry_did_left,
- dentry_did_right,
- dentry_did_root,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- dentry_start_sid,
- dentry_stream_sz,
- 0
- )
-
- # padding
- dentry_name = b''
- dentry_name_sz = len(dentry_name)
- dentry_name_pad = b'\x00'*(64 - dentry_name_sz)
- dentry_type = 0x00 # empty
- dentry_colour = 0x01 # black
- dentry_did_left = -1
- dentry_did_right = -1
- dentry_did_root = -1
- dentry_start_sid = -2
- dentry_stream_sz = 0
-
- self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L',
- dentry_name + dentry_name_pad,
- dentry_name_sz,
- dentry_type,
- dentry_colour,
- dentry_did_left,
- dentry_did_right,
- dentry_did_root,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- dentry_start_sid,
- dentry_stream_sz,
- 0
- ) * 2
-
- def __build_sat(self):
- # Build SAT
- book_sect_count = self.book_stream_len >> 9
- dir_sect_count = len(self.dir_stream) >> 9
-
- total_sect_count = book_sect_count + dir_sect_count
- SAT_sect_count = 0
- MSAT_sect_count = 0
- SAT_sect_count_limit = 109
- while total_sect_count > 128*SAT_sect_count or SAT_sect_count > SAT_sect_count_limit:
- SAT_sect_count += 1
- total_sect_count += 1
- if SAT_sect_count > SAT_sect_count_limit:
- MSAT_sect_count += 1
- total_sect_count += 1
- SAT_sect_count_limit += 127
-
-
- SAT = [self.SID_FREE_SECTOR]*128*SAT_sect_count
-
- sect = 0
- while sect < book_sect_count - 1:
- self.book_stream_sect.append(sect)
- SAT[sect] = sect + 1
- sect += 1
- self.book_stream_sect.append(sect)
- SAT[sect] = self.SID_END_OF_CHAIN
- sect += 1
-
- while sect < book_sect_count + MSAT_sect_count:
- self.MSAT_sect_2nd.append(sect)
- SAT[sect] = self.SID_USED_BY_MSAT
- sect += 1
-
- while sect < book_sect_count + MSAT_sect_count + SAT_sect_count:
- self.SAT_sect.append(sect)
- SAT[sect] = self.SID_USED_BY_SAT
- sect += 1
-
- while sect < book_sect_count + MSAT_sect_count + SAT_sect_count + dir_sect_count - 1:
- self.dir_stream_sect.append(sect)
- SAT[sect] = sect + 1
- sect += 1
- self.dir_stream_sect.append(sect)
- SAT[sect] = self.SID_END_OF_CHAIN
- sect += 1
-
- self.packed_SAT = struct.pack('<%dl' % (SAT_sect_count*128), *SAT)
-
- MSAT_1st = [self.SID_FREE_SECTOR]*109
- for i, SAT_sect_num in zip(list(range(0, 109)), self.SAT_sect):
- MSAT_1st[i] = SAT_sect_num
- self.packed_MSAT_1st = struct.pack('<109l', *MSAT_1st)
-
- MSAT_2nd = [self.SID_FREE_SECTOR]*128*MSAT_sect_count
- if MSAT_sect_count > 0:
- MSAT_2nd[- 1] = self.SID_END_OF_CHAIN
-
- i = 109
- msat_sect = 0
- sid_num = 0
- while i < SAT_sect_count:
- if (sid_num + 1) % 128 == 0:
- #print 'link: ',
- msat_sect += 1
- if msat_sect < len(self.MSAT_sect_2nd):
- MSAT_2nd[sid_num] = self.MSAT_sect_2nd[msat_sect]
- else:
- #print 'sid: ',
- MSAT_2nd[sid_num] = self.SAT_sect[i]
- i += 1
- #print sid_num, MSAT_2nd[sid_num]
- sid_num += 1
-
- self.packed_MSAT_2nd = struct.pack('<%dl' % (MSAT_sect_count*128), *MSAT_2nd)
-
- #print vars()
- #print zip(range(0, sect), SAT)
- #print self.book_stream_sect
- #print self.MSAT_sect_2nd
- #print MSAT_2nd
- #print self.SAT_sect
- #print self.dir_stream_sect
-
-
- def __build_header(self):
- doc_magic = b'\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1'
- file_uid = b'\x00'*16
- rev_num = b'\x3E\x00'
- ver_num = b'\x03\x00'
- byte_order = b'\xFE\xFF'
- log_sect_size = struct.pack('<H', 9)
- log_short_sect_size = struct.pack('<H', 6)
- not_used0 = b'\x00'*10
- total_sat_sectors = struct.pack('<L', len(self.SAT_sect))
- dir_start_sid = struct.pack('<l', self.dir_stream_sect[0])
- not_used1 = b'\x00'*4
- min_stream_size = struct.pack('<L', 0x1000)
- ssat_start_sid = struct.pack('<l', -2)
- total_ssat_sectors = struct.pack('<L', 0)
-
- if len(self.MSAT_sect_2nd) == 0:
- msat_start_sid = struct.pack('<l', -2)
- else:
- msat_start_sid = struct.pack('<l', self.MSAT_sect_2nd[0])
-
- total_msat_sectors = struct.pack('<L', len(self.MSAT_sect_2nd))
-
- self.header = b''.join([ doc_magic,
- file_uid,
- rev_num,
- ver_num,
- byte_order,
- log_sect_size,
- log_short_sect_size,
- not_used0,
- total_sat_sectors,
- dir_start_sid,
- not_used1,
- min_stream_size,
- ssat_start_sid,
- total_ssat_sectors,
- msat_start_sid,
- total_msat_sectors
- ])
-
-
- def save(self, file_name_or_filelike_obj, stream):
- # 1. Align stream on 0x1000 boundary (and therefore on sector boundary)
- padding = b'\x00' * (0x1000 - (len(stream) % 0x1000))
- self.book_stream_len = len(stream) + len(padding)
-
- self.__build_directory()
- self.__build_sat()
- self.__build_header()
-
- f = file_name_or_filelike_obj
- we_own_it = not hasattr(f, 'write')
- if we_own_it:
- f = open(file_name_or_filelike_obj, 'wb')
- f.write(self.header)
- f.write(self.packed_MSAT_1st)
- f.write(stream)
- f.write(padding)
- f.write(self.packed_MSAT_2nd)
- f.write(self.packed_SAT)
- f.write(self.dir_stream)
- if we_own_it:
- f.close()
diff --git a/tablib/packages/xlwt3/ExcelFormula.py b/tablib/packages/xlwt3/ExcelFormula.py deleted file mode 100644 index f7cc771..0000000 --- a/tablib/packages/xlwt3/ExcelFormula.py +++ /dev/null @@ -1,41 +0,0 @@ -from . import ExcelFormulaParser, ExcelFormulaLexer
-import struct
-from .antlr import ANTLRException
-
-
-class Formula(object):
- __slots__ = ["__s", "__parser", "__sheet_refs", "__xcall_refs"]
-
-
- def __init__(self, s):
- try:
- self.__s = s
- lexer = ExcelFormulaLexer.Lexer(s)
- self.__parser = ExcelFormulaParser.Parser(lexer)
- self.__parser.formula()
- self.__sheet_refs = self.__parser.sheet_references
- self.__xcall_refs = self.__parser.xcall_references
- except ANTLRException as e:
- # print e
- raise ExcelFormulaParser.FormulaParseException("can't parse formula " + s)
-
- def get_references(self):
- return self.__sheet_refs, self.__xcall_refs
-
- def patch_references(self, patches):
- for offset, idx in patches:
- self.__parser.rpn = self.__parser.rpn[:offset] + struct.pack('<H', idx) + self.__parser.rpn[offset+2:]
-
- def text(self):
- return self.__s
-
- def rpn(self):
- '''
- Offset Size Contents
- 0 2 Size of the following formula data (sz)
- 2 sz Formula data (RPN token array)
- [2+sz] var. (optional) Additional data for specific tokens
-
- '''
- return struct.pack("<H", len(self.__parser.rpn)) + self.__parser.rpn
-
diff --git a/tablib/packages/xlwt3/ExcelFormulaLexer.py b/tablib/packages/xlwt3/ExcelFormulaLexer.py deleted file mode 100644 index 9b6103c..0000000 --- a/tablib/packages/xlwt3/ExcelFormulaLexer.py +++ /dev/null @@ -1,126 +0,0 @@ -import sys
-from .antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException
-import struct
-from . import ExcelFormulaParser
-from re import compile as recompile, match, UNICODE, IGNORECASE, VERBOSE
-
-
-int_const_pattern = r"\d+\b"
-flt_const_pattern = r"""
- (?:
- (?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
- |
- (?: \d+ \. ) # 1. 12. 123. etc
- )
- # followed by optional exponent part
- (?: [Ee] [+-]? \d+ ) ?
- """
-str_const_pattern = r'"(?:[^"]|"")*"'
-#range2d_pattern = recompile(r"\$?[A-I]?[A-Z]\$?\d+:\$?[A-I]?[A-Z]\$?\d+"
-ref2d_r1c1_pattern = r"[Rr]0*[1-9][0-9]*[Cc]0*[1-9][0-9]*"
-ref2d_pattern = r"\$?[A-I]?[A-Z]\$?0*[1-9][0-9]*"
-true_pattern = r"TRUE\b"
-false_pattern = r"FALSE\b"
-if_pattern = r"IF\b"
-choose_pattern = r"CHOOSE\b"
-name_pattern = r"\w[\.\w]*"
-quotename_pattern = r"'(?:[^']|'')*'" #### It's essential that this bracket be non-grouping.
-ne_pattern = r"<>"
-ge_pattern = r">="
-le_pattern = r"<="
-
-pattern_type_tuples = (
- (flt_const_pattern, ExcelFormulaParser.NUM_CONST),
- (int_const_pattern, ExcelFormulaParser.INT_CONST),
- (str_const_pattern, ExcelFormulaParser.STR_CONST),
-# (range2d_pattern , ExcelFormulaParser.RANGE2D),
- (ref2d_r1c1_pattern, ExcelFormulaParser.REF2D_R1C1),
- (ref2d_pattern , ExcelFormulaParser.REF2D),
- (true_pattern , ExcelFormulaParser.TRUE_CONST),
- (false_pattern , ExcelFormulaParser.FALSE_CONST),
- (if_pattern , ExcelFormulaParser.FUNC_IF),
- (choose_pattern , ExcelFormulaParser.FUNC_CHOOSE),
- (name_pattern , ExcelFormulaParser.NAME),
- (quotename_pattern, ExcelFormulaParser.QUOTENAME),
- (ne_pattern, ExcelFormulaParser.NE),
- (ge_pattern, ExcelFormulaParser.GE),
- (le_pattern, ExcelFormulaParser.LE),
-)
-
-_re = recompile(
- '(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')',
- VERBOSE+IGNORECASE)
-
-_toktype = [None] + [i[1] for i in pattern_type_tuples]
-# need dummy at start because re.MatchObject.lastindex counts from 1
-
-single_char_lookup = {
- '=': ExcelFormulaParser.EQ,
- '<': ExcelFormulaParser.LT,
- '>': ExcelFormulaParser.GT,
- '+': ExcelFormulaParser.ADD,
- '-': ExcelFormulaParser.SUB,
- '*': ExcelFormulaParser.MUL,
- '/': ExcelFormulaParser.DIV,
- ':': ExcelFormulaParser.COLON,
- ';': ExcelFormulaParser.SEMICOLON,
- ',': ExcelFormulaParser.COMMA,
- '(': ExcelFormulaParser.LP,
- ')': ExcelFormulaParser.RP,
- '&': ExcelFormulaParser.CONCAT,
- '%': ExcelFormulaParser.PERCENT,
- '^': ExcelFormulaParser.POWER,
- '!': ExcelFormulaParser.BANG,
- }
-
-class Lexer(TokenStream):
- def __init__(self, text):
- self._text = text[:]
- self._pos = 0
- self._line = 0
-
- def isEOF(self):
- return len(self._text) <= self._pos
-
- def curr_ch(self):
- return self._text[self._pos]
-
- def next_ch(self, n = 1):
- self._pos += n
-
- def is_whitespace(self):
- return self.curr_ch() in " \t\n\r\f\v"
-
- def match_pattern(self):
- m = _re.match(self._text, self._pos)
- if not m:
- return None
- self._pos = m.end(0)
- return Tok(type = _toktype[m.lastindex], text = m.group(0), col = m.start(0) + 1)
-
- def nextToken(self):
- # skip whitespace
- while not self.isEOF() and self.is_whitespace():
- self.next_ch()
- if self.isEOF():
- return Tok(type = EOF)
- # first, try to match token with 2 or more chars
- t = self.match_pattern()
- if t:
- return t
- # second, we want 1-char tokens
- te = self.curr_ch()
- try:
- ty = single_char_lookup[te]
- except KeyError:
- raise TokenStreamException(
- "Unexpected char %r in column %u." % (self.curr_ch(), self._pos))
- self.next_ch()
- return Tok(type=ty, text=te, col=self._pos)
-
-if __name__ == '__main__':
- try:
- for t in Lexer(""" 1.23 456 "abcd" R2C2 a1 iv65536 true false if choose a_name 'qname' <> >= <= """):
- print(t)
- except TokenStreamException as e:
- print("error:", e)
diff --git a/tablib/packages/xlwt3/ExcelFormulaParser.py b/tablib/packages/xlwt3/ExcelFormulaParser.py deleted file mode 100644 index 5e73934..0000000 --- a/tablib/packages/xlwt3/ExcelFormulaParser.py +++ /dev/null @@ -1,659 +0,0 @@ -### $ANTLR 2.7.7 (20060930): "xlwt/excel-formula.g" -> "ExcelFormulaParser.py"$
-### import antlr and other modules ..
-import sys
-from . import antlr
-
-### header action >>>
-import struct
-from . import Utils
-from .UnicodeUtils import upack1
-from .ExcelMagic import *
-
-_RVAdelta = {"R": 0, "V": 0x20, "A": 0x40}
-_RVAdeltaRef = {"R": 0, "V": 0x20, "A": 0x40, "D": 0x20}
-_RVAdeltaArea = {"R": 0, "V": 0x20, "A": 0x40, "D": 0}
-
-
-class FormulaParseException(Exception):
- """
- An exception indicating that a Formula could not be successfully parsed.
- """
-### header action <<<
-### preamble action>>>
-
-### preamble action <<<
-
-### import antlr.Token
-from .antlr import Token
-### >>>The Known Token Types <<<
-SKIP = antlr.SKIP
-INVALID_TYPE = antlr.INVALID_TYPE
-EOF_TYPE = antlr.EOF_TYPE
-EOF = antlr.EOF
-NULL_TREE_LOOKAHEAD = antlr.NULL_TREE_LOOKAHEAD
-MIN_USER_TYPE = antlr.MIN_USER_TYPE
-TRUE_CONST = 4
-FALSE_CONST = 5
-STR_CONST = 6
-NUM_CONST = 7
-INT_CONST = 8
-FUNC_IF = 9
-FUNC_CHOOSE = 10
-NAME = 11
-QUOTENAME = 12
-EQ = 13
-NE = 14
-GT = 15
-LT = 16
-GE = 17
-LE = 18
-ADD = 19
-SUB = 20
-MUL = 21
-DIV = 22
-POWER = 23
-PERCENT = 24
-LP = 25
-RP = 26
-LB = 27
-RB = 28
-COLON = 29
-COMMA = 30
-SEMICOLON = 31
-REF2D = 32
-REF2D_R1C1 = 33
-BANG = 34
-CONCAT = 35
-
-class Parser(antlr.LLkParser):
- ### user action >>>
- ### user action <<<
-
- def __init__(self, *args, **kwargs):
- antlr.LLkParser.__init__(self, *args, **kwargs)
- self.tokenNames = _tokenNames
- ### __init__ header action >>>
- self.rpn = b""
- self.sheet_references = []
- self.xcall_references = []
- ### __init__ header action <<<
-
- def formula(self):
- self.expr("V")
-
- def expr(self, arg_type):
- self.prec0_expr(arg_type)
- while True:
- if ((self.LA(1) >= EQ and self.LA(1) <= LE)):
- pass
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [EQ]:
- pass
- self.match(EQ)
- op = struct.pack('B', ptgEQ)
- elif la1 and la1 in [NE]:
- pass
- self.match(NE)
- op = struct.pack('B', ptgNE)
- elif la1 and la1 in [GT]:
- pass
- self.match(GT)
- op = struct.pack('B', ptgGT)
- elif la1 and la1 in [LT]:
- pass
- self.match(LT)
- op = struct.pack('B', ptgLT)
- elif la1 and la1 in [GE]:
- pass
- self.match(GE)
- op = struct.pack('B', ptgGE)
- elif la1 and la1 in [LE]:
- pass
- self.match(LE)
- op = struct.pack('B', ptgLE)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.prec0_expr(arg_type)
- self.rpn += op
- else:
- break
-
-
- def prec0_expr(self,
- arg_type
- ):
-
- pass
- self.prec1_expr(arg_type)
- while True:
- if (self.LA(1)==CONCAT):
- pass
- pass
- self.match(CONCAT)
- op = struct.pack('B', ptgConcat)
- self.prec1_expr(arg_type)
- self.rpn += op
- else:
- break
-
-
- def prec1_expr(self,
- arg_type
- ):
-
- pass
- self.prec2_expr(arg_type)
- while True:
- if (self.LA(1)==ADD or self.LA(1)==SUB):
- pass
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [ADD]:
- pass
- self.match(ADD)
- op = struct.pack('B', ptgAdd)
- elif la1 and la1 in [SUB]:
- pass
- self.match(SUB)
- op = struct.pack('B', ptgSub)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.prec2_expr(arg_type)
- self.rpn += op;
- # print "**prec1_expr4 %s" % arg_type
- else:
- break
-
-
- def prec2_expr(self,
- arg_type
- ):
-
- pass
- self.prec3_expr(arg_type)
- while True:
- if (self.LA(1)==MUL or self.LA(1)==DIV):
- pass
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [MUL]:
- pass
- self.match(MUL)
- op = struct.pack('B', ptgMul)
- elif la1 and la1 in [DIV]:
- pass
- self.match(DIV)
- op = struct.pack('B', ptgDiv)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.prec3_expr(arg_type)
- self.rpn += op
- else:
- break
-
-
- def prec3_expr(self,
- arg_type
- ):
-
- pass
- self.prec4_expr(arg_type)
- while True:
- if (self.LA(1)==POWER):
- pass
- pass
- self.match(POWER)
- op = struct.pack('B', ptgPower)
- self.prec4_expr(arg_type)
- self.rpn += op
- else:
- break
-
-
- def prec4_expr(self,
- arg_type
- ):
-
- pass
- self.prec5_expr(arg_type)
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [PERCENT]:
- pass
- self.match(PERCENT)
- self.rpn += struct.pack('B', ptgPercent)
- elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,RP,COMMA,SEMICOLON,CONCAT]:
- pass
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
-
- def prec5_expr(self,
- arg_type
- ):
-
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,LP,REF2D]:
- pass
- self.primary(arg_type)
- elif la1 and la1 in [SUB]:
- pass
- self.match(SUB)
- self.primary(arg_type)
- self.rpn += struct.pack('B', ptgUminus)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
-
- def primary(self,
- arg_type
- ):
-
- str_tok = None
- int_tok = None
- num_tok = None
- ref2d_tok = None
- ref2d1_tok = None
- ref2d2_tok = None
- ref3d_ref2d = None
- ref3d_ref2d2 = None
- name_tok = None
- func_tok = None
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [TRUE_CONST]:
- pass
- self.match(TRUE_CONST)
- self.rpn += struct.pack("2B", ptgBool, 1)
- elif la1 and la1 in [FALSE_CONST]:
- pass
- self.match(FALSE_CONST)
- self.rpn += struct.pack("2B", ptgBool, 0)
- elif la1 and la1 in [STR_CONST]:
- pass
- str_tok = self.LT(1)
- self.match(STR_CONST)
- self.rpn += struct.pack("B", ptgStr) + upack1(str_tok.text[1:-1].replace("\"\"", "\""))
- elif la1 and la1 in [NUM_CONST]:
- pass
- num_tok = self.LT(1)
- self.match(NUM_CONST)
- self.rpn += struct.pack("<Bd", ptgNum, float(num_tok.text))
- elif la1 and la1 in [FUNC_IF]:
- pass
- self.match(FUNC_IF)
- self.match(LP)
- self.expr("V")
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [SEMICOLON]:
- pass
- self.match(SEMICOLON)
- elif la1 and la1 in [COMMA]:
- pass
- self.match(COMMA)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.rpn += struct.pack("<BBH", ptgAttr, 0x02, 0) # tAttrIf
- pos0 = len(self.rpn) - 2
- self.expr(arg_type)
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [SEMICOLON]:
- pass
- self.match(SEMICOLON)
- elif la1 and la1 in [COMMA]:
- pass
- self.match(COMMA)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 0) # tAttrSkip
- pos1 = len(self.rpn) - 2
- self.rpn = self.rpn[:pos0] + struct.pack("<H", pos1-pos0) + self.rpn[pos0+2:]
- self.expr(arg_type)
- self.match(RP)
- self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 3) # tAttrSkip
- self.rpn += struct.pack("<BBH", ptgFuncVarR, 3, 1) # 3 = nargs, 1 = IF func
- pos2 = len(self.rpn)
- self.rpn = self.rpn[:pos1] + struct.pack("<H", pos2-(pos1+2)-1) + self.rpn[pos1+2:]
- elif la1 and la1 in [FUNC_CHOOSE]:
- pass
- self.match(FUNC_CHOOSE)
- arg_type = b"R"
- rpn_chunks = []
- self.match(LP)
- self.expr("V")
- rpn_start = len(self.rpn)
- ref_markers = [len(self.sheet_references)]
- while True:
- if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON):
- pass
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [SEMICOLON]:
- pass
- self.match(SEMICOLON)
- elif la1 and la1 in [COMMA]:
- pass
- self.match(COMMA)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- mark = len(self.rpn)
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]:
- pass
- self.expr(arg_type)
- elif la1 and la1 in [RP,COMMA,SEMICOLON]:
- pass
- self.rpn += struct.pack("B", ptgMissArg)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- rpn_chunks.append(self.rpn[mark:])
- ref_markers.append(len(self.sheet_references))
- else:
- break
-
- self.match(RP)
- self.rpn = self.rpn[:rpn_start]
- nc = len(rpn_chunks)
- chunklens = [len(chunk) for chunk in rpn_chunks]
- skiplens = [0] * nc
- skiplens[-1] = 3
- for ic in range(nc-1, 0, -1):
- skiplens[ic-1] = skiplens[ic] + chunklens[ic] + 4
- jump_pos = [2 * nc + 2]
- for ic in range(nc):
- jump_pos.append(jump_pos[-1] + chunklens[ic] + 4)
- chunk_shift = 2 * nc + 6 # size of tAttrChoose
- for ic in range(nc):
- for refx in range(ref_markers[ic], ref_markers[ic+1]):
- ref = self.sheet_references[refx]
- self.sheet_references[refx] = (ref[0], ref[1], ref[2] + chunk_shift)
- chunk_shift += 4 # size of tAttrSkip
- choose_rpn = []
- choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x04, nc)) # 0x04 is tAttrChoose
- choose_rpn.append(struct.pack("<%dH" % (nc+1), *jump_pos))
- for ic in range(nc):
- choose_rpn.append(rpn_chunks[ic])
- choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x08, skiplens[ic])) # 0x08 is tAttrSkip
- choose_rpn.append(struct.pack("<BBH", ptgFuncVarV, nc+1, 100)) # 100 is CHOOSE fn
- self.rpn += b"".join(choose_rpn)
- elif la1 and la1 in [LP]:
- pass
- self.match(LP)
- self.expr(arg_type)
- self.match(RP)
- self.rpn += struct.pack("B", ptgParen)
- else:
- if (self.LA(1)==INT_CONST) and (_tokenSet_0.member(self.LA(2))):
- pass
- int_tok = self.LT(1)
- self.match(INT_CONST)
- # print "**int_const", int_tok.text
- int_value = int(int_tok.text)
- if int_value <= 65535:
- self.rpn += struct.pack("<BH", ptgInt, int_value)
- else:
- self.rpn += struct.pack("<Bd", ptgNum, float(int_value))
- elif (self.LA(1)==REF2D) and (_tokenSet_0.member(self.LA(2))):
- pass
- ref2d_tok = self.LT(1)
- self.match(REF2D)
- # print "**ref2d %s %s" % (ref2d_tok.text, arg_type)
- r, c = Utils.cell_to_packed_rowcol(ref2d_tok.text)
- ptg = ptgRefR + _RVAdeltaRef[arg_type]
- self.rpn += struct.pack("<B2H", ptg, r, c)
- elif (self.LA(1)==REF2D) and (self.LA(2)==COLON):
- pass
- ref2d1_tok = self.LT(1)
- self.match(REF2D)
- self.match(COLON)
- ref2d2_tok = self.LT(1)
- self.match(REF2D)
- r1, c1 = Utils.cell_to_packed_rowcol(ref2d1_tok.text)
- r2, c2 = Utils.cell_to_packed_rowcol(ref2d2_tok.text)
- ptg = ptgAreaR + _RVAdeltaArea[arg_type]
- self.rpn += struct.pack("<B4H", ptg, r1, r2, c1, c2)
- elif (self.LA(1)==INT_CONST or self.LA(1)==NAME or self.LA(1)==QUOTENAME) and (self.LA(2)==COLON or self.LA(2)==BANG):
- pass
- sheet1=self.sheet()
- sheet2 = sheet1
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [COLON]:
- pass
- self.match(COLON)
- sheet2=self.sheet()
- elif la1 and la1 in [BANG]:
- pass
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.match(BANG)
- ref3d_ref2d = self.LT(1)
- self.match(REF2D)
- ptg = ptgRef3dR + _RVAdeltaRef[arg_type]
- rpn_ref2d = b""
- r1, c1 = Utils.cell_to_packed_rowcol(ref3d_ref2d.text)
- rpn_ref2d = struct.pack("<3H", 0x0000, r1, c1)
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [COLON]:
- pass
- self.match(COLON)
- ref3d_ref2d2 = self.LT(1)
- self.match(REF2D)
- ptg = ptgArea3dR + _RVAdeltaArea[arg_type]
- r2, c2 = Utils.cell_to_packed_rowcol(ref3d_ref2d2.text)
- rpn_ref2d = struct.pack("<5H", 0x0000, r1, r2, c1, c2)
- elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,PERCENT,RP,COMMA,SEMICOLON,CONCAT]:
- pass
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- self.rpn += struct.pack("<B", ptg)
- self.sheet_references.append((sheet1, sheet2, len(self.rpn)))
- self.rpn += rpn_ref2d
- elif (self.LA(1)==NAME) and (_tokenSet_0.member(self.LA(2))):
- name_tok = self.LT(1)
- self.match(NAME)
- raise Exception("[formula] found unexpected NAME token (%r)" % name_tok.txt)
- # #### TODO: handle references to defined names here
- elif (self.LA(1)==NAME) and (self.LA(2)==LP):
- func_tok = self.LT(1)
- self.match(NAME)
- func_toku = func_tok.text.upper()
- if func_toku in all_funcs_by_name:
- (opcode,
- min_argc,
- max_argc,
- func_type,
- arg_type_str) = all_funcs_by_name[func_toku]
- arg_type_list = list(arg_type_str)
- else:
- raise Exception("[formula] unknown function (%s)" % func_tok.text)
- # print "**func_tok1 %s %s" % (func_toku, func_type)
- xcall = opcode < 0
- if xcall:
- # The name of the add-in function is passed as the 1st arg
- # of the hidden XCALL function
- self.xcall_references.append((func_toku, len(self.rpn) + 1))
- self.rpn += struct.pack("<BHHH",
- ptgNameXR,
- 0xadde, # ##PATCHME## index to REF entry in EXTERNSHEET record
- 0xefbe, # ##PATCHME## one-based index to EXTERNNAME record
- 0x0000) # unused
- self.match(LP)
- arg_count=self.expr_list(arg_type_list, min_argc, max_argc)
- self.match(RP)
- if arg_count > max_argc or arg_count < min_argc:
- raise Exception("%d parameters for function: %s" % (arg_count, func_tok.text))
- if xcall:
- func_ptg = ptgFuncVarR + _RVAdelta[func_type]
- self.rpn += struct.pack("<2BH", func_ptg, arg_count + 1, 255) # 255 is magic XCALL function
- elif min_argc == max_argc:
- func_ptg = ptgFuncR + _RVAdelta[func_type]
- self.rpn += struct.pack("<BH", func_ptg, opcode)
- elif arg_count == 1 and func_tok.text.upper() == "SUM":
- self.rpn += struct.pack("<BBH", ptgAttr, 0x10, 0) # tAttrSum
- else:
- func_ptg = ptgFuncVarR + _RVAdelta[func_type]
- self.rpn += struct.pack("<2BH", func_ptg, arg_count, opcode)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- def sheet(self):
- ref = None
- sheet_ref_name = None
- sheet_ref_int = None
- sheet_ref_quote = None
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [NAME]:
- sheet_ref_name = self.LT(1)
- self.match(NAME)
- ref = sheet_ref_name.text
- elif la1 and la1 in [INT_CONST]:
- sheet_ref_int = self.LT(1)
- self.match(INT_CONST)
- ref = sheet_ref_int.text
- elif la1 and la1 in [QUOTENAME]:
- sheet_ref_quote = self.LT(1)
- self.match(QUOTENAME)
- ref = sheet_ref_quote.text[1:-1].replace("''", "'")
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- return ref
-
- def expr_list(self,
- arg_type_list, min_argc, max_argc
- ):
- arg_cnt = None
-
- arg_cnt = 0
- arg_type = arg_type_list[arg_cnt]
- # print "**expr_list1[%d] req=%s" % (arg_cnt, arg_type)
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]:
- pass
- self.expr(arg_type)
- arg_cnt += 1
- while True:
- if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON):
- pass
- if arg_cnt < len(arg_type_list):
- arg_type = arg_type_list[arg_cnt]
- else:
- arg_type = arg_type_list[-1]
- if arg_type == "+":
- arg_type = arg_type_list[-2]
- # print "**expr_list2[%d] req=%s" % (arg_cnt, arg_type)
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [SEMICOLON]:
- pass
- self.match(SEMICOLON)
- elif la1 and la1 in [COMMA]:
- pass
- self.match(COMMA)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- la1 = self.LA(1)
- if False:
- pass
- elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]:
- pass
- self.expr(arg_type)
- elif la1 and la1 in [RP,COMMA,SEMICOLON]:
- pass
- self.rpn += struct.pack("B", ptgMissArg)
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- arg_cnt += 1
- else:
- break
-
- elif la1 and la1 in [RP]:
- pass
- else:
- raise antlr.NoViableAltException(self.LT(1), self.getFilename())
-
- return arg_cnt
-
-
-_tokenNames = [
- "<0>",
- "EOF",
- "<2>",
- "NULL_TREE_LOOKAHEAD",
- "TRUE_CONST",
- "FALSE_CONST",
- "STR_CONST",
- "NUM_CONST",
- "INT_CONST",
- "FUNC_IF",
- "FUNC_CHOOSE",
- "NAME",
- "QUOTENAME",
- "EQ",
- "NE",
- "GT",
- "LT",
- "GE",
- "LE",
- "ADD",
- "SUB",
- "MUL",
- "DIV",
- "POWER",
- "PERCENT",
- "LP",
- "RP",
- "LB",
- "RB",
- "COLON",
- "COMMA",
- "SEMICOLON",
- "REF2D",
- "REF2D_R1C1",
- "BANG",
- "CONCAT"
-]
-
-
-### generate bit set
-def mk_tokenSet_0():
- ### var1
- data = [ 37681618946, 0]
- return data
-_tokenSet_0 = antlr.BitSet(mk_tokenSet_0())
-
diff --git a/tablib/packages/xlwt3/ExcelMagic.py b/tablib/packages/xlwt3/ExcelMagic.py deleted file mode 100644 index 90372b4..0000000 --- a/tablib/packages/xlwt3/ExcelMagic.py +++ /dev/null @@ -1,859 +0,0 @@ -""" lots of Excel Magic Numbers """
-
-# Boundaries BIFF8+
-
-MAX_ROW = 65536
-MAX_COL = 256
-
-
-biff_records = {
- 0x0000: "DIMENSIONS",
- 0x0001: "BLANK",
- 0x0002: "INTEGER",
- 0x0003: "NUMBER",
- 0x0004: "LABEL",
- 0x0005: "BOOLERR",
- 0x0006: "FORMULA",
- 0x0007: "STRING",
- 0x0008: "ROW",
- 0x0009: "BOF",
- 0x000A: "EOF",
- 0x000B: "INDEX",
- 0x000C: "CALCCOUNT",
- 0x000D: "CALCMODE",
- 0x000E: "PRECISION",
- 0x000F: "REFMODE",
- 0x0010: "DELTA",
- 0x0011: "ITERATION",
- 0x0012: "PROTECT",
- 0x0013: "PASSWORD",
- 0x0014: "HEADER",
- 0x0015: "FOOTER",
- 0x0016: "EXTERNCOUNT",
- 0x0017: "EXTERNSHEET",
- 0x0018: "NAME",
- 0x0019: "WINDOWPROTECT",
- 0x001A: "VERTICALPAGEBREAKS",
- 0x001B: "HORIZONTALPAGEBREAKS",
- 0x001C: "NOTE",
- 0x001D: "SELECTION",
- 0x001E: "FORMAT",
- 0x001F: "FORMATCOUNT",
- 0x0020: "COLUMNDEFAULT",
- 0x0021: "ARRAY",
- 0x0022: "1904",
- 0x0023: "EXTERNNAME",
- 0x0024: "COLWIDTH",
- 0x0025: "DEFAULTROWHEIGHT",
- 0x0026: "LEFTMARGIN",
- 0x0027: "RIGHTMARGIN",
- 0x0028: "TOPMARGIN",
- 0x0029: "BOTTOMMARGIN",
- 0x002A: "PRINTHEADERS",
- 0x002B: "PRINTGRIDLINES",
- 0x002F: "FILEPASS",
- 0x0031: "FONT",
- 0x0036: "TABLE",
- 0x003C: "CONTINUE",
- 0x003D: "WINDOW1",
- 0x003E: "WINDOW2",
- 0x0040: "BACKUP",
- 0x0041: "PANE",
- 0x0042: "CODEPAGE",
- 0x0043: "XF",
- 0x0044: "IXFE",
- 0x0045: "EFONT",
- 0x004D: "PLS",
- 0x0050: "DCON",
- 0x0051: "DCONREF",
- 0x0053: "DCONNAME",
- 0x0055: "DEFCOLWIDTH",
- 0x0056: "BUILTINFMTCNT",
- 0x0059: "XCT",
- 0x005A: "CRN",
- 0x005B: "FILESHARING",
- 0x005C: "WRITEACCESS",
- 0x005D: "OBJ",
- 0x005E: "UNCALCED",
- 0x005F: "SAFERECALC",
- 0x0060: "TEMPLATE",
- 0x0063: "OBJPROTECT",
- 0x007D: "COLINFO",
- 0x007E: "RK",
- 0x007F: "IMDATA",
- 0x0080: "GUTS",
- 0x0081: "WSBOOL",
- 0x0082: "GRIDSET",
- 0x0083: "HCENTER",
- 0x0084: "VCENTER",
- 0x0085: "BOUNDSHEET",
- 0x0086: "WRITEPROT",
- 0x0087: "ADDIN",
- 0x0088: "EDG",
- 0x0089: "PUB",
- 0x008C: "COUNTRY",
- 0x008D: "HIDEOBJ",
- 0x008E: "BUNDLESOFFSET",
- 0x008F: "BUNDLEHEADER",
- 0x0090: "SORT",
- 0x0091: "SUB",
- 0x0092: "PALETTE",
- 0x0093: "STYLE",
- 0x0094: "LHRECORD",
- 0x0095: "LHNGRAPH",
- 0x0096: "SOUND",
- 0x0098: "LPR",
- 0x0099: "STANDARDWIDTH",
- 0x009A: "FNGROUPNAME",
- 0x009B: "FILTERMODE",
- 0x009C: "FNGROUPCOUNT",
- 0x009D: "AUTOFILTERINFO",
- 0x009E: "AUTOFILTER",
- 0x00A0: "SCL",
- 0x00A1: "SETUP",
- 0x00A9: "COORDLIST",
- 0x00AB: "GCW",
- 0x00AE: "SCENMAN",
- 0x00AF: "SCENARIO",
- 0x00B0: "SXVIEW",
- 0x00B1: "SXVD",
- 0x00B2: "SXVI",
- 0x00B4: "SXIVD",
- 0x00B5: "SXLI",
- 0x00B6: "SXPI",
- 0x00B8: "DOCROUTE",
- 0x00B9: "RECIPNAME",
- 0x00BC: "SHRFMLA",
- 0x00BD: "MULRK",
- 0x00BE: "MULBLANK",
- 0x00C1: "MMS",
- 0x00C2: "ADDMENU",
- 0x00C3: "DELMENU",
- 0x00C5: "SXDI",
- 0x00C6: "SXDB",
- 0x00C7: "SXFIELD",
- 0x00C8: "SXINDEXLIST",
- 0x00C9: "SXDOUBLE",
- 0x00CD: "SXSTRING",
- 0x00CE: "SXDATETIME",
- 0x00D0: "SXTBL",
- 0x00D1: "SXTBRGITEM",
- 0x00D2: "SXTBPG",
- 0x00D3: "OBPROJ",
- 0x00D5: "SXIDSTM",
- 0x00D6: "RSTRING",
- 0x00D7: "DBCELL",
- 0x00DA: "BOOKBOOL",
- 0x00DC: "SXEXT|PARAMQRY",
- 0x00DD: "SCENPROTECT",
- 0x00DE: "OLESIZE",
- 0x00DF: "UDDESC",
- 0x00E0: "XF",
- 0x00E1: "INTERFACEHDR",
- 0x00E2: "INTERFACEEND",
- 0x00E3: "SXVS",
- 0x00E5: "MERGEDCELLS",
- 0x00E9: "BITMAP",
- 0x00EB: "MSODRAWINGGROUP",
- 0x00EC: "MSODRAWING",
- 0x00ED: "MSODRAWINGSELECTION",
- 0x00F0: "SXRULE",
- 0x00F1: "SXEX",
- 0x00F2: "SXFILT",
- 0x00F6: "SXNAME",
- 0x00F7: "SXSELECT",
- 0x00F8: "SXPAIR",
- 0x00F9: "SXFMLA",
- 0x00FB: "SXFORMAT",
- 0x00FC: "SST",
- 0x00FD: "LABELSST",
- 0x00FF: "EXTSST",
- 0x0100: "SXVDEX",
- 0x0103: "SXFORMULA",
- 0x0122: "SXDBEX",
- 0x0137: "CHTRINSERT",
- 0x0138: "CHTRINFO",
- 0x013B: "CHTRCELLCONTENT",
- 0x013D: "TABID",
- 0x0140: "CHTRMOVERANGE",
- 0x014D: "CHTRINSERTTAB",
- 0x015F: "LABELRANGES",
- 0x0160: "USESELFS",
- 0x0161: "DSF",
- 0x0162: "XL5MODIFY",
- 0x0196: "CHTRHEADER",
- 0x01A9: "USERBVIEW",
- 0x01AA: "USERSVIEWBEGIN",
- 0x01AB: "USERSVIEWEND",
- 0x01AD: "QSI",
- 0x01AE: "SUPBOOK",
- 0x01AF: "PROT4REV",
- 0x01B0: "CONDFMT",
- 0x01B1: "CF",
- 0x01B2: "DVAL",
- 0x01B5: "DCONBIN",
- 0x01B6: "TXO",
- 0x01B7: "REFRESHALL",
- 0x01B8: "HLINK",
- 0x01BA: "CODENAME",
- 0x01BB: "SXFDBTYPE",
- 0x01BC: "PROT4REVPASS",
- 0x01BE: "DV",
- 0x01C0: "XL9FILE",
- 0x01C1: "RECALCID",
- 0x0200: "DIMENSIONS",
- 0x0201: "BLANK",
- 0x0203: "NUMBER",
- 0x0204: "LABEL",
- 0x0205: "BOOLERR",
- 0x0206: "FORMULA",
- 0x0207: "STRING",
- 0x0208: "ROW",
- 0x0209: "BOF",
- 0x020B: "INDEX",
- 0x0218: "NAME",
- 0x0221: "ARRAY",
- 0x0223: "EXTERNNAME",
- 0x0225: "DEFAULTROWHEIGHT",
- 0x0231: "FONT",
- 0x0236: "TABLE",
- 0x023E: "WINDOW2",
- 0x0243: "XF",
- 0x027E: "RK",
- 0x0293: "STYLE",
- 0x0406: "FORMULA",
- 0x0409: "BOF",
- 0x041E: "FORMAT",
- 0x0443: "XF",
- 0x04BC: "SHRFMLA",
- 0x0800: "SCREENTIP",
- 0x0803: "WEBQRYSETTINGS",
- 0x0804: "WEBQRYTABLES",
- 0x0809: "BOF",
- 0x0862: "SHEETLAYOUT",
- 0x0867: "SHEETPROTECTION",
- 0x1001: "UNITS",
- 0x1002: "ChartChart",
- 0x1003: "ChartSeries",
- 0x1006: "ChartDataformat",
- 0x1007: "ChartLineformat",
- 0x1009: "ChartMarkerformat",
- 0x100A: "ChartAreaformat",
- 0x100B: "ChartPieformat",
- 0x100C: "ChartAttachedlabel",
- 0x100D: "ChartSeriestext",
- 0x1014: "ChartChartformat",
- 0x1015: "ChartLegend",
- 0x1016: "ChartSerieslist",
- 0x1017: "ChartBar",
- 0x1018: "ChartLine",
- 0x1019: "ChartPie",
- 0x101A: "ChartArea",
- 0x101B: "ChartScatter",
- 0x101C: "ChartChartline",
- 0x101D: "ChartAxis",
- 0x101E: "ChartTick",
- 0x101F: "ChartValuerange",
- 0x1020: "ChartCatserrange",
- 0x1021: "ChartAxislineformat",
- 0x1022: "ChartFormatlink",
- 0x1024: "ChartDefaulttext",
- 0x1025: "ChartText",
- 0x1026: "ChartFontx",
- 0x1027: "ChartObjectLink",
- 0x1032: "ChartFrame",
- 0x1033: "BEGIN",
- 0x1034: "END",
- 0x1035: "ChartPlotarea",
- 0x103A: "Chart3D",
- 0x103C: "ChartPicf",
- 0x103D: "ChartDropbar",
- 0x103E: "ChartRadar",
- 0x103F: "ChartSurface",
- 0x1040: "ChartRadararea",
- 0x1041: "ChartAxisparent",
- 0x1043: "ChartLegendxn",
- 0x1044: "ChartShtprops",
- 0x1045: "ChartSertocrt",
- 0x1046: "ChartAxesused",
- 0x1048: "ChartSbaseref",
- 0x104A: "ChartSerparent",
- 0x104B: "ChartSerauxtrend",
- 0x104E: "ChartIfmt",
- 0x104F: "ChartPos",
- 0x1050: "ChartAlruns",
- 0x1051: "ChartAI",
- 0x105B: "ChartSerauxerrbar",
- 0x105D: "ChartSerfmt",
- 0x105F: "Chart3DDataFormat",
- 0x1060: "ChartFbi",
- 0x1061: "ChartBoppop",
- 0x1062: "ChartAxcext",
- 0x1063: "ChartDat",
- 0x1064: "ChartPlotgrowth",
- 0x1065: "ChartSiindex",
- 0x1066: "ChartGelframe",
- 0x1067: "ChartBoppcustom",
- 0xFFFF: ""
-}
-
-
-all_funcs_by_name = {
- # Includes Analysis ToolPak aka ATP aka add-in aka xcall functions,
- # distinguished by -ve opcode.
- # name: (opcode, min # args, max # args, func return type, func arg types)
- # + in func arg types means more of the same.
- 'ABS' : ( 24, 1, 1, 'V', 'V'),
- 'ACCRINT' : ( -1, 6, 7, 'V', 'VVVVVVV'),
- 'ACCRINTM' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'ACOS' : ( 99, 1, 1, 'V', 'V'),
- 'ACOSH' : (233, 1, 1, 'V', 'V'),
- 'ADDRESS' : (219, 2, 5, 'V', 'VVVVV'),
- 'AMORDEGRC' : ( -1, 7, 7, 'V', 'VVVVVVV'),
- 'AMORLINC' : ( -1, 7, 7, 'V', 'VVVVVVV'),
- 'AND' : ( 36, 1, 30, 'V', 'D+'),
- 'AREAS' : ( 75, 1, 1, 'V', 'R'),
- 'ASC' : (214, 1, 1, 'V', 'V'),
- 'ASIN' : ( 98, 1, 1, 'V', 'V'),
- 'ASINH' : (232, 1, 1, 'V', 'V'),
- 'ATAN' : ( 18, 1, 1, 'V', 'V'),
- 'ATAN2' : ( 97, 2, 2, 'V', 'VV'),
- 'ATANH' : (234, 1, 1, 'V', 'V'),
- 'AVEDEV' : (269, 1, 30, 'V', 'D+'),
- 'AVERAGE' : ( 5, 1, 30, 'V', 'D+'),
- 'AVERAGEA' : (361, 1, 30, 'V', 'D+'),
- 'BAHTTEXT' : (368, 1, 1, 'V', 'V'),
- 'BESSELI' : ( -1, 2, 2, 'V', 'VV'),
- 'BESSELJ' : ( -1, 2, 2, 'V', 'VV'),
- 'BESSELK' : ( -1, 2, 2, 'V', 'VV'),
- 'BESSELY' : ( -1, 2, 2, 'V', 'VV'),
- 'BETADIST' : (270, 3, 5, 'V', 'VVVVV'),
- 'BETAINV' : (272, 3, 5, 'V', 'VVVVV'),
- 'BIN2DEC' : ( -1, 1, 1, 'V', 'V'),
- 'BIN2HEX' : ( -1, 1, 2, 'V', 'VV'),
- 'BIN2OCT' : ( -1, 1, 2, 'V', 'VV'),
- 'BINOMDIST' : (273, 4, 4, 'V', 'VVVV'),
- 'CEILING' : (288, 2, 2, 'V', 'VV'),
- 'CELL' : (125, 1, 2, 'V', 'VR'),
- 'CHAR' : (111, 1, 1, 'V', 'V'),
- 'CHIDIST' : (274, 2, 2, 'V', 'VV'),
- 'CHIINV' : (275, 2, 2, 'V', 'VV'),
- 'CHITEST' : (306, 2, 2, 'V', 'AA'),
- 'CHOOSE' : (100, 2, 30, 'R', 'VR+'),
- 'CLEAN' : (162, 1, 1, 'V', 'V'),
- 'CODE' : (121, 1, 1, 'V', 'V'),
- 'COLUMN' : ( 9, 0, 1, 'V', 'R'),
- 'COLUMNS' : ( 77, 1, 1, 'V', 'R'),
- 'COMBIN' : (276, 2, 2, 'V', 'VV'),
- 'COMPLEX' : ( -1, 2, 3, 'V', 'VVV'),
- 'CONCATENATE' : (336, 1, 30, 'V', 'V+'),
- 'CONFIDENCE' : (277, 3, 3, 'V', 'VVV'),
- 'CONVERT' : ( -1, 3, 3, 'V', 'VVV'),
- 'CORREL' : (307, 2, 2, 'V', 'AA'),
- 'COS' : ( 16, 1, 1, 'V', 'V'),
- 'COSH' : (230, 1, 1, 'V', 'V'),
- 'COUNT' : ( 0, 1, 30, 'V', 'D+'),
- 'COUNTA' : (169, 1, 30, 'V', 'D+'),
- 'COUNTBLANK' : (347, 1, 1, 'V', 'R'),
- 'COUNTIF' : (346, 2, 2, 'V', 'RV'),
- 'COUPDAYBS' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'COUPDAYS' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'COUPDAYSNC' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'COUPNCD' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'COUPNUM' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'COUPPCD' : ( -1, 3, 5, 'V', 'VVVVV'),
- 'COVAR' : (308, 2, 2, 'V', 'AA'),
- 'CRITBINOM' : (278, 3, 3, 'V', 'VVV'),
- 'CUMIPMT' : ( -1, 6, 6, 'V', 'VVVVVV'),
- 'CUMPRINC' : ( -1, 6, 6, 'V', 'VVVVVV'),
- 'DATE' : ( 65, 3, 3, 'V', 'VVV'),
- 'DATEDIF' : (351, 3, 3, 'V', 'VVV'),
- 'DATEVALUE' : (140, 1, 1, 'V', 'V'),
- 'DAVERAGE' : ( 42, 3, 3, 'V', 'RRR'),
- 'DAY' : ( 67, 1, 1, 'V', 'V'),
- 'DAYS360' : (220, 2, 3, 'V', 'VVV'),
- 'DB' : (247, 4, 5, 'V', 'VVVVV'),
- 'DBCS' : (215, 1, 1, 'V', 'V'),
- 'DCOUNT' : ( 40, 3, 3, 'V', 'RRR'),
- 'DCOUNTA' : (199, 3, 3, 'V', 'RRR'),
- 'DDB' : (144, 4, 5, 'V', 'VVVVV'),
- 'DEC2BIN' : ( -1, 1, 2, 'V', 'VV'),
- 'DEC2HEX' : ( -1, 1, 2, 'V', 'VV'),
- 'DEC2OCT' : ( -1, 1, 2, 'V', 'VV'),
- 'DEGREES' : (343, 1, 1, 'V', 'V'),
- 'DELTA' : ( -1, 1, 2, 'V', 'VV'),
- 'DEVSQ' : (318, 1, 30, 'V', 'D+'),
- 'DGET' : (235, 3, 3, 'V', 'RRR'),
- 'DISC' : ( -1, 4, 5, 'V', 'VVVVV'),
- 'DMAX' : ( 44, 3, 3, 'V', 'RRR'),
- 'DMIN' : ( 43, 3, 3, 'V', 'RRR'),
- 'DOLLAR' : ( 13, 1, 2, 'V', 'VV'),
- 'DOLLARDE' : ( -1, 2, 2, 'V', 'VV'),
- 'DOLLARFR' : ( -1, 2, 2, 'V', 'VV'),
- 'DPRODUCT' : (189, 3, 3, 'V', 'RRR'),
- 'DSTDEV' : ( 45, 3, 3, 'V', 'RRR'),
- 'DSTDEVP' : (195, 3, 3, 'V', 'RRR'),
- 'DSUM' : ( 41, 3, 3, 'V', 'RRR'),
- 'DURATION' : ( -1, 5, 6, 'V', 'VVVVVV'),
- 'DVAR' : ( 47, 3, 3, 'V', 'RRR'),
- 'DVARP' : (196, 3, 3, 'V', 'RRR'),
- 'EDATE' : ( -1, 2, 2, 'V', 'VV'),
- 'EFFECT' : ( -1, 2, 2, 'V', 'VV'),
- 'EOMONTH' : ( -1, 1, 2, 'V', 'VV'),
- 'ERF' : ( -1, 1, 2, 'V', 'VV'),
- 'ERFC' : ( -1, 1, 1, 'V', 'V'),
- 'ERROR.TYPE' : (261, 1, 1, 'V', 'V'),
- 'EVEN' : (279, 1, 1, 'V', 'V'),
- 'EXACT' : (117, 2, 2, 'V', 'VV'),
- 'EXP' : ( 21, 1, 1, 'V', 'V'),
- 'EXPONDIST' : (280, 3, 3, 'V', 'VVV'),
- 'FACT' : (184, 1, 1, 'V', 'V'),
- 'FACTDOUBLE' : ( -1, 1, 1, 'V', 'V'),
- 'FALSE' : ( 35, 0, 0, 'V', '-'),
- 'FDIST' : (281, 3, 3, 'V', 'VVV'),
- 'FIND' : (124, 2, 3, 'V', 'VVV'),
- 'FINDB' : (205, 2, 3, 'V', 'VVV'),
- 'FINV' : (282, 3, 3, 'V', 'VVV'),
- 'FISHER' : (283, 1, 1, 'V', 'V'),
- 'FISHERINV' : (284, 1, 1, 'V', 'V'),
- 'FIXED' : ( 14, 2, 3, 'V', 'VVV'),
- 'FLOOR' : (285, 2, 2, 'V', 'VV'),
- 'FORECAST' : (309, 3, 3, 'V', 'VAA'),
- 'FREQUENCY' : (252, 2, 2, 'A', 'RR'),
- 'FTEST' : (310, 2, 2, 'V', 'AA'),
- 'FV' : ( 57, 3, 5, 'V', 'VVVVV'),
- 'FVSCHEDULE' : ( -1, 2, 2, 'V', 'VA'),
- 'GAMMADIST' : (286, 4, 4, 'V', 'VVVV'),
- 'GAMMAINV' : (287, 3, 3, 'V', 'VVV'),
- 'GAMMALN' : (271, 1, 1, 'V', 'V'),
- 'GCD' : ( -1, 1, 29, 'V', 'V+'),
- 'GEOMEAN' : (319, 1, 30, 'V', 'D+'),
- 'GESTEP' : ( -1, 1, 2, 'V', 'VV'),
- 'GETPIVOTDATA': (358, 2, 30, 'A', 'VAV+'),
- 'GROWTH' : ( 52, 1, 4, 'A', 'RRRV'),
- 'HARMEAN' : (320, 1, 30, 'V', 'D+'),
- 'HEX2BIN' : ( -1, 1, 2, 'V', 'VV'),
- 'HEX2DEC' : ( -1, 1, 1, 'V', 'V'),
- 'HEX2OCT' : ( -1, 1, 2, 'V', 'VV'),
- 'HLOOKUP' : (101, 3, 4, 'V', 'VRRV'),
- 'HOUR' : ( 71, 1, 1, 'V', 'V'),
- 'HYPERLINK' : (359, 1, 2, 'V', 'VV'),
- 'HYPGEOMDIST' : (289, 4, 4, 'V', 'VVVV'),
- 'IF' : ( 1, 2, 3, 'R', 'VRR'),
- 'IMABS' : ( -1, 1, 1, 'V', 'V'),
- 'IMAGINARY' : ( -1, 1, 1, 'V', 'V'),
- 'IMARGUMENT' : ( -1, 1, 1, 'V', 'V'),
- 'IMCONJUGATE' : ( -1, 1, 1, 'V', 'V'),
- 'IMCOS' : ( -1, 1, 1, 'V', 'V'),
- 'IMDIV' : ( -1, 2, 2, 'V', 'VV'),
- 'IMEXP' : ( -1, 1, 1, 'V', 'V'),
- 'IMLN' : ( -1, 1, 1, 'V', 'V'),
- 'IMLOG10' : ( -1, 1, 1, 'V', 'V'),
- 'IMLOG2' : ( -1, 1, 1, 'V', 'V'),
- 'IMPOWER' : ( -1, 2, 2, 'V', 'VV'),
- 'IMPRODUCT' : ( -1, 2, 2, 'V', 'VV'),
- 'IMREAL' : ( -1, 1, 1, 'V', 'V'),
- 'IMSIN' : ( -1, 1, 1, 'V', 'V'),
- 'IMSQRT' : ( -1, 1, 1, 'V', 'V'),
- 'IMSUB' : ( -1, 2, 2, 'V', 'VV'),
- 'IMSUM' : ( -1, 1, 29, 'V', 'V+'),
- 'INDEX' : ( 29, 2, 4, 'R', 'RVVV'),
- 'INDIRECT' : (148, 1, 2, 'R', 'VV'),
- 'INFO' : (244, 1, 1, 'V', 'V'),
- 'INT' : ( 25, 1, 1, 'V', 'V'),
- 'INTERCEPT' : (311, 2, 2, 'V', 'AA'),
- 'INTRATE' : ( -1, 4, 5, 'V', 'VVVVV'),
- 'IPMT' : (167, 4, 6, 'V', 'VVVVVV'),
- 'IRR' : ( 62, 1, 2, 'V', 'RV'),
- 'ISBLANK' : (129, 1, 1, 'V', 'V'),
- 'ISERR' : (126, 1, 1, 'V', 'V'),
- 'ISERROR' : ( 3, 1, 1, 'V', 'V'),
- 'ISEVEN' : ( -1, 1, 1, 'V', 'V'),
- 'ISLOGICAL' : (198, 1, 1, 'V', 'V'),
- 'ISNA' : ( 2, 1, 1, 'V', 'V'),
- 'ISNONTEXT' : (190, 1, 1, 'V', 'V'),
- 'ISNUMBER' : (128, 1, 1, 'V', 'V'),
- 'ISODD' : ( -1, 1, 1, 'V', 'V'),
- 'ISPMT' : (350, 4, 4, 'V', 'VVVV'),
- 'ISREF' : (105, 1, 1, 'V', 'R'),
- 'ISTEXT' : (127, 1, 1, 'V', 'V'),
- 'KURT' : (322, 1, 30, 'V', 'D+'),
- 'LARGE' : (325, 2, 2, 'V', 'RV'),
- 'LCM' : ( -1, 1, 29, 'V', 'V+'),
- 'LEFT' : (115, 1, 2, 'V', 'VV'),
- 'LEFTB' : (208, 1, 2, 'V', 'VV'),
- 'LEN' : ( 32, 1, 1, 'V', 'V'),
- 'LENB' : (211, 1, 1, 'V', 'V'),
- 'LINEST' : ( 49, 1, 4, 'A', 'RRVV'),
- 'LN' : ( 22, 1, 1, 'V', 'V'),
- 'LOG' : (109, 1, 2, 'V', 'VV'),
- 'LOG10' : ( 23, 1, 1, 'V', 'V'),
- 'LOGEST' : ( 51, 1, 4, 'A', 'RRVV'),
- 'LOGINV' : (291, 3, 3, 'V', 'VVV'),
- 'LOGNORMDIST' : (290, 3, 3, 'V', 'VVV'),
- 'LOOKUP' : ( 28, 2, 3, 'V', 'VRR'),
- 'LOWER' : (112, 1, 1, 'V', 'V'),
- 'MATCH' : ( 64, 2, 3, 'V', 'VRR'),
- 'MAX' : ( 7, 1, 30, 'V', 'D+'),
- 'MAXA' : (362, 1, 30, 'V', 'D+'),
- 'MDETERM' : (163, 1, 1, 'V', 'A'),
- 'MDURATION' : ( -1, 5, 6, 'V', 'VVVVVV'),
- 'MEDIAN' : (227, 1, 30, 'V', 'D+'),
- 'MID' : ( 31, 3, 3, 'V', 'VVV'),
- 'MIDB' : (210, 3, 3, 'V', 'VVV'),
- 'MIN' : ( 6, 1, 30, 'V', 'D+'),
- 'MINA' : (363, 1, 30, 'V', 'D+'),
- 'MINUTE' : ( 72, 1, 1, 'V', 'V'),
- 'MINVERSE' : (164, 1, 1, 'A', 'A'),
- 'MIRR' : ( 61, 3, 3, 'V', 'RVV'),
- 'MMULT' : (165, 2, 2, 'A', 'AA'),
- 'MOD' : ( 39, 2, 2, 'V', 'VV'),
- 'MODE' : (330, 1, 30, 'V', 'A+'), ################ weird #################
- 'MONTH' : ( 68, 1, 1, 'V', 'V'),
- 'MROUND' : ( -1, 2, 2, 'V', 'VV'),
- 'MULTINOMIAL' : ( -1, 1, 29, 'V', 'V+'),
- 'N' : (131, 1, 1, 'V', 'R'),
- 'NA' : ( 10, 0, 0, 'V', '-'),
- 'NEGBINOMDIST': (292, 3, 3, 'V', 'VVV'),
- 'NETWORKDAYS' : ( -1, 2, 3, 'V', 'VVR'),
- 'NOMINAL' : ( -1, 2, 2, 'V', 'VV'),
- 'NORMDIST' : (293, 4, 4, 'V', 'VVVV'),
- 'NORMINV' : (295, 3, 3, 'V', 'VVV'),
- 'NORMSDIST' : (294, 1, 1, 'V', 'V'),
- 'NORMSINV' : (296, 1, 1, 'V', 'V'),
- 'NOT' : ( 38, 1, 1, 'V', 'V'),
- 'NOW' : ( 74, 0, 0, 'V', '-'),
- 'NPER' : ( 58, 3, 5, 'V', 'VVVVV'),
- 'NPV' : ( 11, 2, 30, 'V', 'VD+'),
- 'OCT2BIN' : ( -1, 1, 2, 'V', 'VV'),
- 'OCT2DEC' : ( -1, 1, 1, 'V', 'V'),
- 'OCT2HEX' : ( -1, 1, 2, 'V', 'VV'),
- 'ODD' : (298, 1, 1, 'V', 'V'),
- 'ODDFPRICE' : ( -1, 9, 9, 'V', 'VVVVVVVVV'),
- 'ODDFYIELD' : ( -1, 9, 9, 'V', 'VVVVVVVVV'),
- 'ODDLPRICE' : ( -1, 8, 8, 'V', 'VVVVVVVV'),
- 'ODDLYIELD' : ( -1, 8, 8, 'V', 'VVVVVVVV'),
- 'OFFSET' : ( 78, 3, 5, 'R', 'RVVVV'),
- 'OR' : ( 37, 1, 30, 'V', 'D+'),
- 'PEARSON' : (312, 2, 2, 'V', 'AA'),
- 'PERCENTILE' : (328, 2, 2, 'V', 'RV'),
- 'PERCENTRANK' : (329, 2, 3, 'V', 'RVV'),
- 'PERMUT' : (299, 2, 2, 'V', 'VV'),
- 'PHONETIC' : (360, 1, 1, 'V', 'R'),
- 'PI' : ( 19, 0, 0, 'V', '-'),
- 'PMT' : ( 59, 3, 5, 'V', 'VVVVV'),
- 'POISSON' : (300, 3, 3, 'V', 'VVV'),
- 'POWER' : (337, 2, 2, 'V', 'VV'),
- 'PPMT' : (168, 4, 6, 'V', 'VVVVVV'),
- 'PRICE' : ( -1, 6, 7, 'V', 'VVVVVVV'),
- 'PRICEDISC' : ( -1, 4, 5, 'V', 'VVVVV'),
- 'PRICEMAT' : ( -1, 5, 6, 'V', 'VVVVVV'),
- 'PROB' : (317, 3, 4, 'V', 'AAVV'),
- 'PRODUCT' : (183, 1, 30, 'V', 'D+'),
- 'PROPER' : (114, 1, 1, 'V', 'V'),
- 'PV' : ( 56, 3, 5, 'V', 'VVVVV'),
- 'QUARTILE' : (327, 2, 2, 'V', 'RV'),
- 'QUOTIENT' : ( -1, 2, 2, 'V', 'VV'),
- 'RADIANS' : (342, 1, 1, 'V', 'V'),
- 'RAND' : ( 63, 0, 0, 'V', '-'),
- 'RANDBETWEEN' : ( -1, 2, 2, 'V', 'VV'),
- 'RANK' : (216, 2, 3, 'V', 'VRV'),
- 'RATE' : ( 60, 3, 6, 'V', 'VVVVVV'),
- 'RECEIVED' : ( -1, 4, 5, 'V', 'VVVVV'),
- 'REPLACE' : (119, 4, 4, 'V', 'VVVV'),
- 'REPLACEB' : (207, 4, 4, 'V', 'VVVV'),
- 'REPT' : ( 30, 2, 2, 'V', 'VV'),
- 'RIGHT' : (116, 1, 2, 'V', 'VV'),
- 'RIGHTB' : (209, 1, 2, 'V', 'VV'),
- 'ROMAN' : (354, 1, 2, 'V', 'VV'),
- 'ROUND' : ( 27, 2, 2, 'V', 'VV'),
- 'ROUNDDOWN' : (213, 2, 2, 'V', 'VV'),
- 'ROUNDUP' : (212, 2, 2, 'V', 'VV'),
- 'ROW' : ( 8, 0, 1, 'V', 'R'),
- 'ROWS' : ( 76, 1, 1, 'V', 'R'),
- 'RSQ' : (313, 2, 2, 'V', 'AA'),
- 'RTD' : (379, 3, 30, 'A', 'VVV+'),
- 'SEARCH' : ( 82, 2, 3, 'V', 'VVV'),
- 'SEARCHB' : (206, 2, 3, 'V', 'VVV'),
- 'SECOND' : ( 73, 1, 1, 'V', 'V'),
- 'SERIESSUM' : ( -1, 4, 4, 'V', 'VVVA'),
- 'SIGN' : ( 26, 1, 1, 'V', 'V'),
- 'SIN' : ( 15, 1, 1, 'V', 'V'),
- 'SINH' : (229, 1, 1, 'V', 'V'),
- 'SKEW' : (323, 1, 30, 'V', 'D+'),
- 'SLN' : (142, 3, 3, 'V', 'VVV'),
- 'SLOPE' : (315, 2, 2, 'V', 'AA'),
- 'SMALL' : (326, 2, 2, 'V', 'RV'),
- 'SQRT' : ( 20, 1, 1, 'V', 'V'),
- 'SQRTPI' : ( -1, 1, 1, 'V', 'V'),
- 'STANDARDIZE' : (297, 3, 3, 'V', 'VVV'),
- 'STDEV' : ( 12, 1, 30, 'V', 'D+'),
- 'STDEVA' : (366, 1, 30, 'V', 'D+'),
- 'STDEVP' : (193, 1, 30, 'V', 'D+'),
- 'STDEVPA' : (364, 1, 30, 'V', 'D+'),
- 'STEYX' : (314, 2, 2, 'V', 'AA'),
- 'SUBSTITUTE' : (120, 3, 4, 'V', 'VVVV'),
- 'SUBTOTAL' : (344, 2, 30, 'V', 'VR+'),
- 'SUM' : ( 4, 1, 30, 'V', 'D+'),
- 'SUMIF' : (345, 2, 3, 'V', 'RVR'),
- 'SUMPRODUCT' : (228, 1, 30, 'V', 'A+'),
- 'SUMSQ' : (321, 1, 30, 'V', 'D+'),
- 'SUMX2MY2' : (304, 2, 2, 'V', 'AA'),
- 'SUMX2PY2' : (305, 2, 2, 'V', 'AA'),
- 'SUMXMY2' : (303, 2, 2, 'V', 'AA'),
- 'SYD' : (143, 4, 4, 'V', 'VVVV'),
- 'T' : (130, 1, 1, 'V', 'R'),
- 'TAN' : ( 17, 1, 1, 'V', 'V'),
- 'TANH' : (231, 1, 1, 'V', 'V'),
- 'TBILLEQ' : ( -1, 3, 3, 'V', 'VVV'),
- 'TBILLPRICE' : ( -1, 3, 3, 'V', 'VVV'),
- 'TBILLYIELD' : ( -1, 3, 3, 'V', 'VVV'),
- 'TDIST' : (301, 3, 3, 'V', 'VVV'),
- 'TEXT' : ( 48, 2, 2, 'V', 'VV'),
- 'TIME' : ( 66, 3, 3, 'V', 'VVV'),
- 'TIMEVALUE' : (141, 1, 1, 'V', 'V'),
- 'TINV' : (332, 2, 2, 'V', 'VV'),
- 'TODAY' : (221, 0, 0, 'V', '-'),
- 'TRANSPOSE' : ( 83, 1, 1, 'A', 'A'),
- 'TREND' : ( 50, 1, 4, 'A', 'RRRV'),
- 'TRIM' : (118, 1, 1, 'V', 'V'),
- 'TRIMMEAN' : (331, 2, 2, 'V', 'RV'),
- 'TRUE' : ( 34, 0, 0, 'V', '-'),
- 'TRUNC' : (197, 1, 2, 'V', 'VV'),
- 'TTEST' : (316, 4, 4, 'V', 'AAVV'),
- 'TYPE' : ( 86, 1, 1, 'V', 'V'),
- 'UPPER' : (113, 1, 1, 'V', 'V'),
- 'USDOLLAR' : (204, 1, 2, 'V', 'VV'),
- 'VALUE' : ( 33, 1, 1, 'V', 'V'),
- 'VAR' : ( 46, 1, 30, 'V', 'D+'),
- 'VARA' : (367, 1, 30, 'V', 'D+'),
- 'VARP' : (194, 1, 30, 'V', 'D+'),
- 'VARPA' : (365, 1, 30, 'V', 'D+'),
- 'VDB' : (222, 5, 7, 'V', 'VVVVVVV'),
- 'VLOOKUP' : (102, 3, 4, 'V', 'VRRV'),
- 'WEEKDAY' : ( 70, 1, 2, 'V', 'VV'),
- 'WEEKNUM' : ( -1, 1, 2, 'V', 'VV'),
- 'WEIBULL' : (302, 4, 4, 'V', 'VVVV'),
- 'WORKDAY' : ( -1, 2, 3, 'V', 'VVR'),
- 'XIRR' : ( -1, 2, 3, 'V', 'AAV'),
- 'XNPV' : ( -1, 3, 3, 'V', 'VAA'),
- 'YEAR' : ( 69, 1, 1, 'V', 'V'),
- 'YEARFRAC' : ( -1, 2, 3, 'V', 'VVV'),
- 'YIELD' : ( -1, 6, 7, 'V', 'VVVVVVV'),
- 'YIELDDISC' : ( -1, 4, 5, 'V', 'VVVVV'),
- 'YIELDMAT' : ( -1, 5, 6, 'V', 'VVVVVV'),
- 'ZTEST' : (324, 2, 3, 'V', 'RVV'),
- }
-
-# Formulas Parse things
-
-ptgExp = 0x01
-ptgTbl = 0x02
-ptgAdd = 0x03
-ptgSub = 0x04
-ptgMul = 0x05
-ptgDiv = 0x06
-ptgPower = 0x07
-ptgConcat = 0x08
-ptgLT = 0x09
-ptgLE = 0x0a
-ptgEQ = 0x0b
-ptgGE = 0x0c
-ptgGT = 0x0d
-ptgNE = 0x0e
-ptgIsect = 0x0f
-ptgUnion = 0x10
-ptgRange = 0x11
-ptgUplus = 0x12
-ptgUminus = 0x13
-ptgPercent = 0x14
-ptgParen = 0x15
-ptgMissArg = 0x16
-ptgStr = 0x17
-ptgExtend = 0x18
-ptgAttr = 0x19
-ptgSheet = 0x1a
-ptgEndSheet = 0x1b
-ptgErr = 0x1c
-ptgBool = 0x1d
-ptgInt = 0x1e
-ptgNum = 0x1f
-
-ptgArrayR = 0x20
-ptgFuncR = 0x21
-ptgFuncVarR = 0x22
-ptgNameR = 0x23
-ptgRefR = 0x24
-ptgAreaR = 0x25
-ptgMemAreaR = 0x26
-ptgMemErrR = 0x27
-ptgMemNoMemR = 0x28
-ptgMemFuncR = 0x29
-ptgRefErrR = 0x2a
-ptgAreaErrR = 0x2b
-ptgRefNR = 0x2c
-ptgAreaNR = 0x2d
-ptgMemAreaNR = 0x2e
-ptgMemNoMemNR = 0x2f
-ptgNameXR = 0x39
-ptgRef3dR = 0x3a
-ptgArea3dR = 0x3b
-ptgRefErr3dR = 0x3c
-ptgAreaErr3dR = 0x3d
-
-ptgArrayV = 0x40
-ptgFuncV = 0x41
-ptgFuncVarV = 0x42
-ptgNameV = 0x43
-ptgRefV = 0x44
-ptgAreaV = 0x45
-ptgMemAreaV = 0x46
-ptgMemErrV = 0x47
-ptgMemNoMemV = 0x48
-ptgMemFuncV = 0x49
-ptgRefErrV = 0x4a
-ptgAreaErrV = 0x4b
-ptgRefNV = 0x4c
-ptgAreaNV = 0x4d
-ptgMemAreaNV = 0x4e
-ptgMemNoMemNV = 0x4f
-ptgFuncCEV = 0x58
-ptgNameXV = 0x59
-ptgRef3dV = 0x5a
-ptgArea3dV = 0x5b
-ptgRefErr3dV = 0x5c
-ptgAreaErr3dV = 0x5d
-
-ptgArrayA = 0x60
-ptgFuncA = 0x61
-ptgFuncVarA = 0x62
-ptgNameA = 0x63
-ptgRefA = 0x64
-ptgAreaA = 0x65
-ptgMemAreaA = 0x66
-ptgMemErrA = 0x67
-ptgMemNoMemA = 0x68
-ptgMemFuncA = 0x69
-ptgRefErrA = 0x6a
-ptgAreaErrA = 0x6b
-ptgRefNA = 0x6c
-ptgAreaNA = 0x6d
-ptgMemAreaNA = 0x6e
-ptgMemNoMemNA = 0x6f
-ptgFuncCEA = 0x78
-ptgNameXA = 0x79
-ptgRef3dA = 0x7a
-ptgArea3dA = 0x7b
-ptgRefErr3dA = 0x7c
-ptgAreaErr3dA = 0x7d
-
-
-PtgNames = {
- ptgExp : "ptgExp",
- ptgTbl : "ptgTbl",
- ptgAdd : "ptgAdd",
- ptgSub : "ptgSub",
- ptgMul : "ptgMul",
- ptgDiv : "ptgDiv",
- ptgPower : "ptgPower",
- ptgConcat : "ptgConcat",
- ptgLT : "ptgLT",
- ptgLE : "ptgLE",
- ptgEQ : "ptgEQ",
- ptgGE : "ptgGE",
- ptgGT : "ptgGT",
- ptgNE : "ptgNE",
- ptgIsect : "ptgIsect",
- ptgUnion : "ptgUnion",
- ptgRange : "ptgRange",
- ptgUplus : "ptgUplus",
- ptgUminus : "ptgUminus",
- ptgPercent : "ptgPercent",
- ptgParen : "ptgParen",
- ptgMissArg : "ptgMissArg",
- ptgStr : "ptgStr",
- ptgExtend : "ptgExtend",
- ptgAttr : "ptgAttr",
- ptgSheet : "ptgSheet",
- ptgEndSheet : "ptgEndSheet",
- ptgErr : "ptgErr",
- ptgBool : "ptgBool",
- ptgInt : "ptgInt",
- ptgNum : "ptgNum",
- ptgArrayR : "ptgArrayR",
- ptgFuncR : "ptgFuncR",
- ptgFuncVarR : "ptgFuncVarR",
- ptgNameR : "ptgNameR",
- ptgRefR : "ptgRefR",
- ptgAreaR : "ptgAreaR",
- ptgMemAreaR : "ptgMemAreaR",
- ptgMemErrR : "ptgMemErrR",
- ptgMemNoMemR : "ptgMemNoMemR",
- ptgMemFuncR : "ptgMemFuncR",
- ptgRefErrR : "ptgRefErrR",
- ptgAreaErrR : "ptgAreaErrR",
- ptgRefNR : "ptgRefNR",
- ptgAreaNR : "ptgAreaNR",
- ptgMemAreaNR : "ptgMemAreaNR",
- ptgMemNoMemNR : "ptgMemNoMemNR",
- ptgNameXR : "ptgNameXR",
- ptgRef3dR : "ptgRef3dR",
- ptgArea3dR : "ptgArea3dR",
- ptgRefErr3dR : "ptgRefErr3dR",
- ptgAreaErr3dR : "ptgAreaErr3dR",
- ptgArrayV : "ptgArrayV",
- ptgFuncV : "ptgFuncV",
- ptgFuncVarV : "ptgFuncVarV",
- ptgNameV : "ptgNameV",
- ptgRefV : "ptgRefV",
- ptgAreaV : "ptgAreaV",
- ptgMemAreaV : "ptgMemAreaV",
- ptgMemErrV : "ptgMemErrV",
- ptgMemNoMemV : "ptgMemNoMemV",
- ptgMemFuncV : "ptgMemFuncV",
- ptgRefErrV : "ptgRefErrV",
- ptgAreaErrV : "ptgAreaErrV",
- ptgRefNV : "ptgRefNV",
- ptgAreaNV : "ptgAreaNV",
- ptgMemAreaNV : "ptgMemAreaNV",
- ptgMemNoMemNV : "ptgMemNoMemNV",
- ptgFuncCEV : "ptgFuncCEV",
- ptgNameXV : "ptgNameXV",
- ptgRef3dV : "ptgRef3dV",
- ptgArea3dV : "ptgArea3dV",
- ptgRefErr3dV : "ptgRefErr3dV",
- ptgAreaErr3dV : "ptgAreaErr3dV",
- ptgArrayA : "ptgArrayA",
- ptgFuncA : "ptgFuncA",
- ptgFuncVarA : "ptgFuncVarA",
- ptgNameA : "ptgNameA",
- ptgRefA : "ptgRefA",
- ptgAreaA : "ptgAreaA",
- ptgMemAreaA : "ptgMemAreaA",
- ptgMemErrA : "ptgMemErrA",
- ptgMemNoMemA : "ptgMemNoMemA",
- ptgMemFuncA : "ptgMemFuncA",
- ptgRefErrA : "ptgRefErrA",
- ptgAreaErrA : "ptgAreaErrA",
- ptgRefNA : "ptgRefNA",
- ptgAreaNA : "ptgAreaNA",
- ptgMemAreaNA : "ptgMemAreaNA",
- ptgMemNoMemNA : "ptgMemNoMemNA",
- ptgFuncCEA : "ptgFuncCEA",
- ptgNameXA : "ptgNameXA",
- ptgRef3dA : "ptgRef3dA",
- ptgArea3dA : "ptgArea3dA",
- ptgRefErr3dA : "ptgRefErr3dA",
- ptgAreaErr3dA : "ptgAreaErr3dA"
-}
-
-
-error_msg_by_code = {
- 0x00: "#NULL!", # intersection of two cell ranges is empty
- 0x07: "#DIV/0!", # division by zero
- 0x0F: "#VALUE!", # wrong type of operand
- 0x17: "#REF!", # illegal or deleted cell reference
- 0x1D: "#NAME?", # wrong function or range name
- 0x24: "#NUM!", # value range overflow
- 0x2A: "#N/A!" # argument or function not available
-}
diff --git a/tablib/packages/xlwt3/Formatting.py b/tablib/packages/xlwt3/Formatting.py deleted file mode 100644 index c92498b..0000000 --- a/tablib/packages/xlwt3/Formatting.py +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/env python
-'''
-The XF record is able to store explicit cell formatting attributes or the
-attributes of a cell style. Explicit formatting includes the reference to
-a cell style XF record. This allows to extend a defined cell style with
-some explicit attributes. The formatting attributes are divided into
-6 groups:
-
-Group Attributes
--------------------------------------
-Number format Number format index (index to FORMAT record)
-Font Font index (index to FONT record)
-Alignment Horizontal and vertical alignment, text wrap, indentation,
- orientation/rotation, text direction
-Border Border line styles and colours
-Background Background area style and colours
-Protection Cell locked, formula hidden
-
-For each group a flag in the cell XF record specifies whether to use the
-attributes contained in that XF record or in the referenced style
-XF record. In style XF records, these flags specify whether the attributes
-will overwrite explicit cell formatting when the style is applied to
-a cell. Changing a cell style (without applying this style to a cell) will
-change all cells which already use that style and do not contain explicit
-cell attributes for the changed style attributes. If a cell XF record does
-not contain explicit attributes in a group (if the attribute group flag
-is not set), it repeats the attributes of its style XF record.
-
-'''
-
-from . import BIFFRecords
-
-class Font(object):
-
- ESCAPEMENT_NONE = 0x00
- ESCAPEMENT_SUPERSCRIPT = 0x01
- ESCAPEMENT_SUBSCRIPT = 0x02
-
- UNDERLINE_NONE = 0x00
- UNDERLINE_SINGLE = 0x01
- UNDERLINE_SINGLE_ACC = 0x21
- UNDERLINE_DOUBLE = 0x02
- UNDERLINE_DOUBLE_ACC = 0x22
-
- FAMILY_NONE = 0x00
- FAMILY_ROMAN = 0x01
- FAMILY_SWISS = 0x02
- FAMILY_MODERN = 0x03
- FAMILY_SCRIPT = 0x04
- FAMILY_DECORATIVE = 0x05
-
- CHARSET_ANSI_LATIN = 0x00
- CHARSET_SYS_DEFAULT = 0x01
- CHARSET_SYMBOL = 0x02
- CHARSET_APPLE_ROMAN = 0x4D
- CHARSET_ANSI_JAP_SHIFT_JIS = 0x80
- CHARSET_ANSI_KOR_HANGUL = 0x81
- CHARSET_ANSI_KOR_JOHAB = 0x82
- CHARSET_ANSI_CHINESE_GBK = 0x86
- CHARSET_ANSI_CHINESE_BIG5 = 0x88
- CHARSET_ANSI_GREEK = 0xA1
- CHARSET_ANSI_TURKISH = 0xA2
- CHARSET_ANSI_VIETNAMESE = 0xA3
- CHARSET_ANSI_HEBREW = 0xB1
- CHARSET_ANSI_ARABIC = 0xB2
- CHARSET_ANSI_BALTIC = 0xBA
- CHARSET_ANSI_CYRILLIC = 0xCC
- CHARSET_ANSI_THAI = 0xDE
- CHARSET_ANSI_LATIN_II = 0xEE
- CHARSET_OEM_LATIN_I = 0xFF
-
- def __init__(self):
- # twip = 1/20 of a point = 1/1440 of a inch
- # usually resolution == 96 pixels per 1 inch
- # (rarely 120 pixels per 1 inch or another one)
-
- self.height = 0x00C8 # 200: this is font with height 10 points
- self.italic = False
- self.struck_out = False
- self.outline = False
- self.shadow = False
- self.colour_index = 0x7FFF
- self.bold = False
- self._weight = 0x0190 # 0x02BC gives bold font
- self.escapement = self.ESCAPEMENT_NONE
- self.underline = self.UNDERLINE_NONE
- self.family = self.FAMILY_NONE
- self.charset = self.CHARSET_SYS_DEFAULT
- self.name = b'Arial'
-
- def get_biff_record(self):
- height = self.height
-
- options = 0x00
- if self.bold:
- options |= 0x01
- self._weight = 0x02BC
- if self.italic:
- options |= 0x02
- if self.underline != self.UNDERLINE_NONE:
- options |= 0x04
- if self.struck_out:
- options |= 0x08
- if self.outline:
- options |= 0x010
- if self.shadow:
- options |= 0x020
-
- colour_index = self.colour_index
- weight = self._weight
- escapement = self.escapement
- underline = self.underline
- family = self.family
- charset = self.charset
- name = self.name
-
- return BIFFRecords.FontRecord(height, options, colour_index, weight, escapement,
- underline, family, charset,
- name)
-
- def _search_key(self):
- return (
- self.height,
- self.italic,
- self.struck_out,
- self.outline,
- self.shadow,
- self.colour_index,
- self.bold,
- self._weight,
- self.escapement,
- self.underline,
- self.family,
- self.charset,
- self.name,
- )
-
-class Alignment(object):
- HORZ_GENERAL = 0x00
- HORZ_LEFT = 0x01
- HORZ_CENTER = 0x02
- HORZ_RIGHT = 0x03
- HORZ_FILLED = 0x04
- HORZ_JUSTIFIED = 0x05 # BIFF4-BIFF8X
- HORZ_CENTER_ACROSS_SEL = 0x06 # Centred across selection (BIFF4-BIFF8X)
- HORZ_DISTRIBUTED = 0x07 # Distributed (BIFF8X)
-
- VERT_TOP = 0x00
- VERT_CENTER = 0x01
- VERT_BOTTOM = 0x02
- VERT_JUSTIFIED = 0x03 # Justified (BIFF5-BIFF8X)
- VERT_DISTRIBUTED = 0x04 # Distributed (BIFF8X)
-
- DIRECTION_GENERAL = 0x00 # BIFF8X
- DIRECTION_LR = 0x01
- DIRECTION_RL = 0x02
-
- ORIENTATION_NOT_ROTATED = 0x00
- ORIENTATION_STACKED = 0x01
- ORIENTATION_90_CC = 0x02
- ORIENTATION_90_CW = 0x03
-
- ROTATION_0_ANGLE = 0x00
- ROTATION_STACKED = 0xFF
-
- WRAP_AT_RIGHT = 0x01
- NOT_WRAP_AT_RIGHT = 0x00
-
- SHRINK_TO_FIT = 0x01
- NOT_SHRINK_TO_FIT = 0x00
-
- def __init__(self):
- self.horz = self.HORZ_GENERAL
- self.vert = self.VERT_BOTTOM
- self.dire = self.DIRECTION_GENERAL
- self.orie = self.ORIENTATION_NOT_ROTATED
- self.rota = self.ROTATION_0_ANGLE
- self.wrap = self.NOT_WRAP_AT_RIGHT
- self.shri = self.NOT_SHRINK_TO_FIT
- self.inde = 0
- self.merg = 0
-
- def _search_key(self):
- return (
- self.horz, self.vert, self.dire, self.orie, self.rota,
- self.wrap, self.shri, self.inde, self.merg,
- )
-
-class Borders(object):
- NO_LINE = 0x00
- THIN = 0x01
- MEDIUM = 0x02
- DASHED = 0x03
- DOTTED = 0x04
- THICK = 0x05
- DOUBLE = 0x06
- HAIR = 0x07
- #The following for BIFF8
- MEDIUM_DASHED = 0x08
- THIN_DASH_DOTTED = 0x09
- MEDIUM_DASH_DOTTED = 0x0A
- THIN_DASH_DOT_DOTTED = 0x0B
- MEDIUM_DASH_DOT_DOTTED = 0x0C
- SLANTED_MEDIUM_DASH_DOTTED = 0x0D
-
- NEED_DIAG1 = 0x01
- NEED_DIAG2 = 0x01
- NO_NEED_DIAG1 = 0x00
- NO_NEED_DIAG2 = 0x00
-
- def __init__(self):
- self.left = self.NO_LINE
- self.right = self.NO_LINE
- self.top = self.NO_LINE
- self.bottom = self.NO_LINE
- self.diag = self.NO_LINE
-
- self.left_colour = 0x40
- self.right_colour = 0x40
- self.top_colour = 0x40
- self.bottom_colour = 0x40
- self.diag_colour = 0x40
-
- self.need_diag1 = self.NO_NEED_DIAG1
- self.need_diag2 = self.NO_NEED_DIAG2
-
- def _search_key(self):
- return (
- self.left, self.right, self.top, self.bottom, self.diag,
- self.left_colour, self.right_colour, self.top_colour,
- self.bottom_colour, self.diag_colour,
- self.need_diag1, self.need_diag2,
- )
-
-class Pattern(object):
- # patterns 0x00 - 0x12
- NO_PATTERN = 0x00
- SOLID_PATTERN = 0x01
-
- def __init__(self):
- self.pattern = self.NO_PATTERN
- self.pattern_fore_colour = 0x40
- self.pattern_back_colour = 0x41
-
- def _search_key(self):
- return (
- self.pattern,
- self.pattern_fore_colour,
- self.pattern_back_colour,
- )
-
-class Protection(object):
- def __init__(self):
- self.cell_locked = 1
- self.formula_hidden = 0
-
- def _search_key(self):
- return (
- self.cell_locked,
- self.formula_hidden,
- )
diff --git a/tablib/packages/xlwt3/Row.py b/tablib/packages/xlwt3/Row.py deleted file mode 100644 index 46447b8..0000000 --- a/tablib/packages/xlwt3/Row.py +++ /dev/null @@ -1,253 +0,0 @@ -# -*- coding: windows-1252 -*-
-
-from . import BIFFRecords
-from . import Style
-from .Cell import StrCell, BlankCell, NumberCell, FormulaCell, MulBlankCell, BooleanCell, ErrorCell, \
- _get_cells_biff_data_mul
-from . import ExcelFormula
-import datetime as dt
-try:
- from decimal import Decimal
-except ImportError:
- # Python 2.3: decimal not supported; create dummy Decimal class
- class Decimal(object):
- pass
-
-
-class Row(object):
- __slots__ = [# private variables
- "__idx",
- "__parent",
- "__parent_wb",
- "__cells",
- "__min_col_idx",
- "__max_col_idx",
- "__xf_index",
- "__has_default_xf_index",
- "__height_in_pixels",
- # public variables
- "height",
- "has_default_height",
- "height_mismatch",
- "level",
- "collapse",
- "hidden",
- "space_above",
- "space_below"]
-
- def __init__(self, rowx, parent_sheet):
- if not (isinstance(rowx, int) and 0 <= rowx <= 65535):
- raise ValueError("row index (%r) not an int in range(65536)" % rowx)
- self.__idx = rowx
- self.__parent = parent_sheet
- self.__parent_wb = parent_sheet.get_parent()
- self.__cells = {}
- self.__min_col_idx = 0
- self.__max_col_idx = 0
- self.__xf_index = 0x0F
- self.__has_default_xf_index = 0
- self.__height_in_pixels = 0x11
-
- self.height = 0x00FF
- self.has_default_height = 0x00
- self.height_mismatch = 0
- self.level = 0
- self.collapse = 0
- self.hidden = 0
- self.space_above = 0
- self.space_below = 0
-
-
- def __adjust_height(self, style):
- twips = style.font.height
- points = float(twips)/20.0
- # Cell height in pixels can be calcuted by following approx. formula:
- # cell height in pixels = font height in points * 83/50 + 2/5
- # It works when screen resolution is 96 dpi
- pix = int(round(points*83.0/50.0 + 2.0/5.0))
- if pix > self.__height_in_pixels:
- self.__height_in_pixels = pix
-
-
- def __adjust_bound_col_idx(self, *args):
- for arg in args:
- iarg = int(arg)
- if not ((0 <= iarg <= 255) and arg == iarg):
- raise ValueError("column index (%r) not an int in range(256)" % arg)
- sheet = self.__parent
- if iarg < self.__min_col_idx:
- self.__min_col_idx = iarg
- if iarg > self.__max_col_idx:
- self.__max_col_idx = iarg
- if iarg < sheet.first_used_col:
- sheet.first_used_col = iarg
- if iarg > sheet.last_used_col:
- sheet.last_used_col = iarg
-
- def __excel_date_dt(self, date):
- if isinstance(date, dt.date) and (not isinstance(date, dt.datetime)):
- epoch = dt.date(1899, 12, 31)
- elif isinstance(date, dt.time):
- date = dt.datetime.combine(dt.datetime(1900, 1, 1), date)
- epoch = dt.datetime(1900, 1, 1, 0, 0, 0)
- else:
- epoch = dt.datetime(1899, 12, 31, 0, 0, 0)
- delta = date - epoch
- xldate = delta.days + float(delta.seconds) / (24*60*60)
- # Add a day for Excel's missing leap day in 1900
- if xldate > 59:
- xldate += 1
- return xldate
-
- def get_height_in_pixels(self):
- return self.__height_in_pixels
-
-
- def set_style(self, style):
- self.__adjust_height(style)
- self.__xf_index = self.__parent_wb.add_style(style)
- self.__has_default_xf_index = 1
-
-
- def get_xf_index(self):
- return self.__xf_index
-
-
- def get_cells_count(self):
- return len(self.__cells)
-
-
- def get_min_col(self):
- return self.__min_col_idx
-
-
- def get_max_col(self):
- return self.__max_col_idx
-
-
- def get_row_biff_data(self):
- height_options = (self.height & 0x07FFF)
- height_options |= (self.has_default_height & 0x01) << 15
-
- options = (self.level & 0x07) << 0
- options |= (self.collapse & 0x01) << 4
- options |= (self.hidden & 0x01) << 5
- options |= (self.height_mismatch & 0x01) << 6
- options |= (self.__has_default_xf_index & 0x01) << 7
- options |= (0x01 & 0x01) << 8
- options |= (self.__xf_index & 0x0FFF) << 16
- options |= (self.space_above & 1) << 28
- options |= (self.space_below & 1) << 29
-
- return BIFFRecords.RowRecord(self.__idx, self.__min_col_idx,
- self.__max_col_idx, height_options, options).get()
-
- def insert_cell(self, col_index, cell_obj):
- if col_index in self.__cells:
- if not self.__parent._cell_overwrite_ok:
- msg = "Attempt to overwrite cell: sheetname=%r rowx=%d colx=%d" \
- % (self.__parent.name, self.__idx, col_index)
- raise Exception(msg)
- prev_cell_obj = self.__cells[col_index]
- sst_idx = getattr(prev_cell_obj, 'sst_idx', None)
- if sst_idx is not None:
- self.__parent_wb.del_str(sst_idx)
- self.__cells[col_index] = cell_obj
-
- def insert_mulcells(self, colx1, colx2, cell_obj):
- self.insert_cell(colx1, cell_obj)
- for col_index in range(colx1+1, colx2+1):
- self.insert_cell(col_index, None)
-
- def get_cells_biff_data(self):
- cell_items = [item for item in self.__cells.items() if item[1] is not None]
- cell_items.sort() # in column order
- return _get_cells_biff_data_mul(self.__idx, cell_items)
- # previously:
- # return ''.join([cell.get_biff_data() for colx, cell in cell_items])
-
- def get_index(self):
- return self.__idx
-
- def set_cell_text(self, colx, value, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.insert_cell(colx, StrCell(self.__idx, colx, xf_index, self.__parent_wb.add_str(value)))
-
- def set_cell_blank(self, colx, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.insert_cell(colx, BlankCell(self.__idx, colx, xf_index))
-
- def set_cell_mulblanks(self, first_colx, last_colx, style=Style.default_style):
- assert 0 <= first_colx <= last_colx <= 255
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(first_colx, last_colx)
- xf_index = self.__parent_wb.add_style(style)
- # ncols = last_colx - first_colx + 1
- self.insert_mulcells(first_colx, last_colx, MulBlankCell(self.__idx, first_colx, last_colx, xf_index))
-
- def set_cell_number(self, colx, number, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.insert_cell(colx, NumberCell(self.__idx, colx, xf_index, number))
-
- def set_cell_date(self, colx, datetime_obj, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.insert_cell(colx,
- NumberCell(self.__idx, colx, xf_index, self.__excel_date_dt(datetime_obj)))
-
- def set_cell_formula(self, colx, formula, style=Style.default_style, calc_flags=0):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.__parent_wb.add_sheet_reference(formula)
- self.insert_cell(colx, FormulaCell(self.__idx, colx, xf_index, formula, calc_flags=0))
-
- def set_cell_boolean(self, colx, value, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.insert_cell(colx, BooleanCell(self.__idx, colx, xf_index, bool(value)))
-
- def set_cell_error(self, colx, error_string_or_code, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(colx)
- xf_index = self.__parent_wb.add_style(style)
- self.insert_cell(colx, ErrorCell(self.__idx, colx, xf_index, error_string_or_code))
-
- def write(self, col, label, style=Style.default_style):
- self.__adjust_height(style)
- self.__adjust_bound_col_idx(col)
- style_index = self.__parent_wb.add_style(style)
- if isinstance(label, str):
- if len(label) > 0:
- self.insert_cell(col,
- StrCell(self.__idx, col, style_index, self.__parent_wb.add_str(label))
- )
- else:
- self.insert_cell(col, BlankCell(self.__idx, col, style_index))
- elif isinstance(label, bool): # bool is subclass of int; test bool first
- self.insert_cell(col, BooleanCell(self.__idx, col, style_index, label))
- elif isinstance(label, (float, int, Decimal)):
- self.insert_cell(col, NumberCell(self.__idx, col, style_index, label))
- elif isinstance(label, (dt.datetime, dt.date, dt.time)):
- date_number = self.__excel_date_dt(label)
- self.insert_cell(col, NumberCell(self.__idx, col, style_index, date_number))
- elif label is None:
- self.insert_cell(col, BlankCell(self.__idx, col, style_index))
- elif isinstance(label, ExcelFormula.Formula):
- self.__parent_wb.add_sheet_reference(label)
- self.insert_cell(col, FormulaCell(self.__idx, col, style_index, label))
- else:
- raise Exception("Unexpected data type %r" % type(label))
-
- write_blanks = set_cell_mulblanks
-
-
-
diff --git a/tablib/packages/xlwt3/Style.py b/tablib/packages/xlwt3/Style.py deleted file mode 100644 index 182fc07..0000000 --- a/tablib/packages/xlwt3/Style.py +++ /dev/null @@ -1,593 +0,0 @@ -# -*- coding: windows-1252 -*-
-
-from . import Formatting
-from .BIFFRecords import *
-import collections
-
-FIRST_USER_DEFINED_NUM_FORMAT_IDX = 164
-
-class XFStyle(object):
-
- def __init__(self):
- self.num_format_str = 'General'
- self.font = Formatting.Font()
- self.alignment = Formatting.Alignment()
- self.borders = Formatting.Borders()
- self.pattern = Formatting.Pattern()
- self.protection = Formatting.Protection()
-
-default_style = XFStyle()
-
-class StyleCollection(object):
- _std_num_fmt_list = [
- 'general',
- '0',
- '0.00',
- '#,##0',
- '#,##0.00',
- '"$"#,##0_);("$"#,##',
- '"$"#,##0_);[Red]("$"#,##',
- '"$"#,##0.00_);("$"#,##',
- '"$"#,##0.00_);[Red]("$"#,##',
- '0%',
- '0.00%',
- '0.00E+00',
- '# ?/?',
- '# ??/??',
- 'M/D/YY',
- 'D-MMM-YY',
- 'D-MMM',
- 'MMM-YY',
- 'h:mm AM/PM',
- 'h:mm:ss AM/PM',
- 'h:mm',
- 'h:mm:ss',
- 'M/D/YY h:mm',
- '_(#,##0_);(#,##0)',
- '_(#,##0_);[Red](#,##0)',
- '_(#,##0.00_);(#,##0.00)',
- '_(#,##0.00_);[Red](#,##0.00)',
- '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',
- '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
- '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
- '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
- 'mm:ss',
- '[h]:mm:ss',
- 'mm:ss.0',
- '##0.0E+0',
- '@'
- ]
-
- def __init__(self, style_compression=0):
- self.style_compression = style_compression
- self.stats = [0, 0, 0, 0, 0, 0]
- self._font_id2x = {}
- self._font_x2id = {}
- self._font_val2x = {}
-
- for x in (0, 1, 2, 3, 5): # The font with index 4 is omitted in all BIFF versions
- font = Formatting.Font()
- search_key = font._search_key()
- self._font_id2x[font] = x
- self._font_x2id[x] = font
- self._font_val2x[search_key] = x
-
- self._xf_id2x = {}
- self._xf_x2id = {}
- self._xf_val2x = {}
-
- self._num_formats = {}
- for fmtidx, fmtstr in zip(list(range(0, 23)), StyleCollection._std_num_fmt_list[0:23]):
- self._num_formats[fmtstr] = fmtidx
- for fmtidx, fmtstr in zip(list(range(37, 50)), StyleCollection._std_num_fmt_list[23:]):
- self._num_formats[fmtstr] = fmtidx
-
- self.default_style = XFStyle()
- self._default_xf = self._add_style(self.default_style)[0]
-
- def add(self, style):
- if style == None:
- return 0x10
- return self._add_style(style)[1]
-
- def _add_style(self, style):
- num_format_str = style.num_format_str
- if num_format_str in self._num_formats:
- num_format_idx = self._num_formats[num_format_str]
- else:
- num_format_idx = (
- FIRST_USER_DEFINED_NUM_FORMAT_IDX
- + len(self._num_formats)
- - len(StyleCollection._std_num_fmt_list)
- )
- self._num_formats[num_format_str] = num_format_idx
-
- font = style.font
- if font in self._font_id2x:
- font_idx = self._font_id2x[font]
- self.stats[0] += 1
- elif self.style_compression:
- search_key = font._search_key()
- font_idx = self._font_val2x.get(search_key)
- if font_idx is not None:
- self._font_id2x[font] = font_idx
- self.stats[1] += 1
- else:
- font_idx = len(self._font_x2id) + 1 # Why plus 1? Font 4 is missing
- self._font_id2x[font] = font_idx
- self._font_val2x[search_key] = font_idx
- self._font_x2id[font_idx] = font
- self.stats[2] += 1
- else:
- font_idx = len(self._font_id2x) + 1
- self._font_id2x[font] = font_idx
- self.stats[2] += 1
-
- gof = (style.alignment, style.borders, style.pattern, style.protection)
- xf = (font_idx, num_format_idx) + gof
- if xf in self._xf_id2x:
- xf_index = self._xf_id2x[xf]
- self.stats[3] += 1
- elif self.style_compression == 2:
- xf_key = (font_idx, num_format_idx) + tuple([obj._search_key() for obj in gof])
- xf_index = self._xf_val2x.get(xf_key)
- if xf_index is not None:
- self._xf_id2x[xf] = xf_index
- self.stats[4] += 1
- else:
- xf_index = 0x10 + len(self._xf_x2id)
- self._xf_id2x[xf] = xf_index
- self._xf_val2x[xf_key] = xf_index
- self._xf_x2id[xf_index] = xf
- self.stats[5] += 1
- else:
- xf_index = 0x10 + len(self._xf_id2x)
- self._xf_id2x[xf] = xf_index
- self.stats[5] += 1
-
- if xf_index >= 0xFFF:
- # 12 bits allowed, 0xFFF is a sentinel value
- raise ValueError("More than 4094 XFs (styles)")
-
- return xf, xf_index
-
- def get_biff_data(self):
- result = b''
- result += self._all_fonts()
- result += self._all_num_formats()
- result += self._all_cell_styles()
- result += self._all_styles()
- return result
-
- def _all_fonts(self):
- result = b''
- if self.style_compression:
- alist = list(self._font_x2id.items())
- else:
- alist = [(x, o) for o, x in list(self._font_id2x.items())]
- alist.sort()
- for font_idx, font in alist:
- result += font.get_biff_record().get()
- return result
-
- def _all_num_formats(self):
- result = b''
- alist = [
- (v, k)
- for k, v in list(self._num_formats.items())
- if v >= FIRST_USER_DEFINED_NUM_FORMAT_IDX
- ]
- alist.sort()
- for fmtidx, fmtstr in alist:
- result += NumberFormatRecord(fmtidx, fmtstr).get()
- return result
-
- def _all_cell_styles(self):
- result = b''
- for i in range(0, 16):
- result += XFRecord(self._default_xf, 'style').get()
- if self.style_compression == 2:
- alist = list(self._xf_x2id.items())
- else:
- alist = [(x, o) for o, x in list(self._xf_id2x.items())]
- alist.sort()
- for xf_idx, xf in alist:
- result += XFRecord(xf).get()
- return result
-
- def _all_styles(self):
- return StyleRecord().get()
-
-# easyxf and its supporting objects ###################################
-
-class EasyXFException(Exception):
- pass
-
-class EasyXFCallerError(EasyXFException):
- pass
-
-class EasyXFAuthorError(EasyXFException):
- pass
-
-class IntULim(object):
- # If astring represents a valid unsigned integer ('123', '0xabcd', etc)
- # and it is <= limit, return the int value; otherwise return None.
-
- def __init__(self, limit):
- self.limit = limit
-
- def __call__(self, astring):
- try:
- value = int(astring, 0)
- except ValueError:
- return None
- if not 0 <= value <= self.limit:
- return None
- return value
-
-bool_map = {
- # Text values for all Boolean attributes
- '1': 1, 'yes': 1, 'true': 1, 'on': 1,
- '0': 0, 'no': 0, 'false': 0, 'off': 0,
- }
-
-border_line_map = {
- # Text values for these borders attributes:
- # left, right, top, bottom and diag
- 'no_line': 0x00,
- 'thin': 0x01,
- 'medium': 0x02,
- 'dashed': 0x03,
- 'dotted': 0x04,
- 'thick': 0x05,
- 'double': 0x06,
- 'hair': 0x07,
- 'medium_dashed': 0x08,
- 'thin_dash_dotted': 0x09,
- 'medium_dash_dotted': 0x0a,
- 'thin_dash_dot_dotted': 0x0b,
- 'medium_dash_dot_dotted': 0x0c,
- 'slanted_medium_dash_dotted': 0x0d,
- }
-
-charset_map = {
- # Text values for font.charset
- 'ansi_latin': 0x00,
- 'sys_default': 0x01,
- 'symbol': 0x02,
- 'apple_roman': 0x4d,
- 'ansi_jap_shift_jis': 0x80,
- 'ansi_kor_hangul': 0x81,
- 'ansi_kor_johab': 0x82,
- 'ansi_chinese_gbk': 0x86,
- 'ansi_chinese_big5': 0x88,
- 'ansi_greek': 0xa1,
- 'ansi_turkish': 0xa2,
- 'ansi_vietnamese': 0xa3,
- 'ansi_hebrew': 0xb1,
- 'ansi_arabic': 0xb2,
- 'ansi_baltic': 0xba,
- 'ansi_cyrillic': 0xcc,
- 'ansi_thai': 0xde,
- 'ansi_latin_ii': 0xee,
- 'oem_latin_i': 0xff,
- }
-
-
-# Text values for colour indices. "grey" is a synonym of "gray".
-# The names are those given by Microsoft Excel 2003 to the colours
-# in the default palette. There is no great correspondence with
-# any W3C name-to-RGB mapping.
-_colour_map_text = """\
-aqua 0x31
-black 0x08
-blue 0x0C
-blue_gray 0x36
-bright_green 0x0B
-brown 0x3C
-coral 0x1D
-cyan_ega 0x0F
-dark_blue 0x12
-dark_blue_ega 0x12
-dark_green 0x3A
-dark_green_ega 0x11
-dark_purple 0x1C
-dark_red 0x10
-dark_red_ega 0x10
-dark_teal 0x38
-dark_yellow 0x13
-gold 0x33
-gray_ega 0x17
-gray25 0x16
-gray40 0x37
-gray50 0x17
-gray80 0x3F
-green 0x11
-ice_blue 0x1F
-indigo 0x3E
-ivory 0x1A
-lavender 0x2E
-light_blue 0x30
-light_green 0x2A
-light_orange 0x34
-light_turquoise 0x29
-light_yellow 0x2B
-lime 0x32
-magenta_ega 0x0E
-ocean_blue 0x1E
-olive_ega 0x13
-olive_green 0x3B
-orange 0x35
-pale_blue 0x2C
-periwinkle 0x18
-pink 0x0E
-plum 0x3D
-purple_ega 0x14
-red 0x0A
-rose 0x2D
-sea_green 0x39
-silver_ega 0x16
-sky_blue 0x28
-tan 0x2F
-teal 0x15
-teal_ega 0x15
-turquoise 0x0F
-violet 0x14
-white 0x09
-yellow 0x0D"""
-
-colour_map = {}
-for _line in _colour_map_text.splitlines():
- _name, _num = _line.split()
- _num = int(_num, 0)
- colour_map[_name] = _num
- if 'gray' in _name:
- colour_map[_name.replace('gray', 'grey')] = _num
-del _colour_map_text, _line, _name, _num
-
-
-pattern_map = {
- # Text values for pattern.pattern
- # xlwt/doc/pattern_examples.xls showcases all of these patterns.
- 'no_fill': 0,
- 'none': 0,
- 'solid': 1,
- 'solid_fill': 1,
- 'solid_pattern': 1,
- 'fine_dots': 2,
- 'alt_bars': 3,
- 'sparse_dots': 4,
- 'thick_horz_bands': 5,
- 'thick_vert_bands': 6,
- 'thick_backward_diag': 7,
- 'thick_forward_diag': 8,
- 'big_spots': 9,
- 'bricks': 10,
- 'thin_horz_bands': 11,
- 'thin_vert_bands': 12,
- 'thin_backward_diag': 13,
- 'thin_forward_diag': 14,
- 'squares': 15,
- 'diamonds': 16,
- }
-
-def any_str_func(s):
- return s.strip()
-
-def colour_index_func(s, maxval=0x7F):
- try:
- value = int(s, 0)
- except ValueError:
- return None
- if not (0 <= value <= maxval):
- return None
- return value
-
-colour_index_func_7 = colour_index_func
-
-def colour_index_func_15(s):
- return colour_index_func(s, maxval=0x7FFF)
-
-def rotation_func(s):
- try:
- value = int(s, 0)
- except ValueError:
- return None
- if not (-90 <= value <= 90):
- raise EasyXFCallerError("rotation %d: should be -90 to +90 degrees" % value)
- if value < 0:
- value = 90 - value # encode as 91 to 180 (clockwise)
- return value
-
-xf_dict = {
- 'align': 'alignment', # synonym
- 'alignment': {
- 'dire': {
- 'general': 0,
- 'lr': 1,
- 'rl': 2,
- },
- 'direction': 'dire',
- 'horiz': 'horz',
- 'horizontal': 'horz',
- 'horz': {
- 'general': 0,
- 'left': 1,
- 'center': 2,
- 'centre': 2, # "align: horiz centre" means xf.alignment.horz is set to 2
- 'right': 3,
- 'filled': 4,
- 'justified': 5,
- 'center_across_selection': 6,
- 'centre_across_selection': 6,
- 'distributed': 7,
- },
- 'inde': IntULim(15), # restriction: 0 <= value <= 15
- 'indent': 'inde',
- 'rota': [{'stacked': 255, 'none': 0, }, rotation_func],
- 'rotation': 'rota',
- 'shri': bool_map,
- 'shrink': 'shri',
- 'shrink_to_fit': 'shri',
- 'vert': {
- 'top': 0,
- 'center': 1,
- 'centre': 1,
- 'bottom': 2,
- 'justified': 3,
- 'distributed': 4,
- },
- 'vertical': 'vert',
- 'wrap': bool_map,
- },
- 'border': 'borders',
- 'borders': {
- 'left': [border_line_map, IntULim(0x0d)],
- 'right': [border_line_map, IntULim(0x0d)],
- 'top': [border_line_map, IntULim(0x0d)],
- 'bottom': [border_line_map, IntULim(0x0d)],
- 'diag': [border_line_map, IntULim(0x0d)],
- 'top_colour': [colour_map, colour_index_func_7],
- 'bottom_colour': [colour_map, colour_index_func_7],
- 'left_colour': [colour_map, colour_index_func_7],
- 'right_colour': [colour_map, colour_index_func_7],
- 'diag_colour': [colour_map, colour_index_func_7],
- 'top_color': 'top_colour',
- 'bottom_color': 'bottom_colour',
- 'left_color': 'left_colour',
- 'right_color': 'right_colour',
- 'diag_color': 'diag-colour',
- 'need_diag_1': bool_map,
- 'need_diag_2': bool_map,
- },
- 'font': {
- 'bold': bool_map,
- 'charset': charset_map,
- 'color': 'colour_index',
- 'color_index': 'colour_index',
- 'colour': 'colour_index',
- 'colour_index': [colour_map, colour_index_func_15],
- 'escapement': {'none': 0, 'superscript': 1, 'subscript': 2},
- 'family': {'none': 0, 'roman': 1, 'swiss': 2, 'modern': 3, 'script': 4, 'decorative': 5, },
- 'height': IntULim(0xFFFF), # practical limits are much narrower e.g. 160 to 1440 (8pt to 72pt)
- 'italic': bool_map,
- 'name': any_str_func,
- 'outline': bool_map,
- 'shadow': bool_map,
- 'struck_out': bool_map,
- 'underline': [bool_map, {'none': 0, 'single': 1, 'single_acc': 0x21, 'double': 2, 'double_acc': 0x22, }],
- },
- 'pattern': {
- 'back_color': 'pattern_back_colour',
- 'back_colour': 'pattern_back_colour',
- 'fore_color': 'pattern_fore_colour',
- 'fore_colour': 'pattern_fore_colour',
- 'pattern': [pattern_map, IntULim(16)],
- 'pattern_back_color': 'pattern_back_colour',
- 'pattern_back_colour': [colour_map, colour_index_func_7],
- 'pattern_fore_color': 'pattern_fore_colour',
- 'pattern_fore_colour': [colour_map, colour_index_func_7],
- },
- 'protection': {
- 'cell_locked' : bool_map,
- 'formula_hidden': bool_map,
- },
- }
-
-def _esplit(s, split_char, esc_char="\\"):
- escaped = False
- olist = ['']
- for c in s:
- if escaped:
- olist[-1] += c
- escaped = False
- elif c == esc_char:
- escaped = True
- elif c == split_char:
- olist.append('')
- else:
- olist[-1] += c
- return olist
-
-def _parse_strg_to_obj(strg, obj, parse_dict,
- field_sep=",", line_sep=";", intro_sep=":", esc_char="\\", debug=False):
- for line in _esplit(strg, line_sep, esc_char):
- line = line.strip()
- if not line:
- break
- split_line = _esplit(line, intro_sep, esc_char)
- if len(split_line) != 2:
- raise EasyXFCallerError('line %r should have exactly 1 "%c"' % (line, intro_sep))
- section, item_str = split_line
- section = section.strip().lower()
- for counter in range(2):
- result = parse_dict.get(section)
- if result is None:
- raise EasyXFCallerError('section %r is unknown' % section)
- if isinstance(result, dict):
- break
- if not isinstance(result, str):
- raise EasyXFAuthorError(
- 'section %r should map to dict or str object; found %r' % (section, type(result)))
- # synonym
- old_section = section
- section = result
- else:
- raise EasyXFAuthorError('Attempt to define synonym of synonym (%r: %r)' % (old_section, result))
- section_dict = result
- section_obj = getattr(obj, section, None)
- if section_obj is None:
- raise EasyXFAuthorError('instance of %s class has no attribute named %s' % (obj.__class__.__name__, section))
- for kv_str in _esplit(item_str, field_sep, esc_char):
- guff = kv_str.split()
- if not guff:
- continue
- k = guff[0].lower().replace('-', '_')
- v = ' '.join(guff[1:])
- if not v:
- raise EasyXFCallerError("no value supplied for %s.%s" % (section, k))
- for counter in range(2):
- result = section_dict.get(k)
- if result is None:
- raise EasyXFCallerError('%s.%s is not a known attribute' % (section, k))
- if not isinstance(result, str):
- break
- # synonym
- old_k = k
- k = result
- else:
- raise EasyXFAuthorError('Attempt to define synonym of synonym (%r: %r)' % (old_k, result))
- value_info = result
- if not isinstance(value_info, list):
- value_info = [value_info]
- for value_rule in value_info:
- if isinstance(value_rule, dict):
- # dict maps strings to integer field values
- vl = v.lower().replace('-', '_')
- if vl in value_rule:
- value = value_rule[vl]
- break
- elif isinstance(value_rule, collections.Callable):
- value = value_rule(v)
- if value is not None:
- break
- else:
- raise EasyXFAuthorError("unknown value rule for attribute %r: %r" % (k, value_rule))
- else:
- raise EasyXFCallerError("unexpected value %r for %s.%s" % (v, section, k))
- try:
- orig = getattr(section_obj, k)
- except AttributeError:
- raise EasyXFAuthorError('%s.%s in dictionary but not in supplied object' % (section, k))
- if debug: print("+++ %s.%s = %r # %s; was %r" % (section, k, value, v, orig))
- setattr(section_obj, k, value)
-
-def easyxf(strg_to_parse="", num_format_str=None,
- field_sep=",", line_sep=";", intro_sep=":", esc_char="\\", debug=False):
- xfobj = XFStyle()
- if num_format_str is not None:
- xfobj.num_format_str = num_format_str
- if strg_to_parse:
- _parse_strg_to_obj(strg_to_parse, xfobj, xf_dict,
- field_sep=field_sep, line_sep=line_sep, intro_sep=intro_sep, esc_char=esc_char, debug=debug)
- return xfobj
diff --git a/tablib/packages/xlwt3/UnicodeUtils.py b/tablib/packages/xlwt3/UnicodeUtils.py deleted file mode 100644 index 204d13c..0000000 --- a/tablib/packages/xlwt3/UnicodeUtils.py +++ /dev/null @@ -1,79 +0,0 @@ -'''
-From BIFF8 on, strings are always stored using UTF-16LE text encoding. The
-character array is a sequence of 16-bit values4. Additionally it is
-possible to use a compressed format, which omits the high bytes of all
-characters, if they are all zero.
-
-The following tables describe the standard format of the entire string, but
-in many records the strings differ from this format. This will be mentioned
-separately. It is possible (but not required) to store Rich-Text formatting
-information and Asian phonetic information inside a Unicode string. This
-results in four different ways to store a string. The character array
-is not zero-terminated.
-
-The string consists of the character count (as usual an 8-bit value or
-a 16-bit value), option flags, the character array and optional formatting
-information. If the string is empty, sometimes the option flags field will
-not occur. This is mentioned at the respective place.
-
-Offset Size Contents
-0 1 or 2 Length of the string (character count, ln)
-1 or 2 1 Option flags:
- Bit Mask Contents
- 0 01H Character compression (ccompr):
- 0 = Compressed (8-bit characters)
- 1 = Uncompressed (16-bit characters)
- 2 04H Asian phonetic settings (phonetic):
- 0 = Does not contain Asian phonetic settings
- 1 = Contains Asian phonetic settings
- 3 08H Rich-Text settings (richtext):
- 0 = Does not contain Rich-Text settings
- 1 = Contains Rich-Text settings
-[2 or 3] 2 (optional, only if richtext=1) Number of Rich-Text formatting runs (rt)
-[var.] 4 (optional, only if phonetic=1) Size of Asian phonetic settings block (in bytes, sz)
-var. ln or
- 2·ln Character array (8-bit characters or 16-bit characters, dependent on ccompr)
-[var.] 4·rt (optional, only if richtext=1) List of rt formatting runs
-[var.] sz (optional, only if phonetic=1) Asian Phonetic Settings Block
-'''
-
-
-from struct import pack
-
-def upack2(s, encoding='ascii'):
- # If not unicode, make it so.
- if isinstance(s, str):
- us = s
- else:
- us = str(s, encoding)
- # Limit is based on number of content characters
- # (not on number of bytes in packed result)
- len_us = len(us)
- if len_us > 65535:
- raise Exception('String longer than 65535 characters')
- try:
- encs = us.encode('latin1')
- # Success here means all chars are in U+0000 to U+00FF
- # inclusive, meaning that we can use "compressed format".
- flag = 0
- except UnicodeEncodeError:
- encs = us.encode('utf_16_le')
- flag = 1
- return pack('<HB', len_us, flag) + encs
-
-def upack1(s, encoding='ascii'):
- # Same as upack2(), but with a one-byte length field.
- if isinstance(s, str):
- us = s
- else:
- us = str(s, encoding)
- len_us = len(us)
- if len_us > 255:
- raise Exception('String longer than 255 characters')
- try:
- encs = us.encode('latin1')
- flag = 0
- except UnicodeEncodeError:
- encs = us.encode('utf_16_le')
- flag = 1
- return pack('<BB', len_us, flag) + encs
diff --git a/tablib/packages/xlwt3/Utils.py b/tablib/packages/xlwt3/Utils.py deleted file mode 100644 index 3509f03..0000000 --- a/tablib/packages/xlwt3/Utils.py +++ /dev/null @@ -1,196 +0,0 @@ -# pyXLWriter: A library for generating Excel Spreadsheets
-# Copyright (c) 2004 Evgeny Filatov <fufff@users.sourceforge.net>
-# Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel)
-#
-# This library is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
-# General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#----------------------------------------------------------------------------
-# This module was written/ported from PERL Spreadsheet::WriteExcel module
-# The author of the PERL Spreadsheet::WriteExcel module is John McNamara
-# <jmcnamara@cpan.org>
-#----------------------------------------------------------------------------
-# See the README.txt distributed with pyXLWriter for more details.
-
-# Portions are (C) Roman V. Kiseliov, 2005
-
-
-# Utilities for work with reference to cells and with sheetnames
-
-
-__rev_id__ = """$Id: Utils.py 3844 2009-05-20 01:02:54Z sjmachin $"""
-
-import re
-from struct import pack
-from .ExcelMagic import MAX_ROW, MAX_COL
-
-
-_re_cell_ex = re.compile(r"(\$?)([A-I]?[A-Z])(\$?)(\d+)", re.IGNORECASE)
-_re_row_range = re.compile(r"\$?(\d+):\$?(\d+)")
-_re_col_range = re.compile(r"\$?([A-I]?[A-Z]):\$?([A-I]?[A-Z])", re.IGNORECASE)
-_re_cell_range = re.compile(r"\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)", re.IGNORECASE)
-_re_cell_ref = re.compile(r"\$?([A-I]?[A-Z]\$?\d+)", re.IGNORECASE)
-
-
-def col_by_name(colname):
- """
- """
- col = 0
- pow = 1
- for i in range(len(colname)-1, -1, -1):
- ch = colname[i]
- col += (ord(ch) - ord('A') + 1) * pow
- pow *= 26
- return col - 1
-
-
-def cell_to_rowcol(cell):
- """Convert an Excel cell reference string in A1 notation
- to numeric row/col notation.
-
- Returns: row, col, row_abs, col_abs
-
- """
- m = _re_cell_ex.match(cell)
- if not m:
- raise Exception("Ill-formed single_cell reference: %s" % cell)
- col_abs, col, row_abs, row = m.groups()
- row_abs = bool(row_abs)
- col_abs = bool(col_abs)
- row = int(row) - 1
- col = col_by_name(col.upper())
- return row, col, row_abs, col_abs
-
-
-def cell_to_rowcol2(cell):
- """Convert an Excel cell reference string in A1 notation
- to numeric row/col notation.
-
- Returns: row, col
-
- """
- m = _re_cell_ex.match(cell)
- if not m:
- raise Exception("Error in cell format")
- col_abs, col, row_abs, row = m.groups()
- # Convert base26 column string to number
- # All your Base are belong to us.
- row = int(row) - 1
- col = col_by_name(col.upper())
- return row, col
-
-
-def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
- """Convert numeric row/col notation to an Excel cell reference string in
- A1 notation.
-
- """
- assert 0 <= row < MAX_ROW # MAX_ROW counts from 1
- assert 0 <= col < MAX_COL # MAX_COL counts from 1
- d = col // 26
- m = col % 26
- chr1 = "" # Most significant character in AA1
- if row_abs:
- row_abs = '$'
- else:
- row_abs = ''
- if col_abs:
- col_abs = '$'
- else:
- col_abs = ''
- if d > 0:
- chr1 = chr(ord('A') + d - 1)
- chr2 = chr(ord('A') + m)
- # Zero index to 1-index
- return col_abs + chr1 + chr2 + row_abs + str(row + 1)
-
-def rowcol_pair_to_cellrange(row1, col1, row2, col2,
- row1_abs=False, col1_abs=False, row2_abs=False, col2_abs=False):
- """Convert two (row,column) pairs
- into a cell range string in A1:B2 notation.
-
- Returns: cell range string
- """
- assert row1 <= row2
- assert col1 <= col2
- return (
- rowcol_to_cell(row1, col1, row1_abs, col1_abs)
- + ":"
- + rowcol_to_cell(row2, col2, row2_abs, col2_abs)
- )
-
-def cellrange_to_rowcol_pair(cellrange):
- """Convert cell range string in A1 notation to numeric row/col
- pair.
-
- Returns: row1, col1, row2, col2
-
- """
- cellrange = cellrange.upper()
- # Convert a row range: '1:3'
- res = _re_row_range.match(cellrange)
- if res:
- row1 = int(res.group(1)) - 1
- col1 = 0
- row2 = int(res.group(2)) - 1
- col2 = -1
- return row1, col1, row2, col2
- # Convert a column range: 'A:A' or 'B:G'.
- # A range such as A:A is equivalent to A1:A16384, so add rows as required
- res = _re_col_range.match(cellrange)
- if res:
- col1 = col_by_name(res.group(1).upper())
- row1 = 0
- col2 = col_by_name(res.group(2).upper())
- row2 = -1
- return row1, col1, row2, col2
- # Convert a cell range: 'A1:B7'
- res = _re_cell_range.match(cellrange)
- if res:
- row1, col1 = cell_to_rowcol2(res.group(1))
- row2, col2 = cell_to_rowcol2(res.group(2))
- return row1, col1, row2, col2
- # Convert a cell reference: 'A1' or 'AD2000'
- res = _re_cell_ref.match(cellrange)
- if res:
- row1, col1 = cell_to_rowcol2(res.group(1))
- return row1, col1, row1, col1
- raise Exception("Unknown cell reference %s" % (cell))
-
-
-def cell_to_packed_rowcol(cell):
- """ pack row and column into the required 4 byte format """
- row, col, row_abs, col_abs = cell_to_rowcol(cell)
- if col >= MAX_COL:
- raise Exception("Column %s greater than IV in formula" % cell)
- if row >= MAX_ROW: # this for BIFF8. for BIFF7 available 2^14
- raise Exception("Row %s greater than %d in formula" % (cell, MAX_ROW))
- col |= int(not row_abs) << 15
- col |= int(not col_abs) << 14
- return row, col
-
-# === sheetname functions ===
-
-def valid_sheet_name(sheet_name):
- if sheet_name == "" or sheet_name[0] == "'" or len(sheet_name) > 31:
- return False
- for c in sheet_name:
- if c in "[]:\\?/*\x00":
- return False
- return True
-
-def quote_sheet_name(unquoted_sheet_name):
- if not valid_sheet_name(unquoted_sheet_name):
- raise Exception(
- 'attempt to quote an invalid worksheet name %r' % unquoted_sheet_name)
- return "'" + unquoted_sheet_name.replace("'", "''") + "'"
diff --git a/tablib/packages/xlwt3/Workbook.py b/tablib/packages/xlwt3/Workbook.py deleted file mode 100644 index ba42e6b..0000000 --- a/tablib/packages/xlwt3/Workbook.py +++ /dev/null @@ -1,635 +0,0 @@ -'''
-Record Order in BIFF8
- Workbook Globals Substream
- BOF Type = workbook globals
- Interface Header
- MMS
- Interface End
- WRITEACCESS
- CODEPAGE
- DSF
- TABID
- FNGROUPCOUNT
- Workbook Protection Block
- WINDOWPROTECT
- PROTECT
- PASSWORD
- PROT4REV
- PROT4REVPASS
- BACKUP
- HIDEOBJ
- WINDOW1
- DATEMODE
- PRECISION
- REFRESHALL
- BOOKBOOL
- FONT +
- FORMAT *
- XF +
- STYLE +
- ? PALETTE
- USESELFS
-
- BOUNDSHEET +
-
- COUNTRY
- ? Link Table
- SST
- ExtSST
- EOF
-'''
-
-from . import BIFFRecords
-from . import Style
-
-class Workbook(object):
-
- #################################################################
- ## Constructor
- #################################################################
- def __init__(self, encoding='ascii', style_compression=0):
- self.encoding = encoding
- self.__owner = 'None'
- self.__country_code = None # 0x07 is Russia :-)
- self.__wnd_protect = 0
- self.__obj_protect = 0
- self.__protect = 0
- self.__backup_on_save = 0
- # for WINDOW1 record
- self.__hpos_twips = 0x01E0
- self.__vpos_twips = 0x005A
- self.__width_twips = 0x3FCF
- self.__height_twips = 0x2A4E
-
- self.__active_sheet = 0
- self.__first_tab_index = 0
- self.__selected_tabs = 0x01
- self.__tab_width_twips = 0x0258
-
- self.__wnd_hidden = 0
- self.__wnd_mini = 0
- self.__hscroll_visible = 1
- self.__vscroll_visible = 1
- self.__tabs_visible = 1
-
- self.__styles = Style.StyleCollection(style_compression)
-
- self.__dates_1904 = 0
- self.__use_cell_values = 1
-
- self.__sst = BIFFRecords.SharedStringTable(self.encoding)
-
- self.__worksheets = []
- self.__worksheet_idx_from_name = {}
- self.__sheet_refs = {}
- self._supbook_xref = {}
- self._xcall_xref = {}
- self._ownbook_supbookx = None
- self._ownbook_supbook_ref = None
- self._xcall_supbookx = None
- self._xcall_supbook_ref = None
-
-
-
- #################################################################
- ## Properties, "getters", "setters"
- #################################################################
-
- def get_style_stats(self):
- return self.__styles.stats[:]
-
- def set_owner(self, value):
- self.__owner = value
-
- def get_owner(self):
- return self.__owner
-
- owner = property(get_owner, set_owner)
-
- #################################################################
-
- def set_country_code(self, value):
- self.__country_code = value
-
- def get_country_code(self):
- return self.__country_code
-
- country_code = property(get_country_code, set_country_code)
-
- #################################################################
-
- def set_wnd_protect(self, value):
- self.__wnd_protect = int(value)
-
- def get_wnd_protect(self):
- return bool(self.__wnd_protect)
-
- wnd_protect = property(get_wnd_protect, set_wnd_protect)
-
- #################################################################
-
- def set_obj_protect(self, value):
- self.__obj_protect = int(value)
-
- def get_obj_protect(self):
- return bool(self.__obj_protect)
-
- obj_protect = property(get_obj_protect, set_obj_protect)
-
- #################################################################
-
- def set_protect(self, value):
- self.__protect = int(value)
-
- def get_protect(self):
- return bool(self.__protect)
-
- protect = property(get_protect, set_protect)
-
- #################################################################
-
- def set_backup_on_save(self, value):
- self.__backup_on_save = int(value)
-
- def get_backup_on_save(self):
- return bool(self.__backup_on_save)
-
- backup_on_save = property(get_backup_on_save, set_backup_on_save)
-
- #################################################################
-
- def set_hpos(self, value):
- self.__hpos_twips = value & 0xFFFF
-
- def get_hpos(self):
- return self.__hpos_twips
-
- hpos = property(get_hpos, set_hpos)
-
- #################################################################
-
- def set_vpos(self, value):
- self.__vpos_twips = value & 0xFFFF
-
- def get_vpos(self):
- return self.__vpos_twips
-
- vpos = property(get_vpos, set_vpos)
-
- #################################################################
-
- def set_width(self, value):
- self.__width_twips = value & 0xFFFF
-
- def get_width(self):
- return self.__width_twips
-
- width = property(get_width, set_width)
-
- #################################################################
-
- def set_height(self, value):
- self.__height_twips = value & 0xFFFF
-
- def get_height(self):
- return self.__height_twips
-
- height = property(get_height, set_height)
-
- #################################################################
-
- def set_active_sheet(self, value):
- self.__active_sheet = value & 0xFFFF
- self.__first_tab_index = self.__active_sheet
-
- def get_active_sheet(self):
- return self.__active_sheet
-
- active_sheet = property(get_active_sheet, set_active_sheet)
-
- #################################################################
-
- def set_tab_width(self, value):
- self.__tab_width_twips = value & 0xFFFF
-
- def get_tab_width(self):
- return self.__tab_width_twips
-
- tab_width = property(get_tab_width, set_tab_width)
-
- #################################################################
-
- def set_wnd_visible(self, value):
- self.__wnd_hidden = int(not value)
-
- def get_wnd_visible(self):
- return not bool(self.__wnd_hidden)
-
- wnd_visible = property(get_wnd_visible, set_wnd_visible)
-
- #################################################################
-
- def set_wnd_mini(self, value):
- self.__wnd_mini = int(value)
-
- def get_wnd_mini(self):
- return bool(self.__wnd_mini)
-
- wnd_mini = property(get_wnd_mini, set_wnd_mini)
-
- #################################################################
-
- def set_hscroll_visible(self, value):
- self.__hscroll_visible = int(value)
-
- def get_hscroll_visible(self):
- return bool(self.__hscroll_visible)
-
- hscroll_visible = property(get_hscroll_visible, set_hscroll_visible)
-
- #################################################################
-
- def set_vscroll_visible(self, value):
- self.__vscroll_visible = int(value)
-
- def get_vscroll_visible(self):
- return bool(self.__vscroll_visible)
-
- vscroll_visible = property(get_vscroll_visible, set_vscroll_visible)
-
- #################################################################
-
- def set_tabs_visible(self, value):
- self.__tabs_visible = int(value)
-
- def get_tabs_visible(self):
- return bool(self.__tabs_visible)
-
- tabs_visible = property(get_tabs_visible, set_tabs_visible)
-
- #################################################################
-
- def set_dates_1904(self, value):
- self.__dates_1904 = int(value)
-
- def get_dates_1904(self):
- return bool(self.__dates_1904)
-
- dates_1904 = property(get_dates_1904, set_dates_1904)
-
- #################################################################
-
- def set_use_cell_values(self, value):
- self.__use_cell_values = int(value)
-
- def get_use_cell_values(self):
- return bool(self.__use_cell_values)
-
- use_cell_values = property(get_use_cell_values, set_use_cell_values)
-
- #################################################################
-
- def get_default_style(self):
- return self.__styles.default_style
-
- default_style = property(get_default_style)
-
- ##################################################################
- ## Methods
- ##################################################################
-
- def add_style(self, style):
- return self.__styles.add(style)
-
- def add_str(self, s):
- return self.__sst.add_str(s)
-
- def del_str(self, sst_idx):
- self.__sst.del_str(sst_idx)
-
- def str_index(self, s):
- return self.__sst.str_index(s)
-
- def add_sheet(self, sheetname, cell_overwrite_ok=False):
- from . import Worksheet, Utils
- if not isinstance(sheetname, str):
- sheetname = sheetname.decode(self.encoding)
- if not Utils.valid_sheet_name(sheetname):
- raise Exception("invalid worksheet name %r" % sheetname)
- lower_name = sheetname.lower()
- if lower_name in self.__worksheet_idx_from_name:
- raise Exception("duplicate worksheet name %r" % sheetname)
- self.__worksheet_idx_from_name[lower_name] = len(self.__worksheets)
- self.__worksheets.append(Worksheet(sheetname, self, cell_overwrite_ok))
- return self.__worksheets[-1]
-
- def get_sheet(self, sheetnum):
- return self.__worksheets[sheetnum]
-
- def raise_bad_sheetname(self, sheetname):
- raise Exception("Formula: unknown sheet name %s" % sheetname)
-
- def convert_sheetindex(self, strg_ref, n_sheets):
- idx = int(strg_ref)
- if 0 <= idx < n_sheets:
- return idx
- msg = "Formula: sheet index (%s) >= number of sheets (%d)" % (strg_ref, n_sheets)
- raise Exception(msg)
-
- def _get_supbook_index(self, tag):
- if tag in self._supbook_xref:
- return self._supbook_xref[tag]
- self._supbook_xref[tag] = idx = len(self._supbook_xref)
- return idx
-
- def setup_ownbook(self):
- self._ownbook_supbookx = self._get_supbook_index(('ownbook', 0))
- self._ownbook_supbook_ref = None
- reference = (self._ownbook_supbookx, 0xFFFE, 0xFFFE)
- if reference in self.__sheet_refs:
- raise Exception("can't happen")
- self.__sheet_refs[reference] = self._ownbook_supbook_ref = len(self.__sheet_refs)
-
- def setup_xcall(self):
- self._xcall_supbookx = self._get_supbook_index(('xcall', 0))
- self._xcall_supbook_ref = None
- reference = (self._xcall_supbookx, 0xFFFE, 0xFFFE)
- if reference in self.__sheet_refs:
- raise Exception("can't happen")
- self.__sheet_refs[reference] = self._xcall_supbook_ref = len(self.__sheet_refs)
-
- def add_sheet_reference(self, formula):
- patches = []
- n_sheets = len(self.__worksheets)
- sheet_refs, xcall_refs = formula.get_references()
-
- for ref0, ref1, offset in sheet_refs:
- if not ref0.isdigit():
- try:
- ref0n = self.__worksheet_idx_from_name[ref0.lower()]
- except KeyError:
- self.raise_bad_sheetname(ref0)
- else:
- ref0n = self.convert_sheetindex(ref0, n_sheets)
- if ref1 == ref0:
- ref1n = ref0n
- elif not ref1.isdigit():
- try:
- ref1n = self.__worksheet_idx_from_name[ref1.lower()]
- except KeyError:
- self.raise_bad_sheetname(ref1)
- else:
- ref1n = self.convert_sheetindex(ref1, n_sheets)
- if ref1n < ref0n:
- msg = "Formula: sheets out of order; %r:%r -> (%d, %d)" \
- % (ref0, ref1, ref0n, ref1n)
- raise Exception(msg)
- if self._ownbook_supbookx is None:
- self.setup_ownbook()
- reference = (self._ownbook_supbookx, ref0n, ref1n)
- if reference in self.__sheet_refs:
- patches.append((offset, self.__sheet_refs[reference]))
- else:
- nrefs = len(self.__sheet_refs)
- if nrefs > 65535:
- raise Exception('More than 65536 inter-sheet references')
- self.__sheet_refs[reference] = nrefs
- patches.append((offset, nrefs))
-
- for funcname, offset in xcall_refs:
- if self._ownbook_supbookx is None:
- self.setup_ownbook()
- if self._xcall_supbookx is None:
- self.setup_xcall()
- # print funcname, self._supbook_xref
- patches.append((offset, self._xcall_supbook_ref))
- if not isinstance(funcname, str):
- funcname = funcname.decode(self.encoding)
- if funcname in self._xcall_xref:
- idx = self._xcall_xref[funcname]
- else:
- self._xcall_xref[funcname] = idx = len(self._xcall_xref)
- patches.append((offset + 2, idx + 1))
-
- formula.patch_references(patches)
-
- ##################################################################
- ## BIFF records generation
- ##################################################################
-
- def __bof_rec(self):
- return BIFFRecords.Biff8BOFRecord(BIFFRecords.Biff8BOFRecord.BOOK_GLOBAL).get()
-
- def __eof_rec(self):
- return BIFFRecords.EOFRecord().get()
-
- def __intf_hdr_rec(self):
- return BIFFRecords.InteraceHdrRecord().get()
-
- def __intf_end_rec(self):
- return BIFFRecords.InteraceEndRecord().get()
-
- def __intf_mms_rec(self):
- return BIFFRecords.MMSRecord().get()
-
- def __write_access_rec(self):
- return BIFFRecords.WriteAccessRecord(self.__owner).get()
-
- def __wnd_protect_rec(self):
- return BIFFRecords.WindowProtectRecord(self.__wnd_protect).get()
-
- def __obj_protect_rec(self):
- return BIFFRecords.ObjectProtectRecord(self.__obj_protect).get()
-
- def __protect_rec(self):
- return BIFFRecords.ProtectRecord(self.__protect).get()
-
- def __password_rec(self):
- return BIFFRecords.PasswordRecord().get()
-
- def __prot4rev_rec(self):
- return BIFFRecords.Prot4RevRecord().get()
-
- def __prot4rev_pass_rec(self):
- return BIFFRecords.Prot4RevPassRecord().get()
-
- def __backup_rec(self):
- return BIFFRecords.BackupRecord(self.__backup_on_save).get()
-
- def __hide_obj_rec(self):
- return BIFFRecords.HideObjRecord().get()
-
- def __window1_rec(self):
- flags = 0
- flags |= (self.__wnd_hidden) << 0
- flags |= (self.__wnd_mini) << 1
- flags |= (self.__hscroll_visible) << 3
- flags |= (self.__vscroll_visible) << 4
- flags |= (self.__tabs_visible) << 5
-
- return BIFFRecords.Window1Record(self.__hpos_twips, self.__vpos_twips,
- self.__width_twips, self.__height_twips,
- flags,
- self.__active_sheet, self.__first_tab_index,
- self.__selected_tabs, self.__tab_width_twips).get()
-
- def __codepage_rec(self):
- return BIFFRecords.CodepageBiff8Record().get()
-
- def __country_rec(self):
- if not self.__country_code:
- return b''
- return BIFFRecords.CountryRecord(self.__country_code, self.__country_code).get()
-
- def __dsf_rec(self):
- return BIFFRecords.DSFRecord().get()
-
- def __tabid_rec(self):
- return BIFFRecords.TabIDRecord(len(self.__worksheets)).get()
-
- def __fngroupcount_rec(self):
- return BIFFRecords.FnGroupCountRecord().get()
-
- def __datemode_rec(self):
- return BIFFRecords.DateModeRecord(self.__dates_1904).get()
-
- def __precision_rec(self):
- return BIFFRecords.PrecisionRecord(self.__use_cell_values).get()
-
- def __refresh_all_rec(self):
- return BIFFRecords.RefreshAllRecord().get()
-
- def __bookbool_rec(self):
- return BIFFRecords.BookBoolRecord().get()
-
- def __all_fonts_num_formats_xf_styles_rec(self):
- return self.__styles.get_biff_data()
-
- def __palette_rec(self):
- result = b''
- return result
-
- def __useselfs_rec(self):
- return BIFFRecords.UseSelfsRecord().get()
-
- def __boundsheets_rec(self, data_len_before, data_len_after, sheet_biff_lens):
- # .................................
- # BOUNDSEHEET0
- # BOUNDSEHEET1
- # BOUNDSEHEET2
- # ..................................
- # WORKSHEET0
- # WORKSHEET1
- # WORKSHEET2
- boundsheets_len = 0
- for sheet in self.__worksheets:
- boundsheets_len += len(BIFFRecords.BoundSheetRecord(
- 0x00, sheet.visibility, sheet.name, self.encoding
- ).get())
-
- start = data_len_before + boundsheets_len + data_len_after
-
- result = b''
- for sheet_biff_len, sheet in zip(sheet_biff_lens, self.__worksheets):
- result += BIFFRecords.BoundSheetRecord(
- start, sheet.visibility, sheet.name, self.encoding
- ).get()
- start += sheet_biff_len
- return result
-
- def __all_links_rec(self):
- pieces = []
- temp = [(idx, tag) for tag, idx in list(self._supbook_xref.items())]
- temp.sort()
- for idx, tag in temp:
- stype, snum = tag
- if stype == 'ownbook':
- rec = BIFFRecords.InternalReferenceSupBookRecord(len(self.__worksheets)).get()
- pieces.append(rec)
- elif stype == 'xcall':
- rec = BIFFRecords.XcallSupBookRecord().get()
- pieces.append(rec)
- temp = [(idx, name) for name, idx in list(self._xcall_xref.items())]
- temp.sort()
- for idx, name in temp:
- rec = BIFFRecords.ExternnameRecord(
- options=0, index=0, name=name, fmla='\x02\x00\x1c\x17').get()
- pieces.append(rec)
- else:
- raise Exception('unknown supbook stype %r' % stype)
- if len(self.__sheet_refs) > 0:
- # get references in index order
- temp = [(idx, ref) for ref, idx in list(self.__sheet_refs.items())]
- temp.sort()
- temp = [ref for idx, ref in temp]
- externsheet_record = BIFFRecords.ExternSheetRecord(temp).get()
- pieces.append(externsheet_record)
- return b''.join(pieces)
-
- def __sst_rec(self):
- return self.__sst.get_biff_record()
-
- def __ext_sst_rec(self, abs_stream_pos):
- return b''
- #return BIFFRecords.ExtSSTRecord(abs_stream_pos, self.sst_record.str_placement,
- #self.sst_record.portions_len).get()
-
- def get_biff_data(self):
- before = b''
- before += self.__bof_rec()
- before += self.__intf_hdr_rec()
- before += self.__intf_mms_rec()
- before += self.__intf_end_rec()
- before += self.__write_access_rec()
- before += self.__codepage_rec()
- before += self.__dsf_rec()
- before += self.__tabid_rec()
- before += self.__fngroupcount_rec()
- before += self.__wnd_protect_rec()
- before += self.__protect_rec()
- before += self.__obj_protect_rec()
- before += self.__password_rec()
- before += self.__prot4rev_rec()
- before += self.__prot4rev_pass_rec()
- before += self.__backup_rec()
- before += self.__hide_obj_rec()
- before += self.__window1_rec()
- before += self.__datemode_rec()
- before += self.__precision_rec()
- before += self.__refresh_all_rec()
- before += self.__bookbool_rec()
- before += self.__all_fonts_num_formats_xf_styles_rec()
- before += self.__palette_rec()
- before += self.__useselfs_rec()
-
- country = self.__country_rec()
- all_links = self.__all_links_rec()
-
- shared_str_table = self.__sst_rec()
- after = country + all_links + shared_str_table
-
- ext_sst = self.__ext_sst_rec(0) # need fake cause we need calc stream pos
- eof = self.__eof_rec()
-
- self.__worksheets[self.__active_sheet].selected = True
- sheets = b''
- sheet_biff_lens = []
- for sheet in self.__worksheets:
- data = sheet.get_biff_data()
- sheets += data
- sheet_biff_lens.append(len(data))
-
- bundlesheets = self.__boundsheets_rec(len(before), len(after)+len(ext_sst)+len(eof), sheet_biff_lens)
-
- sst_stream_pos = len(before) + len(bundlesheets) + len(country) + len(all_links)
- ext_sst = self.__ext_sst_rec(sst_stream_pos)
-
- return before + bundlesheets + after + ext_sst + eof + sheets
-
- def save(self, filename):
- from . import CompoundDoc
-
- doc = CompoundDoc.XlsDoc()
- doc.save(filename, self.get_biff_data())
-
-
diff --git a/tablib/packages/xlwt3/Worksheet.py b/tablib/packages/xlwt3/Worksheet.py deleted file mode 100644 index f358dd6..0000000 --- a/tablib/packages/xlwt3/Worksheet.py +++ /dev/null @@ -1,1296 +0,0 @@ -'''
- BOF
- UNCALCED
- INDEX
- Calculation Settings Block
- PRINTHEADERS
- PRINTGRIDLINES
- GRIDSET
- GUTS
- DEFAULTROWHEIGHT
- WSBOOL
- Page Settings Block
- Worksheet Protection Block
- DEFCOLWIDTH
- COLINFO
- SORT
- DIMENSIONS
- Row Blocks
- WINDOW2
- SCL
- PANE
- SELECTION
- STANDARDWIDTH
- MERGEDCELLS
- LABELRANGES
- PHONETIC
- Conditional Formatting Table
- Hyperlink Table
- Data Validity Table
- SHEETLAYOUT (BIFF8X only)
- SHEETPROTECTION (BIFF8X only)
- RANGEPROTECTION (BIFF8X only)
- EOF
-'''
-
-from . import BIFFRecords
-from . import Bitmap
-from . import Formatting
-from . import Style
-import tempfile
-
-
-class Worksheet(object):
- from .Workbook import Workbook
-
- #################################################################
- ## Constructor
- #################################################################
- def __init__(self, sheetname, parent_book, cell_overwrite_ok=False):
- from . import Row
- self.Row = Row #(to_py3): Row.Row -> Row
-
- from . import Column
- self.Column = Column #(to_py3): Column.Column -> Column
-
- self.__name = sheetname
- self.__parent = parent_book
- self._cell_overwrite_ok = cell_overwrite_ok
-
- self.__rows = {}
- self.__cols = {}
- self.__merged_ranges = []
- self.__bmp_rec = b''
-
- self.__show_formulas = 0
- self.__show_grid = 1
- self.__show_headers = 1
- self.__panes_frozen = 0
- ### self.__show_empty_as_zero = 1 ### deprecated with extreme prejudice 2009-05-19
- self.show_zero_values = 1
- self.__auto_colour_grid = 1
- self.__cols_right_to_left = 0
- self.__show_outline = 1
- self.__remove_splits = 0
- self.__selected = 0
- # RED HERRING ALERT: "sheet_visible" is a clone of the "selected" attribute.
- # Typically a workbook created by the Excel UI will have one sheet
- # (the sheet that was selected when the user saved it)
- # with both bits set to 1, and all other sheets will have both
- # bits set to 0. The true visibility of the sheet is found in the "visibility"
- # attribute obtained from the BOUNDSHEET record.
- self.__sheet_visible = 0
- self.__page_preview = 0
-
- self.__first_visible_row = 0
- self.__first_visible_col = 0
- self.__grid_colour = 0x40
- self.__preview_magn = 60 # percent
- self.__normal_magn = 100 # percent
-
- self.visibility = 0 # from/to BOUNDSHEET record.
-
- self.__vert_split_pos = None
- self.__horz_split_pos = None
- self.__vert_split_first_visible = None
- self.__horz_split_first_visible = None
- self.__split_active_pane = None
-
- self.__row_gut_width = 0
- self.__col_gut_height = 0
-
- self.__show_auto_page_breaks = 1
- self.__dialogue_sheet = 0
- self.__auto_style_outline = 0
- self.__outline_below = 0
- self.__outline_right = 0
- self.__fit_num_pages = 0
- self.__show_row_outline = 1
- self.__show_col_outline = 1
- self.__alt_expr_eval = 0
- self.__alt_formula_entries = 0
-
- self.__row_default_height = 0x00FF
- self.row_default_height_mismatch = 0
- self.row_default_hidden = 0
- self.row_default_space_above = 0
- self.row_default_space_below = 0
-
- self.__col_default_width = 0x0008
-
- self.__calc_mode = 1
- self.__calc_count = 0x0064
- self.__RC_ref_mode = 1
- self.__iterations_on = 0
- self.__delta = 0.001
- self.__save_recalc = 0
-
- self.__print_headers = 0
- self.__print_grid = 0
- self.__grid_set = 1
- self.__vert_page_breaks = []
- self.__horz_page_breaks = []
- self.__header_str = '&P'
- self.__footer_str = '&F'
- self.__print_centered_vert = 0
- self.__print_centered_horz = 1
- self.__left_margin = 0.3 #0.5
- self.__right_margin = 0.3 #0.5
- self.__top_margin = 0.61 #1.0
- self.__bottom_margin = 0.37 #1.0
- self.__paper_size_code = 9 # A4
- self.__print_scaling = 100
- self.__start_page_number = 1
- self.__fit_width_to_pages = 1
- self.__fit_height_to_pages = 1
- self.__print_in_rows = 1
- self.__portrait = 1
- self.__print_not_colour = 0
- self.__print_draft = 0
- self.__print_notes = 0
- self.__print_notes_at_end = 0
- self.__print_omit_errors = 0
- self.__print_hres = 0x012C # 300 dpi
- self.__print_vres = 0x012C # 300 dpi
- self.__header_margin = 0.1
- self.__footer_margin = 0.1
- self.__copies_num = 1
-
- self.__wnd_protect = 0
- self.__obj_protect = 0
- self.__protect = 0
- self.__scen_protect = 0
- self.__password = b''
-
- self.last_used_row = 0
- self.first_used_row = 65535
- self.last_used_col = 0
- self.first_used_col = 255
- self.row_tempfile = None
- self.__flushed_rows = {}
- self.__row_visible_levels = 0
-
- #################################################################
- ## Properties, "getters", "setters"
- #################################################################
-
- def set_name(self, value):
- self.__name = value
-
- def get_name(self):
- return self.__name
-
- name = property(get_name, set_name)
-
- #################################################################
-
- def get_parent(self):
- return self.__parent
-
- parent = property(get_parent)
-
- #################################################################
-
- def get_rows(self):
- return self.__rows
-
- rows = property(get_rows)
-
- #################################################################
-
- def get_cols(self):
- return self.__cols
-
- cols = property(get_cols)
-
- #################################################################
-
- def get_merged_ranges(self):
- return self.__merged_ranges
-
- merged_ranges = property(get_merged_ranges)
-
- #################################################################
-
- def get_bmp_rec(self):
- return self.__bmp_rec
-
- bmp_rec = property(get_bmp_rec)
-
- #################################################################
-
- def set_show_formulas(self, value):
- self.__show_formulas = int(value)
-
- def get_show_formulas(self):
- return bool(self.__show_formulas)
-
- show_formulas = property(get_show_formulas, set_show_formulas)
-
- #################################################################
-
- def set_show_grid(self, value):
- self.__show_grid = int(value)
-
- def get_show_grid(self):
- return bool(self.__show_grid)
-
- show_grid = property(get_show_grid, set_show_grid)
-
- #################################################################
-
- def set_show_headers(self, value):
- self.__show_headers = int(value)
-
- def get_show_headers(self):
- return bool(self.__show_headers)
-
- show_headers = property(get_show_headers, set_show_headers)
-
- #################################################################
-
- def set_panes_frozen(self, value):
- self.__panes_frozen = int(value)
-
- def get_panes_frozen(self):
- return bool(self.__panes_frozen)
-
- panes_frozen = property(get_panes_frozen, set_panes_frozen)
-
- #################################################################
-
- ### def set_show_empty_as_zero(self, value):
- ### self.__show_empty_as_zero = int(value)
-
- ### def get_show_empty_as_zero(self):
- ### return bool(self.__show_empty_as_zero)
-
- ### show_empty_as_zero = property(get_show_empty_as_zero, set_show_empty_as_zero)
-
- #################################################################
-
- def set_auto_colour_grid(self, value):
- self.__auto_colour_grid = int(value)
-
- def get_auto_colour_grid(self):
- return bool(self.__auto_colour_grid)
-
- auto_colour_grid = property(get_auto_colour_grid, set_auto_colour_grid)
-
- #################################################################
-
- def set_cols_right_to_left(self, value):
- self.__cols_right_to_left = int(value)
-
- def get_cols_right_to_left(self):
- return bool(self.__cols_right_to_left)
-
- cols_right_to_left = property(get_cols_right_to_left, set_cols_right_to_left)
-
- #################################################################
-
- def set_show_outline(self, value):
- self.__show_outline = int(value)
-
- def get_show_outline(self):
- return bool(self.__show_outline)
-
- show_outline = property(get_show_outline, set_show_outline)
-
- #################################################################
-
- def set_remove_splits(self, value):
- self.__remove_splits = int(value)
-
- def get_remove_splits(self):
- return bool(self.__remove_splits)
-
- remove_splits = property(get_remove_splits, set_remove_splits)
-
- #################################################################
-
- def set_selected(self, value):
- self.__selected = int(value)
-
- def get_selected(self):
- return bool(self.__selected)
-
- selected = property(get_selected, set_selected)
-
- #################################################################
-
- def set_sheet_visible(self, value):
- self.__sheet_visible = int(value)
-
- def get_sheet_visible(self):
- return bool(self.__sheet_visible)
-
- sheet_visible = property(get_sheet_visible, set_sheet_visible)
-
- #################################################################
-
- def set_page_preview(self, value):
- self.__page_preview = int(value)
-
- def get_page_preview(self):
- return bool(self.__page_preview)
-
- page_preview = property(get_page_preview, set_page_preview)
-
- #################################################################
-
- def set_first_visible_row(self, value):
- self.__first_visible_row = value
-
- def get_first_visible_row(self):
- return self.__first_visible_row
-
- first_visible_row = property(get_first_visible_row, set_first_visible_row)
-
- #################################################################
-
- def set_first_visible_col(self, value):
- self.__first_visible_col = value
-
- def get_first_visible_col(self):
- return self.__first_visible_col
-
- first_visible_col = property(get_first_visible_col, set_first_visible_col)
-
- #################################################################
-
- def set_grid_colour(self, value):
- self.__grid_colour = value
-
- def get_grid_colour(self):
- return self.__grid_colour
-
- grid_colour = property(get_grid_colour, set_grid_colour)
-
- #################################################################
-
- def set_preview_magn(self, value):
- self.__preview_magn = value
-
- def get_preview_magn(self):
- return self.__preview_magn
-
- preview_magn = property(get_preview_magn, set_preview_magn)
-
- #################################################################
-
- def set_normal_magn(self, value):
- self.__normal_magn = value
-
- def get_normal_magn(self):
- return self.__normal_magn
-
- normal_magn = property(get_normal_magn, set_normal_magn)
-
- #################################################################
-
- def set_vert_split_pos(self, value):
- self.__vert_split_pos = abs(value)
-
- def get_vert_split_pos(self):
- return self.__vert_split_pos
-
- vert_split_pos = property(get_vert_split_pos, set_vert_split_pos)
-
- #################################################################
-
- def set_horz_split_pos(self, value):
- self.__horz_split_pos = abs(value)
-
- def get_horz_split_pos(self):
- return self.__horz_split_pos
-
- horz_split_pos = property(get_horz_split_pos, set_horz_split_pos)
-
- #################################################################
-
- def set_vert_split_first_visible(self, value):
- self.__vert_split_first_visible = abs(value)
-
- def get_vert_split_first_visible(self):
- return self.__vert_split_first_visible
-
- vert_split_first_visible = property(get_vert_split_first_visible, set_vert_split_first_visible)
-
- #################################################################
-
- def set_horz_split_first_visible(self, value):
- self.__horz_split_first_visible = abs(value)
-
- def get_horz_split_first_visible(self):
- return self.__horz_split_first_visible
-
- horz_split_first_visible = property(get_horz_split_first_visible, set_horz_split_first_visible)
-
- #################################################################
-
- #def set_split_active_pane(self, value):
- # self.__split_active_pane = abs(value) & 0x03
- #
- #def get_split_active_pane(self):
- # return self.__split_active_pane
- #
- #split_active_pane = property(get_split_active_pane, set_split_active_pane)
-
- #################################################################
-
- #def set_row_gut_width(self, value):
- # self.__row_gut_width = value
- #
- #def get_row_gut_width(self):
- # return self.__row_gut_width
- #
- #row_gut_width = property(get_row_gut_width, set_row_gut_width)
- #
- #################################################################
- #
- #def set_col_gut_height(self, value):
- # self.__col_gut_height = value
- #
- #def get_col_gut_height(self):
- # return self.__col_gut_height
- #
- #col_gut_height = property(get_col_gut_height, set_col_gut_height)
- #
- #################################################################
-
- def set_show_auto_page_breaks(self, value):
- self.__show_auto_page_breaks = int(value)
-
- def get_show_auto_page_breaks(self):
- return bool(self.__show_auto_page_breaks)
-
- show_auto_page_breaks = property(get_show_auto_page_breaks, set_show_auto_page_breaks)
-
- #################################################################
-
- def set_dialogue_sheet(self, value):
- self.__dialogue_sheet = int(value)
-
- def get_dialogue_sheet(self):
- return bool(self.__dialogue_sheet)
-
- dialogue_sheet = property(get_dialogue_sheet, set_dialogue_sheet)
-
- #################################################################
-
- def set_auto_style_outline(self, value):
- self.__auto_style_outline = int(value)
-
- def get_auto_style_outline(self):
- return bool(self.__auto_style_outline)
-
- auto_style_outline = property(get_auto_style_outline, set_auto_style_outline)
-
- #################################################################
-
- def set_outline_below(self, value):
- self.__outline_below = int(value)
-
- def get_outline_below(self):
- return bool(self.__outline_below)
-
- outline_below = property(get_outline_below, set_outline_below)
-
- #################################################################
-
- def set_outline_right(self, value):
- self.__outline_right = int(value)
-
- def get_outline_right(self):
- return bool(self.__outline_right)
-
- outline_right = property(get_outline_right, set_outline_right)
-
- #################################################################
-
- def set_fit_num_pages(self, value):
- self.__fit_num_pages = value
-
- def get_fit_num_pages(self):
- return self.__fit_num_pages
-
- fit_num_pages = property(get_fit_num_pages, set_fit_num_pages)
-
- #################################################################
-
- def set_show_row_outline(self, value):
- self.__show_row_outline = int(value)
-
- def get_show_row_outline(self):
- return bool(self.__show_row_outline)
-
- show_row_outline = property(get_show_row_outline, set_show_row_outline)
-
- #################################################################
-
- def set_show_col_outline(self, value):
- self.__show_col_outline = int(value)
-
- def get_show_col_outline(self):
- return bool(self.__show_col_outline)
-
- show_col_outline = property(get_show_col_outline, set_show_col_outline)
-
- #################################################################
-
- def set_alt_expr_eval(self, value):
- self.__alt_expr_eval = int(value)
-
- def get_alt_expr_eval(self):
- return bool(self.__alt_expr_eval)
-
- alt_expr_eval = property(get_alt_expr_eval, set_alt_expr_eval)
-
- #################################################################
-
- def set_alt_formula_entries(self, value):
- self.__alt_formula_entries = int(value)
-
- def get_alt_formula_entries(self):
- return bool(self.__alt_formula_entries)
-
- alt_formula_entries = property(get_alt_formula_entries, set_alt_formula_entries)
-
- #################################################################
-
- def set_row_default_height(self, value):
- self.__row_default_height = value
-
- def get_row_default_height(self):
- return self.__row_default_height
-
- row_default_height = property(get_row_default_height, set_row_default_height)
-
- #################################################################
-
- def set_col_default_width(self, value):
- self.__col_default_width = value
-
- def get_col_default_width(self):
- return self.__col_default_width
-
- col_default_width = property(get_col_default_width, set_col_default_width)
-
- #################################################################
-
- def set_calc_mode(self, value):
- self.__calc_mode = value & 0x03
-
- def get_calc_mode(self):
- return self.__calc_mode
-
- calc_mode = property(get_calc_mode, set_calc_mode)
-
- #################################################################
-
- def set_calc_count(self, value):
- self.__calc_count = value
-
- def get_calc_count(self):
- return self.__calc_count
-
- calc_count = property(get_calc_count, set_calc_count)
-
- #################################################################
-
- def set_RC_ref_mode(self, value):
- self.__RC_ref_mode = int(value)
-
- def get_RC_ref_mode(self):
- return bool(self.__RC_ref_mode)
-
- RC_ref_mode = property(get_RC_ref_mode, set_RC_ref_mode)
-
- #################################################################
-
- def set_iterations_on(self, value):
- self.__iterations_on = int(value)
-
- def get_iterations_on(self):
- return bool(self.__iterations_on)
-
- iterations_on = property(get_iterations_on, set_iterations_on)
-
- #################################################################
-
- def set_delta(self, value):
- self.__delta = value
-
- def get_delta(self):
- return self.__delta
-
- delta = property(get_delta, set_delta)
-
- #################################################################
-
- def set_save_recalc(self, value):
- self.__save_recalc = int(value)
-
- def get_save_recalc(self):
- return bool(self.__save_recalc)
-
- save_recalc = property(get_save_recalc, set_save_recalc)
-
- #################################################################
-
- def set_print_headers(self, value):
- self.__print_headers = int(value)
-
- def get_print_headers(self):
- return bool(self.__print_headers)
-
- print_headers = property(get_print_headers, set_print_headers)
-
- #################################################################
-
- def set_print_grid(self, value):
- self.__print_grid = int(value)
-
- def get_print_grid(self):
- return bool(self.__print_grid)
-
- print_grid = property(get_print_grid, set_print_grid)
-
- #################################################################
- #
- #def set_grid_set(self, value):
- # self.__grid_set = int(value)
- #
- #def get_grid_set(self):
- # return bool(self.__grid_set)
- #
- #grid_set = property(get_grid_set, set_grid_set)
- #
- #################################################################
-
- def set_vert_page_breaks(self, value):
- self.__vert_page_breaks = value
-
- def get_vert_page_breaks(self):
- return self.__vert_page_breaks
-
- vert_page_breaks = property(get_vert_page_breaks, set_vert_page_breaks)
-
- #################################################################
-
- def set_horz_page_breaks(self, value):
- self.__horz_page_breaks = value
-
- def get_horz_page_breaks(self):
- return self.__horz_page_breaks
-
- horz_page_breaks = property(get_horz_page_breaks, set_horz_page_breaks)
-
- #################################################################
-
- def set_header_str(self, value):
- if isinstance(value, str):
- value = str(value, self.__parent.encoding)
- self.__header_str = value
-
- def get_header_str(self):
- return self.__header_str
-
- header_str = property(get_header_str, set_header_str)
-
- #################################################################
-
- def set_footer_str(self, value):
- if isinstance(value, str):
- value = str(value, self.__parent.encoding)
- self.__footer_str = value
-
- def get_footer_str(self):
- return self.__footer_str
-
- footer_str = property(get_footer_str, set_footer_str)
-
- #################################################################
-
- def set_print_centered_vert(self, value):
- self.__print_centered_vert = int(value)
-
- def get_print_centered_vert(self):
- return bool(self.__print_centered_vert)
-
- print_centered_vert = property(get_print_centered_vert, set_print_centered_vert)
-
- #################################################################
-
- def set_print_centered_horz(self, value):
- self.__print_centered_horz = int(value)
-
- def get_print_centered_horz(self):
- return bool(self.__print_centered_horz)
-
- print_centered_horz = property(get_print_centered_horz, set_print_centered_horz)
-
- #################################################################
-
- def set_left_margin(self, value):
- self.__left_margin = value
-
- def get_left_margin(self):
- return self.__left_margin
-
- left_margin = property(get_left_margin, set_left_margin)
-
- #################################################################
-
- def set_right_margin(self, value):
- self.__right_margin = value
-
- def get_right_margin(self):
- return self.__right_margin
-
- right_margin = property(get_right_margin, set_right_margin)
-
- #################################################################
-
- def set_top_margin(self, value):
- self.__top_margin = value
-
- def get_top_margin(self):
- return self.__top_margin
-
- top_margin = property(get_top_margin, set_top_margin)
-
- #################################################################
-
- def set_bottom_margin(self, value):
- self.__bottom_margin = value
-
- def get_bottom_margin(self):
- return self.__bottom_margin
-
- bottom_margin = property(get_bottom_margin, set_bottom_margin)
-
- #################################################################
-
- def set_paper_size_code(self, value):
- self.__paper_size_code = value
-
- def get_paper_size_code(self):
- return self.__paper_size_code
-
- paper_size_code = property(get_paper_size_code, set_paper_size_code)
-
- #################################################################
-
- def set_print_scaling(self, value):
- self.__print_scaling = value
-
- def get_print_scaling(self):
- return self.__print_scaling
-
- print_scaling = property(get_print_scaling, set_print_scaling)
-
- #################################################################
-
- def set_start_page_number(self, value):
- self.__start_page_number = value
-
- def get_start_page_number(self):
- return self.__start_page_number
-
- start_page_number = property(get_start_page_number, set_start_page_number)
-
- #################################################################
-
- def set_fit_width_to_pages(self, value):
- self.__fit_width_to_pages = value
-
- def get_fit_width_to_pages(self):
- return self.__fit_width_to_pages
-
- fit_width_to_pages = property(get_fit_width_to_pages, set_fit_width_to_pages)
-
- #################################################################
-
- def set_fit_height_to_pages(self, value):
- self.__fit_height_to_pages = value
-
- def get_fit_height_to_pages(self):
- return self.__fit_height_to_pages
-
- fit_height_to_pages = property(get_fit_height_to_pages, set_fit_height_to_pages)
-
- #################################################################
-
- def set_print_in_rows(self, value):
- self.__print_in_rows = int(value)
-
- def get_print_in_rows(self):
- return bool(self.__print_in_rows)
-
- print_in_rows = property(get_print_in_rows, set_print_in_rows)
-
- #################################################################
-
- def set_portrait(self, value):
- self.__portrait = int(value)
-
- def get_portrait(self):
- return bool(self.__portrait)
-
- portrait = property(get_portrait, set_portrait)
-
- #################################################################
-
- def set_print_colour(self, value):
- self.__print_not_colour = int(not value)
-
- def get_print_colour(self):
- return not bool(self.__print_not_colour)
-
- print_colour = property(get_print_colour, set_print_colour)
-
- #################################################################
-
- def set_print_draft(self, value):
- self.__print_draft = int(value)
-
- def get_print_draft(self):
- return bool(self.__print_draft)
-
- print_draft = property(get_print_draft, set_print_draft)
-
- #################################################################
-
- def set_print_notes(self, value):
- self.__print_notes = int(value)
-
- def get_print_notes(self):
- return bool(self.__print_notes)
-
- print_notes = property(get_print_notes, set_print_notes)
-
- #################################################################
-
- def set_print_notes_at_end(self, value):
- self.__print_notes_at_end = int(value)
-
- def get_print_notes_at_end(self):
- return bool(self.__print_notes_at_end)
-
- print_notes_at_end = property(get_print_notes_at_end, set_print_notes_at_end)
-
- #################################################################
-
- def set_print_omit_errors(self, value):
- self.__print_omit_errors = int(value)
-
- def get_print_omit_errors(self):
- return bool(self.__print_omit_errors)
-
- print_omit_errors = property(get_print_omit_errors, set_print_omit_errors)
-
- #################################################################
-
- def set_print_hres(self, value):
- self.__print_hres = value
-
- def get_print_hres(self):
- return self.__print_hres
-
- print_hres = property(get_print_hres, set_print_hres)
-
- #################################################################
-
- def set_print_vres(self, value):
- self.__print_vres = value
-
- def get_print_vres(self):
- return self.__print_vres
-
- print_vres = property(get_print_vres, set_print_vres)
-
- #################################################################
-
- def set_header_margin(self, value):
- self.__header_margin = value
-
- def get_header_margin(self):
- return self.__header_margin
-
- header_margin = property(get_header_margin, set_header_margin)
-
- #################################################################
-
- def set_footer_margin(self, value):
- self.__footer_margin = value
-
- def get_footer_margin(self):
- return self.__footer_margin
-
- footer_margin = property(get_footer_margin, set_footer_margin)
-
- #################################################################
-
- def set_copies_num(self, value):
- self.__copies_num = value
-
- def get_copies_num(self):
- return self.__copies_num
-
- copies_num = property(get_copies_num, set_copies_num)
-
- ##################################################################
-
- def set_wnd_protect(self, value):
- self.__wnd_protect = int(value)
-
- def get_wnd_protect(self):
- return bool(self.__wnd_protect)
-
- wnd_protect = property(get_wnd_protect, set_wnd_protect)
-
- #################################################################
-
- def set_obj_protect(self, value):
- self.__obj_protect = int(value)
-
- def get_obj_protect(self):
- return bool(self.__obj_protect)
-
- obj_protect = property(get_obj_protect, set_obj_protect)
-
- #################################################################
-
- def set_protect(self, value):
- self.__protect = int(value)
-
- def get_protect(self):
- return bool(self.__protect)
-
- protect = property(get_protect, set_protect)
-
- #################################################################
-
- def set_scen_protect(self, value):
- self.__scen_protect = int(value)
-
- def get_scen_protect(self):
- return bool(self.__scen_protect)
-
- scen_protect = property(get_scen_protect, set_scen_protect)
-
- #################################################################
-
- def set_password(self, value):
- self.__password = value
-
- def get_password(self):
- return self.__password
-
- password = property(get_password, set_password)
-
- ##################################################################
- ## Methods
- ##################################################################
-
- def get_parent(self):
- return self.__parent
-
- def write(self, r, c, label=b"", style=Style.default_style):
- self.row(r).write(c, label, style)
-
- def merge(self, r1, r2, c1, c2, style=Style.default_style):
- # Stand-alone merge of previously written cells.
- # Problems: (1) style to be used should be existing style of
- # the top-left cell, not an arg.
- # (2) should ensure that any previous data value in
- # non-top-left cells is nobbled.
- # Note: if a cell is set by a data record then later
- # is referenced by a [MUL]BLANK record, Excel will blank
- # out the cell on the screen, but OOo & Gnu will not
- # blank it out. Need to do something better than writing
- # multiple records. In the meantime, avoid this method and use
- # write_merge() instead.
- if c2 > c1:
- self.row(r1).write_blanks(c1 + 1, c2, style)
- for r in range(r1+1, r2+1):
- self.row(r).write_blanks(c1, c2, style)
- self.__merged_ranges.append((r1, r2, c1, c2))
-
- def write_merge(self, r1, r2, c1, c2, label=b"", style=Style.default_style):
- assert 0 <= c1 <= c2 <= 255
- assert 0 <= r1 <= r2 <= 65535
- self.write(r1, c1, label, style)
- if c2 > c1:
- self.row(r1).write_blanks(c1 + 1, c2, style) # skip (r1, c1)
- for r in range(r1+1, r2+1):
- self.row(r).write_blanks(c1, c2, style)
- self.__merged_ranges.append((r1, r2, c1, c2))
-
- def insert_bitmap(self, filename, row, col, x = 0, y = 0, scale_x = 1, scale_y = 1):
- bmp = Bitmap.ImDataBmpRecord(filename)
- obj = Bitmap.ObjBmpRecord(row, col, self, bmp, x, y, scale_x, scale_y)
-
- self.__bmp_rec += obj.get() + bmp.get()
-
- def col(self, indx):
- if indx not in self.__cols:
- self.__cols[indx] = self.Column(indx, self)
- return self.__cols[indx]
-
- def row(self, indx):
- if indx not in self.__rows:
- if indx in self.__flushed_rows:
- raise Exception("Attempt to reuse row index %d of sheet %r after flushing" % (indx, self.__name))
- self.__rows[indx] = self.Row(indx, self)
- if indx > self.last_used_row:
- self.last_used_row = indx
- if indx < self.first_used_row:
- self.first_used_row = indx
- return self.__rows[indx]
-
- def row_height(self, row): # in pixels
- if row in self.__rows:
- return self.__rows[row].get_height_in_pixels()
- else:
- return 17
-
- def col_width(self, col): # in pixels
- if col in self.__cols:
- return self.__cols[col].width_in_pixels()
- else:
- return 64
-
-
- ##################################################################
- ## BIFF records generation
- ##################################################################
-
- def __bof_rec(self):
- return BIFFRecords.Biff8BOFRecord(BIFFRecords.Biff8BOFRecord.WORKSHEET).get()
-
- def __update_row_visible_levels(self):
- if self.__rows:
- temp = max([self.__rows[r].level for r in self.__rows]) + 1
- self.__row_visible_levels = max(temp, self.__row_visible_levels)
-
- def __guts_rec(self):
- self.__update_row_visible_levels()
- col_visible_levels = 0
- if len(self.__cols) != 0:
- col_visible_levels = max([self.__cols[c].level for c in self.__cols]) + 1
- return BIFFRecords.GutsRecord(
- self.__row_gut_width, self.__col_gut_height, self.__row_visible_levels, col_visible_levels).get()
-
- def __defaultrowheight_rec(self):
- options = 0x0000
- options |= (self.row_default_height_mismatch & 1) << 0
- options |= (self.row_default_hidden & 1) << 1
- options |= (self.row_default_space_above & 1) << 2
- options |= (self.row_default_space_below & 1) << 3
- defht = self.__row_default_height
- return BIFFRecords.DefaultRowHeightRecord(options, defht).get()
-
- def __wsbool_rec(self):
- options = 0x00
- options |= (self.__show_auto_page_breaks & 0x01) << 0
- options |= (self.__dialogue_sheet & 0x01) << 4
- options |= (self.__auto_style_outline & 0x01) << 5
- options |= (self.__outline_below & 0x01) << 6
- options |= (self.__outline_right & 0x01) << 7
- options |= (self.__fit_num_pages & 0x01) << 8
- options |= (self.__show_row_outline & 0x01) << 10
- options |= (self.__show_col_outline & 0x01) << 11
- options |= (self.__alt_expr_eval & 0x01) << 14
- options |= (self.__alt_formula_entries & 0x01) << 15
-
- return BIFFRecords.WSBoolRecord(options).get()
-
- def __eof_rec(self):
- return BIFFRecords.EOFRecord().get()
-
- def __colinfo_rec(self):
- result = b''
- for col in self.__cols:
- result += self.__cols[col].get_biff_record()
- return result
-
- def __dimensions_rec(self):
- return BIFFRecords.DimensionsRecord(
- self.first_used_row, self.last_used_row,
- self.first_used_col, self.last_used_col
- ).get()
-
- def __window2_rec(self):
- # Appends SCL record.
- options = 0
- options |= (self.__show_formulas & 0x01) << 0
- options |= (self.__show_grid & 0x01) << 1
- options |= (self.__show_headers & 0x01) << 2
- options |= (self.__panes_frozen & 0x01) << 3
- options |= (self.show_zero_values & 0x01) << 4
- options |= (self.__auto_colour_grid & 0x01) << 5
- options |= (self.__cols_right_to_left & 0x01) << 6
- options |= (self.__show_outline & 0x01) << 7
- options |= (self.__remove_splits & 0x01) << 8
- options |= (self.__selected & 0x01) << 9
- options |= (self.__sheet_visible & 0x01) << 10
- options |= (self.__page_preview & 0x01) << 11
- if self.__page_preview:
- scl_magn = self.__preview_magn
- else:
- scl_magn = self.__normal_magn
- return BIFFRecords.Window2Record(
- options, self.__first_visible_row, self.__first_visible_col,
- self.__grid_colour,
- self.__preview_magn, self.__normal_magn, scl_magn).get()
-
- def __panes_rec(self):
- if self.__vert_split_pos is None and self.__horz_split_pos is None:
- return b""
-
- if self.__vert_split_pos is None:
- self.__vert_split_pos = 0
- if self.__horz_split_pos is None:
- self.__horz_split_pos = 0
-
- if self.__panes_frozen:
- if self.__vert_split_first_visible is None:
- self.__vert_split_first_visible = self.__vert_split_pos
- if self.__horz_split_first_visible is None:
- self.__horz_split_first_visible = self.__horz_split_pos
- else:
- if self.__vert_split_first_visible is None:
- self.__vert_split_first_visible = 0
- if self.__horz_split_first_visible is None:
- self.__horz_split_first_visible = 0
- # inspired by pyXLWriter
- self.__horz_split_pos = 20*self.__horz_split_pos + 255
- self.__vert_split_pos = int(113.879*self.__vert_split_pos + 390)
-
- if self.__vert_split_pos > 0 and self.__horz_split_pos > 0:
- self.__split_active_pane = 0
- elif self.__vert_split_pos > 0 and self.__horz_split_pos == 0:
- self.__split_active_pane = 1
- elif self.__vert_split_pos == 0 and self.__horz_split_pos > 0:
- self.__split_active_pane = 2
- else:
- self.__split_active_pane = 3
-
- result = BIFFRecords.PanesRecord(self.__vert_split_pos,
- self.__horz_split_pos,
- self.__horz_split_first_visible,
- self.__vert_split_first_visible,
- self.__split_active_pane).get()
- return result
-
- def __row_blocks_rec(self):
- result = []
- for row in self.__rows.values():
- result.append(row.get_row_biff_data())
- result.append(row.get_cells_biff_data())
- return b''.join(result)
-
- def __merged_rec(self):
- return BIFFRecords.MergedCellsRecord(self.__merged_ranges).get()
-
- def __bitmaps_rec(self):
- return self.__bmp_rec
-
- def __calc_settings_rec(self):
- result = b''
- result += BIFFRecords.CalcModeRecord(self.__calc_mode & 0x01).get()
- result += BIFFRecords.CalcCountRecord(self.__calc_count & 0xFFFF).get()
- result += BIFFRecords.RefModeRecord(self.__RC_ref_mode & 0x01).get()
- result += BIFFRecords.IterationRecord(self.__iterations_on & 0x01).get()
- result += BIFFRecords.DeltaRecord(self.__delta).get()
- result += BIFFRecords.SaveRecalcRecord(self.__save_recalc & 0x01).get()
- return result
-
- def __print_settings_rec(self):
- result = b''
- result += BIFFRecords.PrintHeadersRecord(self.__print_headers).get()
- result += BIFFRecords.PrintGridLinesRecord(self.__print_grid).get()
- result += BIFFRecords.GridSetRecord(self.__grid_set).get()
- result += BIFFRecords.HorizontalPageBreaksRecord(self.__horz_page_breaks).get()
- result += BIFFRecords.VerticalPageBreaksRecord(self.__vert_page_breaks).get()
- result += BIFFRecords.HeaderRecord(self.__header_str).get()
- result += BIFFRecords.FooterRecord(self.__footer_str).get()
- result += BIFFRecords.HCenterRecord(self.__print_centered_horz).get()
- result += BIFFRecords.VCenterRecord(self.__print_centered_vert).get()
- result += BIFFRecords.LeftMarginRecord(self.__left_margin).get()
- result += BIFFRecords.RightMarginRecord(self.__right_margin).get()
- result += BIFFRecords.TopMarginRecord(self.__top_margin).get()
- result += BIFFRecords.BottomMarginRecord(self.__bottom_margin).get()
-
- setup_page_options = (self.__print_in_rows & 0x01) << 0
- setup_page_options |= (self.__portrait & 0x01) << 1
- setup_page_options |= (0x00 & 0x01) << 2
- setup_page_options |= (self.__print_not_colour & 0x01) << 3
- setup_page_options |= (self.__print_draft & 0x01) << 4
- setup_page_options |= (self.__print_notes & 0x01) << 5
- setup_page_options |= (0x00 & 0x01) << 6
- setup_page_options |= (0x01 & 0x01) << 7
- setup_page_options |= (self.__print_notes_at_end & 0x01) << 9
- setup_page_options |= (self.__print_omit_errors & 0x03) << 10
-
- result += BIFFRecords.SetupPageRecord(self.__paper_size_code,
- self.__print_scaling,
- self.__start_page_number,
- self.__fit_width_to_pages,
- self.__fit_height_to_pages,
- setup_page_options,
- self.__print_hres,
- self.__print_vres,
- self.__header_margin,
- self.__footer_margin,
- self.__copies_num).get()
- return result
-
- def __protection_rec(self):
- result = b''
- result += BIFFRecords.ProtectRecord(self.__protect).get()
- result += BIFFRecords.ScenProtectRecord(self.__scen_protect).get()
- result += BIFFRecords.WindowProtectRecord(self.__wnd_protect).get()
- result += BIFFRecords.ObjectProtectRecord(self.__obj_protect).get()
- result += BIFFRecords.PasswordRecord(self.__password).get()
- return result
-
- def get_biff_data(self):
- result = [
- self.__bof_rec(),
- self.__calc_settings_rec(),
- self.__guts_rec(),
- self.__defaultrowheight_rec(),
- self.__wsbool_rec(),
- self.__colinfo_rec(),
- self.__dimensions_rec(),
- self.__print_settings_rec(),
- self.__protection_rec(),
- ]
- if self.row_tempfile:
- self.row_tempfile.flush()
- self.row_tempfile.seek(0)
- result.append(self.row_tempfile.read())
- result.extend([
- self.__row_blocks_rec(),
- self.__merged_rec(),
- self.__bitmaps_rec(),
- self.__window2_rec(),
- self.__panes_rec(),
- self.__eof_rec(),
- ])
- return b''.join(result)
-
- def flush_row_data(self):
- if self.row_tempfile is None:
- self.row_tempfile = tempfile.TemporaryFile()
- self.row_tempfile.write(self.__row_blocks_rec())
- for rowx in self.__rows:
- self.__flushed_rows[rowx] = 1
- self.__update_row_visible_levels()
- self.__rows = {}
-
-
diff --git a/tablib/packages/xlwt3/__init__.py b/tablib/packages/xlwt3/__init__.py deleted file mode 100644 index ee8373e..0000000 --- a/tablib/packages/xlwt3/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -import sys
-
-from .Workbook import Workbook
-from .Worksheet import Worksheet
-from .Row import Row
-from .Column import Column
-from .Formatting import Font, Alignment, Borders, Pattern, Protection
-from .Style import XFStyle, easyxf
-from .ExcelFormula import *
diff --git a/tablib/packages/xlwt3/antlr.py b/tablib/packages/xlwt3/antlr.py deleted file mode 100644 index b7b5029..0000000 --- a/tablib/packages/xlwt3/antlr.py +++ /dev/null @@ -1,2868 +0,0 @@ -## This file is part of PyANTLR. See LICENSE.txt for license
-## details..........Copyright (C) Wolfgang Haefelinger, 2004.
-
-## This file was copied for use with xlwt from the 2.7.7 ANTLR distribution. Yes, it
-## says 2.7.5 below. The 2.7.5 distribution version didn't have a
-## version in it.
-
-## Here is the contents of the ANTLR 2.7.7 LICENSE.txt referred to above.
-
-# SOFTWARE RIGHTS
-#
-# ANTLR 1989-2006 Developed by Terence Parr
-# Partially supported by University of San Francisco & jGuru.com
-#
-# We reserve no legal rights to the ANTLR--it is fully in the
-# public domain. An individual or company may do whatever
-# they wish with source code distributed with ANTLR or the
-# code generated by ANTLR, including the incorporation of
-# ANTLR, or its output, into commerical software.
-#
-# We encourage users to develop software with ANTLR. However,
-# we do ask that credit is given to us for developing
-# ANTLR. By "credit", we mean that if you use ANTLR or
-# incorporate any source code into one of your programs
-# (commercial product, research project, or otherwise) that
-# you acknowledge this fact somewhere in the documentation,
-# research report, etc... If you like ANTLR and have
-# developed a nice tool with the output, please mention that
-# you developed it using ANTLR. In addition, we ask that the
-# headers remain intact in our source code. As long as these
-# guidelines are kept, we expect to continue enhancing this
-# system and expect to make other tools available as they are
-# completed.
-#
-# The primary ANTLR guy:
-#
-# Terence Parr
-# parrt@cs.usfca.edu
-# parrt@antlr.org
-
-## End of contents of the ANTLR 2.7.7 LICENSE.txt ########################
-
-## get sys module
-import sys
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### global symbols ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-### ANTLR Standard Tokens
-SKIP = -1
-INVALID_TYPE = 0
-EOF_TYPE = 1
-EOF = 1
-NULL_TREE_LOOKAHEAD = 3
-MIN_USER_TYPE = 4
-
-### ANTLR's EOF Symbol
-EOF_CHAR = ''
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### general functions ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-## Version should be automatically derived from configure.in. For now,
-## we need to bump it ourselfs. Don't remove the <version> tags.
-## <version>
-def version():
- r = {
- 'major' : '2',
- 'minor' : '7',
- 'micro' : '5',
- 'patch' : '' ,
- 'version': '2.7.5'
- }
- return r
-## </version>
-
-def error(fmt,*args):
- if fmt:
- print("error: ", fmt % tuple(args))
-
-def ifelse(cond,_then,_else):
- if cond :
- r = _then
- else:
- r = _else
- return r
-
-def is_string_type(x):
- # return (isinstance(x,str) or isinstance(x,unicode))
- # Simplify; xlwt doesn't support Python < 2.3
- return isinstance(str)
-
-def assert_string_type(x):
- assert is_string_type(x)
- pass
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### ANTLR Exceptions ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class ANTLRException(Exception):
-
- def __init__(self, *args):
- Exception.__init__(self, *args)
-
-
-class RecognitionException(ANTLRException):
-
- def __init__(self, *args):
- ANTLRException.__init__(self, *args)
- self.fileName = None
- self.line = -1
- self.column = -1
- if len(args) >= 2:
- self.fileName = args[1]
- if len(args) >= 3:
- self.line = args[2]
- if len(args) >= 4:
- self.column = args[3]
-
- def __str__(self):
- buf = ['']
- if self.fileName:
- buf.append(self.fileName + ":")
- if self.line != -1:
- if not self.fileName:
- buf.append("line ")
- buf.append(str(self.line))
- if self.column != -1:
- buf.append(":" + str(self.column))
- buf.append(":")
- buf.append(" ")
- return str('').join(buf)
-
- __repr__ = __str__
-
-
-class NoViableAltException(RecognitionException):
-
- def __init__(self, *args):
- RecognitionException.__init__(self, *args)
- self.token = None
- self.node = None
- if isinstance(args[0],AST):
- self.node = args[0]
- elif isinstance(args[0],Token):
- self.token = args[0]
- else:
- raise TypeError("NoViableAltException requires Token or AST argument")
-
- def __str__(self):
- if self.token:
- line = self.token.getLine()
- col = self.token.getColumn()
- text = self.token.getText()
- return "unexpected symbol at line %s (column %s): \"%s\"" % (line,col,text)
- if self.node == ASTNULL:
- return "unexpected end of subtree"
- assert self.node
- ### hackish, we assume that an AST contains method getText
- return "unexpected node: %s" % (self.node.getText())
-
- __repr__ = __str__
-
-
-class NoViableAltForCharException(RecognitionException):
-
- def __init__(self, *args):
- self.foundChar = None
- if len(args) == 2:
- self.foundChar = args[0]
- scanner = args[1]
- RecognitionException.__init__(self, "NoViableAlt",
- scanner.getFilename(),
- scanner.getLine(),
- scanner.getColumn())
- elif len(args) == 4:
- self.foundChar = args[0]
- fileName = args[1]
- line = args[2]
- column = args[3]
- RecognitionException.__init__(self, "NoViableAlt",
- fileName, line, column)
- else:
- RecognitionException.__init__(self, "NoViableAlt",
- '', -1, -1)
-
- def __str__(self):
- mesg = "unexpected char: "
- if self.foundChar >= ' ' and self.foundChar <= '~':
- mesg += "'" + self.foundChar + "'"
- elif self.foundChar:
- mesg += "0x" + hex(ord(self.foundChar)).upper()[2:]
- else:
- mesg += "<None>"
- return mesg
-
- __repr__ = __str__
-
-
-class SemanticException(RecognitionException):
-
- def __init__(self, *args):
- RecognitionException.__init__(self, *args)
-
-
-class MismatchedCharException(RecognitionException):
-
- NONE = 0
- CHAR = 1
- NOT_CHAR = 2
- RANGE = 3
- NOT_RANGE = 4
- SET = 5
- NOT_SET = 6
-
- def __init__(self, *args):
- self.args = args
- if len(args) == 5:
- # Expected range / not range
- if args[3]:
- self.mismatchType = MismatchedCharException.NOT_RANGE
- else:
- self.mismatchType = MismatchedCharException.RANGE
- self.foundChar = args[0]
- self.expecting = args[1]
- self.upper = args[2]
- self.scanner = args[4]
- RecognitionException.__init__(self, "Mismatched char range",
- self.scanner.getFilename(),
- self.scanner.getLine(),
- self.scanner.getColumn())
- elif len(args) == 4 and is_string_type(args[1]):
- # Expected char / not char
- if args[2]:
- self.mismatchType = MismatchedCharException.NOT_CHAR
- else:
- self.mismatchType = MismatchedCharException.CHAR
- self.foundChar = args[0]
- self.expecting = args[1]
- self.scanner = args[3]
- RecognitionException.__init__(self, "Mismatched char",
- self.scanner.getFilename(),
- self.scanner.getLine(),
- self.scanner.getColumn())
- elif len(args) == 4 and isinstance(args[1], BitSet):
- # Expected BitSet / not BitSet
- if args[2]:
- self.mismatchType = MismatchedCharException.NOT_SET
- else:
- self.mismatchType = MismatchedCharException.SET
- self.foundChar = args[0]
- self.set = args[1]
- self.scanner = args[3]
- RecognitionException.__init__(self, "Mismatched char set",
- self.scanner.getFilename(),
- self.scanner.getLine(),
- self.scanner.getColumn())
- else:
- self.mismatchType = MismatchedCharException.NONE
- RecognitionException.__init__(self, "Mismatched char")
-
- ## Append a char to the msg buffer. If special,
- # then show escaped version
- #
- def appendCharName(self, sb, c):
- if not c or c == 65535:
- # 65535 = (char) -1 = EOF
- sb.append("'<EOF>'")
- elif c == '\n':
- sb.append("'\\n'")
- elif c == '\r':
- sb.append("'\\r'");
- elif c == '\t':
- sb.append("'\\t'")
- else:
- sb.append('\'' + c + '\'')
-
- ##
- # Returns an error message with line number/column information
- #
- def __str__(self):
- sb = ['']
- sb.append(RecognitionException.__str__(self))
-
- if self.mismatchType == MismatchedCharException.CHAR:
- sb.append("expecting ")
- self.appendCharName(sb, self.expecting)
- sb.append(", found ")
- self.appendCharName(sb, self.foundChar)
- elif self.mismatchType == MismatchedCharException.NOT_CHAR:
- sb.append("expecting anything but '")
- self.appendCharName(sb, self.expecting)
- sb.append("'; got it anyway")
- elif self.mismatchType in [MismatchedCharException.RANGE, MismatchedCharException.NOT_RANGE]:
- sb.append("expecting char ")
- if self.mismatchType == MismatchedCharException.NOT_RANGE:
- sb.append("NOT ")
- sb.append("in range: ")
- appendCharName(sb, self.expecting)
- sb.append("..")
- appendCharName(sb, self.upper)
- sb.append(", found ")
- appendCharName(sb, self.foundChar)
- elif self.mismatchType in [MismatchedCharException.SET, MismatchedCharException.NOT_SET]:
- sb.append("expecting ")
- if self.mismatchType == MismatchedCharException.NOT_SET:
- sb.append("NOT ")
- sb.append("one of (")
- for i in range(len(self.set)):
- self.appendCharName(sb, self.set[i])
- sb.append("), found ")
- self.appendCharName(sb, self.foundChar)
-
- return str().join(sb).strip()
-
- __repr__ = __str__
-
-
-class MismatchedTokenException(RecognitionException):
-
- NONE = 0
- TOKEN = 1
- NOT_TOKEN = 2
- RANGE = 3
- NOT_RANGE = 4
- SET = 5
- NOT_SET = 6
-
- def __init__(self, *args):
- self.args = args
- self.tokenNames = []
- self.token = None
- self.tokenText = ''
- self.node = None
- if len(args) == 6:
- # Expected range / not range
- if args[3]:
- self.mismatchType = MismatchedTokenException.NOT_RANGE
- else:
- self.mismatchType = MismatchedTokenException.RANGE
- self.tokenNames = args[0]
- self.expecting = args[2]
- self.upper = args[3]
- self.fileName = args[5]
-
- elif len(args) == 4 and isinstance(args[2], int):
- # Expected token / not token
- if args[3]:
- self.mismatchType = MismatchedTokenException.NOT_TOKEN
- else:
- self.mismatchType = MismatchedTokenException.TOKEN
- self.tokenNames = args[0]
- self.expecting = args[2]
-
- elif len(args) == 4 and isinstance(args[2], BitSet):
- # Expected BitSet / not BitSet
- if args[3]:
- self.mismatchType = MismatchedTokenException.NOT_SET
- else:
- self.mismatchType = MismatchedTokenException.SET
- self.tokenNames = args[0]
- self.set = args[2]
-
- else:
- self.mismatchType = MismatchedTokenException.NONE
- RecognitionException.__init__(self, "Mismatched Token: expecting any AST node", "<AST>", -1, -1)
-
- if len(args) >= 2:
- if isinstance(args[1],Token):
- self.token = args[1]
- self.tokenText = self.token.getText()
- RecognitionException.__init__(self, "Mismatched Token",
- self.fileName,
- self.token.getLine(),
- self.token.getColumn())
- elif isinstance(args[1],AST):
- self.node = args[1]
- self.tokenText = str(self.node)
- RecognitionException.__init__(self, "Mismatched Token",
- "<AST>",
- self.node.getLine(),
- self.node.getColumn())
- else:
- self.tokenText = "<empty tree>"
- RecognitionException.__init__(self, "Mismatched Token",
- "<AST>", -1, -1)
-
- def appendTokenName(self, sb, tokenType):
- if tokenType == INVALID_TYPE:
- sb.append("<Set of tokens>")
- elif tokenType < 0 or tokenType >= len(self.tokenNames):
- sb.append("<" + str(tokenType) + ">")
- else:
- sb.append(self.tokenNames[tokenType])
-
- ##
- # Returns an error message with line number/column information
- #
- def __str__(self):
- sb = ['']
- sb.append(RecognitionException.__str__(self))
-
- if self.mismatchType == MismatchedTokenException.TOKEN:
- sb.append("expecting ")
- self.appendTokenName(sb, self.expecting)
- sb.append(", found " + self.tokenText)
- elif self.mismatchType == MismatchedTokenException.NOT_TOKEN:
- sb.append("expecting anything but '")
- self.appendTokenName(sb, self.expecting)
- sb.append("'; got it anyway")
- elif self.mismatchType in [MismatchedTokenException.RANGE, MismatchedTokenException.NOT_RANGE]:
- sb.append("expecting token ")
- if self.mismatchType == MismatchedTokenException.NOT_RANGE:
- sb.append("NOT ")
- sb.append("in range: ")
- appendTokenName(sb, self.expecting)
- sb.append("..")
- appendTokenName(sb, self.upper)
- sb.append(", found " + self.tokenText)
- elif self.mismatchType in [MismatchedTokenException.SET, MismatchedTokenException.NOT_SET]:
- sb.append("expecting ")
- if self.mismatchType == MismatchedTokenException.NOT_SET:
- sb.append("NOT ")
- sb.append("one of (")
- for i in range(len(self.set)):
- self.appendTokenName(sb, self.set[i])
- sb.append("), found " + self.tokenText)
-
- return str().join(sb).strip()
-
- __repr__ = __str__
-
-
-class TokenStreamException(ANTLRException):
-
- def __init__(self, *args):
- ANTLRException.__init__(self, *args)
-
-
-# Wraps an Exception in a TokenStreamException
-class TokenStreamIOException(TokenStreamException):
-
- def __init__(self, *args):
- if args and isinstance(args[0], Exception):
- io = args[0]
- TokenStreamException.__init__(self, str(io))
- self.io = io
- else:
- TokenStreamException.__init__(self, *args)
- self.io = self
-
-
-# Wraps a RecognitionException in a TokenStreamException
-class TokenStreamRecognitionException(TokenStreamException):
-
- def __init__(self, *args):
- if args and isinstance(args[0], RecognitionException):
- recog = args[0]
- TokenStreamException.__init__(self, str(recog))
- self.recog = recog
- else:
- raise TypeError("TokenStreamRecognitionException requires RecognitionException argument")
-
- def __str__(self):
- return str(self.recog)
-
- __repr__ = __str__
-
-
-class TokenStreamRetryException(TokenStreamException):
-
- def __init__(self, *args):
- TokenStreamException.__init__(self, *args)
-
-
-class CharStreamException(ANTLRException):
-
- def __init__(self, *args):
- ANTLRException.__init__(self, *args)
-
-
-# Wraps an Exception in a CharStreamException
-class CharStreamIOException(CharStreamException):
-
- def __init__(self, *args):
- if args and isinstance(args[0], Exception):
- io = args[0]
- CharStreamException.__init__(self, str(io))
- self.io = io
- else:
- CharStreamException.__init__(self, *args)
- self.io = self
-
-
-class TryAgain(Exception):
- pass
-
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### Token ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class Token(object):
- SKIP = -1
- INVALID_TYPE = 0
- EOF_TYPE = 1
- EOF = 1
- NULL_TREE_LOOKAHEAD = 3
- MIN_USER_TYPE = 4
-
- def __init__(self,**argv):
- try:
- self.type = argv['type']
- except:
- self.type = INVALID_TYPE
- try:
- self.text = argv['text']
- except:
- self.text = "<no text>"
-
- def isEOF(self):
- return (self.type == EOF_TYPE)
-
- def getColumn(self):
- return 0
-
- def getLine(self):
- return 0
-
- def getFilename(self):
- return None
-
- def setFilename(self,name):
- return self
-
- def getText(self):
- return "<no text>"
-
- def setText(self,text):
- if is_string_type(text):
- pass
- else:
- raise TypeError("Token.setText requires string argument")
- return self
-
- def setColumn(self,column):
- return self
-
- def setLine(self,line):
- return self
-
- def getType(self):
- return self.type
-
- def setType(self,type):
- if isinstance(type,int):
- self.type = type
- else:
- raise TypeError("Token.setType requires integer argument")
- return self
-
- def toString(self):
- ## not optimal
- type_ = self.type
- if type_ == 3:
- tval = 'NULL_TREE_LOOKAHEAD'
- elif type_ == 1:
- tval = 'EOF_TYPE'
- elif type_ == 0:
- tval = 'INVALID_TYPE'
- elif type_ == -1:
- tval = 'SKIP'
- else:
- tval = type_
- return '["%s",<%s>]' % (self.getText(),tval)
-
- __str__ = toString
- __repr__ = toString
-
-### static attribute ..
-Token.badToken = Token( type=INVALID_TYPE, text="<no text>")
-
-if __name__ == "__main__":
- print("testing ..")
- T = Token.badToken
- print(T)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CommonToken ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class CommonToken(Token):
-
- def __init__(self,**argv):
- Token.__init__(self,**argv)
- self.line = 0
- self.col = 0
- try:
- self.line = argv['line']
- except:
- pass
- try:
- self.col = argv['col']
- except:
- pass
-
- def getLine(self):
- return self.line
-
- def getText(self):
- return self.text
-
- def getColumn(self):
- return self.col
-
- def setLine(self,line):
- self.line = line
- return self
-
- def setText(self,text):
- self.text = text
- return self
-
- def setColumn(self,col):
- self.col = col
- return self
-
- def toString(self):
- ## not optimal
- type_ = self.type
- if type_ == 3:
- tval = 'NULL_TREE_LOOKAHEAD'
- elif type_ == 1:
- tval = 'EOF_TYPE'
- elif type_ == 0:
- tval = 'INVALID_TYPE'
- elif type_ == -1:
- tval = 'SKIP'
- else:
- tval = type_
- d = {
- 'text' : self.text,
- 'type' : tval,
- 'line' : self.line,
- 'colm' : self.col
- }
-
- fmt = '["%(text)s",<%(type)s>,line=%(line)s,col=%(colm)s]'
- return fmt % d
-
- __str__ = toString
- __repr__ = toString
-
-
-if __name__ == '__main__' :
- T = CommonToken()
- print(T)
- T = CommonToken(col=15,line=1,text="some text", type=5)
- print(T)
- T = CommonToken()
- T.setLine(1).setColumn(15).setText("some text").setType(5)
- print(T)
- print(T.getLine())
- print(T.getColumn())
- print(T.getText())
- print(T.getType())
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CommonHiddenStreamToken ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class CommonHiddenStreamToken(CommonToken):
- def __init__(self,*args):
- CommonToken.__init__(self,*args)
- self.hiddenBefore = None
- self.hiddenAfter = None
-
- def getHiddenAfter(self):
- return self.hiddenAfter
-
- def getHiddenBefore(self):
- return self.hiddenBefore
-
- def setHiddenAfter(self,t):
- self.hiddenAfter = t
-
- def setHiddenBefore(self, t):
- self.hiddenBefore = t
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### Queue ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-## Shall be a circular buffer on tokens ..
-class Queue(object):
-
- def __init__(self):
- self.buffer = [] # empty list
-
- def append(self,item):
- self.buffer.append(item)
-
- def elementAt(self,index):
- return self.buffer[index]
-
- def reset(self):
- self.buffer = []
-
- def removeFirst(self):
- self.buffer.pop(0)
-
- def length(self):
- return len(self.buffer)
-
- def __str__(self):
- return str(self.buffer)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### InputBuffer ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class InputBuffer(object):
- def __init__(self):
- self.nMarkers = 0
- self.markerOffset = 0
- self.numToConsume = 0
- self.queue = Queue()
-
- def __str__(self):
- return "(%s,%s,%s,%s)" % (
- self.nMarkers,
- self.markerOffset,
- self.numToConsume,
- self.queue)
-
- def __repr__(self):
- return str(self)
-
- def commit(self):
- self.nMarkers -= 1
-
- def consume(self) :
- self.numToConsume += 1
-
- ## probably better to return a list of items
- ## because of unicode. Or return a unicode
- ## string ..
- def getLAChars(self) :
- i = self.markerOffset
- n = self.queue.length()
- s = ''
- while i<n:
- s += self.queue.elementAt(i)
- return s
-
- ## probably better to return a list of items
- ## because of unicode chars
- def getMarkedChars(self) :
- s = ''
- i = 0
- n = self.markerOffset
- while i<n:
- s += self.queue.elementAt(i)
- return s
-
- def isMarked(self) :
- return self.nMarkers != 0
-
- def fill(self,k):
- ### abstract method
- raise NotImplementedError()
-
- def LA(self,k) :
- self.fill(k)
- return self.queue.elementAt(self.markerOffset + k - 1)
-
- def mark(self) :
- self.syncConsume()
- self.nMarkers += 1
- return self.markerOffset
-
- def rewind(self,mark) :
- self.syncConsume()
- self.markerOffset = mark
- self.nMarkers -= 1
-
- def reset(self) :
- self.nMarkers = 0
- self.markerOffset = 0
- self.numToConsume = 0
- self.queue.reset()
-
- def syncConsume(self) :
- while self.numToConsume > 0:
- if self.nMarkers > 0:
- # guess mode -- leave leading characters and bump offset.
- self.markerOffset += 1
- else:
- # normal mode -- remove first character
- self.queue.removeFirst()
- self.numToConsume -= 1
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CharBuffer ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class CharBuffer(InputBuffer):
- def __init__(self,reader):
- ##assert isinstance(reader,file)
- super(CharBuffer,self).__init__()
- ## a reader is supposed to be anything that has
- ## a method 'read(int)'.
- self.input = reader
-
- def __str__(self):
- base = super(CharBuffer,self).__str__()
- return "CharBuffer{%s,%s" % (base,str(input))
-
- def fill(self,amount):
- try:
- self.syncConsume()
- while self.queue.length() < (amount + self.markerOffset) :
- ## retrieve just one char - what happend at end
- ## of input?
- c = self.input.read(1)
- ### python's behaviour is to return the empty string on
- ### EOF, ie. no exception whatsoever is thrown. An empty
- ### python string has the nice feature that it is of
- ### type 'str' and "not ''" would return true. Contrary,
- ### one can't do this: '' in 'abc'. This should return
- ### false, but all we get is then a TypeError as an
- ### empty string is not a character.
-
- ### Let's assure then that we have either seen a
- ### character or an empty string (EOF).
- assert len(c) == 0 or len(c) == 1
-
- ### And it shall be of type string (ASCII or UNICODE).
- assert is_string_type(c)
-
- ### Just append EOF char to buffer. Note that buffer may
- ### contain then just more than one EOF char ..
-
- ### use unicode chars instead of ASCII ..
- self.queue.append(c)
- except Exception as e:
- raise CharStreamIOException(e)
- ##except: # (mk) Cannot happen ...
- ##error ("unexpected exception caught ..")
- ##assert 0
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### LexerSharedInputState ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class LexerSharedInputState(object):
- def __init__(self,ibuf):
- assert isinstance(ibuf,InputBuffer)
- self.input = ibuf
- self.column = 1
- self.line = 1
- self.tokenStartColumn = 1
- self.tokenStartLine = 1
- self.guessing = 0
- self.filename = None
-
- def reset(self):
- self.column = 1
- self.line = 1
- self.tokenStartColumn = 1
- self.tokenStartLine = 1
- self.guessing = 0
- self.filename = None
- self.input.reset()
-
- def LA(self,k):
- return self.input.LA(k)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TokenStream ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TokenStream(object):
- def nextToken(self):
- pass
-
- def __iter__(self):
- return TokenStreamIterator(self)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TokenStreamIterator ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TokenStreamIterator(object):
- def __init__(self,inst):
- if isinstance(inst,TokenStream):
- self.inst = inst
- return
- raise TypeError("TokenStreamIterator requires TokenStream object")
-
- def __next__(self):
- assert self.inst
- item = self.inst.nextToken()
- if not item or item.isEOF():
- raise StopIteration()
- return item
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TokenStreamSelector ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TokenStreamSelector(TokenStream):
-
- def __init__(self):
- self._input = None
- self._stmap = {}
- self._stack = []
-
- def addInputStream(self,stream,key):
- self._stmap[key] = stream
-
- def getCurrentStream(self):
- return self._input
-
- def getStream(self,sname):
- try:
- stream = self._stmap[sname]
- except:
- raise ValueError("TokenStream " + sname + " not found");
- return stream;
-
- def nextToken(self):
- while 1:
- try:
- return self._input.nextToken()
- except TokenStreamRetryException as r:
- ### just retry "forever"
- pass
-
- def pop(self):
- stream = self._stack.pop();
- self.select(stream);
- return stream;
-
- def push(self,arg):
- self._stack.append(self._input);
- self.select(arg)
-
- def retry(self):
- raise TokenStreamRetryException()
-
- def select(self,arg):
- if isinstance(arg,TokenStream):
- self._input = arg
- return
- if is_string_type(arg):
- self._input = self.getStream(arg)
- return
- raise TypeError("TokenStreamSelector.select requires " +
- "TokenStream or string argument")
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TokenStreamBasicFilter ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TokenStreamBasicFilter(TokenStream):
-
- def __init__(self,input):
-
- self.input = input;
- self.discardMask = BitSet()
-
- def discard(self,arg):
- if isinstance(arg,int):
- self.discardMask.add(arg)
- return
- if isinstance(arg,BitSet):
- self.discardMark = arg
- return
- raise TypeError("TokenStreamBasicFilter.discard requires" +
- "integer or BitSet argument")
-
- def nextToken(self):
- tok = self.input.nextToken()
- while tok and self.discardMask.member(tok.getType()):
- tok = self.input.nextToken()
- return tok
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TokenStreamHiddenTokenFilter ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TokenStreamHiddenTokenFilter(TokenStreamBasicFilter):
-
- def __init__(self,input):
- TokenStreamBasicFilter.__init__(self,input)
- self.hideMask = BitSet()
- self.nextMonitoredToken = None
- self.lastHiddenToken = None
- self.firstHidden = None
-
- def consume(self):
- self.nextMonitoredToken = self.input.nextToken()
-
- def consumeFirst(self):
- self.consume()
-
- p = None;
- while self.hideMask.member(self.LA(1).getType()) or \
- self.discardMask.member(self.LA(1).getType()):
- if self.hideMask.member(self.LA(1).getType()):
- if not p:
- p = self.LA(1)
- else:
- p.setHiddenAfter(self.LA(1))
- self.LA(1).setHiddenBefore(p)
- p = self.LA(1)
- self.lastHiddenToken = p
- if not self.firstHidden:
- self.firstHidden = p
- self.consume()
-
- def getDiscardMask(self):
- return self.discardMask
-
- def getHiddenAfter(self,t):
- return t.getHiddenAfter()
-
- def getHiddenBefore(self,t):
- return t.getHiddenBefore()
-
- def getHideMask(self):
- return self.hideMask
-
- def getInitialHiddenToken(self):
- return self.firstHidden
-
- def hide(self,m):
- if isinstance(m,int):
- self.hideMask.add(m)
- return
- if isinstance(m.BitMask):
- self.hideMask = m
- return
-
- def LA(self,i):
- return self.nextMonitoredToken
-
- def nextToken(self):
- if not self.LA(1):
- self.consumeFirst()
-
- monitored = self.LA(1)
-
- monitored.setHiddenBefore(self.lastHiddenToken)
- self.lastHiddenToken = None
-
- self.consume()
- p = monitored
-
- while self.hideMask.member(self.LA(1).getType()) or \
- self.discardMask.member(self.LA(1).getType()):
- if self.hideMask.member(self.LA(1).getType()):
- p.setHiddenAfter(self.LA(1))
- if p != monitored:
- self.LA(1).setHiddenBefore(p)
- p = self.lastHiddenToken = self.LA(1)
- self.consume()
- return monitored
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### StringBuffer ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class StringBuffer:
- def __init__(self,string=None):
- if string:
- self.text = list(string)
- else:
- self.text = []
-
- def setLength(self,sz):
- if not sz :
- self.text = []
- return
- assert sz>0
- if sz >= self.length():
- return
- ### just reset to empty buffer
- self.text = self.text[0:sz]
-
- def length(self):
- return len(self.text)
-
- def append(self,c):
- self.text.append(c)
-
- ### return buffer as string. Arg 'a' is used as index
- ## into the buffer and 2nd argument shall be the length.
- ## If 2nd args is absent, we return chars till end of
- ## buffer starting with 'a'.
- def getString(self,a=None,length=None):
- if not a :
- a = 0
- assert a>=0
- if a>= len(self.text) :
- return ""
-
- if not length:
- ## no second argument
- L = self.text[a:]
- else:
- assert (a+length) <= len(self.text)
- b = a + length
- L = self.text[a:b]
- s = ""
- for x in L : s += x
- return s
-
- toString = getString ## alias
-
- def __str__(self):
- return str(self.text)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### Reader ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-## When reading Japanese chars, it happens that a stream returns a
-## 'char' of length 2. This looks like a bug in the appropriate
-## codecs - but I'm rather unsure about this. Anyway, if this is
-## the case, I'm going to split this string into a list of chars
-## and put them on hold, ie. on a buffer. Next time when called
-## we read from buffer until buffer is empty.
-## wh: nov, 25th -> problem does not appear in Python 2.4.0.c1.
-
-class Reader(object):
- def __init__(self,stream):
- self.cin = stream
- self.buf = []
-
- def read(self,num):
- assert num==1
-
- if len(self.buf):
- return self.buf.pop()
-
- ## Read a char - this may return a string.
- ## Is this a bug in codecs/Python?
- c = self.cin.read(1)
-
- if not c or len(c)==1:
- return c
-
- L = list(c)
- L.reverse()
- for x in L:
- self.buf.append(x)
-
- ## read one char ..
- return self.read(1)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CharScanner ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class CharScanner(TokenStream):
- ## class members
- NO_CHAR = 0
- EOF_CHAR = '' ### EOF shall be the empty string.
-
- def __init__(self, *argv, **kwargs):
- super(CharScanner, self).__init__()
- self.saveConsumedInput = True
- self.tokenClass = None
- self.caseSensitive = True
- self.caseSensitiveLiterals = True
- self.literals = None
- self.tabsize = 8
- self._returnToken = None
- self.commitToPath = False
- self.traceDepth = 0
- self.text = StringBuffer()
- self.hashString = hash(self)
- self.setTokenObjectClass(CommonToken)
- self.setInput(*argv)
-
- def __iter__(self):
- return CharScannerIterator(self)
-
- def setInput(self,*argv):
- ## case 1:
- ## if there's no arg we default to read from
- ## standard input
- if not argv:
- import sys
- self.setInput(sys.stdin)
- return
-
- ## get 1st argument
- arg1 = argv[0]
-
- ## case 2:
- ## if arg1 is a string, we assume it's a file name
- ## and open a stream using 2nd argument as open
- ## mode. If there's no 2nd argument we fall back to
- ## mode '+rb'.
- if is_string_type(arg1):
- f = open(arg1,"rb")
- self.setInput(f)
- self.setFilename(arg1)
- return
-
- ## case 3:
- ## if arg1 is a file we wrap it by a char buffer (
- ## some additional checks?? No, can't do this in
- ## general).
- if isinstance(arg1,file):
- self.setInput(CharBuffer(arg1))
- return
-
- ## case 4:
- ## if arg1 is of type SharedLexerInputState we use
- ## argument as is.
- if isinstance(arg1,LexerSharedInputState):
- self.inputState = arg1
- return
-
- ## case 5:
- ## check whether argument type is of type input
- ## buffer. If so create a SharedLexerInputState and
- ## go ahead.
- if isinstance(arg1,InputBuffer):
- self.setInput(LexerSharedInputState(arg1))
- return
-
- ## case 6:
- ## check whether argument type has a method read(int)
- ## If so create CharBuffer ...
- try:
- if arg1.read:
- rd = Reader(arg1)
- cb = CharBuffer(rd)
- ss = LexerSharedInputState(cb)
- self.inputState = ss
- return
- except:
- pass
-
- ## case 7:
- ## raise wrong argument exception
- raise TypeError(argv)
-
- def setTabSize(self,size) :
- self.tabsize = size
-
- def getTabSize(self) :
- return self.tabsize
-
- def setCaseSensitive(self,t) :
- self.caseSensitive = t
-
- def setCommitToPath(self,commit) :
- self.commitToPath = commit
-
- def setFilename(self,f) :
- self.inputState.filename = f
-
- def setLine(self,line) :
- self.inputState.line = line
-
- def setText(self,s) :
- self.resetText()
- self.text.append(s)
-
- def getCaseSensitive(self) :
- return self.caseSensitive
-
- def getCaseSensitiveLiterals(self) :
- return self.caseSensitiveLiterals
-
- def getColumn(self) :
- return self.inputState.column
-
- def setColumn(self,c) :
- self.inputState.column = c
-
- def getCommitToPath(self) :
- return self.commitToPath
-
- def getFilename(self) :
- return self.inputState.filename
-
- def getInputBuffer(self) :
- return self.inputState.input
-
- def getInputState(self) :
- return self.inputState
-
- def setInputState(self,state) :
- assert isinstance(state,LexerSharedInputState)
- self.inputState = state
-
- def getLine(self) :
- return self.inputState.line
-
- def getText(self) :
- return str(self.text)
-
- def getTokenObject(self) :
- return self._returnToken
-
- def LA(self,i) :
- c = self.inputState.input.LA(i)
- if not self.caseSensitive:
- ### E0006
- c = c.__class__.lower(c)
- return c
-
- def makeToken(self,type) :
- try:
- ## dynamically load a class
- assert self.tokenClass
- tok = self.tokenClass()
- tok.setType(type)
- tok.setColumn(self.inputState.tokenStartColumn)
- tok.setLine(self.inputState.tokenStartLine)
- return tok
- except:
- self.panic("unable to create new token")
- return Token.badToken
-
- def mark(self) :
- return self.inputState.input.mark()
-
- def _match_bitset(self,b) :
- if b.member(self.LA(1)):
- self.consume()
- else:
- raise MismatchedCharException(self.LA(1), b, False, self)
-
- def _match_string(self,s) :
- for c in s:
- if self.LA(1) == c:
- self.consume()
- else:
- raise MismatchedCharException(self.LA(1), c, False, self)
-
- def match(self,item):
- if is_string_type(item):
- return self._match_string(item)
- else:
- return self._match_bitset(item)
-
- def matchNot(self,c) :
- if self.LA(1) != c:
- self.consume()
- else:
- raise MismatchedCharException(self.LA(1), c, True, self)
-
- def matchRange(self,c1,c2) :
- if self.LA(1) < c1 or self.LA(1) > c2 :
- raise MismatchedCharException(self.LA(1), c1, c2, False, self)
- else:
- self.consume()
-
- def newline(self) :
- self.inputState.line += 1
- self.inputState.column = 1
-
- def tab(self) :
- c = self.getColumn()
- nc = ( ((c-1)/self.tabsize) + 1) * self.tabsize + 1
- self.setColumn(nc)
-
- def panic(self,s='') :
- print("CharScanner: panic: " + s)
- sys.exit(1)
-
- def reportError(self,ex) :
- print(ex)
-
- def reportError(self,s) :
- if not self.getFilename():
- print("error: " + str(s))
- else:
- print(self.getFilename() + ": error: " + str(s))
-
- def reportWarning(self,s) :
- if not self.getFilename():
- print("warning: " + str(s))
- else:
- print(self.getFilename() + ": warning: " + str(s))
-
- def resetText(self) :
- self.text.setLength(0)
- self.inputState.tokenStartColumn = self.inputState.column
- self.inputState.tokenStartLine = self.inputState.line
-
- def rewind(self,pos) :
- self.inputState.input.rewind(pos)
-
- def setTokenObjectClass(self,cl):
- self.tokenClass = cl
-
- def testForLiteral(self,token):
- if not token:
- return
- assert isinstance(token,Token)
-
- _type = token.getType()
-
- ## special tokens can't be literals
- if _type in [SKIP,INVALID_TYPE,EOF_TYPE,NULL_TREE_LOOKAHEAD] :
- return
-
- _text = token.getText()
- if not _text:
- return
-
- assert is_string_type(_text)
- _type = self.testLiteralsTable(_text,_type)
- token.setType(_type)
- return _type
-
- def testLiteralsTable(self,*args):
- if is_string_type(args[0]):
- s = args[0]
- i = args[1]
- else:
- s = self.text.getString()
- i = args[0]
-
- ## check whether integer has been given
- if not isinstance(i,int):
- assert isinstance(i,int)
-
- ## check whether we have a dict
- assert isinstance(self.literals,dict)
- try:
- ## E0010
- if not self.caseSensitiveLiterals:
- s = s.__class__.lower(s)
- i = self.literals[s]
- except:
- pass
- return i
-
- def toLower(self,c):
- return c.__class__.lower()
-
- def traceIndent(self):
- print(' ' * self.traceDepth)
-
- def traceIn(self,rname):
- self.traceDepth += 1
- self.traceIndent()
- print("> lexer %s c== %s" % (rname,self.LA(1)))
-
- def traceOut(self,rname):
- self.traceIndent()
- print("< lexer %s c== %s" % (rname,self.LA(1)))
- self.traceDepth -= 1
-
- def uponEOF(self):
- pass
-
- def append(self,c):
- if self.saveConsumedInput :
- self.text.append(c)
-
- def commit(self):
- self.inputState.input.commit()
-
- def consume(self):
- if not self.inputState.guessing:
- c = self.LA(1)
- if self.caseSensitive:
- self.append(c)
- else:
- # use input.LA(), not LA(), to get original case
- # CharScanner.LA() would toLower it.
- c = self.inputState.input.LA(1)
- self.append(c)
-
- if c and c in "\t":
- self.tab()
- else:
- self.inputState.column += 1
- self.inputState.input.consume()
-
- ## Consume chars until one matches the given char
- def consumeUntil_char(self,c):
- while self.LA(1) != EOF_CHAR and self.LA(1) != c:
- self.consume()
-
- ## Consume chars until one matches the given set
- def consumeUntil_bitset(self,bitset):
- while self.LA(1) != EOF_CHAR and not self.set.member(self.LA(1)):
- self.consume()
-
- ### If symbol seen is EOF then generate and set token, otherwise
- ### throw exception.
- def default(self,la1):
- if not la1 :
- self.uponEOF()
- self._returnToken = self.makeToken(EOF_TYPE)
- else:
- self.raise_NoViableAlt(la1)
-
- def filterdefault(self,la1,*args):
- if not la1:
- self.uponEOF()
- self._returnToken = self.makeToken(EOF_TYPE)
- return
-
- if not args:
- self.consume()
- raise TryAgain()
- else:
- ### apply filter object
- self.commit();
- try:
- func=args[0]
- args=args[1:]
- func(*args)
- except RecognitionException as e:
- ## catastrophic failure
- self.reportError(e);
- self.consume();
- raise TryAgain()
-
- def raise_NoViableAlt(self,la1=None):
- if not la1: la1 = self.LA(1)
- fname = self.getFilename()
- line = self.getLine()
- col = self.getColumn()
- raise NoViableAltForCharException(la1,fname,line,col)
-
- def set_return_token(self,_create,_token,_ttype,_offset):
- if _create and not _token and (not _ttype == SKIP):
- string = self.text.getString(_offset)
- _token = self.makeToken(_ttype)
- _token.setText(string)
- self._returnToken = _token
- return _token
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CharScannerIterator ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class CharScannerIterator:
-
- def __init__(self,inst):
- if isinstance(inst,CharScanner):
- self.inst = inst
- return
- raise TypeError("CharScannerIterator requires CharScanner object")
-
- def __next__(self):
- assert self.inst
- item = self.inst.nextToken()
- if not item or item.isEOF():
- raise StopIteration()
- return item
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### BitSet ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-### I'm assuming here that a long is 64bits. It appears however, that
-### a long is of any size. That means we can use a single long as the
-### bitset (!), ie. Python would do almost all the work (TBD).
-
-class BitSet(object):
- BITS = 64
- NIBBLE = 4
- LOG_BITS = 6
- MOD_MASK = BITS -1
-
- def __init__(self,data=None):
- if not data:
- BitSet.__init__(self,[int(0)])
- return
- if isinstance(data,int):
- BitSet.__init__(self,[int(data)])
- return
- if isinstance(data,int):
- BitSet.__init__(self,[data])
- return
- if not isinstance(data,list):
- raise TypeError("BitSet requires integer, long, or " +
- "list argument")
- for x in data:
- if not isinstance(x,int):
- raise TypeError(self,"List argument item is " +
- "not a long: %s" % (x))
- self.data = data
-
- def __str__(self):
- bits = len(self.data) * BitSet.BITS
- s = ""
- for i in range(0,bits):
- if self.at(i):
- s += "1"
- else:
- s += "o"
- if not ((i+1) % 10):
- s += '|%s|' % (i+1)
- return s
-
- def __repr__(self):
- return str(self)
-
- def member(self,item):
- if not item:
- return False
-
- if isinstance(item,int):
- return self.at(item)
-
- if not is_string_type(item):
- raise TypeError(self,"char or unichar expected: %s" % (item))
-
- ## char is a (unicode) string with at most lenght 1, ie.
- ## a char.
-
- if len(item) != 1:
- raise TypeError(self,"char expected: %s" % (item))
-
- ### handle ASCII/UNICODE char
- num = ord(item)
-
- ### check whether position num is in bitset
- return self.at(num)
-
- def wordNumber(self,bit):
- return bit >> BitSet.LOG_BITS
-
- def bitMask(self,bit):
- pos = bit & BitSet.MOD_MASK ## bit mod BITS
- return (1 << pos)
-
- def set(self,bit,on=True):
- # grow bitset as required (use with care!)
- i = self.wordNumber(bit)
- mask = self.bitMask(bit)
- if i>=len(self.data):
- d = i - len(self.data) + 1
- for x in range(0,d):
- self.data.append(0)
- assert len(self.data) == i+1
- if on:
- self.data[i] |= mask
- else:
- self.data[i] &= (~mask)
-
- ### make add an alias for set
- add = set
-
- def off(self,bit,off=True):
- self.set(bit,not off)
-
- def at(self,bit):
- i = self.wordNumber(bit)
- v = self.data[i]
- m = self.bitMask(bit)
- return v & m
-
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### some further funcs ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-def illegalarg_ex(func):
- raise ValueError(
- "%s is only valid if parser is built for debugging" %
- (func.__name__))
-
-def runtime_ex(func):
- raise RuntimeException(
- "%s is only valid if parser is built for debugging" %
- (func.__name__))
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TokenBuffer ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TokenBuffer(object):
- def __init__(self,stream):
- self.input = stream
- self.nMarkers = 0
- self.markerOffset = 0
- self.numToConsume = 0
- self.queue = Queue()
-
- def reset(self) :
- self.nMarkers = 0
- self.markerOffset = 0
- self.numToConsume = 0
- self.queue.reset()
-
- def consume(self) :
- self.numToConsume += 1
-
- def fill(self, amount):
- self.syncConsume()
- while self.queue.length() < (amount + self.markerOffset):
- self.queue.append(self.input.nextToken())
-
- def getInput(self):
- return self.input
-
- def LA(self,k) :
- self.fill(k)
- return self.queue.elementAt(self.markerOffset + k - 1).type
-
- def LT(self,k) :
- self.fill(k)
- return self.queue.elementAt(self.markerOffset + k - 1)
-
- def mark(self) :
- self.syncConsume()
- self.nMarkers += 1
- return self.markerOffset
-
- def rewind(self,mark) :
- self.syncConsume()
- self.markerOffset = mark
- self.nMarkers -= 1
-
- def syncConsume(self) :
- while self.numToConsume > 0:
- if self.nMarkers > 0:
- # guess mode -- leave leading characters and bump offset.
- self.markerOffset += 1
- else:
- # normal mode -- remove first character
- self.queue.removeFirst()
- self.numToConsume -= 1
-
- def __str__(self):
- return "(%s,%s,%s,%s,%s)" % (
- self.input,
- self.nMarkers,
- self.markerOffset,
- self.numToConsume,
- self.queue)
-
- def __repr__(self):
- return str(self)
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### ParserSharedInputState ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class ParserSharedInputState(object):
-
- def __init__(self):
- self.input = None
- self.reset()
-
- def reset(self):
- self.guessing = 0
- self.filename = None
- if self.input:
- self.input.reset()
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### Parser ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class Parser(object):
-
- def __init__(self, *args, **kwargs):
- self.tokenNames = None
- self.returnAST = None
- self.astFactory = None
- self.tokenTypeToASTClassMap = {}
- self.ignoreInvalidDebugCalls = False
- self.traceDepth = 0
- if not args:
- self.inputState = ParserSharedInputState()
- return
- arg0 = args[0]
- assert isinstance(arg0,ParserSharedInputState)
- self.inputState = arg0
- return
-
- def getTokenTypeToASTClassMap(self):
- return self.tokenTypeToASTClassMap
-
-
- def addMessageListener(self, l):
- if not self.ignoreInvalidDebugCalls:
- illegalarg_ex(addMessageListener)
-
- def addParserListener(self,l) :
- if (not self.ignoreInvalidDebugCalls) :
- illegalarg_ex(addParserListener)
-
- def addParserMatchListener(self, l) :
- if (not self.ignoreInvalidDebugCalls) :
- illegalarg_ex(addParserMatchListener)
-
- def addParserTokenListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- illegalarg_ex(addParserTokenListener)
-
- def addSemanticPredicateListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- illegalarg_ex(addSemanticPredicateListener)
-
- def addSyntacticPredicateListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- illegalarg_ex(addSyntacticPredicateListener)
-
- def addTraceListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- illegalarg_ex(addTraceListener)
-
- def consume(self):
- raise NotImplementedError()
-
- def _consumeUntil_type(self,tokenType):
- while self.LA(1) != EOF_TYPE and self.LA(1) != tokenType:
- self.consume()
-
- def _consumeUntil_bitset(self, set):
- while self.LA(1) != EOF_TYPE and not set.member(self.LA(1)):
- self.consume()
-
- def consumeUntil(self,arg):
- if isinstance(arg,int):
- self._consumeUntil_type(arg)
- else:
- self._consumeUntil_bitset(arg)
-
- def defaultDebuggingSetup(self):
- pass
-
- def getAST(self) :
- return self.returnAST
-
- def getASTFactory(self) :
- return self.astFactory
-
- def getFilename(self) :
- return self.inputState.filename
-
- def getInputState(self) :
- return self.inputState
-
- def setInputState(self, state) :
- self.inputState = state
-
- def getTokenName(self,num) :
- return self.tokenNames[num]
-
- def getTokenNames(self) :
- return self.tokenNames
-
- def isDebugMode(self) :
- return self.false
-
- def LA(self, i):
- raise NotImplementedError()
-
- def LT(self, i):
- raise NotImplementedError()
-
- def mark(self):
- return self.inputState.input.mark()
-
- def _match_int(self,t):
- if (self.LA(1) != t):
- raise MismatchedTokenException(
- self.tokenNames, self.LT(1), t, False, self.getFilename())
- else:
- self.consume()
-
- def _match_set(self, b):
- if (not b.member(self.LA(1))):
- raise MismatchedTokenException(
- self.tokenNames,self.LT(1), b, False, self.getFilename())
- else:
- self.consume()
-
- def match(self,set) :
- if isinstance(set,int):
- self._match_int(set)
- return
- if isinstance(set,BitSet):
- self._match_set(set)
- return
- raise TypeError("Parser.match requires integer ot BitSet argument")
-
- def matchNot(self,t):
- if self.LA(1) == t:
- raise MismatchedTokenException(
- tokenNames, self.LT(1), t, True, self.getFilename())
- else:
- self.consume()
-
- def removeMessageListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeMessageListener)
-
- def removeParserListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeParserListener)
-
- def removeParserMatchListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeParserMatchListener)
-
- def removeParserTokenListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeParserTokenListener)
-
- def removeSemanticPredicateListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeSemanticPredicateListener)
-
- def removeSyntacticPredicateListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeSyntacticPredicateListener)
-
- def removeTraceListener(self, l) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(removeTraceListener)
-
- def reportError(self,x) :
- fmt = "syntax error:"
- f = self.getFilename()
- if f:
- fmt = ("%s:" % f) + fmt
- if isinstance(x,Token):
- line = x.getColumn()
- col = x.getLine()
- text = x.getText()
- fmt = fmt + 'unexpected symbol at line %s (column %s) : "%s"'
- print(fmt % (line,col,text), file=sys.stderr)
- else:
- print(fmt,str(x), file=sys.stderr)
-
- def reportWarning(self,s):
- f = self.getFilename()
- if f:
- print("%s:warning: %s" % (f,str(x)))
- else:
- print("warning: %s" % (str(x)))
-
- def rewind(self, pos) :
- self.inputState.input.rewind(pos)
-
- def setASTFactory(self, f) :
- self.astFactory = f
-
- def setASTNodeClass(self, cl) :
- self.astFactory.setASTNodeType(cl)
-
- def setASTNodeType(self, nodeType) :
- self.setASTNodeClass(nodeType)
-
- def setDebugMode(self, debugMode) :
- if (not self.ignoreInvalidDebugCalls):
- runtime_ex(setDebugMode)
-
- def setFilename(self, f) :
- self.inputState.filename = f
-
- def setIgnoreInvalidDebugCalls(self, value) :
- self.ignoreInvalidDebugCalls = value
-
- def setTokenBuffer(self, t) :
- self.inputState.input = t
-
- def traceIndent(self):
- print(" " * self.traceDepth)
-
- def traceIn(self,rname):
- self.traceDepth += 1
- self.trace("> ", rname)
-
- def traceOut(self,rname):
- self.trace("< ", rname)
- self.traceDepth -= 1
-
- ### wh: moved from ASTFactory to Parser
- def addASTChild(self,currentAST, child):
- if not child:
- return
- if not currentAST.root:
- currentAST.root = child
- elif not currentAST.child:
- currentAST.root.setFirstChild(child)
- else:
- currentAST.child.setNextSibling(child)
- currentAST.child = child
- currentAST.advanceChildToEnd()
-
- ### wh: moved from ASTFactory to Parser
- def makeASTRoot(self,currentAST,root) :
- if root:
- ### Add the current root as a child of new root
- root.addChild(currentAST.root)
- ### The new current child is the last sibling of the old root
- currentAST.child = currentAST.root
- currentAST.advanceChildToEnd()
- ### Set the new root
- currentAST.root = root
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### LLkParser ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class LLkParser(Parser):
-
- def __init__(self, *args, **kwargs):
- try:
- arg1 = args[0]
- except:
- arg1 = 1
-
- if isinstance(arg1,int):
- super(LLkParser,self).__init__()
- self.k = arg1
- return
-
- if isinstance(arg1,ParserSharedInputState):
- super(LLkParser,self).__init__(arg1)
- self.set_k(1,*args)
- return
-
- if isinstance(arg1,TokenBuffer):
- super(LLkParser,self).__init__()
- self.setTokenBuffer(arg1)
- self.set_k(1,*args)
- return
-
- if isinstance(arg1,TokenStream):
- super(LLkParser,self).__init__()
- tokenBuf = TokenBuffer(arg1)
- self.setTokenBuffer(tokenBuf)
- self.set_k(1,*args)
- return
-
- ### unknown argument
- raise TypeError("LLkParser requires integer, " +
- "ParserSharedInputStream or TokenStream argument")
-
- def consume(self):
- self.inputState.input.consume()
-
- def LA(self,i):
- return self.inputState.input.LA(i)
-
- def LT(self,i):
- return self.inputState.input.LT(i)
-
- def set_k(self,index,*args):
- try:
- self.k = args[index]
- except:
- self.k = 1
-
- def trace(self,ee,rname):
- print(type(self))
- self.traceIndent()
- guess = ""
- if self.inputState.guessing > 0:
- guess = " [guessing]"
- print((ee + rname + guess))
- for i in range(1,self.k+1):
- if i != 1:
- print(", ")
- if self.LT(i) :
- v = self.LT(i).getText()
- else:
- v = "null"
- print("LA(%s) == %s" % (i,v))
- print("\n")
-
- def traceIn(self,rname):
- self.traceDepth += 1;
- self.trace("> ", rname);
-
- def traceOut(self,rname):
- self.trace("< ", rname);
- self.traceDepth -= 1;
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TreeParserSharedInputState ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TreeParserSharedInputState(object):
- def __init__(self):
- self.guessing = 0
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### TreeParser ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class TreeParser(object):
-
- def __init__(self, *args, **kwargs):
- self.inputState = TreeParserSharedInputState()
- self._retTree = None
- self.tokenNames = []
- self.returnAST = None
- self.astFactory = ASTFactory()
- self.traceDepth = 0
-
- def getAST(self):
- return self.returnAST
-
- def getASTFactory(self):
- return self.astFactory
-
- def getTokenName(self,num) :
- return self.tokenNames[num]
-
- def getTokenNames(self):
- return self.tokenNames
-
- def match(self,t,set) :
- assert isinstance(set,int) or isinstance(set,BitSet)
- if not t or t == ASTNULL:
- raise MismatchedTokenException(self.getTokenNames(), t,set, False)
-
- if isinstance(set,int) and t.getType() != set:
- raise MismatchedTokenException(self.getTokenNames(), t,set, False)
-
- if isinstance(set,BitSet) and not set.member(t.getType):
- raise MismatchedTokenException(self.getTokenNames(), t,set, False)
-
- def matchNot(self,t, ttype) :
- if not t or (t == ASTNULL) or (t.getType() == ttype):
- raise MismatchedTokenException(getTokenNames(), t, ttype, True)
-
- def reportError(self,ex):
- print("error:",ex, file=sys.stderr)
-
- def reportWarning(self, s):
- print("warning:",s)
-
- def setASTFactory(self,f):
- self.astFactory = f
-
- def setASTNodeType(self,nodeType):
- self.setASTNodeClass(nodeType)
-
- def setASTNodeClass(self,nodeType):
- self.astFactory.setASTNodeType(nodeType)
-
- def traceIndent(self):
- print(" " * self.traceDepth)
-
- def traceIn(self,rname,t):
- self.traceDepth += 1
- self.traceIndent()
- print(("> " + rname + "(" +
- ifelse(t,str(t),"null") + ")" +
- ifelse(self.inputState.guessing>0,"[guessing]","")))
-
- def traceOut(self,rname,t):
- self.traceIndent()
- print(("< " + rname + "(" +
- ifelse(t,str(t),"null") + ")" +
- ifelse(self.inputState.guessing>0,"[guessing]","")))
- self.traceDepth -= 1
-
- ### wh: moved from ASTFactory to TreeParser
- def addASTChild(self,currentAST, child):
- if not child:
- return
- if not currentAST.root:
- currentAST.root = child
- elif not currentAST.child:
- currentAST.root.setFirstChild(child)
- else:
- currentAST.child.setNextSibling(child)
- currentAST.child = child
- currentAST.advanceChildToEnd()
-
- ### wh: moved from ASTFactory to TreeParser
- def makeASTRoot(self,currentAST,root):
- if root:
- ### Add the current root as a child of new root
- root.addChild(currentAST.root)
- ### The new current child is the last sibling of the old root
- currentAST.child = currentAST.root
- currentAST.advanceChildToEnd()
- ### Set the new root
- currentAST.root = root
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### funcs to work on trees ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-def rightmost(ast):
- if ast:
- while(ast.right):
- ast = ast.right
- return ast
-
-def cmptree(s,t,partial):
- while(s and t):
- ### as a quick optimization, check roots first.
- if not s.equals(t):
- return False
-
- ### if roots match, do full list match test on children.
- if not cmptree(s.getFirstChild(),t.getFirstChild(),partial):
- return False
-
- s = s.getNextSibling()
- t = t.getNextSibling()
-
- r = ifelse(partial,not t,not s and not t)
- return r
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### AST ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class AST(object):
- def __init__(self):
- pass
-
- def addChild(self, c):
- pass
-
- def equals(self, t):
- return False
-
- def equalsList(self, t):
- return False
-
- def equalsListPartial(self, t):
- return False
-
- def equalsTree(self, t):
- return False
-
- def equalsTreePartial(self, t):
- return False
-
- def findAll(self, tree):
- return None
-
- def findAllPartial(self, subtree):
- return None
-
- def getFirstChild(self):
- return self
-
- def getNextSibling(self):
- return self
-
- def getText(self):
- return ""
-
- def getType(self):
- return INVALID_TYPE
-
- def getLine(self):
- return 0
-
- def getColumn(self):
- return 0
-
- def getNumberOfChildren(self):
- return 0
-
- def initialize(self, t, txt):
- pass
-
- def initialize(self, t):
- pass
-
- def setFirstChild(self, c):
- pass
-
- def setNextSibling(self, n):
- pass
-
- def setText(self, text):
- pass
-
- def setType(self, ttype):
- pass
-
- def toString(self):
- self.getText()
-
- __str__ = toString
-
- def toStringList(self):
- return self.getText()
-
- def toStringTree(self):
- return self.getText()
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### ASTNULLType ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-### There is only one instance of this class **/
-class ASTNULLType(AST):
- def __init__(self):
- AST.__init__(self)
- pass
-
- def getText(self):
- return "<ASTNULL>"
-
- def getType(self):
- return NULL_TREE_LOOKAHEAD
-
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### BaseAST ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class BaseAST(AST):
-
- verboseStringConversion = False
- tokenNames = None
-
- def __init__(self):
- self.down = None ## kid
- self.right = None ## sibling
-
- def addChild(self,node):
- if node:
- t = rightmost(self.down)
- if t:
- t.right = node
- else:
- assert not self.down
- self.down = node
-
- def getNumberOfChildren(self):
- t = self.down
- n = 0
- while t:
- n += 1
- t = t.right
- return n
-
- def doWorkForFindAll(self,v,target,partialMatch):
- sibling = self
-
- while sibling:
- c1 = partialMatch and sibling.equalsTreePartial(target)
- if c1:
- v.append(sibling)
- else:
- c2 = not partialMatch and sibling.equalsTree(target)
- if c2:
- v.append(sibling)
-
- ### regardless of match or not, check any children for matches
- if sibling.getFirstChild():
- sibling.getFirstChild().doWorkForFindAll(v,target,partialMatch)
-
- sibling = sibling.getNextSibling()
-
- ### Is node t equal to 'self' in terms of token type and text?
- def equals(self,t):
- if not t:
- return False
- return self.getText() == t.getText() and self.getType() == t.getType()
-
- ### Is t an exact structural and equals() match of this tree. The
- ### 'self' reference is considered the start of a sibling list.
- ###
- def equalsList(self, t):
- return cmptree(self, t, partial=False)
-
- ### Is 't' a subtree of this list?
- ### The siblings of the root are NOT ignored.
- ###
- def equalsListPartial(self,t):
- return cmptree(self,t,partial=True)
-
- ### Is tree rooted at 'self' equal to 't'? The siblings
- ### of 'self' are ignored.
- ###
- def equalsTree(self, t):
- return self.equals(t) and \
- cmptree(self.getFirstChild(), t.getFirstChild(), partial=False)
-
- ### Is 't' a subtree of the tree rooted at 'self'? The siblings
- ### of 'self' are ignored.
- ###
- def equalsTreePartial(self, t):
- if not t:
- return True
- return self.equals(t) and cmptree(
- self.getFirstChild(), t.getFirstChild(), partial=True)
-
- ### Walk the tree looking for all exact subtree matches. Return
- ### an ASTEnumerator that lets the caller walk the list
- ### of subtree roots found herein.
- def findAll(self,target):
- roots = []
-
- ### the empty tree cannot result in an enumeration
- if not target:
- return None
- # find all matches recursively
- self.doWorkForFindAll(roots, target, False)
- return roots
-
- ### Walk the tree looking for all subtrees. Return
- ### an ASTEnumerator that lets the caller walk the list
- ### of subtree roots found herein.
- def findAllPartial(self,sub):
- roots = []
-
- ### the empty tree cannot result in an enumeration
- if not sub:
- return None
-
- self.doWorkForFindAll(roots, sub, True) ### find all matches recursively
- return roots
-
- ### Get the first child of this node None if not children
- def getFirstChild(self):
- return self.down
-
- ### Get the next sibling in line after this one
- def getNextSibling(self):
- return self.right
-
- ### Get the token text for this node
- def getText(self):
- return ""
-
- ### Get the token type for this node
- def getType(self):
- return 0
-
- def getLine(self):
- return 0
-
- def getColumn(self):
- return 0
-
- ### Remove all children */
- def removeChildren(self):
- self.down = None
-
- def setFirstChild(self,c):
- self.down = c
-
- def setNextSibling(self, n):
- self.right = n
-
- ### Set the token text for this node
- def setText(self, text):
- pass
-
- ### Set the token type for this node
- def setType(self, ttype):
- pass
-
- ### static
- def setVerboseStringConversion(verbose,names):
- verboseStringConversion = verbose
- tokenNames = names
- setVerboseStringConversion = staticmethod(setVerboseStringConversion)
-
- ### Return an array of strings that maps token ID to it's text.
- ## @since 2.7.3
- def getTokenNames():
- return tokenNames
-
- def toString(self):
- return self.getText()
-
- ### return tree as lisp string - sibling included
- def toStringList(self):
- ts = self.toStringTree()
- sib = self.getNextSibling()
- if sib:
- ts += sib.toStringList()
- return ts
-
- __str__ = toStringList
-
- ### return tree as string - siblings ignored
- def toStringTree(self):
- ts = ""
- kid = self.getFirstChild()
- if kid:
- ts += " ("
- ts += " " + self.toString()
- if kid:
- ts += kid.toStringList()
- ts += " )"
- return ts
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CommonAST ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-### Common AST node implementation
-class CommonAST(BaseAST):
- def __init__(self,token=None):
- super(CommonAST,self).__init__()
- self.ttype = INVALID_TYPE
- self.text = "<no text>"
- self.line = 0
- self.column= 0
- self.initialize(token)
- #assert self.text
-
- ### Get the token text for this node
- def getText(self):
- return self.text
-
- ### Get the token type for this node
- def getType(self):
- return self.ttype
-
- ### Get the line for this node
- def getLine(self):
- return self.line
-
- ### Get the column for this node
- def getColumn(self):
- return self.column
-
- def initialize(self,*args):
- if not args:
- return
-
- arg0 = args[0]
-
- if isinstance(arg0,int):
- arg1 = args[1]
- self.setType(arg0)
- self.setText(arg1)
- return
-
- if isinstance(arg0,AST) or isinstance(arg0,Token):
- self.setText(arg0.getText())
- self.setType(arg0.getType())
- self.line = arg0.getLine()
- self.column = arg0.getColumn()
- return
-
- ### Set the token text for this node
- def setText(self,text_):
- assert is_string_type(text_)
- self.text = text_
-
- ### Set the token type for this node
- def setType(self,ttype_):
- assert isinstance(ttype_,int)
- self.ttype = ttype_
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### CommonASTWithHiddenTokens ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class CommonASTWithHiddenTokens(CommonAST):
-
- def __init__(self,*args):
- CommonAST.__init__(self,*args)
- self.hiddenBefore = None
- self.hiddenAfter = None
-
- def getHiddenAfter(self):
- return self.hiddenAfter
-
- def getHiddenBefore(self):
- return self.hiddenBefore
-
- def initialize(self,*args):
- CommonAST.initialize(self,*args)
- if args and isinstance(args[0],Token):
- assert isinstance(args[0],CommonHiddenStreamToken)
- self.hiddenBefore = args[0].getHiddenBefore()
- self.hiddenAfter = args[0].getHiddenAfter()
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### ASTPair ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class ASTPair(object):
- def __init__(self):
- self.root = None ### current root of tree
- self.child = None ### current child to which siblings are added
-
- ### Make sure that child is the last sibling */
- def advanceChildToEnd(self):
- if self.child:
- while self.child.getNextSibling():
- self.child = self.child.getNextSibling()
-
- ### Copy an ASTPair. Don't call it clone() because we want type-safety */
- def copy(self):
- tmp = ASTPair()
- tmp.root = self.root
- tmp.child = self.child
- return tmp
-
- def toString(self):
- r = ifelse(not root,"null",self.root.getText())
- c = ifelse(not child,"null",self.child.getText())
- return "[%s,%s]" % (r,c)
-
- __str__ = toString
- __repr__ = toString
-
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### ASTFactory ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class ASTFactory(object):
- def __init__(self,table=None):
- self._class = None
- self._classmap = ifelse(table,table,None)
-
- def create(self,*args):
- if not args:
- return self.create(INVALID_TYPE)
-
- arg0 = args[0]
- arg1 = None
- arg2 = None
-
- try:
- arg1 = args[1]
- arg2 = args[2]
- except:
- pass
-
- # ctor(int)
- if isinstance(arg0,int) and not arg2:
- ### get class for 'self' type
- c = self.getASTNodeType(arg0)
- t = self.create(c)
- if t:
- t.initialize(arg0, ifelse(arg1,arg1,""))
- return t
-
- # ctor(int,something)
- if isinstance(arg0,int) and arg2:
- t = self.create(arg2)
- if t:
- t.initialize(arg0,arg1)
- return t
-
- # ctor(AST)
- if isinstance(arg0,AST):
- t = self.create(arg0.getType())
- if t:
- t.initialize(arg0)
- return t
-
- # ctor(token)
- if isinstance(arg0,Token) and not arg1:
- ttype = arg0.getType()
- assert isinstance(ttype,int)
- t = self.create(ttype)
- if t:
- t.initialize(arg0)
- return t
-
- # ctor(token,class)
- if isinstance(arg0,Token) and arg1:
- assert isinstance(arg1,type)
- assert issubclass(arg1,AST)
- # this creates instance of 'arg1' using 'arg0' as
- # argument. Wow, that's magic!
- t = arg1(arg0)
- assert t and isinstance(t,AST)
- return t
-
- # ctor(class)
- if isinstance(arg0,type):
- ### next statement creates instance of type (!)
- t = arg0()
- assert isinstance(t,AST)
- return t
-
-
- def setASTNodeClass(self,className=None):
- if not className:
- return
- assert isinstance(className,type)
- assert issubclass(className,AST)
- self._class = className
-
- ### kind of misnomer - use setASTNodeClass instead.
- setASTNodeType = setASTNodeClass
-
- def getASTNodeClass(self):
- return self._class
-
-
-
- def getTokenTypeToASTClassMap(self):
- return self._classmap
-
- def setTokenTypeToASTClassMap(self,amap):
- self._classmap = amap
-
- def error(self, e):
- import sys
- print(e, file=sys.stderr)
-
- def setTokenTypeASTNodeType(self, tokenType, className):
- """
- Specify a mapping between a token type and a (AST) class.
- """
- if not self._classmap:
- self._classmap = {}
-
- if not className:
- try:
- del self._classmap[tokenType]
- except:
- pass
- else:
- ### here we should also perform actions to ensure that
- ### a. class can be loaded
- ### b. class is a subclass of AST
- ###
- assert isinstance(className,type)
- assert issubclass(className,AST) ## a & b
- ### enter the class
- self._classmap[tokenType] = className
-
- def getASTNodeType(self,tokenType):
- """
- For a given token type return the AST node type. First we
- lookup a mapping table, second we try _class
- and finally we resolve to "antlr.CommonAST".
- """
-
- # first
- if self._classmap:
- try:
- c = self._classmap[tokenType]
- if c:
- return c
- except:
- pass
- # second
- if self._class:
- return self._class
-
- # default
- return CommonAST
-
- ### methods that have been moved to file scope - just listed
- ### here to be somewhat consistent with original API
- def dup(self,t):
- return antlr.dup(t,self)
-
- def dupList(self,t):
- return antlr.dupList(t,self)
-
- def dupTree(self,t):
- return antlr.dupTree(t,self)
-
- ### methods moved to other classes
- ### 1. makeASTRoot -> Parser
- ### 2. addASTChild -> Parser
-
- ### non-standard: create alias for longish method name
- maptype = setTokenTypeASTNodeType
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### ASTVisitor ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-class ASTVisitor(object):
- def __init__(self,*args):
- pass
-
- def visit(self,ast):
- pass
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-### static methods and variables ###
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx###
-
-ASTNULL = ASTNULLType()
-
-### wh: moved from ASTFactory as there's nothing ASTFactory-specific
-### in this method.
-def make(*nodes):
- if not nodes:
- return None
-
- for i in range(0,len(nodes)):
- node = nodes[i]
- if node:
- assert isinstance(node,AST)
-
- root = nodes[0]
- tail = None
- if root:
- root.setFirstChild(None)
-
- for i in range(1,len(nodes)):
- if not nodes[i]:
- continue
- if not root:
- root = tail = nodes[i]
- elif not tail:
- root.setFirstChild(nodes[i])
- tail = root.getFirstChild()
- else:
- tail.setNextSibling(nodes[i])
- tail = tail.getNextSibling()
-
- ### Chase tail to last sibling
- while tail.getNextSibling():
- tail = tail.getNextSibling()
- return root
-
-def dup(t,factory):
- if not t:
- return None
-
- if factory:
- dup_t = factory.create(t.__class__)
- else:
- raise TypeError("dup function requires ASTFactory argument")
- dup_t.initialize(t)
- return dup_t
-
-def dupList(t,factory):
- result = dupTree(t,factory)
- nt = result
- while t:
- ## for each sibling of the root
- t = t.getNextSibling()
- nt.setNextSibling(dupTree(t,factory))
- nt = nt.getNextSibling()
- return result
-
-def dupTree(t,factory):
- result = dup(t,factory)
- if t:
- result.setFirstChild(dupList(t.getFirstChild(),factory))
- return result
-
-###xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-### $Id: antlr.py 3750 2009-02-13 00:13:04Z sjmachin $
-
-# Local Variables: ***
-# mode: python ***
-# py-indent-offset: 4 ***
-# End: ***
|
