sheet.py 105 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420
  1. # -*- coding: cp1252 -*-
  2. ##
  3. # <p> Portions copyright © 2005-2013 Stephen John Machin, Lingfo Pty Ltd</p>
  4. # <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p>
  5. ##
  6. # 2010-04-25 SJM fix zoom factors cooking logic
  7. # 2010-04-15 CW r4253 fix zoom factors cooking logic
  8. # 2010-04-09 CW r4248 add a flag so xlutils knows whether or not to write a PANE record
  9. # 2010-03-29 SJM Fixed bug in adding new empty rows in put_cell_ragged
  10. # 2010-03-28 SJM Tailored put_cell method for each of ragged_rows=False (fixed speed regression) and =True (faster)
  11. # 2010-03-25 CW r4236 Slight refactoring to remove method calls
  12. # 2010-03-25 CW r4235 Collapse expand_cells into put_cell and enhance the raggedness. This should save even more memory!
  13. # 2010-03-25 CW r4234 remove duplicate chunks for extend_cells; refactor to remove put_number_cell and put_blank_cell which essentially duplicated the code of put_cell
  14. # 2010-03-10 SJM r4222 Added reading of the PANE record.
  15. # 2010-03-10 SJM r4221 Preliminary work on "cooked" mag factors; use at own peril
  16. # 2010-03-01 SJM Reading SCL record
  17. # 2010-03-01 SJM Added ragged_rows functionality
  18. # 2009-08-23 SJM Reduced CPU time taken by parsing MULBLANK records.
  19. # 2009-08-18 SJM Used __slots__ and sharing to reduce memory consumed by Rowinfo instances
  20. # 2009-05-31 SJM Fixed problem with no CODEPAGE record on extremely minimal BIFF2.x 3rd-party file
  21. # 2009-04-27 SJM Integrated on_demand patch by Armando Serrano Lombillo
  22. # 2008-02-09 SJM Excel 2.0: build XFs on the fly from cell attributes
  23. # 2007-12-04 SJM Added support for Excel 2.x (BIFF2) files.
  24. # 2007-10-11 SJM Added missing entry for blank cell type to ctype_text
  25. # 2007-07-11 SJM Allow for BIFF2/3-style FORMAT record in BIFF4/8 file
  26. # 2007-04-22 SJM Remove experimental "trimming" facility.
  27. from __future__ import print_function
  28. from array import array
  29. from struct import unpack, calcsize
  30. from .biffh import *
  31. from .timemachine import *
  32. from .formula import dump_formula, decompile_formula, rangename2d, FMLA_TYPE_CELL, FMLA_TYPE_SHARED
  33. from .formatting import nearest_colour_index, Format
  34. DEBUG = 0
  35. OBJ_MSO_DEBUG = 0
  36. _WINDOW2_options = (
  37. # Attribute names and initial values to use in case
  38. # a WINDOW2 record is not written.
  39. ("show_formulas", 0),
  40. ("show_grid_lines", 1),
  41. ("show_sheet_headers", 1),
  42. ("panes_are_frozen", 0),
  43. ("show_zero_values", 1),
  44. ("automatic_grid_line_colour", 1),
  45. ("columns_from_right_to_left", 0),
  46. ("show_outline_symbols", 1),
  47. ("remove_splits_if_pane_freeze_is_removed", 0),
  48. # Multiple sheets can be selected, but only one can be active
  49. # (hold down Ctrl and click multiple tabs in the file in OOo)
  50. ("sheet_selected", 0),
  51. # "sheet_visible" should really be called "sheet_active"
  52. # and is 1 when this sheet is the sheet displayed when the file
  53. # is open. More than likely only one sheet should ever be set as
  54. # visible.
  55. # This would correspond to the Book's sheet_active attribute, but
  56. # that doesn't exist as WINDOW1 records aren't currently processed.
  57. # The real thing is the visibility attribute from the BOUNDSHEET record.
  58. ("sheet_visible", 0),
  59. ("show_in_page_break_preview", 0),
  60. )
  61. ##
  62. # <p>Contains the data for one worksheet.</p>
  63. #
  64. # <p>In the cell access functions, "rowx" is a row index, counting from zero, and "colx" is a
  65. # column index, counting from zero.
  66. # Negative values for row/column indexes and slice positions are supported in the expected fashion.</p>
  67. #
  68. # <p>For information about cell types and cell values, refer to the documentation of the {@link #Cell} class.</p>
  69. #
  70. # <p>WARNING: You don't call this class yourself. You access Sheet objects via the Book object that
  71. # was returned when you called xlrd.open_workbook("myfile.xls").</p>
  72. class Sheet(BaseObject):
  73. ##
  74. # Name of sheet.
  75. name = ''
  76. ##
  77. # A reference to the Book object to which this sheet belongs.
  78. # Example usage: some_sheet.book.datemode
  79. book = None
  80. ##
  81. # Number of rows in sheet. A row index is in range(thesheet.nrows).
  82. nrows = 0
  83. ##
  84. # Nominal number of columns in sheet. It is 1 + the maximum column index
  85. # found, ignoring trailing empty cells. See also open_workbook(ragged_rows=?)
  86. # and Sheet.{@link #Sheet.row_len}(row_index).
  87. ncols = 0
  88. ##
  89. # The map from a column index to a {@link #Colinfo} object. Often there is an entry
  90. # in COLINFO records for all column indexes in range(257).
  91. # Note that xlrd ignores the entry for the non-existent
  92. # 257th column. On the other hand, there may be no entry for unused columns.
  93. # <br /> -- New in version 0.6.1. Populated only if open_workbook(formatting_info=True).
  94. colinfo_map = {}
  95. ##
  96. # The map from a row index to a {@link #Rowinfo} object. Note that it is possible
  97. # to have missing entries -- at least one source of XLS files doesn't
  98. # bother writing ROW records.
  99. # <br /> -- New in version 0.6.1. Populated only if open_workbook(formatting_info=True).
  100. rowinfo_map = {}
  101. ##
  102. # List of address ranges of cells containing column labels.
  103. # These are set up in Excel by Insert > Name > Labels > Columns.
  104. # <br> -- New in version 0.6.0
  105. # <br>How to deconstruct the list:
  106. # <pre>
  107. # for crange in thesheet.col_label_ranges:
  108. # rlo, rhi, clo, chi = crange
  109. # for rx in xrange(rlo, rhi):
  110. # for cx in xrange(clo, chi):
  111. # print "Column label at (rowx=%d, colx=%d) is %r" \
  112. # (rx, cx, thesheet.cell_value(rx, cx))
  113. # </pre>
  114. col_label_ranges = []
  115. ##
  116. # List of address ranges of cells containing row labels.
  117. # For more details, see <i>col_label_ranges</i> above.
  118. # <br> -- New in version 0.6.0
  119. row_label_ranges = []
  120. ##
  121. # List of address ranges of cells which have been merged.
  122. # These are set up in Excel by Format > Cells > Alignment, then ticking
  123. # the "Merge cells" box.
  124. # <br> Note that the upper limits are exclusive: i.e. <tt>[2, 3, 7, 9]</tt> only
  125. # spans two cells.
  126. # <br> -- New in version 0.6.1. Extracted only if open_workbook(formatting_info=True).
  127. # <br>How to deconstruct the list:
  128. # <pre>
  129. # for crange in thesheet.merged_cells:
  130. # rlo, rhi, clo, chi = crange
  131. # for rowx in xrange(rlo, rhi):
  132. # for colx in xrange(clo, chi):
  133. # # cell (rlo, clo) (the top left one) will carry the data
  134. # # and formatting info; the remainder will be recorded as
  135. # # blank cells, but a renderer will apply the formatting info
  136. # # for the top left cell (e.g. border, pattern) to all cells in
  137. # # the range.
  138. # </pre>
  139. merged_cells = []
  140. ##
  141. # Mapping of (rowx, colx) to list of (offset, font_index) tuples. The offset
  142. # defines where in the string the font begins to be used.
  143. # Offsets are expected to be in ascending order.
  144. # If the first offset is not zero, the meaning is that the cell's XF's font should
  145. # be used from offset 0.
  146. # <br /> This is a sparse mapping. There is no entry for cells that are not formatted with
  147. # rich text.
  148. # <br>How to use:
  149. # <pre>
  150. # runlist = thesheet.rich_text_runlist_map.get((rowx, colx))
  151. # if runlist:
  152. # for offset, font_index in runlist:
  153. # # do work here.
  154. # pass
  155. # </pre>
  156. # Populated only if open_workbook(formatting_info=True).
  157. # <br /> -- New in version 0.7.2.
  158. # <br /> &nbsp;
  159. rich_text_runlist_map = {}
  160. ##
  161. # Default column width from DEFCOLWIDTH record, else None.
  162. # From the OOo docs:<br />
  163. # """Column width in characters, using the width of the zero character
  164. # from default font (first FONT record in the file). Excel adds some
  165. # extra space to the default width, depending on the default font and
  166. # default font size. The algorithm how to exactly calculate the resulting
  167. # column width is not known.<br />
  168. # Example: The default width of 8 set in this record results in a column
  169. # width of 8.43 using Arial font with a size of 10 points."""<br />
  170. # For the default hierarchy, refer to the {@link #Colinfo} class.
  171. # <br /> -- New in version 0.6.1
  172. defcolwidth = None
  173. ##
  174. # Default column width from STANDARDWIDTH record, else None.
  175. # From the OOo docs:<br />
  176. # """Default width of the columns in 1/256 of the width of the zero
  177. # character, using default font (first FONT record in the file)."""<br />
  178. # For the default hierarchy, refer to the {@link #Colinfo} class.
  179. # <br /> -- New in version 0.6.1
  180. standardwidth = None
  181. ##
  182. # Default value to be used for a row if there is
  183. # no ROW record for that row.
  184. # From the <i>optional</i> DEFAULTROWHEIGHT record.
  185. default_row_height = None
  186. ##
  187. # Default value to be used for a row if there is
  188. # no ROW record for that row.
  189. # From the <i>optional</i> DEFAULTROWHEIGHT record.
  190. default_row_height_mismatch = None
  191. ##
  192. # Default value to be used for a row if there is
  193. # no ROW record for that row.
  194. # From the <i>optional</i> DEFAULTROWHEIGHT record.
  195. default_row_hidden = None
  196. ##
  197. # Default value to be used for a row if there is
  198. # no ROW record for that row.
  199. # From the <i>optional</i> DEFAULTROWHEIGHT record.
  200. default_additional_space_above = None
  201. ##
  202. # Default value to be used for a row if there is
  203. # no ROW record for that row.
  204. # From the <i>optional</i> DEFAULTROWHEIGHT record.
  205. default_additional_space_below = None
  206. ##
  207. # Visibility of the sheet. 0 = visible, 1 = hidden (can be unhidden
  208. # by user -- Format/Sheet/Unhide), 2 = "very hidden" (can be unhidden
  209. # only by VBA macro).
  210. visibility = 0
  211. ##
  212. # A 256-element tuple corresponding to the contents of the GCW record for this sheet.
  213. # If no such record, treat as all bits zero.
  214. # Applies to BIFF4-7 only. See docs of the {@link #Colinfo} class for discussion.
  215. gcw = (0, ) * 256
  216. ##
  217. # <p>A list of {@link #Hyperlink} objects corresponding to HLINK records found
  218. # in the worksheet.<br />-- New in version 0.7.2 </p>
  219. hyperlink_list = []
  220. ##
  221. # <p>A sparse mapping from (rowx, colx) to an item in {@link #Sheet.hyperlink_list}.
  222. # Cells not covered by a hyperlink are not mapped.
  223. # It is possible using the Excel UI to set up a hyperlink that
  224. # covers a larger-than-1x1 rectangle of cells.
  225. # Hyperlink rectangles may overlap (Excel doesn't check).
  226. # When a multiply-covered cell is clicked on, the hyperlink that is activated
  227. # (and the one that is mapped here) is the last in hyperlink_list.
  228. # <br />-- New in version 0.7.2 </p>
  229. hyperlink_map = {}
  230. ##
  231. # <p>A sparse mapping from (rowx, colx) to a {@link #Note} object.
  232. # Cells not containing a note ("comment") are not mapped.
  233. # <br />-- New in version 0.7.2 </p>
  234. cell_note_map = {}
  235. ##
  236. # Number of columns in left pane (frozen panes; for split panes, see comments below in code)
  237. vert_split_pos = 0
  238. ##
  239. # Number of rows in top pane (frozen panes; for split panes, see comments below in code)
  240. horz_split_pos = 0
  241. ##
  242. # Index of first visible row in bottom frozen/split pane
  243. horz_split_first_visible = 0
  244. ##
  245. # Index of first visible column in right frozen/split pane
  246. vert_split_first_visible = 0
  247. ##
  248. # Frozen panes: ignore it. Split panes: explanation and diagrams in OOo docs.
  249. split_active_pane = 0
  250. ##
  251. # Boolean specifying if a PANE record was present, ignore unless you're xlutils.copy
  252. has_pane_record = 0
  253. ##
  254. # A list of the horizontal page breaks in this sheet.
  255. # Breaks are tuples in the form (index of row after break, start col index, end col index).
  256. # Populated only if open_workbook(formatting_info=True).
  257. # <br /> -- New in version 0.7.2
  258. horizontal_page_breaks = []
  259. ##
  260. # A list of the vertical page breaks in this sheet.
  261. # Breaks are tuples in the form (index of col after break, start row index, end row index).
  262. # Populated only if open_workbook(formatting_info=True).
  263. # <br /> -- New in version 0.7.2
  264. vertical_page_breaks = []
  265. def __init__(self, book, position, name, number):
  266. self.book = book
  267. self.biff_version = book.biff_version
  268. self._position = position
  269. self.logfile = book.logfile
  270. self.bt = array('B', [XL_CELL_EMPTY])
  271. self.bf = array('h', [-1])
  272. self.name = name
  273. self.number = number
  274. self.verbosity = book.verbosity
  275. self.formatting_info = book.formatting_info
  276. self.ragged_rows = book.ragged_rows
  277. if self.ragged_rows:
  278. self.put_cell = self.put_cell_ragged
  279. else:
  280. self.put_cell = self.put_cell_unragged
  281. self._xf_index_to_xl_type_map = book._xf_index_to_xl_type_map
  282. self.nrows = 0 # actual, including possibly empty cells
  283. self.ncols = 0
  284. self._maxdatarowx = -1 # highest rowx containing a non-empty cell
  285. self._maxdatacolx = -1 # highest colx containing a non-empty cell
  286. self._dimnrows = 0 # as per DIMENSIONS record
  287. self._dimncols = 0
  288. self._cell_values = []
  289. self._cell_types = []
  290. self._cell_xf_indexes = []
  291. self.defcolwidth = None
  292. self.standardwidth = None
  293. self.default_row_height = None
  294. self.default_row_height_mismatch = 0
  295. self.default_row_hidden = 0
  296. self.default_additional_space_above = 0
  297. self.default_additional_space_below = 0
  298. self.colinfo_map = {}
  299. self.rowinfo_map = {}
  300. self.col_label_ranges = []
  301. self.row_label_ranges = []
  302. self.merged_cells = []
  303. self.rich_text_runlist_map = {}
  304. self.horizontal_page_breaks = []
  305. self.vertical_page_breaks = []
  306. self._xf_index_stats = [0, 0, 0, 0]
  307. self.visibility = book._sheet_visibility[number] # from BOUNDSHEET record
  308. for attr, defval in _WINDOW2_options:
  309. setattr(self, attr, defval)
  310. self.first_visible_rowx = 0
  311. self.first_visible_colx = 0
  312. self.gridline_colour_index = 0x40
  313. self.gridline_colour_rgb = None # pre-BIFF8
  314. self.hyperlink_list = []
  315. self.hyperlink_map = {}
  316. self.cell_note_map = {}
  317. # Values calculated by xlrd to predict the mag factors that
  318. # will actually be used by Excel to display your worksheet.
  319. # Pass these values to xlwt when writing XLS files.
  320. # Warning 1: Behaviour of OOo Calc and Gnumeric has been observed to differ from Excel's.
  321. # Warning 2: A value of zero means almost exactly what it says. Your sheet will be
  322. # displayed as a very tiny speck on the screen. xlwt will reject attempts to set
  323. # a mag_factor that is not (10 <= mag_factor <= 400).
  324. self.cooked_page_break_preview_mag_factor = 60
  325. self.cooked_normal_view_mag_factor = 100
  326. # Values (if any) actually stored on the XLS file
  327. self.cached_page_break_preview_mag_factor = 0 # default (60%), from WINDOW2 record
  328. self.cached_normal_view_mag_factor = 0 # default (100%), from WINDOW2 record
  329. self.scl_mag_factor = None # from SCL record
  330. self._ixfe = None # BIFF2 only
  331. self._cell_attr_to_xfx = {} # BIFF2.0 only
  332. #### Don't initialise this here, use class attribute initialisation.
  333. #### self.gcw = (0, ) * 256 ####
  334. if self.biff_version >= 80:
  335. self.utter_max_rows = 65536
  336. else:
  337. self.utter_max_rows = 16384
  338. self.utter_max_cols = 256
  339. self._first_full_rowx = -1
  340. # self._put_cell_exceptions = 0
  341. # self._put_cell_row_widenings = 0
  342. # self._put_cell_rows_appended = 0
  343. # self._put_cell_cells_appended = 0
  344. ##
  345. # {@link #Cell} object in the given row and column.
  346. def cell(self, rowx, colx):
  347. if self.formatting_info:
  348. xfx = self.cell_xf_index(rowx, colx)
  349. else:
  350. xfx = None
  351. return Cell(
  352. self._cell_types[rowx][colx],
  353. self._cell_values[rowx][colx],
  354. xfx,
  355. )
  356. ##
  357. # Value of the cell in the given row and column.
  358. def cell_value(self, rowx, colx):
  359. return self._cell_values[rowx][colx]
  360. ##
  361. # Type of the cell in the given row and column.
  362. # Refer to the documentation of the {@link #Cell} class.
  363. def cell_type(self, rowx, colx):
  364. return self._cell_types[rowx][colx]
  365. ##
  366. # XF index of the cell in the given row and column.
  367. # This is an index into Book.{@link #Book.xf_list}.
  368. # <br /> -- New in version 0.6.1
  369. def cell_xf_index(self, rowx, colx):
  370. self.req_fmt_info()
  371. xfx = self._cell_xf_indexes[rowx][colx]
  372. if xfx > -1:
  373. self._xf_index_stats[0] += 1
  374. return xfx
  375. # Check for a row xf_index
  376. try:
  377. xfx = self.rowinfo_map[rowx].xf_index
  378. if xfx > -1:
  379. self._xf_index_stats[1] += 1
  380. return xfx
  381. except KeyError:
  382. pass
  383. # Check for a column xf_index
  384. try:
  385. xfx = self.colinfo_map[colx].xf_index
  386. if xfx == -1: xfx = 15
  387. self._xf_index_stats[2] += 1
  388. return xfx
  389. except KeyError:
  390. # If all else fails, 15 is used as hardwired global default xf_index.
  391. self._xf_index_stats[3] += 1
  392. return 15
  393. ##
  394. # Returns the effective number of cells in the given row. For use with
  395. # open_workbook(ragged_rows=True) which is likely to produce rows
  396. # with fewer than {@link #Sheet.ncols} cells.
  397. # <br /> -- New in version 0.7.2
  398. def row_len(self, rowx):
  399. return len(self._cell_values[rowx])
  400. ##
  401. # Returns a sequence of the {@link #Cell} objects in the given row.
  402. def row(self, rowx):
  403. return [
  404. self.cell(rowx, colx)
  405. for colx in xrange(len(self._cell_values[rowx]))
  406. ]
  407. ##
  408. # Returns a generator for iterating through each row.
  409. def get_rows(self):
  410. return (self.row(index) for index in range(self.nrows))
  411. ##
  412. # Returns a slice of the types
  413. # of the cells in the given row.
  414. def row_types(self, rowx, start_colx=0, end_colx=None):
  415. if end_colx is None:
  416. return self._cell_types[rowx][start_colx:]
  417. return self._cell_types[rowx][start_colx:end_colx]
  418. ##
  419. # Returns a slice of the values
  420. # of the cells in the given row.
  421. def row_values(self, rowx, start_colx=0, end_colx=None):
  422. if end_colx is None:
  423. return self._cell_values[rowx][start_colx:]
  424. return self._cell_values[rowx][start_colx:end_colx]
  425. ##
  426. # Returns a slice of the {@link #Cell} objects in the given row.
  427. def row_slice(self, rowx, start_colx=0, end_colx=None):
  428. nc = len(self._cell_values[rowx])
  429. if start_colx < 0:
  430. start_colx += nc
  431. if start_colx < 0:
  432. start_colx = 0
  433. if end_colx is None or end_colx > nc:
  434. end_colx = nc
  435. elif end_colx < 0:
  436. end_colx += nc
  437. return [
  438. self.cell(rowx, colx)
  439. for colx in xrange(start_colx, end_colx)
  440. ]
  441. ##
  442. # Returns a slice of the {@link #Cell} objects in the given column.
  443. def col_slice(self, colx, start_rowx=0, end_rowx=None):
  444. nr = self.nrows
  445. if start_rowx < 0:
  446. start_rowx += nr
  447. if start_rowx < 0:
  448. start_rowx = 0
  449. if end_rowx is None or end_rowx > nr:
  450. end_rowx = nr
  451. elif end_rowx < 0:
  452. end_rowx += nr
  453. return [
  454. self.cell(rowx, colx)
  455. for rowx in xrange(start_rowx, end_rowx)
  456. ]
  457. ##
  458. # Returns a slice of the values of the cells in the given column.
  459. def col_values(self, colx, start_rowx=0, end_rowx=None):
  460. nr = self.nrows
  461. if start_rowx < 0:
  462. start_rowx += nr
  463. if start_rowx < 0:
  464. start_rowx = 0
  465. if end_rowx is None or end_rowx > nr:
  466. end_rowx = nr
  467. elif end_rowx < 0:
  468. end_rowx += nr
  469. return [
  470. self._cell_values[rowx][colx]
  471. for rowx in xrange(start_rowx, end_rowx)
  472. ]
  473. ##
  474. # Returns a slice of the types of the cells in the given column.
  475. def col_types(self, colx, start_rowx=0, end_rowx=None):
  476. nr = self.nrows
  477. if start_rowx < 0:
  478. start_rowx += nr
  479. if start_rowx < 0:
  480. start_rowx = 0
  481. if end_rowx is None or end_rowx > nr:
  482. end_rowx = nr
  483. elif end_rowx < 0:
  484. end_rowx += nr
  485. return [
  486. self._cell_types[rowx][colx]
  487. for rowx in xrange(start_rowx, end_rowx)
  488. ]
  489. ##
  490. # Returns a sequence of the {@link #Cell} objects in the given column.
  491. def col(self, colx):
  492. return self.col_slice(colx)
  493. # Above two lines just for the docs. Here's the real McCoy:
  494. col = col_slice
  495. # === Following methods are used in building the worksheet.
  496. # === They are not part of the API.
  497. def tidy_dimensions(self):
  498. if self.verbosity >= 3:
  499. fprintf(self.logfile,
  500. "tidy_dimensions: nrows=%d ncols=%d \n",
  501. self.nrows, self.ncols,
  502. )
  503. if 1 and self.merged_cells:
  504. nr = nc = 0
  505. umaxrows = self.utter_max_rows
  506. umaxcols = self.utter_max_cols
  507. for crange in self.merged_cells:
  508. rlo, rhi, clo, chi = crange
  509. if not (0 <= rlo < rhi <= umaxrows) \
  510. or not (0 <= clo < chi <= umaxcols):
  511. fprintf(self.logfile,
  512. "*** WARNING: sheet #%d (%r), MERGEDCELLS bad range %r\n",
  513. self.number, self.name, crange)
  514. if rhi > nr: nr = rhi
  515. if chi > nc: nc = chi
  516. if nc > self.ncols:
  517. self.ncols = nc
  518. self._first_full_rowx = -2
  519. if nr > self.nrows:
  520. # we put one empty cell at (nr-1,0) to make sure
  521. # we have the right number of rows. The ragged rows
  522. # will sort out the rest if needed.
  523. self.put_cell(nr-1, 0, XL_CELL_EMPTY, UNICODE_LITERAL(''), -1)
  524. if self.verbosity >= 1 \
  525. and (self.nrows != self._dimnrows or self.ncols != self._dimncols):
  526. fprintf(self.logfile,
  527. "NOTE *** sheet %d (%r): DIMENSIONS R,C = %d,%d should be %d,%d\n",
  528. self.number,
  529. self.name,
  530. self._dimnrows,
  531. self._dimncols,
  532. self.nrows,
  533. self.ncols,
  534. )
  535. if not self.ragged_rows:
  536. # fix ragged rows
  537. ncols = self.ncols
  538. s_cell_types = self._cell_types
  539. s_cell_values = self._cell_values
  540. s_cell_xf_indexes = self._cell_xf_indexes
  541. s_fmt_info = self.formatting_info
  542. # for rowx in xrange(self.nrows):
  543. if self._first_full_rowx == -2:
  544. ubound = self.nrows
  545. else:
  546. ubound = self._first_full_rowx
  547. for rowx in xrange(ubound):
  548. trow = s_cell_types[rowx]
  549. rlen = len(trow)
  550. nextra = ncols - rlen
  551. if nextra > 0:
  552. s_cell_values[rowx][rlen:] = [UNICODE_LITERAL('')] * nextra
  553. trow[rlen:] = self.bt * nextra
  554. if s_fmt_info:
  555. s_cell_xf_indexes[rowx][rlen:] = self.bf * nextra
  556. def put_cell_ragged(self, rowx, colx, ctype, value, xf_index):
  557. if ctype is None:
  558. # we have a number, so look up the cell type
  559. ctype = self._xf_index_to_xl_type_map[xf_index]
  560. assert 0 <= colx < self.utter_max_cols
  561. assert 0 <= rowx < self.utter_max_rows
  562. fmt_info = self.formatting_info
  563. try:
  564. nr = rowx + 1
  565. if self.nrows < nr:
  566. scta = self._cell_types.append
  567. scva = self._cell_values.append
  568. scxa = self._cell_xf_indexes.append
  569. bt = self.bt
  570. bf = self.bf
  571. for _unused in xrange(self.nrows, nr):
  572. scta(bt * 0)
  573. scva([])
  574. if fmt_info:
  575. scxa(bf * 0)
  576. self.nrows = nr
  577. types_row = self._cell_types[rowx]
  578. values_row = self._cell_values[rowx]
  579. if fmt_info:
  580. fmt_row = self._cell_xf_indexes[rowx]
  581. ltr = len(types_row)
  582. if colx >= self.ncols:
  583. self.ncols = colx + 1
  584. num_empty = colx - ltr
  585. if not num_empty:
  586. # most common case: colx == previous colx + 1
  587. # self._put_cell_cells_appended += 1
  588. types_row.append(ctype)
  589. values_row.append(value)
  590. if fmt_info:
  591. fmt_row.append(xf_index)
  592. return
  593. if num_empty > 0:
  594. num_empty += 1
  595. # self._put_cell_row_widenings += 1
  596. # types_row.extend(self.bt * num_empty)
  597. # values_row.extend([UNICODE_LITERAL('')] * num_empty)
  598. # if fmt_info:
  599. # fmt_row.extend(self.bf * num_empty)
  600. types_row[ltr:] = self.bt * num_empty
  601. values_row[ltr:] = [UNICODE_LITERAL('')] * num_empty
  602. if fmt_info:
  603. fmt_row[ltr:] = self.bf * num_empty
  604. types_row[colx] = ctype
  605. values_row[colx] = value
  606. if fmt_info:
  607. fmt_row[colx] = xf_index
  608. except:
  609. print("put_cell", rowx, colx, file=self.logfile)
  610. raise
  611. def put_cell_unragged(self, rowx, colx, ctype, value, xf_index):
  612. if ctype is None:
  613. # we have a number, so look up the cell type
  614. ctype = self._xf_index_to_xl_type_map[xf_index]
  615. # assert 0 <= colx < self.utter_max_cols
  616. # assert 0 <= rowx < self.utter_max_rows
  617. try:
  618. self._cell_types[rowx][colx] = ctype
  619. self._cell_values[rowx][colx] = value
  620. if self.formatting_info:
  621. self._cell_xf_indexes[rowx][colx] = xf_index
  622. except IndexError:
  623. # print >> self.logfile, "put_cell extending", rowx, colx
  624. # self.extend_cells(rowx+1, colx+1)
  625. # self._put_cell_exceptions += 1
  626. nr = rowx + 1
  627. nc = colx + 1
  628. assert 1 <= nc <= self.utter_max_cols
  629. assert 1 <= nr <= self.utter_max_rows
  630. if nc > self.ncols:
  631. self.ncols = nc
  632. # The row self._first_full_rowx and all subsequent rows
  633. # are guaranteed to have length == self.ncols. Thus the
  634. # "fix ragged rows" section of the tidy_dimensions method
  635. # doesn't need to examine them.
  636. if nr < self.nrows:
  637. # cell data is not in non-descending row order *AND*
  638. # self.ncols has been bumped up.
  639. # This very rare case ruins this optmisation.
  640. self._first_full_rowx = -2
  641. elif rowx > self._first_full_rowx > -2:
  642. self._first_full_rowx = rowx
  643. if nr <= self.nrows:
  644. # New cell is in an existing row, so extend that row (if necessary).
  645. # Note that nr < self.nrows means that the cell data
  646. # is not in ascending row order!!
  647. trow = self._cell_types[rowx]
  648. nextra = self.ncols - len(trow)
  649. if nextra > 0:
  650. # self._put_cell_row_widenings += 1
  651. trow.extend(self.bt * nextra)
  652. if self.formatting_info:
  653. self._cell_xf_indexes[rowx].extend(self.bf * nextra)
  654. self._cell_values[rowx].extend([UNICODE_LITERAL('')] * nextra)
  655. else:
  656. scta = self._cell_types.append
  657. scva = self._cell_values.append
  658. scxa = self._cell_xf_indexes.append
  659. fmt_info = self.formatting_info
  660. nc = self.ncols
  661. bt = self.bt
  662. bf = self.bf
  663. for _unused in xrange(self.nrows, nr):
  664. # self._put_cell_rows_appended += 1
  665. scta(bt * nc)
  666. scva([UNICODE_LITERAL('')] * nc)
  667. if fmt_info:
  668. scxa(bf * nc)
  669. self.nrows = nr
  670. # === end of code from extend_cells()
  671. try:
  672. self._cell_types[rowx][colx] = ctype
  673. self._cell_values[rowx][colx] = value
  674. if self.formatting_info:
  675. self._cell_xf_indexes[rowx][colx] = xf_index
  676. except:
  677. print("put_cell", rowx, colx, file=self.logfile)
  678. raise
  679. except:
  680. print("put_cell", rowx, colx, file=self.logfile)
  681. raise
  682. # === Methods after this line neither know nor care about how cells are stored.
  683. def read(self, bk):
  684. global rc_stats
  685. DEBUG = 0
  686. blah = DEBUG or self.verbosity >= 2
  687. blah_rows = DEBUG or self.verbosity >= 4
  688. blah_formulas = 0 and blah
  689. r1c1 = 0
  690. oldpos = bk._position
  691. bk._position = self._position
  692. XL_SHRFMLA_ETC_ETC = (
  693. XL_SHRFMLA, XL_ARRAY, XL_TABLEOP, XL_TABLEOP2,
  694. XL_ARRAY2, XL_TABLEOP_B2,
  695. )
  696. self_put_cell = self.put_cell
  697. local_unpack = unpack
  698. bk_get_record_parts = bk.get_record_parts
  699. bv = self.biff_version
  700. fmt_info = self.formatting_info
  701. do_sst_rich_text = fmt_info and bk._rich_text_runlist_map
  702. rowinfo_sharing_dict = {}
  703. txos = {}
  704. eof_found = 0
  705. while 1:
  706. # if DEBUG: print "SHEET.READ: about to read from position %d" % bk._position
  707. rc, data_len, data = bk_get_record_parts()
  708. # if rc in rc_stats:
  709. # rc_stats[rc] += 1
  710. # else:
  711. # rc_stats[rc] = 1
  712. # if DEBUG: print "SHEET.READ: op 0x%04x, %d bytes %r" % (rc, data_len, data)
  713. if rc == XL_NUMBER:
  714. # [:14] in following stmt ignores extraneous rubbish at end of record.
  715. # Sample file testEON-8.xls supplied by Jan Kraus.
  716. rowx, colx, xf_index, d = local_unpack('<HHHd', data[:14])
  717. # if xf_index == 0:
  718. # fprintf(self.logfile,
  719. # "NUMBER: r=%d c=%d xfx=%d %f\n", rowx, colx, xf_index, d)
  720. self_put_cell(rowx, colx, None, d, xf_index)
  721. elif rc == XL_LABELSST:
  722. rowx, colx, xf_index, sstindex = local_unpack('<HHHi', data)
  723. # print "LABELSST", rowx, colx, sstindex, bk._sharedstrings[sstindex]
  724. self_put_cell(rowx, colx, XL_CELL_TEXT, bk._sharedstrings[sstindex], xf_index)
  725. if do_sst_rich_text:
  726. runlist = bk._rich_text_runlist_map.get(sstindex)
  727. if runlist:
  728. self.rich_text_runlist_map[(rowx, colx)] = runlist
  729. elif rc == XL_LABEL:
  730. rowx, colx, xf_index = local_unpack('<HHH', data[0:6])
  731. if bv < BIFF_FIRST_UNICODE:
  732. strg = unpack_string(data, 6, bk.encoding or bk.derive_encoding(), lenlen=2)
  733. else:
  734. strg = unpack_unicode(data, 6, lenlen=2)
  735. self_put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index)
  736. elif rc == XL_RSTRING:
  737. rowx, colx, xf_index = local_unpack('<HHH', data[0:6])
  738. if bv < BIFF_FIRST_UNICODE:
  739. strg, pos = unpack_string_update_pos(data, 6, bk.encoding or bk.derive_encoding(), lenlen=2)
  740. nrt = BYTES_ORD(data[pos])
  741. pos += 1
  742. runlist = []
  743. for _unused in xrange(nrt):
  744. runlist.append(unpack('<BB', data[pos:pos+2]))
  745. pos += 2
  746. assert pos == len(data)
  747. else:
  748. strg, pos = unpack_unicode_update_pos(data, 6, lenlen=2)
  749. nrt = unpack('<H', data[pos:pos+2])[0]
  750. pos += 2
  751. runlist = []
  752. for _unused in xrange(nrt):
  753. runlist.append(unpack('<HH', data[pos:pos+4]))
  754. pos += 4
  755. assert pos == len(data)
  756. self_put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index)
  757. self.rich_text_runlist_map[(rowx, colx)] = runlist
  758. elif rc == XL_RK:
  759. rowx, colx, xf_index = local_unpack('<HHH', data[:6])
  760. d = unpack_RK(data[6:10])
  761. self_put_cell(rowx, colx, None, d, xf_index)
  762. elif rc == XL_MULRK:
  763. mulrk_row, mulrk_first = local_unpack('<HH', data[0:4])
  764. mulrk_last, = local_unpack('<H', data[-2:])
  765. pos = 4
  766. for colx in xrange(mulrk_first, mulrk_last+1):
  767. xf_index, = local_unpack('<H', data[pos:pos+2])
  768. d = unpack_RK(data[pos+2:pos+6])
  769. pos += 6
  770. self_put_cell(mulrk_row, colx, None, d, xf_index)
  771. elif rc == XL_ROW:
  772. # Version 0.6.0a3: ROW records are just not worth using (for memory allocation).
  773. # Version 0.6.1: now used for formatting info.
  774. if not fmt_info: continue
  775. rowx, bits1, bits2 = local_unpack('<H4xH4xi', data[0:16])
  776. if not(0 <= rowx < self.utter_max_rows):
  777. print("*** NOTE: ROW record has row index %d; " \
  778. "should have 0 <= rowx < %d -- record ignored!" \
  779. % (rowx, self.utter_max_rows), file=self.logfile)
  780. continue
  781. key = (bits1, bits2)
  782. r = rowinfo_sharing_dict.get(key)
  783. if r is None:
  784. rowinfo_sharing_dict[key] = r = Rowinfo()
  785. # Using upkbits() is far too slow on a file
  786. # with 30 sheets each with 10K rows :-(
  787. # upkbits(r, bits1, (
  788. # ( 0, 0x7FFF, 'height'),
  789. # (15, 0x8000, 'has_default_height'),
  790. # ))
  791. # upkbits(r, bits2, (
  792. # ( 0, 0x00000007, 'outline_level'),
  793. # ( 4, 0x00000010, 'outline_group_starts_ends'),
  794. # ( 5, 0x00000020, 'hidden'),
  795. # ( 6, 0x00000040, 'height_mismatch'),
  796. # ( 7, 0x00000080, 'has_default_xf_index'),
  797. # (16, 0x0FFF0000, 'xf_index'),
  798. # (28, 0x10000000, 'additional_space_above'),
  799. # (29, 0x20000000, 'additional_space_below'),
  800. # ))
  801. # So:
  802. r.height = bits1 & 0x7fff
  803. r.has_default_height = (bits1 >> 15) & 1
  804. r.outline_level = bits2 & 7
  805. r.outline_group_starts_ends = (bits2 >> 4) & 1
  806. r.hidden = (bits2 >> 5) & 1
  807. r.height_mismatch = (bits2 >> 6) & 1
  808. r.has_default_xf_index = (bits2 >> 7) & 1
  809. r.xf_index = (bits2 >> 16) & 0xfff
  810. r.additional_space_above = (bits2 >> 28) & 1
  811. r.additional_space_below = (bits2 >> 29) & 1
  812. if not r.has_default_xf_index:
  813. r.xf_index = -1
  814. self.rowinfo_map[rowx] = r
  815. if 0 and r.xf_index > -1:
  816. fprintf(self.logfile,
  817. "**ROW %d %d %d\n",
  818. self.number, rowx, r.xf_index)
  819. if blah_rows:
  820. print('ROW', rowx, bits1, bits2, file=self.logfile)
  821. r.dump(self.logfile,
  822. header="--- sh #%d, rowx=%d ---" % (self.number, rowx))
  823. elif rc in XL_FORMULA_OPCODES: # 06, 0206, 0406
  824. # DEBUG = 1
  825. # if DEBUG: print "FORMULA: rc: 0x%04x data: %r" % (rc, data)
  826. if bv >= 50:
  827. rowx, colx, xf_index, result_str, flags = local_unpack('<HHH8sH', data[0:16])
  828. lenlen = 2
  829. tkarr_offset = 20
  830. elif bv >= 30:
  831. rowx, colx, xf_index, result_str, flags = local_unpack('<HHH8sH', data[0:16])
  832. lenlen = 2
  833. tkarr_offset = 16
  834. else: # BIFF2
  835. rowx, colx, cell_attr, result_str, flags = local_unpack('<HH3s8sB', data[0:16])
  836. xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx, colx)
  837. lenlen = 1
  838. tkarr_offset = 16
  839. if blah_formulas: # testing formula dumper
  840. #### XXXX FIXME
  841. fprintf(self.logfile, "FORMULA: rowx=%d colx=%d\n", rowx, colx)
  842. fmlalen = local_unpack("<H", data[20:22])[0]
  843. decompile_formula(bk, data[22:], fmlalen, FMLA_TYPE_CELL,
  844. browx=rowx, bcolx=colx, blah=1, r1c1=r1c1)
  845. if result_str[6:8] == b"\xFF\xFF":
  846. first_byte = BYTES_ORD(result_str[0])
  847. if first_byte == 0:
  848. # need to read next record (STRING)
  849. gotstring = 0
  850. # if flags & 8:
  851. if 1: # "flags & 8" applies only to SHRFMLA
  852. # actually there's an optional SHRFMLA or ARRAY etc record to skip over
  853. rc2, data2_len, data2 = bk.get_record_parts()
  854. if rc2 == XL_STRING or rc2 == XL_STRING_B2:
  855. gotstring = 1
  856. elif rc2 == XL_ARRAY:
  857. row1x, rownx, col1x, colnx, array_flags, tokslen = \
  858. local_unpack("<HHBBBxxxxxH", data2[:14])
  859. if blah_formulas:
  860. fprintf(self.logfile, "ARRAY: %d %d %d %d %d\n",
  861. row1x, rownx, col1x, colnx, array_flags)
  862. # dump_formula(bk, data2[14:], tokslen, bv, reldelta=0, blah=1)
  863. elif rc2 == XL_SHRFMLA:
  864. row1x, rownx, col1x, colnx, nfmlas, tokslen = \
  865. local_unpack("<HHBBxBH", data2[:10])
  866. if blah_formulas:
  867. fprintf(self.logfile, "SHRFMLA (sub): %d %d %d %d %d\n",
  868. row1x, rownx, col1x, colnx, nfmlas)
  869. decompile_formula(bk, data2[10:], tokslen, FMLA_TYPE_SHARED,
  870. blah=1, browx=rowx, bcolx=colx, r1c1=r1c1)
  871. elif rc2 not in XL_SHRFMLA_ETC_ETC:
  872. raise XLRDError(
  873. "Expected SHRFMLA, ARRAY, TABLEOP* or STRING record; found 0x%04x" % rc2)
  874. # if DEBUG: print "gotstring:", gotstring
  875. # now for the STRING record
  876. if not gotstring:
  877. rc2, _unused_len, data2 = bk.get_record_parts()
  878. if rc2 not in (XL_STRING, XL_STRING_B2):
  879. raise XLRDError("Expected STRING record; found 0x%04x" % rc2)
  880. # if DEBUG: print "STRING: data=%r BIFF=%d cp=%d" % (data2, self.biff_version, bk.encoding)
  881. strg = self.string_record_contents(data2)
  882. self.put_cell(rowx, colx, XL_CELL_TEXT, strg, xf_index)
  883. # if DEBUG: print "FORMULA strg %r" % strg
  884. elif first_byte == 1:
  885. # boolean formula result
  886. value = BYTES_ORD(result_str[2])
  887. self_put_cell(rowx, colx, XL_CELL_BOOLEAN, value, xf_index)
  888. elif first_byte == 2:
  889. # Error in cell
  890. value = BYTES_ORD(result_str[2])
  891. self_put_cell(rowx, colx, XL_CELL_ERROR, value, xf_index)
  892. elif first_byte == 3:
  893. # empty ... i.e. empty (zero-length) string, NOT an empty cell.
  894. self_put_cell(rowx, colx, XL_CELL_TEXT, "", xf_index)
  895. else:
  896. raise XLRDError("unexpected special case (0x%02x) in FORMULA" % first_byte)
  897. else:
  898. # it is a number
  899. d = local_unpack('<d', result_str)[0]
  900. self_put_cell(rowx, colx, None, d, xf_index)
  901. elif rc == XL_BOOLERR:
  902. rowx, colx, xf_index, value, is_err = local_unpack('<HHHBB', data[:8])
  903. # Note OOo Calc 2.0 writes 9-byte BOOLERR records.
  904. # OOo docs say 8. Excel writes 8.
  905. cellty = (XL_CELL_BOOLEAN, XL_CELL_ERROR)[is_err]
  906. # if DEBUG: print "XL_BOOLERR", rowx, colx, xf_index, value, is_err
  907. self_put_cell(rowx, colx, cellty, value, xf_index)
  908. elif rc == XL_COLINFO:
  909. if not fmt_info: continue
  910. c = Colinfo()
  911. first_colx, last_colx, c.width, c.xf_index, flags \
  912. = local_unpack("<HHHHH", data[:10])
  913. #### Colinfo.width is denominated in 256ths of a character,
  914. #### *not* in characters.
  915. if not(0 <= first_colx <= last_colx <= 256):
  916. # Note: 256 instead of 255 is a common mistake.
  917. # We silently ignore the non-existing 257th column in that case.
  918. print("*** NOTE: COLINFO record has first col index %d, last %d; " \
  919. "should have 0 <= first <= last <= 255 -- record ignored!" \
  920. % (first_colx, last_colx), file=self.logfile)
  921. del c
  922. continue
  923. upkbits(c, flags, (
  924. ( 0, 0x0001, 'hidden'),
  925. ( 1, 0x0002, 'bit1_flag'),
  926. # *ALL* colinfos created by Excel in "default" cases are 0x0002!!
  927. # Maybe it's "locked" by analogy with XFProtection data.
  928. ( 8, 0x0700, 'outline_level'),
  929. (12, 0x1000, 'collapsed'),
  930. ))
  931. for colx in xrange(first_colx, last_colx+1):
  932. if colx > 255: break # Excel does 0 to 256 inclusive
  933. self.colinfo_map[colx] = c
  934. if 0:
  935. fprintf(self.logfile,
  936. "**COL %d %d %d\n",
  937. self.number, colx, c.xf_index)
  938. if blah:
  939. fprintf(
  940. self.logfile,
  941. "COLINFO sheet #%d cols %d-%d: wid=%d xf_index=%d flags=0x%04x\n",
  942. self.number, first_colx, last_colx, c.width, c.xf_index, flags,
  943. )
  944. c.dump(self.logfile, header='===')
  945. elif rc == XL_DEFCOLWIDTH:
  946. self.defcolwidth, = local_unpack("<H", data[:2])
  947. if 0: print('DEFCOLWIDTH', self.defcolwidth, file=self.logfile)
  948. elif rc == XL_STANDARDWIDTH:
  949. if data_len != 2:
  950. print('*** ERROR *** STANDARDWIDTH', data_len, repr(data), file=self.logfile)
  951. self.standardwidth, = local_unpack("<H", data[:2])
  952. if 0: print('STANDARDWIDTH', self.standardwidth, file=self.logfile)
  953. elif rc == XL_GCW:
  954. if not fmt_info: continue # useless w/o COLINFO
  955. assert data_len == 34
  956. assert data[0:2] == b"\x20\x00"
  957. iguff = unpack("<8i", data[2:34])
  958. gcw = []
  959. for bits in iguff:
  960. for j in xrange(32):
  961. gcw.append(bits & 1)
  962. bits >>= 1
  963. self.gcw = tuple(gcw)
  964. if 0:
  965. showgcw = "".join(map(lambda x: "F "[x], gcw)).rstrip().replace(' ', '.')
  966. print("GCW:", showgcw, file=self.logfile)
  967. elif rc == XL_BLANK:
  968. if not fmt_info: continue
  969. rowx, colx, xf_index = local_unpack('<HHH', data[:6])
  970. # if 0: print >> self.logfile, "BLANK", rowx, colx, xf_index
  971. self_put_cell(rowx, colx, XL_CELL_BLANK, '', xf_index)
  972. elif rc == XL_MULBLANK: # 00BE
  973. if not fmt_info: continue
  974. nitems = data_len >> 1
  975. result = local_unpack("<%dH" % nitems, data)
  976. rowx, mul_first = result[:2]
  977. mul_last = result[-1]
  978. # print >> self.logfile, "MULBLANK", rowx, mul_first, mul_last, data_len, nitems, mul_last + 4 - mul_first
  979. assert nitems == mul_last + 4 - mul_first
  980. pos = 2
  981. for colx in xrange(mul_first, mul_last + 1):
  982. self_put_cell(rowx, colx, XL_CELL_BLANK, '', result[pos])
  983. pos += 1
  984. elif rc == XL_DIMENSION or rc == XL_DIMENSION2:
  985. if data_len == 0:
  986. # Four zero bytes after some other record. See github issue 64.
  987. continue
  988. # if data_len == 10:
  989. # Was crashing on BIFF 4.0 file w/o the two trailing unused bytes.
  990. # Reported by Ralph Heimburger.
  991. if bv < 80:
  992. dim_tuple = local_unpack('<HxxH', data[2:8])
  993. else:
  994. dim_tuple = local_unpack('<ixxH', data[4:12])
  995. self.nrows, self.ncols = 0, 0
  996. self._dimnrows, self._dimncols = dim_tuple
  997. if bv in (21, 30, 40) and self.book.xf_list and not self.book._xf_epilogue_done:
  998. self.book.xf_epilogue()
  999. if blah:
  1000. fprintf(self.logfile,
  1001. "sheet %d(%r) DIMENSIONS: ncols=%d nrows=%d\n",
  1002. self.number, self.name, self._dimncols, self._dimnrows
  1003. )
  1004. elif rc == XL_HLINK:
  1005. self.handle_hlink(data)
  1006. elif rc == XL_QUICKTIP:
  1007. self.handle_quicktip(data)
  1008. elif rc == XL_EOF:
  1009. DEBUG = 0
  1010. if DEBUG: print("SHEET.READ: EOF", file=self.logfile)
  1011. eof_found = 1
  1012. break
  1013. elif rc == XL_OBJ:
  1014. # handle SHEET-level objects; note there's a separate Book.handle_obj
  1015. saved_obj = self.handle_obj(data)
  1016. if saved_obj: saved_obj_id = saved_obj.id
  1017. else: saved_obj_id = None
  1018. elif rc == XL_MSO_DRAWING:
  1019. self.handle_msodrawingetc(rc, data_len, data)
  1020. elif rc == XL_TXO:
  1021. txo = self.handle_txo(data)
  1022. if txo and saved_obj_id:
  1023. txos[saved_obj_id] = txo
  1024. saved_obj_id = None
  1025. elif rc == XL_NOTE:
  1026. self.handle_note(data, txos)
  1027. elif rc == XL_FEAT11:
  1028. self.handle_feat11(data)
  1029. elif rc in bofcodes: ##### EMBEDDED BOF #####
  1030. version, boftype = local_unpack('<HH', data[0:4])
  1031. if boftype != 0x20: # embedded chart
  1032. print("*** Unexpected embedded BOF (0x%04x) at offset %d: version=0x%04x type=0x%04x" \
  1033. % (rc, bk._position - data_len - 4, version, boftype), file=self.logfile)
  1034. while 1:
  1035. code, data_len, data = bk.get_record_parts()
  1036. if code == XL_EOF:
  1037. break
  1038. if DEBUG: print("---> found EOF", file=self.logfile)
  1039. elif rc == XL_COUNTRY:
  1040. bk.handle_country(data)
  1041. elif rc == XL_LABELRANGES:
  1042. pos = 0
  1043. pos = unpack_cell_range_address_list_update_pos(
  1044. self.row_label_ranges, data, pos, bv, addr_size=8,
  1045. )
  1046. pos = unpack_cell_range_address_list_update_pos(
  1047. self.col_label_ranges, data, pos, bv, addr_size=8,
  1048. )
  1049. assert pos == data_len
  1050. elif rc == XL_ARRAY:
  1051. row1x, rownx, col1x, colnx, array_flags, tokslen = \
  1052. local_unpack("<HHBBBxxxxxH", data[:14])
  1053. if blah_formulas:
  1054. print("ARRAY:", row1x, rownx, col1x, colnx, array_flags, file=self.logfile)
  1055. # dump_formula(bk, data[14:], tokslen, bv, reldelta=0, blah=1)
  1056. elif rc == XL_SHRFMLA:
  1057. row1x, rownx, col1x, colnx, nfmlas, tokslen = \
  1058. local_unpack("<HHBBxBH", data[:10])
  1059. if blah_formulas:
  1060. print("SHRFMLA (main):", row1x, rownx, col1x, colnx, nfmlas, file=self.logfile)
  1061. decompile_formula(bk, data[10:], tokslen, FMLA_TYPE_SHARED,
  1062. blah=1, browx=rowx, bcolx=colx, r1c1=r1c1)
  1063. elif rc == XL_CONDFMT:
  1064. if not fmt_info: continue
  1065. assert bv >= 80
  1066. num_CFs, needs_recalc, browx1, browx2, bcolx1, bcolx2 = \
  1067. unpack("<6H", data[0:12])
  1068. if self.verbosity >= 1:
  1069. fprintf(self.logfile,
  1070. "\n*** WARNING: Ignoring CONDFMT (conditional formatting) record\n" \
  1071. "*** in Sheet %d (%r).\n" \
  1072. "*** %d CF record(s); needs_recalc_or_redraw = %d\n" \
  1073. "*** Bounding box is %s\n",
  1074. self.number, self.name, num_CFs, needs_recalc,
  1075. rangename2d(browx1, browx2+1, bcolx1, bcolx2+1),
  1076. )
  1077. olist = [] # updated by the function
  1078. pos = unpack_cell_range_address_list_update_pos(
  1079. olist, data, 12, bv, addr_size=8)
  1080. # print >> self.logfile, repr(result), len(result)
  1081. if self.verbosity >= 1:
  1082. fprintf(self.logfile,
  1083. "*** %d individual range(s):\n" \
  1084. "*** %s\n",
  1085. len(olist),
  1086. ", ".join([rangename2d(*coords) for coords in olist]),
  1087. )
  1088. elif rc == XL_CF:
  1089. if not fmt_info: continue
  1090. cf_type, cmp_op, sz1, sz2, flags = unpack("<BBHHi", data[0:10])
  1091. font_block = (flags >> 26) & 1
  1092. bord_block = (flags >> 28) & 1
  1093. patt_block = (flags >> 29) & 1
  1094. if self.verbosity >= 1:
  1095. fprintf(self.logfile,
  1096. "\n*** WARNING: Ignoring CF (conditional formatting) sub-record.\n" \
  1097. "*** cf_type=%d, cmp_op=%d, sz1=%d, sz2=%d, flags=0x%08x\n" \
  1098. "*** optional data blocks: font=%d, border=%d, pattern=%d\n",
  1099. cf_type, cmp_op, sz1, sz2, flags,
  1100. font_block, bord_block, patt_block,
  1101. )
  1102. # hex_char_dump(data, 0, data_len, fout=self.logfile)
  1103. pos = 12
  1104. if font_block:
  1105. (font_height, font_options, weight, escapement, underline,
  1106. font_colour_index, two_bits, font_esc, font_underl) = \
  1107. unpack("<64x i i H H B 3x i 4x i i i 18x", data[pos:pos+118])
  1108. font_style = (two_bits > 1) & 1
  1109. posture = (font_options > 1) & 1
  1110. font_canc = (two_bits > 7) & 1
  1111. cancellation = (font_options > 7) & 1
  1112. if self.verbosity >= 1:
  1113. fprintf(self.logfile,
  1114. "*** Font info: height=%d, weight=%d, escapement=%d,\n" \
  1115. "*** underline=%d, colour_index=%d, esc=%d, underl=%d,\n" \
  1116. "*** style=%d, posture=%d, canc=%d, cancellation=%d\n",
  1117. font_height, weight, escapement, underline,
  1118. font_colour_index, font_esc, font_underl,
  1119. font_style, posture, font_canc, cancellation,
  1120. )
  1121. pos += 118
  1122. if bord_block:
  1123. pos += 8
  1124. if patt_block:
  1125. pos += 4
  1126. fmla1 = data[pos:pos+sz1]
  1127. pos += sz1
  1128. if blah and sz1:
  1129. fprintf(self.logfile,
  1130. "*** formula 1:\n",
  1131. )
  1132. dump_formula(bk, fmla1, sz1, bv, reldelta=0, blah=1)
  1133. fmla2 = data[pos:pos+sz2]
  1134. pos += sz2
  1135. assert pos == data_len
  1136. if blah and sz2:
  1137. fprintf(self.logfile,
  1138. "*** formula 2:\n",
  1139. )
  1140. dump_formula(bk, fmla2, sz2, bv, reldelta=0, blah=1)
  1141. elif rc == XL_DEFAULTROWHEIGHT:
  1142. if data_len == 4:
  1143. bits, self.default_row_height = unpack("<HH", data[:4])
  1144. elif data_len == 2:
  1145. self.default_row_height, = unpack("<H", data)
  1146. bits = 0
  1147. fprintf(self.logfile,
  1148. "*** WARNING: DEFAULTROWHEIGHT record len is 2, " \
  1149. "should be 4; assuming BIFF2 format\n")
  1150. else:
  1151. bits = 0
  1152. fprintf(self.logfile,
  1153. "*** WARNING: DEFAULTROWHEIGHT record len is %d, " \
  1154. "should be 4; ignoring this record\n",
  1155. data_len)
  1156. self.default_row_height_mismatch = bits & 1
  1157. self.default_row_hidden = (bits >> 1) & 1
  1158. self.default_additional_space_above = (bits >> 2) & 1
  1159. self.default_additional_space_below = (bits >> 3) & 1
  1160. elif rc == XL_MERGEDCELLS:
  1161. if not fmt_info: continue
  1162. pos = unpack_cell_range_address_list_update_pos(
  1163. self.merged_cells, data, 0, bv, addr_size=8)
  1164. if blah:
  1165. fprintf(self.logfile,
  1166. "MERGEDCELLS: %d ranges\n", (pos - 2) // 8)
  1167. assert pos == data_len, \
  1168. "MERGEDCELLS: pos=%d data_len=%d" % (pos, data_len)
  1169. elif rc == XL_WINDOW2:
  1170. if bv >= 80 and data_len >= 14:
  1171. (options,
  1172. self.first_visible_rowx, self.first_visible_colx,
  1173. self.gridline_colour_index,
  1174. self.cached_page_break_preview_mag_factor,
  1175. self.cached_normal_view_mag_factor
  1176. ) = unpack("<HHHHxxHH", data[:14])
  1177. else:
  1178. assert bv >= 30 # BIFF3-7
  1179. (options,
  1180. self.first_visible_rowx, self.first_visible_colx,
  1181. ) = unpack("<HHH", data[:6])
  1182. self.gridline_colour_rgb = unpack("<BBB", data[6:9])
  1183. self.gridline_colour_index = nearest_colour_index(
  1184. self.book.colour_map, self.gridline_colour_rgb, debug=0)
  1185. # options -- Bit, Mask, Contents:
  1186. # 0 0001H 0 = Show formula results 1 = Show formulas
  1187. # 1 0002H 0 = Do not show grid lines 1 = Show grid lines
  1188. # 2 0004H 0 = Do not show sheet headers 1 = Show sheet headers
  1189. # 3 0008H 0 = Panes are not frozen 1 = Panes are frozen (freeze)
  1190. # 4 0010H 0 = Show zero values as empty cells 1 = Show zero values
  1191. # 5 0020H 0 = Manual grid line colour 1 = Automatic grid line colour
  1192. # 6 0040H 0 = Columns from left to right 1 = Columns from right to left
  1193. # 7 0080H 0 = Do not show outline symbols 1 = Show outline symbols
  1194. # 8 0100H 0 = Keep splits if pane freeze is removed 1 = Remove splits if pane freeze is removed
  1195. # 9 0200H 0 = Sheet not selected 1 = Sheet selected (BIFF5-BIFF8)
  1196. # 10 0400H 0 = Sheet not visible 1 = Sheet visible (BIFF5-BIFF8)
  1197. # 11 0800H 0 = Show in normal view 1 = Show in page break preview (BIFF8)
  1198. # The freeze flag specifies, if a following PANE record (6.71) describes unfrozen or frozen panes.
  1199. for attr, _unused_defval in _WINDOW2_options:
  1200. setattr(self, attr, options & 1)
  1201. options >>= 1
  1202. elif rc == XL_SCL:
  1203. num, den = unpack("<HH", data)
  1204. result = 0
  1205. if den:
  1206. result = (num * 100) // den
  1207. if not(10 <= result <= 400):
  1208. if DEBUG or self.verbosity >= 0:
  1209. print((
  1210. "WARNING *** SCL rcd sheet %d: should have 0.1 <= num/den <= 4; got %d/%d"
  1211. % (self.number, num, den)
  1212. ), file=self.logfile)
  1213. result = 100
  1214. self.scl_mag_factor = result
  1215. elif rc == XL_PANE:
  1216. (
  1217. self.vert_split_pos,
  1218. self.horz_split_pos,
  1219. self.horz_split_first_visible,
  1220. self.vert_split_first_visible,
  1221. self.split_active_pane,
  1222. ) = unpack("<HHHHB", data[:9])
  1223. self.has_pane_record = 1
  1224. elif rc == XL_HORIZONTALPAGEBREAKS:
  1225. if not fmt_info: continue
  1226. num_breaks, = local_unpack("<H", data[:2])
  1227. assert num_breaks * (2 + 4 * (bv >= 80)) + 2 == data_len
  1228. pos = 2
  1229. if bv < 80:
  1230. while pos < data_len:
  1231. self.horizontal_page_breaks.append((local_unpack("<H", data[pos:pos+2])[0], 0, 255))
  1232. pos += 2
  1233. else:
  1234. while pos < data_len:
  1235. self.horizontal_page_breaks.append(local_unpack("<HHH", data[pos:pos+6]))
  1236. pos += 6
  1237. elif rc == XL_VERTICALPAGEBREAKS:
  1238. if not fmt_info: continue
  1239. num_breaks, = local_unpack("<H", data[:2])
  1240. assert num_breaks * (2 + 4 * (bv >= 80)) + 2 == data_len
  1241. pos = 2
  1242. if bv < 80:
  1243. while pos < data_len:
  1244. self.vertical_page_breaks.append((local_unpack("<H", data[pos:pos+2])[0], 0, 65535))
  1245. pos += 2
  1246. else:
  1247. while pos < data_len:
  1248. self.vertical_page_breaks.append(local_unpack("<HHH", data[pos:pos+6]))
  1249. pos += 6
  1250. #### all of the following are for BIFF <= 4W
  1251. elif bv <= 45:
  1252. if rc == XL_FORMAT or rc == XL_FORMAT2:
  1253. bk.handle_format(data, rc)
  1254. elif rc == XL_FONT or rc == XL_FONT_B3B4:
  1255. bk.handle_font(data)
  1256. elif rc == XL_STYLE:
  1257. if not self.book._xf_epilogue_done:
  1258. self.book.xf_epilogue()
  1259. bk.handle_style(data)
  1260. elif rc == XL_PALETTE:
  1261. bk.handle_palette(data)
  1262. elif rc == XL_BUILTINFMTCOUNT:
  1263. bk.handle_builtinfmtcount(data)
  1264. elif rc == XL_XF4 or rc == XL_XF3 or rc == XL_XF2: #### N.B. not XL_XF
  1265. bk.handle_xf(data)
  1266. elif rc == XL_DATEMODE:
  1267. bk.handle_datemode(data)
  1268. elif rc == XL_CODEPAGE:
  1269. bk.handle_codepage(data)
  1270. elif rc == XL_FILEPASS:
  1271. bk.handle_filepass(data)
  1272. elif rc == XL_WRITEACCESS:
  1273. bk.handle_writeaccess(data)
  1274. elif rc == XL_IXFE:
  1275. self._ixfe = local_unpack('<H', data)[0]
  1276. elif rc == XL_NUMBER_B2:
  1277. rowx, colx, cell_attr, d = local_unpack('<HH3sd', data)
  1278. self_put_cell(rowx, colx, None, d, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
  1279. elif rc == XL_INTEGER:
  1280. rowx, colx, cell_attr, d = local_unpack('<HH3sH', data)
  1281. self_put_cell(rowx, colx, None, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
  1282. elif rc == XL_LABEL_B2:
  1283. rowx, colx, cell_attr = local_unpack('<HH3s', data[0:7])
  1284. strg = unpack_string(data, 7, bk.encoding or bk.derive_encoding(), lenlen=1)
  1285. self_put_cell(rowx, colx, XL_CELL_TEXT, strg, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
  1286. elif rc == XL_BOOLERR_B2:
  1287. rowx, colx, cell_attr, value, is_err = local_unpack('<HH3sBB', data)
  1288. cellty = (XL_CELL_BOOLEAN, XL_CELL_ERROR)[is_err]
  1289. # if DEBUG: print "XL_BOOLERR_B2", rowx, colx, cell_attr, value, is_err
  1290. self_put_cell(rowx, colx, cellty, value, self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
  1291. elif rc == XL_BLANK_B2:
  1292. if not fmt_info: continue
  1293. rowx, colx, cell_attr = local_unpack('<HH3s', data[:7])
  1294. self_put_cell(rowx, colx, XL_CELL_BLANK, '', self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
  1295. elif rc == XL_EFONT:
  1296. bk.handle_efont(data)
  1297. elif rc == XL_ROW_B2:
  1298. if not fmt_info: continue
  1299. rowx, bits1, bits2 = local_unpack('<H4xH2xB', data[0:11])
  1300. if not(0 <= rowx < self.utter_max_rows):
  1301. print("*** NOTE: ROW_B2 record has row index %d; " \
  1302. "should have 0 <= rowx < %d -- record ignored!" \
  1303. % (rowx, self.utter_max_rows), file=self.logfile)
  1304. continue
  1305. if not (bits2 & 1): # has_default_xf_index is false
  1306. xf_index = -1
  1307. elif data_len == 18:
  1308. # Seems the XF index in the cell_attr is dodgy
  1309. xfx = local_unpack('<H', data[16:18])[0]
  1310. xf_index = self.fixed_BIFF2_xfindex(cell_attr=None, rowx=rowx, colx=-1, true_xfx=xfx)
  1311. else:
  1312. cell_attr = data[13:16]
  1313. xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx, colx=-1)
  1314. key = (bits1, bits2, xf_index)
  1315. r = rowinfo_sharing_dict.get(key)
  1316. if r is None:
  1317. rowinfo_sharing_dict[key] = r = Rowinfo()
  1318. r.height = bits1 & 0x7fff
  1319. r.has_default_height = (bits1 >> 15) & 1
  1320. r.has_default_xf_index = bits2 & 1
  1321. r.xf_index = xf_index
  1322. # r.outline_level = 0 # set in __init__
  1323. # r.outline_group_starts_ends = 0 # set in __init__
  1324. # r.hidden = 0 # set in __init__
  1325. # r.height_mismatch = 0 # set in __init__
  1326. # r.additional_space_above = 0 # set in __init__
  1327. # r.additional_space_below = 0 # set in __init__
  1328. self.rowinfo_map[rowx] = r
  1329. if 0 and r.xf_index > -1:
  1330. fprintf(self.logfile,
  1331. "**ROW %d %d %d\n",
  1332. self.number, rowx, r.xf_index)
  1333. if blah_rows:
  1334. print('ROW_B2', rowx, bits1, has_defaults, file=self.logfile)
  1335. r.dump(self.logfile,
  1336. header="--- sh #%d, rowx=%d ---" % (self.number, rowx))
  1337. elif rc == XL_COLWIDTH: # BIFF2 only
  1338. if not fmt_info: continue
  1339. first_colx, last_colx, width\
  1340. = local_unpack("<BBH", data[:4])
  1341. if not(first_colx <= last_colx):
  1342. print("*** NOTE: COLWIDTH record has first col index %d, last %d; " \
  1343. "should have first <= last -- record ignored!" \
  1344. % (first_colx, last_colx), file=self.logfile)
  1345. continue
  1346. for colx in xrange(first_colx, last_colx+1):
  1347. if colx in self.colinfo_map:
  1348. c = self.colinfo_map[colx]
  1349. else:
  1350. c = Colinfo()
  1351. self.colinfo_map[colx] = c
  1352. c.width = width
  1353. if blah:
  1354. fprintf(
  1355. self.logfile,
  1356. "COLWIDTH sheet #%d cols %d-%d: wid=%d\n",
  1357. self.number, first_colx, last_colx, width
  1358. )
  1359. elif rc == XL_COLUMNDEFAULT: # BIFF2 only
  1360. if not fmt_info: continue
  1361. first_colx, last_colx = local_unpack("<HH", data[:4])
  1362. #### Warning OOo docs wrong; first_colx <= colx < last_colx
  1363. if blah:
  1364. fprintf(
  1365. self.logfile,
  1366. "COLUMNDEFAULT sheet #%d cols in range(%d, %d)\n",
  1367. self.number, first_colx, last_colx
  1368. )
  1369. if not(0 <= first_colx < last_colx <= 256):
  1370. print("*** NOTE: COLUMNDEFAULT record has first col index %d, last %d; " \
  1371. "should have 0 <= first < last <= 256" \
  1372. % (first_colx, last_colx), file=self.logfile)
  1373. last_colx = min(last_colx, 256)
  1374. for colx in xrange(first_colx, last_colx):
  1375. offset = 4 + 3 * (colx - first_colx)
  1376. cell_attr = data[offset:offset+3]
  1377. xf_index = self.fixed_BIFF2_xfindex(cell_attr, rowx=-1, colx=colx)
  1378. if colx in self.colinfo_map:
  1379. c = self.colinfo_map[colx]
  1380. else:
  1381. c = Colinfo()
  1382. self.colinfo_map[colx] = c
  1383. c.xf_index = xf_index
  1384. elif rc == XL_WINDOW2_B2: # BIFF 2 only
  1385. attr_names = ("show_formulas", "show_grid_lines", "show_sheet_headers",
  1386. "panes_are_frozen", "show_zero_values")
  1387. for attr, char in zip(attr_names, data[0:5]):
  1388. setattr(self, attr, int(char != b'\0'))
  1389. (self.first_visible_rowx, self.first_visible_colx,
  1390. self.automatic_grid_line_colour,
  1391. ) = unpack("<HHB", data[5:10])
  1392. self.gridline_colour_rgb = unpack("<BBB", data[10:13])
  1393. self.gridline_colour_index = nearest_colour_index(
  1394. self.book.colour_map, self.gridline_colour_rgb, debug=0)
  1395. else:
  1396. # if DEBUG: print "SHEET.READ: Unhandled record type %02x %d bytes %r" % (rc, data_len, data)
  1397. pass
  1398. if not eof_found:
  1399. raise XLRDError("Sheet %d (%r) missing EOF record" \
  1400. % (self.number, self.name))
  1401. self.tidy_dimensions()
  1402. self.update_cooked_mag_factors()
  1403. bk._position = oldpos
  1404. return 1
  1405. def string_record_contents(self, data):
  1406. bv = self.biff_version
  1407. bk = self.book
  1408. lenlen = (bv >= 30) + 1
  1409. nchars_expected = unpack("<" + "BH"[lenlen - 1], data[:lenlen])[0]
  1410. offset = lenlen
  1411. if bv < 80:
  1412. enc = bk.encoding or bk.derive_encoding()
  1413. nchars_found = 0
  1414. result = UNICODE_LITERAL("")
  1415. while 1:
  1416. if bv >= 80:
  1417. flag = BYTES_ORD(data[offset]) & 1
  1418. enc = ("latin_1", "utf_16_le")[flag]
  1419. offset += 1
  1420. chunk = unicode(data[offset:], enc)
  1421. result += chunk
  1422. nchars_found += len(chunk)
  1423. if nchars_found == nchars_expected:
  1424. return result
  1425. if nchars_found > nchars_expected:
  1426. msg = ("STRING/CONTINUE: expected %d chars, found %d"
  1427. % (nchars_expected, nchars_found))
  1428. raise XLRDError(msg)
  1429. rc, _unused_len, data = bk.get_record_parts()
  1430. if rc != XL_CONTINUE:
  1431. raise XLRDError(
  1432. "Expected CONTINUE record; found record-type 0x%04X" % rc)
  1433. offset = 0
  1434. def update_cooked_mag_factors(self):
  1435. # Cached values are used ONLY for the non-active view mode.
  1436. # When the user switches to the non-active view mode,
  1437. # if the cached value for that mode is not valid,
  1438. # Excel pops up a window which says:
  1439. # "The number must be between 10 and 400. Try again by entering a number in this range."
  1440. # When the user hits OK, it drops into the non-active view mode
  1441. # but uses the magn from the active mode.
  1442. # NOTE: definition of "valid" depends on mode ... see below
  1443. blah = DEBUG or self.verbosity > 0
  1444. if self.show_in_page_break_preview:
  1445. if self.scl_mag_factor is None: # no SCL record
  1446. self.cooked_page_break_preview_mag_factor = 100 # Yes, 100, not 60, NOT a typo
  1447. else:
  1448. self.cooked_page_break_preview_mag_factor = self.scl_mag_factor
  1449. zoom = self.cached_normal_view_mag_factor
  1450. if not (10 <= zoom <=400):
  1451. if blah:
  1452. print((
  1453. "WARNING *** WINDOW2 rcd sheet %d: Bad cached_normal_view_mag_factor: %d"
  1454. % (self.number, self.cached_normal_view_mag_factor)
  1455. ), file=self.logfile)
  1456. zoom = self.cooked_page_break_preview_mag_factor
  1457. self.cooked_normal_view_mag_factor = zoom
  1458. else:
  1459. # normal view mode
  1460. if self.scl_mag_factor is None: # no SCL record
  1461. self.cooked_normal_view_mag_factor = 100
  1462. else:
  1463. self.cooked_normal_view_mag_factor = self.scl_mag_factor
  1464. zoom = self.cached_page_break_preview_mag_factor
  1465. if not zoom:
  1466. # VALID, defaults to 60
  1467. zoom = 60
  1468. elif not (10 <= zoom <= 400):
  1469. if blah:
  1470. print((
  1471. "WARNING *** WINDOW2 rcd sheet %r: Bad cached_page_break_preview_mag_factor: %r"
  1472. % (self.number, self.cached_page_break_preview_mag_factor)
  1473. ), file=self.logfile)
  1474. zoom = self.cooked_normal_view_mag_factor
  1475. self.cooked_page_break_preview_mag_factor = zoom
  1476. def fixed_BIFF2_xfindex(self, cell_attr, rowx, colx, true_xfx=None):
  1477. DEBUG = 0
  1478. blah = DEBUG or self.verbosity >= 2
  1479. if self.biff_version == 21:
  1480. if self.book.xf_list:
  1481. if true_xfx is not None:
  1482. xfx = true_xfx
  1483. else:
  1484. xfx = BYTES_ORD(cell_attr[0]) & 0x3F
  1485. if xfx == 0x3F:
  1486. if self._ixfe is None:
  1487. raise XLRDError("BIFF2 cell record has XF index 63 but no preceding IXFE record.")
  1488. xfx = self._ixfe
  1489. # OOo docs are capable of interpretation that each
  1490. # cell record is preceded immediately by its own IXFE record.
  1491. # Empirical evidence is that (sensibly) an IXFE record applies to all
  1492. # following cell records until another IXFE comes along.
  1493. return xfx
  1494. # Have either Excel 2.0, or broken 2.1 w/o XF records -- same effect.
  1495. self.biff_version = self.book.biff_version = 20
  1496. #### check that XF slot in cell_attr is zero
  1497. xfx_slot = BYTES_ORD(cell_attr[0]) & 0x3F
  1498. assert xfx_slot == 0
  1499. xfx = self._cell_attr_to_xfx.get(cell_attr)
  1500. if xfx is not None:
  1501. return xfx
  1502. if blah:
  1503. fprintf(self.logfile, "New cell_attr %r at (%r, %r)\n", cell_attr, rowx, colx)
  1504. if not self.book.xf_list:
  1505. for xfx in xrange(16):
  1506. self.insert_new_BIFF20_xf(cell_attr=b"\x40\x00\x00", style=xfx < 15)
  1507. xfx = self.insert_new_BIFF20_xf(cell_attr=cell_attr)
  1508. return xfx
  1509. def insert_new_BIFF20_xf(self, cell_attr, style=0):
  1510. DEBUG = 0
  1511. blah = DEBUG or self.verbosity >= 2
  1512. book = self.book
  1513. xfx = len(book.xf_list)
  1514. xf = self.fake_XF_from_BIFF20_cell_attr(cell_attr, style)
  1515. xf.xf_index = xfx
  1516. book.xf_list.append(xf)
  1517. if blah:
  1518. xf.dump(self.logfile, header="=== Faked XF %d ===" % xfx, footer="======")
  1519. if xf.format_key not in book.format_map:
  1520. if xf.format_key:
  1521. msg = "ERROR *** XF[%d] unknown format key (%d, 0x%04x)\n"
  1522. fprintf(self.logfile, msg,
  1523. xf.xf_index, xf.format_key, xf.format_key)
  1524. fmt = Format(xf.format_key, FUN, UNICODE_LITERAL("General"))
  1525. book.format_map[xf.format_key] = fmt
  1526. book.format_list.append(fmt)
  1527. cellty_from_fmtty = {
  1528. FNU: XL_CELL_NUMBER,
  1529. FUN: XL_CELL_NUMBER,
  1530. FGE: XL_CELL_NUMBER,
  1531. FDT: XL_CELL_DATE,
  1532. FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text.
  1533. }
  1534. fmt = book.format_map[xf.format_key]
  1535. cellty = cellty_from_fmtty[fmt.type]
  1536. self._xf_index_to_xl_type_map[xf.xf_index] = cellty
  1537. self._cell_attr_to_xfx[cell_attr] = xfx
  1538. return xfx
  1539. def fake_XF_from_BIFF20_cell_attr(self, cell_attr, style=0):
  1540. from .formatting import XF, XFAlignment, XFBorder, XFBackground, XFProtection
  1541. xf = XF()
  1542. xf.alignment = XFAlignment()
  1543. xf.alignment.indent_level = 0
  1544. xf.alignment.shrink_to_fit = 0
  1545. xf.alignment.text_direction = 0
  1546. xf.border = XFBorder()
  1547. xf.border.diag_up = 0
  1548. xf.border.diag_down = 0
  1549. xf.border.diag_colour_index = 0
  1550. xf.border.diag_line_style = 0 # no line
  1551. xf.background = XFBackground()
  1552. xf.protection = XFProtection()
  1553. (prot_bits, font_and_format, halign_etc) = unpack('<BBB', cell_attr)
  1554. xf.format_key = font_and_format & 0x3F
  1555. xf.font_index = (font_and_format & 0xC0) >> 6
  1556. upkbits(xf.protection, prot_bits, (
  1557. (6, 0x40, 'cell_locked'),
  1558. (7, 0x80, 'formula_hidden'),
  1559. ))
  1560. xf.alignment.hor_align = halign_etc & 0x07
  1561. for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')):
  1562. if halign_etc & mask:
  1563. colour_index, line_style = 8, 1 # black, thin
  1564. else:
  1565. colour_index, line_style = 0, 0 # none, none
  1566. setattr(xf.border, side + '_colour_index', colour_index)
  1567. setattr(xf.border, side + '_line_style', line_style)
  1568. bg = xf.background
  1569. if halign_etc & 0x80:
  1570. bg.fill_pattern = 17
  1571. else:
  1572. bg.fill_pattern = 0
  1573. bg.background_colour_index = 9 # white
  1574. bg.pattern_colour_index = 8 # black
  1575. xf.parent_style_index = (0x0FFF, 0)[style]
  1576. xf.alignment.vert_align = 2 # bottom
  1577. xf.alignment.rotation = 0
  1578. for attr_stem in \
  1579. "format font alignment border background protection".split():
  1580. attr = "_" + attr_stem + "_flag"
  1581. setattr(xf, attr, 1)
  1582. return xf
  1583. def req_fmt_info(self):
  1584. if not self.formatting_info:
  1585. raise XLRDError("Feature requires open_workbook(..., formatting_info=True)")
  1586. ##
  1587. # Determine column display width.
  1588. # <br /> -- New in version 0.6.1
  1589. # <br />
  1590. # @param colx Index of the queried column, range 0 to 255.
  1591. # Note that it is possible to find out the width that will be used to display
  1592. # columns with no cell information e.g. column IV (colx=255).
  1593. # @return The column width that will be used for displaying
  1594. # the given column by Excel, in units of 1/256th of the width of a
  1595. # standard character (the digit zero in the first font).
  1596. def computed_column_width(self, colx):
  1597. self.req_fmt_info()
  1598. if self.biff_version >= 80:
  1599. colinfo = self.colinfo_map.get(colx, None)
  1600. if colinfo is not None:
  1601. return colinfo.width
  1602. if self.standardwidth is not None:
  1603. return self.standardwidth
  1604. elif self.biff_version >= 40:
  1605. if self.gcw[colx]:
  1606. if self.standardwidth is not None:
  1607. return self.standardwidth
  1608. else:
  1609. colinfo = self.colinfo_map.get(colx, None)
  1610. if colinfo is not None:
  1611. return colinfo.width
  1612. elif self.biff_version == 30:
  1613. colinfo = self.colinfo_map.get(colx, None)
  1614. if colinfo is not None:
  1615. return colinfo.width
  1616. # All roads lead to Rome and the DEFCOLWIDTH ...
  1617. if self.defcolwidth is not None:
  1618. return self.defcolwidth * 256
  1619. return 8 * 256 # 8 is what Excel puts in a DEFCOLWIDTH record
  1620. def handle_hlink(self, data):
  1621. # DEBUG = 1
  1622. if DEBUG: print("\n=== hyperlink ===", file=self.logfile)
  1623. record_size = len(data)
  1624. h = Hyperlink()
  1625. h.frowx, h.lrowx, h.fcolx, h.lcolx, guid0, dummy, options = unpack('<HHHH16s4si', data[:32])
  1626. assert guid0 == b"\xD0\xC9\xEA\x79\xF9\xBA\xCE\x11\x8C\x82\x00\xAA\x00\x4B\xA9\x0B"
  1627. assert dummy == b"\x02\x00\x00\x00"
  1628. if DEBUG: print("options: %08X" % options, file=self.logfile)
  1629. offset = 32
  1630. def get_nul_terminated_unicode(buf, ofs):
  1631. nb = unpack('<L', buf[ofs:ofs+4])[0] * 2
  1632. ofs += 4
  1633. uc = unicode(buf[ofs:ofs+nb], 'UTF-16le')[:-1]
  1634. ofs += nb
  1635. return uc, ofs
  1636. if options & 0x14: # has a description
  1637. h.desc, offset = get_nul_terminated_unicode(data, offset)
  1638. if options & 0x80: # has a target
  1639. h.target, offset = get_nul_terminated_unicode(data, offset)
  1640. if (options & 1) and not (options & 0x100): # HasMoniker and not MonikerSavedAsString
  1641. # an OLEMoniker structure
  1642. clsid, = unpack('<16s', data[offset:offset + 16])
  1643. if DEBUG: fprintf(self.logfile, "clsid=%r\n", clsid)
  1644. offset += 16
  1645. if clsid == b"\xE0\xC9\xEA\x79\xF9\xBA\xCE\x11\x8C\x82\x00\xAA\x00\x4B\xA9\x0B":
  1646. # E0H C9H EAH 79H F9H BAH CEH 11H 8CH 82H 00H AAH 00H 4BH A9H 0BH
  1647. # URL Moniker
  1648. h.type = UNICODE_LITERAL('url')
  1649. nbytes = unpack('<L', data[offset:offset + 4])[0]
  1650. offset += 4
  1651. h.url_or_path = unicode(data[offset:offset + nbytes], 'UTF-16le')
  1652. if DEBUG: fprintf(self.logfile, "initial url=%r len=%d\n", h.url_or_path, len(h.url_or_path))
  1653. endpos = h.url_or_path.find('\x00')
  1654. if DEBUG: print("endpos=%d" % endpos, file=self.logfile)
  1655. h.url_or_path = h.url_or_path[:endpos]
  1656. true_nbytes = 2 * (endpos + 1)
  1657. offset += true_nbytes
  1658. extra_nbytes = nbytes - true_nbytes
  1659. extra_data = data[offset:offset + extra_nbytes]
  1660. offset += extra_nbytes
  1661. if DEBUG:
  1662. fprintf(
  1663. self.logfile,
  1664. "url=%r\nextra=%r\nnbytes=%d true_nbytes=%d extra_nbytes=%d\n",
  1665. h.url_or_path, extra_data, nbytes, true_nbytes, extra_nbytes,
  1666. )
  1667. assert extra_nbytes in (24, 0)
  1668. elif clsid == b"\x03\x03\x00\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46":
  1669. # file moniker
  1670. h.type = UNICODE_LITERAL('local file')
  1671. uplevels, nbytes = unpack("<Hi", data[offset:offset + 6])
  1672. offset += 6
  1673. shortpath = b"..\\" * uplevels + data[offset:offset + nbytes - 1] #### BYTES, not unicode
  1674. if DEBUG: fprintf(self.logfile, "uplevels=%d shortpath=%r\n", uplevels, shortpath)
  1675. offset += nbytes
  1676. offset += 24 # OOo: "unknown byte sequence"
  1677. # above is version 0xDEAD + 20 reserved zero bytes
  1678. sz = unpack('<i', data[offset:offset + 4])[0]
  1679. if DEBUG: print("sz=%d" % sz, file=self.logfile)
  1680. offset += 4
  1681. if sz:
  1682. xl = unpack('<i', data[offset:offset + 4])[0]
  1683. offset += 4
  1684. offset += 2 # "unknown byte sequence" MS: 0x0003
  1685. extended_path = unicode(data[offset:offset + xl], 'UTF-16le') # not zero-terminated
  1686. offset += xl
  1687. h.url_or_path = extended_path
  1688. else:
  1689. h.url_or_path = shortpath
  1690. #### MS KLUDGE WARNING ####
  1691. # The "shortpath" is bytes encoded in the **UNKNOWN** creator's "ANSI" encoding.
  1692. else:
  1693. fprintf(self.logfile, "*** unknown clsid %r\n", clsid)
  1694. elif options & 0x163 == 0x103: # UNC
  1695. h.type = UNICODE_LITERAL('unc')
  1696. h.url_or_path, offset = get_nul_terminated_unicode(data, offset)
  1697. elif options & 0x16B == 8:
  1698. h.type = UNICODE_LITERAL('workbook')
  1699. else:
  1700. h.type = UNICODE_LITERAL('unknown')
  1701. if options & 0x8: # has textmark
  1702. h.textmark, offset = get_nul_terminated_unicode(data, offset)
  1703. if DEBUG:
  1704. h.dump(header="... object dump ...")
  1705. print("offset=%d record_size=%d" % (offset, record_size))
  1706. extra_nbytes = record_size - offset
  1707. if extra_nbytes > 0:
  1708. fprintf(
  1709. self.logfile,
  1710. "*** WARNING: hyperlink at r=%d c=%d has %d extra data bytes: %s\n",
  1711. h.frowx,
  1712. h.fcolx,
  1713. extra_nbytes,
  1714. REPR(data[-extra_nbytes:])
  1715. )
  1716. # Seen: b"\x00\x00" also b"A\x00", b"V\x00"
  1717. elif extra_nbytes < 0:
  1718. raise XLRDError("Bug or corrupt file, send copy of input file for debugging")
  1719. self.hyperlink_list.append(h)
  1720. for rowx in xrange(h.frowx, h.lrowx+1):
  1721. for colx in xrange(h.fcolx, h.lcolx+1):
  1722. self.hyperlink_map[rowx, colx] = h
  1723. def handle_quicktip(self, data):
  1724. rcx, frowx, lrowx, fcolx, lcolx = unpack('<5H', data[:10])
  1725. assert rcx == XL_QUICKTIP
  1726. assert self.hyperlink_list
  1727. h = self.hyperlink_list[-1]
  1728. assert (frowx, lrowx, fcolx, lcolx) == (h.frowx, h.lrowx, h.fcolx, h.lcolx)
  1729. assert data[-2:] == b'\x00\x00'
  1730. h.quicktip = unicode(data[10:-2], 'utf_16_le')
  1731. def handle_msodrawingetc(self, recid, data_len, data):
  1732. if not OBJ_MSO_DEBUG:
  1733. return
  1734. DEBUG = 1
  1735. if self.biff_version < 80:
  1736. return
  1737. o = MSODrawing()
  1738. pos = 0
  1739. while pos < data_len:
  1740. tmp, fbt, cb = unpack('<HHI', data[pos:pos+8])
  1741. ver = tmp & 0xF
  1742. inst = (tmp >> 4) & 0xFFF
  1743. if ver == 0xF:
  1744. ndb = 0 # container
  1745. else:
  1746. ndb = cb
  1747. if DEBUG:
  1748. hex_char_dump(data, pos, ndb + 8, base=0, fout=self.logfile)
  1749. fprintf(self.logfile,
  1750. "fbt:0x%04X inst:%d ver:0x%X cb:%d (0x%04X)\n",
  1751. fbt, inst, ver, cb, cb)
  1752. if fbt == 0xF010: # Client Anchor
  1753. assert ndb == 18
  1754. (o.anchor_unk,
  1755. o.anchor_colx_lo, o.anchor_rowx_lo,
  1756. o.anchor_colx_hi, o.anchor_rowx_hi) = unpack('<Hiiii', data[pos+8:pos+8+ndb])
  1757. elif fbt == 0xF011: # Client Data
  1758. # must be followed by an OBJ record
  1759. assert cb == 0
  1760. assert pos + 8 == data_len
  1761. else:
  1762. pass
  1763. pos += ndb + 8
  1764. else:
  1765. # didn't break out of while loop
  1766. assert pos == data_len
  1767. if DEBUG:
  1768. o.dump(self.logfile, header="=== MSODrawing ===", footer= " ")
  1769. def handle_obj(self, data):
  1770. if self.biff_version < 80:
  1771. return None
  1772. o = MSObj()
  1773. data_len = len(data)
  1774. pos = 0
  1775. if OBJ_MSO_DEBUG:
  1776. fprintf(self.logfile, "... OBJ record len=%d...\n", data_len)
  1777. while pos < data_len:
  1778. ft, cb = unpack('<HH', data[pos:pos+4])
  1779. if OBJ_MSO_DEBUG:
  1780. fprintf(self.logfile, "pos=%d ft=0x%04X cb=%d\n", pos, ft, cb)
  1781. hex_char_dump(data, pos, cb + 4, base=0, fout=self.logfile)
  1782. if pos == 0 and not (ft == 0x15 and cb == 18):
  1783. if self.verbosity:
  1784. fprintf(self.logfile, "*** WARNING Ignoring antique or corrupt OBJECT record\n")
  1785. return None
  1786. if ft == 0x15: # ftCmo ... s/b first
  1787. assert pos == 0
  1788. o.type, o.id, option_flags = unpack('<HHH', data[pos+4:pos+10])
  1789. upkbits(o, option_flags, (
  1790. ( 0, 0x0001, 'locked'),
  1791. ( 4, 0x0010, 'printable'),
  1792. ( 8, 0x0100, 'autofilter'), # not documented in Excel 97 dev kit
  1793. ( 9, 0x0200, 'scrollbar_flag'), # not documented in Excel 97 dev kit
  1794. (13, 0x2000, 'autofill'),
  1795. (14, 0x4000, 'autoline'),
  1796. ))
  1797. elif ft == 0x00:
  1798. if data[pos:data_len] == b'\0' * (data_len - pos):
  1799. # ignore "optional reserved" data at end of record
  1800. break
  1801. msg = "Unexpected data at end of OBJECT record"
  1802. fprintf(self.logfile, "*** ERROR %s\n" % msg)
  1803. hex_char_dump(data, pos, data_len - pos, base=0, fout=self.logfile)
  1804. raise XLRDError(msg)
  1805. elif ft == 0x0C: # Scrollbar
  1806. values = unpack('<5H', data[pos+8:pos+18])
  1807. for value, tag in zip(values, ('value', 'min', 'max', 'inc', 'page')):
  1808. setattr(o, 'scrollbar_' + tag, value)
  1809. elif ft == 0x0D: # "Notes structure" [used for cell comments]
  1810. # not documented in Excel 97 dev kit
  1811. if OBJ_MSO_DEBUG: fprintf(self.logfile, "*** OBJ record has ft==0x0D 'notes' structure\n")
  1812. elif ft == 0x13: # list box data
  1813. if o.autofilter: # non standard exit. NOT documented
  1814. break
  1815. else:
  1816. pass
  1817. pos += cb + 4
  1818. else:
  1819. # didn't break out of while loop
  1820. pass
  1821. if OBJ_MSO_DEBUG:
  1822. o.dump(self.logfile, header="=== MSOBj ===", footer= " ")
  1823. return o
  1824. def handle_note(self, data, txos):
  1825. if OBJ_MSO_DEBUG:
  1826. fprintf(self.logfile, '... NOTE record ...\n')
  1827. hex_char_dump(data, 0, len(data), base=0, fout=self.logfile)
  1828. o = Note()
  1829. data_len = len(data)
  1830. if self.biff_version < 80:
  1831. o.rowx, o.colx, expected_bytes = unpack('<HHH', data[:6])
  1832. nb = len(data) - 6
  1833. assert nb <= expected_bytes
  1834. pieces = [data[6:]]
  1835. expected_bytes -= nb
  1836. while expected_bytes > 0:
  1837. rc2, data2_len, data2 = self.book.get_record_parts()
  1838. assert rc2 == XL_NOTE
  1839. dummy_rowx, nb = unpack('<H2xH', data2[:6])
  1840. assert dummy_rowx == 0xFFFF
  1841. assert nb == data2_len - 6
  1842. pieces.append(data2[6:])
  1843. expected_bytes -= nb
  1844. assert expected_bytes == 0
  1845. enc = self.book.encoding or self.book.derive_encoding()
  1846. o.text = unicode(b''.join(pieces), enc)
  1847. o.rich_text_runlist = [(0, 0)]
  1848. o.show = 0
  1849. o.row_hidden = 0
  1850. o.col_hidden = 0
  1851. o.author = UNICODE_LITERAL('')
  1852. o._object_id = None
  1853. self.cell_note_map[o.rowx, o.colx] = o
  1854. return
  1855. # Excel 8.0+
  1856. o.rowx, o.colx, option_flags, o._object_id = unpack('<4H', data[:8])
  1857. o.show = (option_flags >> 1) & 1
  1858. o.row_hidden = (option_flags >> 7) & 1
  1859. o.col_hidden = (option_flags >> 8) & 1
  1860. # XL97 dev kit book says NULL [sic] bytes padding between string count and string data
  1861. # to ensure that string is word-aligned. Appears to be nonsense.
  1862. o.author, endpos = unpack_unicode_update_pos(data, 8, lenlen=2)
  1863. # There is a random/undefined byte after the author string (not counted in the
  1864. # string length).
  1865. # Issue 4 on github: Google Spreadsheet doesn't write the undefined byte.
  1866. assert (data_len - endpos) in (0, 1)
  1867. if OBJ_MSO_DEBUG:
  1868. o.dump(self.logfile, header="=== Note ===", footer= " ")
  1869. txo = txos.get(o._object_id)
  1870. if txo:
  1871. o.text = txo.text
  1872. o.rich_text_runlist = txo.rich_text_runlist
  1873. self.cell_note_map[o.rowx, o.colx] = o
  1874. def handle_txo(self, data):
  1875. if self.biff_version < 80:
  1876. return
  1877. o = MSTxo()
  1878. data_len = len(data)
  1879. fmt = '<HH6sHHH'
  1880. fmtsize = calcsize(fmt)
  1881. option_flags, o.rot, controlInfo, cchText, cbRuns, o.ifntEmpty = unpack(fmt, data[:fmtsize])
  1882. o.fmla = data[fmtsize:]
  1883. upkbits(o, option_flags, (
  1884. ( 3, 0x000E, 'horz_align'),
  1885. ( 6, 0x0070, 'vert_align'),
  1886. ( 9, 0x0200, 'lock_text'),
  1887. (14, 0x4000, 'just_last'),
  1888. (15, 0x8000, 'secret_edit'),
  1889. ))
  1890. totchars = 0
  1891. o.text = UNICODE_LITERAL('')
  1892. while totchars < cchText:
  1893. rc2, data2_len, data2 = self.book.get_record_parts()
  1894. assert rc2 == XL_CONTINUE
  1895. if OBJ_MSO_DEBUG:
  1896. hex_char_dump(data2, 0, data2_len, base=0, fout=self.logfile)
  1897. nb = BYTES_ORD(data2[0]) # 0 means latin1, 1 means utf_16_le
  1898. nchars = data2_len - 1
  1899. if nb:
  1900. assert nchars % 2 == 0
  1901. nchars //= 2
  1902. utext, endpos = unpack_unicode_update_pos(data2, 0, known_len=nchars)
  1903. assert endpos == data2_len
  1904. o.text += utext
  1905. totchars += nchars
  1906. o.rich_text_runlist = []
  1907. totruns = 0
  1908. while totruns < cbRuns: # counts of BYTES, not runs
  1909. rc3, data3_len, data3 = self.book.get_record_parts()
  1910. # print totruns, cbRuns, rc3, data3_len, repr(data3)
  1911. assert rc3 == XL_CONTINUE
  1912. assert data3_len % 8 == 0
  1913. for pos in xrange(0, data3_len, 8):
  1914. run = unpack('<HH4x', data3[pos:pos+8])
  1915. o.rich_text_runlist.append(run)
  1916. totruns += 8
  1917. # remove trailing entries that point to the end of the string
  1918. while o.rich_text_runlist and o.rich_text_runlist[-1][0] == cchText:
  1919. del o.rich_text_runlist[-1]
  1920. if OBJ_MSO_DEBUG:
  1921. o.dump(self.logfile, header="=== MSTxo ===", footer= " ")
  1922. print(o.rich_text_runlist, file=self.logfile)
  1923. return o
  1924. def handle_feat11(self, data):
  1925. if not OBJ_MSO_DEBUG:
  1926. return
  1927. # rt: Record type; this matches the BIFF rt in the first two bytes of the record; =0872h
  1928. # grbitFrt: FRT cell reference flag (see table below for details)
  1929. # Ref0: Range reference to a worksheet cell region if grbitFrt=1 (bitFrtRef). Otherwise blank.
  1930. # isf: Shared feature type index =5 for Table
  1931. # fHdr: =0 since this is for feat not feat header
  1932. # reserved0: Reserved for future use =0 for Table
  1933. # cref: Count of ref ranges this feature is on
  1934. # cbFeatData: Count of byte for the current feature data.
  1935. # reserved1: =0 currently not used
  1936. # Ref1: Repeat of Ref0. UNDOCUMENTED
  1937. rt, grbitFrt, Ref0, isf, fHdr, reserved0, cref, cbFeatData, reserved1, Ref1 = unpack('<HH8sHBiHiH8s', data[0:35])
  1938. assert reserved0 == 0
  1939. assert reserved1 == 0
  1940. assert isf == 5
  1941. assert rt == 0x872
  1942. assert fHdr == 0
  1943. assert Ref1 == Ref0
  1944. print(self.logfile, "FEAT11: grbitFrt=%d Ref0=%r cref=%d cbFeatData=%d\n", grbitFrt, Ref0, cref, cbFeatData)
  1945. # lt: Table data source type:
  1946. # =0 for Excel Worksheet Table =1 for read-write SharePoint linked List
  1947. # =2 for XML mapper Table =3 for Query Table
  1948. # idList: The ID of the Table (unique per worksheet)
  1949. # crwHeader: How many header/title rows the Table has at the top
  1950. # crwTotals: How many total rows the Table has at the bottom
  1951. # idFieldNext: Next id to try when assigning a unique id to a new field
  1952. # cbFSData: The size of the Fixed Data portion of the Table data structure.
  1953. # rupBuild: the rupBuild that generated the record
  1954. # unusedShort: UNUSED short that can be used later. The value is reserved during round-tripping.
  1955. # listFlags: Collection of bit flags: (see listFlags' bit setting table below for detail.)
  1956. # lPosStmCache: Table data stream position of cached data
  1957. # cbStmCache: Count of bytes of cached data
  1958. # cchStmCache: Count of characters of uncompressed cached data in the stream
  1959. # lem: Table edit mode (see List (Table) Editing Mode (lem) setting table below for details.)
  1960. # rgbHashParam: Hash value for SharePoint Table
  1961. # cchName: Count of characters in the Table name string rgbName
  1962. (lt, idList, crwHeader, crwTotals, idFieldNext, cbFSData,
  1963. rupBuild, unusedShort, listFlags, lPosStmCache, cbStmCache,
  1964. cchStmCache, lem, rgbHashParam, cchName) = unpack('<iiiiiiHHiiiii16sH', data[35:35+66])
  1965. print("lt=%d idList=%d crwHeader=%d crwTotals=%d idFieldNext=%d cbFSData=%d\n"\
  1966. "rupBuild=%d unusedShort=%d listFlags=%04X lPosStmCache=%d cbStmCache=%d\n"\
  1967. "cchStmCache=%d lem=%d rgbHashParam=%r cchName=%d" % (
  1968. lt, idList, crwHeader, crwTotals, idFieldNext, cbFSData,
  1969. rupBuild, unusedShort,listFlags, lPosStmCache, cbStmCache,
  1970. cchStmCache, lem, rgbHashParam, cchName), file=self.logfile)
  1971. class MSODrawing(BaseObject):
  1972. pass
  1973. class MSObj(BaseObject):
  1974. pass
  1975. class MSTxo(BaseObject):
  1976. pass
  1977. ##
  1978. # <p> Represents a user "comment" or "note".
  1979. # Note objects are accessible through Sheet.{@link #Sheet.cell_note_map}.
  1980. # <br />-- New in version 0.7.2
  1981. # </p>
  1982. class Note(BaseObject):
  1983. ##
  1984. # Author of note
  1985. author = UNICODE_LITERAL('')
  1986. ##
  1987. # True if the containing column is hidden
  1988. col_hidden = 0
  1989. ##
  1990. # Column index
  1991. colx = 0
  1992. ##
  1993. # List of (offset_in_string, font_index) tuples.
  1994. # Unlike Sheet.{@link #Sheet.rich_text_runlist_map}, the first offset should always be 0.
  1995. rich_text_runlist = None
  1996. ##
  1997. # True if the containing row is hidden
  1998. row_hidden = 0
  1999. ##
  2000. # Row index
  2001. rowx = 0
  2002. ##
  2003. # True if note is always shown
  2004. show = 0
  2005. ##
  2006. # Text of the note
  2007. text = UNICODE_LITERAL('')
  2008. ##
  2009. # <p>Contains the attributes of a hyperlink.
  2010. # Hyperlink objects are accessible through Sheet.{@link #Sheet.hyperlink_list}
  2011. # and Sheet.{@link #Sheet.hyperlink_map}.
  2012. # <br />-- New in version 0.7.2
  2013. # </p>
  2014. class Hyperlink(BaseObject):
  2015. ##
  2016. # Index of first row
  2017. frowx = None
  2018. ##
  2019. # Index of last row
  2020. lrowx = None
  2021. ##
  2022. # Index of first column
  2023. fcolx = None
  2024. ##
  2025. # Index of last column
  2026. lcolx = None
  2027. ##
  2028. # Type of hyperlink. Unicode string, one of 'url', 'unc',
  2029. # 'local file', 'workbook', 'unknown'
  2030. type = None
  2031. ##
  2032. # The URL or file-path, depending in the type. Unicode string, except
  2033. # in the rare case of a local but non-existent file with non-ASCII
  2034. # characters in the name, in which case only the "8.3" filename is available,
  2035. # as a bytes (3.x) or str (2.x) string, <i>with unknown encoding.</i>
  2036. url_or_path = None
  2037. ##
  2038. # Description ... this is displayed in the cell,
  2039. # and should be identical to the cell value. Unicode string, or None. It seems
  2040. # impossible NOT to have a description created by the Excel UI.
  2041. desc = None
  2042. ##
  2043. # Target frame. Unicode string. Note: I have not seen a case of this.
  2044. # It seems impossible to create one in the Excel UI.
  2045. target = None
  2046. ##
  2047. # "Textmark": the piece after the "#" in
  2048. # "http://docs.python.org/library#struct_module", or the Sheet1!A1:Z99
  2049. # part when type is "workbook".
  2050. textmark = None
  2051. ##
  2052. # The text of the "quick tip" displayed when the cursor
  2053. # hovers over the hyperlink.
  2054. quicktip = None
  2055. # === helpers ===
  2056. def unpack_RK(rk_str):
  2057. flags = BYTES_ORD(rk_str[0])
  2058. if flags & 2:
  2059. # There's a SIGNED 30-bit integer in there!
  2060. i, = unpack('<i', rk_str)
  2061. i >>= 2 # div by 4 to drop the 2 flag bits
  2062. if flags & 1:
  2063. return i / 100.0
  2064. return float(i)
  2065. else:
  2066. # It's the most significant 30 bits of an IEEE 754 64-bit FP number
  2067. d, = unpack('<d', b'\0\0\0\0' + BYTES_LITERAL(chr(flags & 252)) + rk_str[1:4])
  2068. if flags & 1:
  2069. return d / 100.0
  2070. return d
  2071. ##### =============== Cell ======================================== #####
  2072. cellty_from_fmtty = {
  2073. FNU: XL_CELL_NUMBER,
  2074. FUN: XL_CELL_NUMBER,
  2075. FGE: XL_CELL_NUMBER,
  2076. FDT: XL_CELL_DATE,
  2077. FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text.
  2078. }
  2079. ctype_text = {
  2080. XL_CELL_EMPTY: 'empty',
  2081. XL_CELL_TEXT: 'text',
  2082. XL_CELL_NUMBER: 'number',
  2083. XL_CELL_DATE: 'xldate',
  2084. XL_CELL_BOOLEAN: 'bool',
  2085. XL_CELL_ERROR: 'error',
  2086. XL_CELL_BLANK: 'blank',
  2087. }
  2088. ##
  2089. # <p>Contains the data for one cell.</p>
  2090. #
  2091. # <p>WARNING: You don't call this class yourself. You access Cell objects
  2092. # via methods of the {@link #Sheet} object(s) that you found in the {@link #Book} object that
  2093. # was returned when you called xlrd.open_workbook("myfile.xls").</p>
  2094. # <p> Cell objects have three attributes: <i>ctype</i> is an int, <i>value</i>
  2095. # (which depends on <i>ctype</i>) and <i>xf_index</i>.
  2096. # If "formatting_info" is not enabled when the workbook is opened, xf_index will be None.
  2097. # The following table describes the types of cells and how their values
  2098. # are represented in Python.</p>
  2099. #
  2100. # <table border="1" cellpadding="7">
  2101. # <tr>
  2102. # <th>Type symbol</th>
  2103. # <th>Type number</th>
  2104. # <th>Python value</th>
  2105. # </tr>
  2106. # <tr>
  2107. # <td>XL_CELL_EMPTY</td>
  2108. # <td align="center">0</td>
  2109. # <td>empty string u''</td>
  2110. # </tr>
  2111. # <tr>
  2112. # <td>XL_CELL_TEXT</td>
  2113. # <td align="center">1</td>
  2114. # <td>a Unicode string</td>
  2115. # </tr>
  2116. # <tr>
  2117. # <td>XL_CELL_NUMBER</td>
  2118. # <td align="center">2</td>
  2119. # <td>float</td>
  2120. # </tr>
  2121. # <tr>
  2122. # <td>XL_CELL_DATE</td>
  2123. # <td align="center">3</td>
  2124. # <td>float</td>
  2125. # </tr>
  2126. # <tr>
  2127. # <td>XL_CELL_BOOLEAN</td>
  2128. # <td align="center">4</td>
  2129. # <td>int; 1 means TRUE, 0 means FALSE</td>
  2130. # </tr>
  2131. # <tr>
  2132. # <td>XL_CELL_ERROR</td>
  2133. # <td align="center">5</td>
  2134. # <td>int representing internal Excel codes; for a text representation,
  2135. # refer to the supplied dictionary error_text_from_code</td>
  2136. # </tr>
  2137. # <tr>
  2138. # <td>XL_CELL_BLANK</td>
  2139. # <td align="center">6</td>
  2140. # <td>empty string u''. Note: this type will appear only when
  2141. # open_workbook(..., formatting_info=True) is used.</td>
  2142. # </tr>
  2143. # </table>
  2144. #<p></p>
  2145. class Cell(BaseObject):
  2146. __slots__ = ['ctype', 'value', 'xf_index']
  2147. def __init__(self, ctype, value, xf_index=None):
  2148. self.ctype = ctype
  2149. self.value = value
  2150. self.xf_index = xf_index
  2151. def __repr__(self):
  2152. if self.xf_index is None:
  2153. return "%s:%r" % (ctype_text[self.ctype], self.value)
  2154. else:
  2155. return "%s:%r (XF:%r)" % (ctype_text[self.ctype], self.value, self.xf_index)
  2156. empty_cell = Cell(XL_CELL_EMPTY, UNICODE_LITERAL(''))
  2157. ##### =============== Colinfo and Rowinfo ============================== #####
  2158. ##
  2159. # Width and default formatting information that applies to one or
  2160. # more columns in a sheet. Derived from COLINFO records.
  2161. #
  2162. # <p> Here is the default hierarchy for width, according to the OOo docs:
  2163. #
  2164. # <br />"""In BIFF3, if a COLINFO record is missing for a column,
  2165. # the width specified in the record DEFCOLWIDTH is used instead.
  2166. #
  2167. # <br />In BIFF4-BIFF7, the width set in this [COLINFO] record is only used,
  2168. # if the corresponding bit for this column is cleared in the GCW
  2169. # record, otherwise the column width set in the DEFCOLWIDTH record
  2170. # is used (the STANDARDWIDTH record is always ignored in this case [see footnote!]).
  2171. #
  2172. # <br />In BIFF8, if a COLINFO record is missing for a column,
  2173. # the width specified in the record STANDARDWIDTH is used.
  2174. # If this [STANDARDWIDTH] record is also missing,
  2175. # the column width of the record DEFCOLWIDTH is used instead."""
  2176. # <br />
  2177. #
  2178. # Footnote: The docs on the GCW record say this:
  2179. # """<br />
  2180. # If a bit is set, the corresponding column uses the width set in the STANDARDWIDTH
  2181. # record. If a bit is cleared, the corresponding column uses the width set in the
  2182. # COLINFO record for this column.
  2183. # <br />If a bit is set, and the worksheet does not contain the STANDARDWIDTH record, or if
  2184. # the bit is cleared, and the worksheet does not contain the COLINFO record, the DEFCOLWIDTH
  2185. # record of the worksheet will be used instead.
  2186. # <br />"""<br />
  2187. # At the moment (2007-01-17) xlrd is going with the GCW version of the story.
  2188. # Reference to the source may be useful: see the computed_column_width(colx) method
  2189. # of the Sheet class.
  2190. # <br />-- New in version 0.6.1
  2191. # </p>
  2192. class Colinfo(BaseObject):
  2193. ##
  2194. # Width of the column in 1/256 of the width of the zero character,
  2195. # using default font (first FONT record in the file).
  2196. width = 0
  2197. ##
  2198. # XF index to be used for formatting empty cells.
  2199. xf_index = -1
  2200. ##
  2201. # 1 = column is hidden
  2202. hidden = 0
  2203. ##
  2204. # Value of a 1-bit flag whose purpose is unknown
  2205. # but is often seen set to 1
  2206. bit1_flag = 0
  2207. ##
  2208. # Outline level of the column, in range(7).
  2209. # (0 = no outline)
  2210. outline_level = 0
  2211. ##
  2212. # 1 = column is collapsed
  2213. collapsed = 0
  2214. _USE_SLOTS = 1
  2215. ##
  2216. # <p>Height and default formatting information that applies to a row in a sheet.
  2217. # Derived from ROW records.
  2218. # <br /> -- New in version 0.6.1</p>
  2219. #
  2220. # <p><b>height</b>: Height of the row, in twips. One twip == 1/20 of a point.</p>
  2221. #
  2222. # <p><b>has_default_height</b>: 0 = Row has custom height; 1 = Row has default height.</p>
  2223. #
  2224. # <p><b>outline_level</b>: Outline level of the row (0 to 7) </p>
  2225. #
  2226. # <p><b>outline_group_starts_ends</b>: 1 = Outline group starts or ends here (depending on where the
  2227. # outline buttons are located, see WSBOOL record [TODO ??]),
  2228. # <i>and</i> is collapsed </p>
  2229. #
  2230. # <p><b>hidden</b>: 1 = Row is hidden (manually, or by a filter or outline group) </p>
  2231. #
  2232. # <p><b>height_mismatch</b>: 1 = Row height and default font height do not match </p>
  2233. #
  2234. # <p><b>has_default_xf_index</b>: 1 = the xf_index attribute is usable; 0 = ignore it </p>
  2235. #
  2236. # <p><b>xf_index</b>: Index to default XF record for empty cells in this row.
  2237. # Don't use this if has_default_xf_index == 0. </p>
  2238. #
  2239. # <p><b>additional_space_above</b>: This flag is set, if the upper border of at least one cell in this row
  2240. # or if the lower border of at least one cell in the row above is
  2241. # formatted with a thick line style. Thin and medium line styles are not
  2242. # taken into account. </p>
  2243. #
  2244. # <p><b>additional_space_below</b>: This flag is set, if the lower border of at least one cell in this row
  2245. # or if the upper border of at least one cell in the row below is
  2246. # formatted with a medium or thick line style. Thin line styles are not
  2247. # taken into account. </p>
  2248. class Rowinfo(BaseObject):
  2249. if _USE_SLOTS:
  2250. __slots__ = (
  2251. "height",
  2252. "has_default_height",
  2253. "outline_level",
  2254. "outline_group_starts_ends",
  2255. "hidden",
  2256. "height_mismatch",
  2257. "has_default_xf_index",
  2258. "xf_index",
  2259. "additional_space_above",
  2260. "additional_space_below",
  2261. )
  2262. def __init__(self):
  2263. self.height = None
  2264. self.has_default_height = None
  2265. self.outline_level = None
  2266. self.outline_group_starts_ends = None
  2267. self.hidden = None
  2268. self.height_mismatch = None
  2269. self.has_default_xf_index = None
  2270. self.xf_index = None
  2271. self.additional_space_above = None
  2272. self.additional_space_below = None
  2273. def __getstate__(self):
  2274. return (
  2275. self.height,
  2276. self.has_default_height,
  2277. self.outline_level,
  2278. self.outline_group_starts_ends,
  2279. self.hidden,
  2280. self.height_mismatch,
  2281. self.has_default_xf_index,
  2282. self.xf_index,
  2283. self.additional_space_above,
  2284. self.additional_space_below,
  2285. )
  2286. def __setstate__(self, state):
  2287. (
  2288. self.height,
  2289. self.has_default_height,
  2290. self.outline_level,
  2291. self.outline_group_starts_ends,
  2292. self.hidden,
  2293. self.height_mismatch,
  2294. self.has_default_xf_index,
  2295. self.xf_index,
  2296. self.additional_space_above,
  2297. self.additional_space_below,
  2298. ) = state