Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/xlrd/formatting.py: 17%
560 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# -*- coding: utf-8 -*-
2# Copyright (c) 2005-2012 Stephen John Machin, Lingfo Pty Ltd
3# This module is part of the xlrd package, which is released under a
4# BSD-style licence.
5# No part of the content of this file was derived from the works of
6# David Giffin.
7"""
8Module for formatting information.
9"""
11from __future__ import print_function
13import re
14from struct import unpack
16from .biffh import (
17 FDT, FGE, FNU, FTX, FUN, XL_CELL_DATE, XL_CELL_NUMBER, XL_CELL_TEXT,
18 XL_FORMAT, XL_FORMAT2, BaseObject, XLRDError, fprintf, unpack_string,
19 unpack_unicode, upkbits, upkbitsL,
20)
21from .timemachine import *
23DEBUG = 0
25_cellty_from_fmtty = {
26 FNU: XL_CELL_NUMBER,
27 FUN: XL_CELL_NUMBER,
28 FGE: XL_CELL_NUMBER,
29 FDT: XL_CELL_DATE,
30 FTX: XL_CELL_NUMBER, # Yes, a number can be formatted as text.
31}
33excel_default_palette_b5 = (
34 ( 0, 0, 0), (255, 255, 255), (255, 0, 0), ( 0, 255, 0),
35 ( 0, 0, 255), (255, 255, 0), (255, 0, 255), ( 0, 255, 255),
36 (128, 0, 0), ( 0, 128, 0), ( 0, 0, 128), (128, 128, 0),
37 (128, 0, 128), ( 0, 128, 128), (192, 192, 192), (128, 128, 128),
38 (153, 153, 255), (153, 51, 102), (255, 255, 204), (204, 255, 255),
39 (102, 0, 102), (255, 128, 128), ( 0, 102, 204), (204, 204, 255),
40 ( 0, 0, 128), (255, 0, 255), (255, 255, 0), ( 0, 255, 255),
41 (128, 0, 128), (128, 0, 0), ( 0, 128, 128), ( 0, 0, 255),
42 ( 0, 204, 255), (204, 255, 255), (204, 255, 204), (255, 255, 153),
43 (153, 204, 255), (255, 153, 204), (204, 153, 255), (227, 227, 227),
44 ( 51, 102, 255), ( 51, 204, 204), (153, 204, 0), (255, 204, 0),
45 (255, 153, 0), (255, 102, 0), (102, 102, 153), (150, 150, 150),
46 ( 0, 51, 102), ( 51, 153, 102), ( 0, 51, 0), ( 51, 51, 0),
47 (153, 51, 0), (153, 51, 102), ( 51, 51, 153), ( 51, 51, 51),
48)
50excel_default_palette_b2 = excel_default_palette_b5[:16]
52# Following table borrowed from Gnumeric 1.4 source.
53# Checked against OOo docs and MS docs.
54excel_default_palette_b8 = ( # (red, green, blue)
55 ( 0, 0, 0), (255,255,255), (255, 0, 0), ( 0,255, 0), # 0
56 ( 0, 0,255), (255,255, 0), (255, 0,255), ( 0,255,255), # 4
57 (128, 0, 0), ( 0,128, 0), ( 0, 0,128), (128,128, 0), # 8
58 (128, 0,128), ( 0,128,128), (192,192,192), (128,128,128), # 12
59 (153,153,255), (153, 51,102), (255,255,204), (204,255,255), # 16
60 (102, 0,102), (255,128,128), ( 0,102,204), (204,204,255), # 20
61 ( 0, 0,128), (255, 0,255), (255,255, 0), ( 0,255,255), # 24
62 (128, 0,128), (128, 0, 0), ( 0,128,128), ( 0, 0,255), # 28
63 ( 0,204,255), (204,255,255), (204,255,204), (255,255,153), # 32
64 (153,204,255), (255,153,204), (204,153,255), (255,204,153), # 36
65 ( 51,102,255), ( 51,204,204), (153,204, 0), (255,204, 0), # 40
66 (255,153, 0), (255,102, 0), (102,102,153), (150,150,150), # 44
67 ( 0, 51,102), ( 51,153,102), ( 0, 51, 0), ( 51, 51, 0), # 48
68 (153, 51, 0), (153, 51,102), ( 51, 51,153), ( 51, 51, 51), # 52
69)
71default_palette = {
72 80: excel_default_palette_b8,
73 70: excel_default_palette_b5,
74 50: excel_default_palette_b5,
75 45: excel_default_palette_b2,
76 40: excel_default_palette_b2,
77 30: excel_default_palette_b2,
78 21: excel_default_palette_b2,
79 20: excel_default_palette_b2,
80}
82# 00H = Normal
83# 01H = RowLevel_lv (see next field)
84# 02H = ColLevel_lv (see next field)
85# 03H = Comma
86# 04H = Currency
87# 05H = Percent
88# 06H = Comma [0] (BIFF4-BIFF8)
89# 07H = Currency [0] (BIFF4-BIFF8)
90# 08H = Hyperlink (BIFF8)
91# 09H = Followed Hyperlink (BIFF8)
92built_in_style_names = [
93 "Normal",
94 "RowLevel_",
95 "ColLevel_",
96 "Comma",
97 "Currency",
98 "Percent",
99 "Comma [0]",
100 "Currency [0]",
101 "Hyperlink",
102 "Followed Hyperlink",
103]
105def initialise_colour_map(book):
106 book.colour_map = {}
107 book.colour_indexes_used = {}
108 if not book.formatting_info:
109 return
110 # Add the 8 invariant colours
111 for i in xrange(8):
112 book.colour_map[i] = excel_default_palette_b8[i]
113 # Add the default palette depending on the version
114 dpal = default_palette[book.biff_version]
115 ndpal = len(dpal)
116 for i in xrange(ndpal):
117 book.colour_map[i+8] = dpal[i]
118 # Add the specials -- None means the RGB value is not known
119 # System window text colour for border lines
120 book.colour_map[ndpal+8] = None
121 # System window background colour for pattern background
122 book.colour_map[ndpal+8+1] = None
123 # System ToolTip text colour (used in note objects)
124 book.colour_map[0x51] = None
125 # 32767, system window text colour for fonts
126 book.colour_map[0x7FFF] = None
129def nearest_colour_index(colour_map, rgb, debug=0):
130 """
131 General purpose function. Uses Euclidean distance.
132 So far used only for pre-BIFF8 ``WINDOW2`` record.
133 Doesn't have to be fast.
134 Doesn't have to be fancy.
135 """
136 best_metric = 3 * 256 * 256
137 best_colourx = 0
138 for colourx, cand_rgb in colour_map.items():
139 if cand_rgb is None:
140 continue
141 metric = 0
142 for v1, v2 in zip(rgb, cand_rgb):
143 metric += (v1 - v2) * (v1 - v2)
144 if metric < best_metric:
145 best_metric = metric
146 best_colourx = colourx
147 if metric == 0:
148 break
149 if 0 and debug:
150 print("nearest_colour_index for %r is %r -> %r; best_metric is %d"
151 % (rgb, best_colourx, colour_map[best_colourx], best_metric))
152 return best_colourx
154class EqNeAttrs(object):
155 """
156 This mixin class exists solely so that :class:`Format`, :class:`Font`, and
157 :class:`XF` objects can be compared by value of their attributes.
158 """
160 def __eq__(self, other):
161 return self.__dict__ == other.__dict__
163 def __ne__(self, other):
164 return self.__dict__ != other.__dict__
166class Font(BaseObject, EqNeAttrs):
167 """
168 An Excel "font" contains the details of not only what is normally
169 considered a font, but also several other display attributes.
170 Items correspond to those in the Excel UI's Format -> Cells -> Font tab.
172 .. versionadded:: 0.6.1
173 """
175 #: 1 = Characters are bold. Redundant; see "weight" attribute.
176 bold = 0
178 #: Values:
179 #: ::
180 #:
181 #: 0 = ANSI Latin
182 #: 1 = System default
183 #: 2 = Symbol,
184 #: 77 = Apple Roman,
185 #: 128 = ANSI Japanese Shift-JIS,
186 #: 129 = ANSI Korean (Hangul),
187 #: 130 = ANSI Korean (Johab),
188 #: 134 = ANSI Chinese Simplified GBK,
189 #: 136 = ANSI Chinese Traditional BIG5,
190 #: 161 = ANSI Greek,
191 #: 162 = ANSI Turkish,
192 #: 163 = ANSI Vietnamese,
193 #: 177 = ANSI Hebrew,
194 #: 178 = ANSI Arabic,
195 #: 186 = ANSI Baltic,
196 #: 204 = ANSI Cyrillic,
197 #: 222 = ANSI Thai,
198 #: 238 = ANSI Latin II (Central European),
199 #: 255 = OEM Latin I
200 character_set = 0
202 #: An explanation of "colour index" is given in :ref:`palette`.
203 colour_index = 0
205 #: 1 = Superscript, 2 = Subscript.
206 escapement = 0
208 #: Values:
209 #: ::
210 #:
211 #: 0 = None (unknown or don't care)
212 #: 1 = Roman (variable width, serifed)
213 #: 2 = Swiss (variable width, sans-serifed)
214 #: 3 = Modern (fixed width, serifed or sans-serifed)
215 #: 4 = Script (cursive)
216 #: 5 = Decorative (specialised, for example Old English, Fraktur)
217 family = 0
219 #: The 0-based index used to refer to this Font() instance.
220 #: Note that index 4 is never used; xlrd supplies a dummy place-holder.
221 font_index = 0
223 #: Height of the font (in twips). A twip = 1/20 of a point.
224 height = 0
226 #: 1 = Characters are italic.
227 italic = 0
229 #: The name of the font. Example: ``"Arial"``.
230 name = UNICODE_LITERAL("")
232 #: 1 = Characters are struck out.
233 struck_out = 0
235 #: Values:
236 #: ::
237 #:
238 #: 0 = None
239 #: 1 = Single; 0x21 (33) = Single accounting
240 #: 2 = Double; 0x22 (34) = Double accounting
241 underline_type = 0
243 #: 1 = Characters are underlined. Redundant; see
244 #: :attr:`underline_type` attribute.
245 underlined = 0
247 #: Font weight (100-1000). Standard values are 400 for normal text
248 #: and 700 for bold text.
249 weight = 400
251 #: 1 = Font is outline style (Macintosh only)
252 outline = 0
254 #: 1 = Font is shadow style (Macintosh only)
255 shadow = 0
257def handle_efont(book, data): # BIFF2 only
258 if not book.formatting_info:
259 return
260 book.font_list[-1].colour_index = unpack('<H', data)[0]
262def handle_font(book, data):
263 if not book.formatting_info:
264 return
265 if not book.encoding:
266 book.derive_encoding()
267 blah = DEBUG or book.verbosity >= 2
268 bv = book.biff_version
269 k = len(book.font_list)
270 if k == 4:
271 f = Font()
272 f.name = UNICODE_LITERAL('Dummy Font')
273 f.font_index = k
274 book.font_list.append(f)
275 k += 1
276 f = Font()
277 f.font_index = k
278 book.font_list.append(f)
279 if bv >= 50:
280 (
281 f.height, option_flags, f.colour_index, f.weight,
282 f.escapement, f.underline_type, f.family,
283 f.character_set,
284 ) = unpack('<HHHHHBBB', data[0:13])
285 f.bold = option_flags & 1
286 f.italic = (option_flags & 2) >> 1
287 f.underlined = (option_flags & 4) >> 2
288 f.struck_out = (option_flags & 8) >> 3
289 f.outline = (option_flags & 16) >> 4
290 f.shadow = (option_flags & 32) >> 5
291 if bv >= 80:
292 f.name = unpack_unicode(data, 14, lenlen=1)
293 else:
294 f.name = unpack_string(data, 14, book.encoding, lenlen=1)
295 elif bv >= 30:
296 f.height, option_flags, f.colour_index = unpack('<HHH', data[0:6])
297 f.bold = option_flags & 1
298 f.italic = (option_flags & 2) >> 1
299 f.underlined = (option_flags & 4) >> 2
300 f.struck_out = (option_flags & 8) >> 3
301 f.outline = (option_flags & 16) >> 4
302 f.shadow = (option_flags & 32) >> 5
303 f.name = unpack_string(data, 6, book.encoding, lenlen=1)
304 # Now cook up the remaining attributes ...
305 f.weight = [400, 700][f.bold]
306 f.escapement = 0 # None
307 f.underline_type = f.underlined # None or Single
308 f.family = 0 # Unknown / don't care
309 f.character_set = 1 # System default (0 means "ANSI Latin")
310 else: # BIFF2
311 f.height, option_flags = unpack('<HH', data[0:4])
312 f.colour_index = 0x7FFF # "system window text colour"
313 f.bold = option_flags & 1
314 f.italic = (option_flags & 2) >> 1
315 f.underlined = (option_flags & 4) >> 2
316 f.struck_out = (option_flags & 8) >> 3
317 f.outline = 0
318 f.shadow = 0
319 f.name = unpack_string(data, 4, book.encoding, lenlen=1)
320 # Now cook up the remaining attributes ...
321 f.weight = [400, 700][f.bold]
322 f.escapement = 0 # None
323 f.underline_type = f.underlined # None or Single
324 f.family = 0 # Unknown / don't care
325 f.character_set = 1 # System default (0 means "ANSI Latin")
326 if blah:
327 f.dump(
328 book.logfile,
329 header="--- handle_font: font[%d] ---" % f.font_index,
330 footer="-------------------",
331 )
333# === "Number formats" ===
335class Format(BaseObject, EqNeAttrs):
336 """
337 "Number format" information from a ``FORMAT`` record.
339 .. versionadded:: 0.6.1
340 """
342 #: The key into :attr:`~xlrd.book.Book.format_map`
343 format_key = 0
345 #: A classification that has been inferred from the format string.
346 #: Currently, this is used only to distinguish between numbers and dates.
347 #: Values::
348 #:
349 #: FUN = 0 # unknown
350 #: FDT = 1 # date
351 #: FNU = 2 # number
352 #: FGE = 3 # general
353 #: FTX = 4 # text
354 type = FUN
356 #: The format string
357 format_str = UNICODE_LITERAL('')
359 def __init__(self, format_key, ty, format_str):
360 self.format_key = format_key
361 self.type = ty
362 self.format_str = format_str
364std_format_strings = {
365 # "std" == "standard for US English locale"
366 # #### TODO ... a lot of work to tailor these to the user's locale.
367 # See e.g. gnumeric-1.x.y/src/formats.c
368 0x00: "General",
369 0x01: "0",
370 0x02: "0.00",
371 0x03: "#,##0",
372 0x04: "#,##0.00",
373 0x05: "$#,##0_);($#,##0)",
374 0x06: "$#,##0_);[Red]($#,##0)",
375 0x07: "$#,##0.00_);($#,##0.00)",
376 0x08: "$#,##0.00_);[Red]($#,##0.00)",
377 0x09: "0%",
378 0x0a: "0.00%",
379 0x0b: "0.00E+00",
380 0x0c: "# ?/?",
381 0x0d: "# ??/??",
382 0x0e: "m/d/yy",
383 0x0f: "d-mmm-yy",
384 0x10: "d-mmm",
385 0x11: "mmm-yy",
386 0x12: "h:mm AM/PM",
387 0x13: "h:mm:ss AM/PM",
388 0x14: "h:mm",
389 0x15: "h:mm:ss",
390 0x16: "m/d/yy h:mm",
391 0x25: "#,##0_);(#,##0)",
392 0x26: "#,##0_);[Red](#,##0)",
393 0x27: "#,##0.00_);(#,##0.00)",
394 0x28: "#,##0.00_);[Red](#,##0.00)",
395 0x29: "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
396 0x2a: "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
397 0x2b: "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
398 0x2c: "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
399 0x2d: "mm:ss",
400 0x2e: "[h]:mm:ss",
401 0x2f: "mm:ss.0",
402 0x30: "##0.0E+0",
403 0x31: "@",
404}
406fmt_code_ranges = [ # both-inclusive ranges of "standard" format codes
407 # Source: the openoffice.org doc't
408 # and the OOXML spec Part 4, section 3.8.30
409 ( 0, 0, FGE),
410 ( 1, 13, FNU),
411 (14, 22, FDT),
412 (27, 36, FDT), # CJK date formats
413 (37, 44, FNU),
414 (45, 47, FDT),
415 (48, 48, FNU),
416 (49, 49, FTX),
417 # Gnumeric assumes (or assumed) that built-in formats finish at 49, not at 163
418 (50, 58, FDT), # CJK date formats
419 (59, 62, FNU), # Thai number (currency?) formats
420 (67, 70, FNU), # Thai number (currency?) formats
421 (71, 81, FDT), # Thai date formats
422]
424std_format_code_types = {}
425for lo, hi, ty in fmt_code_ranges:
426 for x in xrange(lo, hi+1):
427 std_format_code_types[x] = ty
428del lo, hi, ty, x
430date_chars = UNICODE_LITERAL('ymdhs') # year, month/minute, day, hour, second
431date_char_dict = {}
432for _c in date_chars + date_chars.upper():
433 date_char_dict[_c] = 5
434del _c, date_chars
436skip_char_dict = {}
437for _c in UNICODE_LITERAL('$-+/(): '):
438 skip_char_dict[_c] = 1
440num_char_dict = {
441 UNICODE_LITERAL('0'): 5,
442 UNICODE_LITERAL('#'): 5,
443 UNICODE_LITERAL('?'): 5,
444}
446non_date_formats = {
447 UNICODE_LITERAL('0.00E+00'):1,
448 UNICODE_LITERAL('##0.0E+0'):1,
449 UNICODE_LITERAL('General') :1,
450 UNICODE_LITERAL('GENERAL') :1, # OOo Calc 1.1.4 does this.
451 UNICODE_LITERAL('general') :1, # pyExcelerator 0.6.3 does this.
452 UNICODE_LITERAL('@') :1,
453}
455fmt_bracketed_sub = re.compile(r'\[[^]]*\]').sub
457# Boolean format strings (actual cases)
458# '"Yes";"Yes";"No"'
459# '"True";"True";"False"'
460# '"On";"On";"Off"'
462def is_date_format_string(book, fmt):
463 # Heuristics:
464 # Ignore "text" and [stuff in square brackets (aarrgghh -- see below)].
465 # Handle backslashed-escaped chars properly.
466 # E.g. hh\hmm\mss\s should produce a display like 23h59m59s
467 # Date formats have one or more of ymdhs (caseless) in them.
468 # Numeric formats have # and 0.
469 # N.B. 'General"."' hence get rid of "text" first.
470 # TODO: Find where formats are interpreted in Gnumeric
471 # TODO: '[h]\\ \\h\\o\\u\\r\\s' ([h] means don't care about hours > 23)
472 state = 0
473 s = ''
475 for c in fmt:
476 if state == 0:
477 if c == UNICODE_LITERAL('"'):
478 state = 1
479 elif c in UNICODE_LITERAL(r"\_*"):
480 state = 2
481 elif c in skip_char_dict:
482 pass
483 else:
484 s += c
485 elif state == 1:
486 if c == UNICODE_LITERAL('"'):
487 state = 0
488 elif state == 2:
489 # Ignore char after backslash, underscore or asterisk
490 state = 0
491 assert 0 <= state <= 2
492 if book.verbosity >= 4:
493 print("is_date_format_string: reduced format is %s" % REPR(s), file=book.logfile)
494 s = fmt_bracketed_sub('', s)
495 if s in non_date_formats:
496 return False
497 state = 0
498 separator = ";"
499 got_sep = 0
500 date_count = num_count = 0
501 for c in s:
502 if c in date_char_dict:
503 date_count += date_char_dict[c]
504 elif c in num_char_dict:
505 num_count += num_char_dict[c]
506 elif c == separator:
507 got_sep = 1
508 # print num_count, date_count, repr(fmt)
509 if date_count and not num_count:
510 return True
511 if num_count and not date_count:
512 return False
513 if date_count:
514 if book.verbosity:
515 fprintf(book.logfile,
516 'WARNING *** is_date_format: ambiguous d=%d n=%d fmt=%r\n',
517 date_count, num_count, fmt)
518 elif not got_sep:
519 if book.verbosity:
520 fprintf(book.logfile,
521 "WARNING *** format %r produces constant result\n",
522 fmt)
523 return date_count > num_count
525def handle_format(self, data, rectype=XL_FORMAT):
526 DEBUG = 0
527 bv = self.biff_version
528 if rectype == XL_FORMAT2:
529 bv = min(bv, 30)
530 if not self.encoding:
531 self.derive_encoding()
532 strpos = 2
533 if bv >= 50:
534 fmtkey = unpack('<H', data[0:2])[0]
535 else:
536 fmtkey = self.actualfmtcount
537 if bv <= 30:
538 strpos = 0
539 self.actualfmtcount += 1
540 if bv >= 80:
541 unistrg = unpack_unicode(data, 2)
542 else:
543 unistrg = unpack_string(data, strpos, self.encoding, lenlen=1)
544 blah = DEBUG or self.verbosity >= 3
545 if blah:
546 fprintf(self.logfile,
547 "FORMAT: count=%d fmtkey=0x%04x (%d) s=%r\n",
548 self.actualfmtcount, fmtkey, fmtkey, unistrg)
549 is_date_s = self.is_date_format_string(unistrg)
550 ty = [FGE, FDT][is_date_s]
551 if not(fmtkey > 163 or bv < 50):
552 # user_defined if fmtkey > 163
553 # N.B. Gnumeric incorrectly starts these at 50 instead of 164 :-(
554 # if earlier than BIFF 5, standard info is useless
555 std_ty = std_format_code_types.get(fmtkey, FUN)
556 # print "std ty", std_ty
557 is_date_c = std_ty == FDT
558 if self.verbosity and 0 < fmtkey < 50 and (is_date_c ^ is_date_s):
559 DEBUG = 2
560 fprintf(self.logfile,
561 "WARNING *** Conflict between "
562 "std format key %d and its format string %r\n",
563 fmtkey, unistrg)
564 if DEBUG == 2:
565 fprintf(self.logfile,
566 "ty: %d; is_date_c: %r; is_date_s: %r; fmt_strg: %r",
567 ty, is_date_c, is_date_s, unistrg)
568 fmtobj = Format(fmtkey, ty, unistrg)
569 if blah:
570 fmtobj.dump(self.logfile,
571 header="--- handle_format [%d] ---" % (self.actualfmtcount-1, ))
572 self.format_map[fmtkey] = fmtobj
573 self.format_list.append(fmtobj)
575# =============================================================================
577def handle_palette(book, data):
578 if not book.formatting_info:
579 return
580 blah = DEBUG or book.verbosity >= 2
581 n_colours, = unpack('<H', data[:2])
582 expected_n_colours = (16, 56)[book.biff_version >= 50]
583 if (DEBUG or book.verbosity >= 1) and n_colours != expected_n_colours:
584 fprintf(book.logfile,
585 "NOTE *** Expected %d colours in PALETTE record, found %d\n",
586 expected_n_colours, n_colours)
587 elif blah:
588 fprintf(book.logfile,
589 "PALETTE record with %d colours\n", n_colours)
590 fmt = '<xx%di' % n_colours # use i to avoid long integers
591 expected_size = 4 * n_colours + 2
592 actual_size = len(data)
593 tolerance = 4
594 if not expected_size <= actual_size <= expected_size + tolerance:
595 raise XLRDError('PALETTE record: expected size %d, actual size %d' % (expected_size, actual_size))
596 colours = unpack(fmt, data[:expected_size])
597 assert book.palette_record == [] # There should be only 1 PALETTE record
598 # a colour will be 0xbbggrr
599 # IOW, red is at the little end
600 for i in xrange(n_colours):
601 c = colours[i]
602 red = c & 0xff
603 green = (c >> 8) & 0xff
604 blue = (c >> 16) & 0xff
605 old_rgb = book.colour_map[8+i]
606 new_rgb = (red, green, blue)
607 book.palette_record.append(new_rgb)
608 book.colour_map[8+i] = new_rgb
609 if blah:
610 if new_rgb != old_rgb:
611 print("%2d: %r -> %r" % (i, old_rgb, new_rgb), file=book.logfile)
613def palette_epilogue(book):
614 # Check colour indexes in fonts etc.
615 # This must be done here as FONT records
616 # come *before* the PALETTE record :-(
617 for font in book.font_list:
618 if font.font_index == 4: # the missing font record
619 continue
620 cx = font.colour_index
621 if cx == 0x7fff: # system window text colour
622 continue
623 if cx in book.colour_map:
624 book.colour_indexes_used[cx] = 1
625 elif book.verbosity:
626 print("Size of colour table:", len(book.colour_map), file=book.logfile)
627 fprintf(book.logfile, "*** Font #%d (%r): colour index 0x%04x is unknown\n",
628 font.font_index, font.name, cx)
629 if book.verbosity >= 1:
630 used = sorted(book.colour_indexes_used.keys())
631 print("\nColour indexes used:\n%r\n" % used, file=book.logfile)
633def handle_style(book, data):
634 if not book.formatting_info:
635 return
636 blah = DEBUG or book.verbosity >= 2
637 bv = book.biff_version
638 flag_and_xfx, built_in_id, level = unpack('<HBB', data[:4])
639 xf_index = flag_and_xfx & 0x0fff
640 if data == b"\0\0\0\0" and "Normal" not in book.style_name_map:
641 # Erroneous record (doesn't have built-in bit set).
642 # Example file supplied by Jeff Bell.
643 built_in = 1
644 built_in_id = 0
645 xf_index = 0
646 name = "Normal"
647 level = 255
648 elif flag_and_xfx & 0x8000:
649 # built-in style
650 built_in = 1
651 name = built_in_style_names[built_in_id]
652 if 1 <= built_in_id <= 2:
653 name += str(level + 1)
654 else:
655 # user-defined style
656 built_in = 0
657 built_in_id = 0
658 level = 0
659 if bv >= 80:
660 try:
661 name = unpack_unicode(data, 2, lenlen=2)
662 except UnicodeDecodeError:
663 print("STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d"
664 % (built_in, xf_index, built_in_id, level), file=book.logfile)
665 print("raw bytes:", repr(data[2:]), file=book.logfile)
666 raise
667 else:
668 name = unpack_string(data, 2, book.encoding, lenlen=1)
669 if blah and not name:
670 print("WARNING *** A user-defined style has a zero-length name", file=book.logfile)
671 book.style_name_map[name] = (built_in, xf_index)
672 if blah:
673 fprintf(book.logfile, "STYLE: built_in=%d xf_index=%d built_in_id=%d level=%d name=%r\n",
674 built_in, xf_index, built_in_id, level, name)
676def check_colour_indexes_in_obj(book, obj, orig_index):
677 alist = sorted(obj.__dict__.items())
678 for attr, nobj in alist:
679 if hasattr(nobj, 'dump'):
680 check_colour_indexes_in_obj(book, nobj, orig_index)
681 elif attr.find('colour_index') >= 0:
682 if nobj in book.colour_map:
683 book.colour_indexes_used[nobj] = 1
684 continue
685 oname = obj.__class__.__name__
686 print("*** xf #%d : %s.%s = 0x%04x (unknown)"
687 % (orig_index, oname, attr, nobj), file=book.logfile)
689def fill_in_standard_formats(book):
690 for x in std_format_code_types.keys():
691 if x not in book.format_map:
692 ty = std_format_code_types[x]
693 # Note: many standard format codes (mostly CJK date formats) have
694 # format strings that vary by locale; xlrd does not (yet)
695 # handle those; the type (date or numeric) is recorded but the fmt_str will be None.
696 fmt_str = std_format_strings.get(x)
697 fmtobj = Format(x, ty, fmt_str)
698 book.format_map[x] = fmtobj
700def handle_xf(self, data):
701 # self is a Book instance
702 # DEBUG = 0
703 blah = DEBUG or self.verbosity >= 3
704 bv = self.biff_version
705 xf = XF()
706 xf.alignment = XFAlignment()
707 xf.alignment.indent_level = 0
708 xf.alignment.shrink_to_fit = 0
709 xf.alignment.text_direction = 0
710 xf.border = XFBorder()
711 xf.border.diag_up = 0
712 xf.border.diag_down = 0
713 xf.border.diag_colour_index = 0
714 xf.border.diag_line_style = 0 # no line
715 xf.background = XFBackground()
716 xf.protection = XFProtection()
717 # fill in the known standard formats
718 if bv >= 50 and not self.xfcount:
719 # i.e. do this once before we process the first XF record
720 fill_in_standard_formats(self)
721 if bv >= 80:
722 unpack_fmt = '<HHHBBBBIiH'
723 (
724 xf.font_index, xf.format_key, pkd_type_par,
725 pkd_align1, xf.alignment.rotation, pkd_align2,
726 pkd_used, pkd_brdbkg1, pkd_brdbkg2, pkd_brdbkg3,
727 ) = unpack(unpack_fmt, data[0:20])
728 upkbits(xf.protection, pkd_type_par, (
729 (0, 0x01, 'cell_locked'),
730 (1, 0x02, 'formula_hidden'),
731 ))
732 upkbits(xf, pkd_type_par, (
733 (2, 0x0004, 'is_style'),
734 # Following is not in OOo docs, but is mentioned
735 # in Gnumeric source and also in (deep breath)
736 # org.apache.poi.hssf.record.ExtendedFormatRecord.java
737 (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
738 (4, 0xFFF0, 'parent_style_index'),
739 ))
740 upkbits(xf.alignment, pkd_align1, (
741 (0, 0x07, 'hor_align'),
742 (3, 0x08, 'text_wrapped'),
743 (4, 0x70, 'vert_align'),
744 ))
745 upkbits(xf.alignment, pkd_align2, (
746 (0, 0x0f, 'indent_level'),
747 (4, 0x10, 'shrink_to_fit'),
748 (6, 0xC0, 'text_direction'),
749 ))
750 reg = pkd_used >> 2
751 attr_stems = [
752 'format',
753 'font',
754 'alignment',
755 'border',
756 'background',
757 'protection',
758 ]
759 for attr_stem in attr_stems:
760 attr = "_" + attr_stem + "_flag"
761 setattr(xf, attr, reg & 1)
762 reg >>= 1
763 upkbitsL(xf.border, pkd_brdbkg1, (
764 (0, 0x0000000f, 'left_line_style'),
765 (4, 0x000000f0, 'right_line_style'),
766 (8, 0x00000f00, 'top_line_style'),
767 (12, 0x0000f000, 'bottom_line_style'),
768 (16, 0x007f0000, 'left_colour_index'),
769 (23, 0x3f800000, 'right_colour_index'),
770 (30, 0x40000000, 'diag_down'),
771 (31, 0x80000000, 'diag_up'),
772 ))
773 upkbits(xf.border, pkd_brdbkg2, (
774 (0, 0x0000007F, 'top_colour_index'),
775 (7, 0x00003F80, 'bottom_colour_index'),
776 (14, 0x001FC000, 'diag_colour_index'),
777 (21, 0x01E00000, 'diag_line_style'),
778 ))
779 upkbitsL(xf.background, pkd_brdbkg2, (
780 (26, 0xFC000000, 'fill_pattern'),
781 ))
782 upkbits(xf.background, pkd_brdbkg3, (
783 (0, 0x007F, 'pattern_colour_index'),
784 (7, 0x3F80, 'background_colour_index'),
785 ))
786 elif bv >= 50:
787 unpack_fmt = '<HHHBBIi'
788 (
789 xf.font_index, xf.format_key, pkd_type_par,
790 pkd_align1, pkd_orient_used,
791 pkd_brdbkg1, pkd_brdbkg2,
792 ) = unpack(unpack_fmt, data[0:16])
793 upkbits(xf.protection, pkd_type_par, (
794 (0, 0x01, 'cell_locked'),
795 (1, 0x02, 'formula_hidden'),
796 ))
797 upkbits(xf, pkd_type_par, (
798 (2, 0x0004, 'is_style'),
799 (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
800 (4, 0xFFF0, 'parent_style_index'),
801 ))
802 upkbits(xf.alignment, pkd_align1, (
803 (0, 0x07, 'hor_align'),
804 (3, 0x08, 'text_wrapped'),
805 (4, 0x70, 'vert_align'),
806 ))
807 orientation = pkd_orient_used & 0x03
808 xf.alignment.rotation = [0, 255, 90, 180][orientation]
809 reg = pkd_orient_used >> 2
810 attr_stems = [
811 'format',
812 'font',
813 'alignment',
814 'border',
815 'background',
816 'protection',
817 ]
818 for attr_stem in attr_stems:
819 attr = "_" + attr_stem + "_flag"
820 setattr(xf, attr, reg & 1)
821 reg >>= 1
822 upkbitsL(xf.background, pkd_brdbkg1, (
823 ( 0, 0x0000007F, 'pattern_colour_index'),
824 ( 7, 0x00003F80, 'background_colour_index'),
825 (16, 0x003F0000, 'fill_pattern'),
826 ))
827 upkbitsL(xf.border, pkd_brdbkg1, (
828 (22, 0x01C00000, 'bottom_line_style'),
829 (25, 0xFE000000, 'bottom_colour_index'),
830 ))
831 upkbits(xf.border, pkd_brdbkg2, (
832 ( 0, 0x00000007, 'top_line_style'),
833 ( 3, 0x00000038, 'left_line_style'),
834 ( 6, 0x000001C0, 'right_line_style'),
835 ( 9, 0x0000FE00, 'top_colour_index'),
836 (16, 0x007F0000, 'left_colour_index'),
837 (23, 0x3F800000, 'right_colour_index'),
838 ))
839 elif bv >= 40:
840 unpack_fmt = '<BBHBBHI'
841 (
842 xf.font_index, xf.format_key, pkd_type_par,
843 pkd_align_orient, pkd_used,
844 pkd_bkg_34, pkd_brd_34,
845 ) = unpack(unpack_fmt, data[0:12])
846 upkbits(xf.protection, pkd_type_par, (
847 (0, 0x01, 'cell_locked'),
848 (1, 0x02, 'formula_hidden'),
849 ))
850 upkbits(xf, pkd_type_par, (
851 (2, 0x0004, 'is_style'),
852 (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
853 (4, 0xFFF0, 'parent_style_index'),
854 ))
855 upkbits(xf.alignment, pkd_align_orient, (
856 (0, 0x07, 'hor_align'),
857 (3, 0x08, 'text_wrapped'),
858 (4, 0x30, 'vert_align'),
859 ))
860 orientation = (pkd_align_orient & 0xC0) >> 6
861 xf.alignment.rotation = [0, 255, 90, 180][orientation]
862 reg = pkd_used >> 2
863 attr_stems = [
864 'format',
865 'font',
866 'alignment',
867 'border',
868 'background',
869 'protection',
870 ]
871 for attr_stem in attr_stems:
872 attr = "_" + attr_stem + "_flag"
873 setattr(xf, attr, reg & 1)
874 reg >>= 1
875 upkbits(xf.background, pkd_bkg_34, (
876 ( 0, 0x003F, 'fill_pattern'),
877 ( 6, 0x07C0, 'pattern_colour_index'),
878 (11, 0xF800, 'background_colour_index'),
879 ))
880 upkbitsL(xf.border, pkd_brd_34, (
881 ( 0, 0x00000007, 'top_line_style'),
882 ( 3, 0x000000F8, 'top_colour_index'),
883 ( 8, 0x00000700, 'left_line_style'),
884 (11, 0x0000F800, 'left_colour_index'),
885 (16, 0x00070000, 'bottom_line_style'),
886 (19, 0x00F80000, 'bottom_colour_index'),
887 (24, 0x07000000, 'right_line_style'),
888 (27, 0xF8000000, 'right_colour_index'),
889 ))
890 elif bv == 30:
891 unpack_fmt = '<BBBBHHI'
892 (
893 xf.font_index, xf.format_key, pkd_type_prot,
894 pkd_used, pkd_align_par,
895 pkd_bkg_34, pkd_brd_34,
896 ) = unpack(unpack_fmt, data[0:12])
897 upkbits(xf.protection, pkd_type_prot, (
898 (0, 0x01, 'cell_locked'),
899 (1, 0x02, 'formula_hidden'),
900 ))
901 upkbits(xf, pkd_type_prot, (
902 (2, 0x0004, 'is_style'),
903 (3, 0x0008, 'lotus_123_prefix'), # Meaning is not known.
904 ))
905 upkbits(xf.alignment, pkd_align_par, (
906 (0, 0x07, 'hor_align'),
907 (3, 0x08, 'text_wrapped'),
908 ))
909 upkbits(xf, pkd_align_par, (
910 (4, 0xFFF0, 'parent_style_index'),
911 ))
912 reg = pkd_used >> 2
913 attr_stems = [
914 'format',
915 'font',
916 'alignment',
917 'border',
918 'background',
919 'protection',
920 ]
921 for attr_stem in attr_stems:
922 attr = "_" + attr_stem + "_flag"
923 setattr(xf, attr, reg & 1)
924 reg >>= 1
925 upkbits(xf.background, pkd_bkg_34, (
926 ( 0, 0x003F, 'fill_pattern'),
927 ( 6, 0x07C0, 'pattern_colour_index'),
928 (11, 0xF800, 'background_colour_index'),
929 ))
930 upkbitsL(xf.border, pkd_brd_34, (
931 ( 0, 0x00000007, 'top_line_style'),
932 ( 3, 0x000000F8, 'top_colour_index'),
933 ( 8, 0x00000700, 'left_line_style'),
934 (11, 0x0000F800, 'left_colour_index'),
935 (16, 0x00070000, 'bottom_line_style'),
936 (19, 0x00F80000, 'bottom_colour_index'),
937 (24, 0x07000000, 'right_line_style'),
938 (27, 0xF8000000, 'right_colour_index'),
939 ))
940 xf.alignment.vert_align = 2 # bottom
941 xf.alignment.rotation = 0
942 elif bv == 21:
943 ## Warning: incomplete treatment; formatting_info not fully supported.
944 ## Probably need to offset incoming BIFF2 XF[n] to BIFF8-like XF[n+16],
945 ## and create XF[0:16] like the standard ones in BIFF8 *AND* add 16 to
946 ## all XF references in cell records :-(
947 (xf.font_index, format_etc, halign_etc) = unpack('<BxBB', data)
948 xf.format_key = format_etc & 0x3F
949 upkbits(xf.protection, format_etc, (
950 (6, 0x40, 'cell_locked'),
951 (7, 0x80, 'formula_hidden'),
952 ))
953 upkbits(xf.alignment, halign_etc, (
954 (0, 0x07, 'hor_align'),
955 ))
956 for mask, side in ((0x08, 'left'), (0x10, 'right'), (0x20, 'top'), (0x40, 'bottom')):
957 if halign_etc & mask:
958 colour_index, line_style = 8, 1 # black, thin
959 else:
960 colour_index, line_style = 0, 0 # none, none
961 setattr(xf.border, side + '_colour_index', colour_index)
962 setattr(xf.border, side + '_line_style', line_style)
963 bg = xf.background
964 if halign_etc & 0x80:
965 bg.fill_pattern = 17
966 else:
967 bg.fill_pattern = 0
968 bg.background_colour_index = 9 # white
969 bg.pattern_colour_index = 8 # black
970 xf.parent_style_index = 0 # ???????????
971 xf.alignment.vert_align = 2 # bottom
972 xf.alignment.rotation = 0
973 attr_stems = [
974 'format',
975 'font',
976 'alignment',
977 'border',
978 'background',
979 'protection',
980 ]
981 for attr_stem in attr_stems:
982 attr = "_" + attr_stem + "_flag"
983 setattr(xf, attr, 1)
984 else:
985 raise XLRDError('programmer stuff-up: bv=%d' % bv)
987 xf.xf_index = len(self.xf_list)
988 self.xf_list.append(xf)
989 self.xfcount += 1
990 if blah:
991 xf.dump(
992 self.logfile,
993 header="--- handle_xf: xf[%d] ---" % xf.xf_index,
994 footer=" ",
995 )
996 try:
997 fmt = self.format_map[xf.format_key]
998 cellty = _cellty_from_fmtty[fmt.type]
999 except KeyError:
1000 cellty = XL_CELL_NUMBER
1001 self._xf_index_to_xl_type_map[xf.xf_index] = cellty
1003 # Now for some assertions ...
1004 if self.formatting_info:
1005 if self.verbosity and xf.is_style and xf.parent_style_index != 0x0FFF:
1006 msg = "WARNING *** XF[%d] is a style XF but parent_style_index is 0x%04x, not 0x0fff\n"
1007 fprintf(self.logfile, msg, xf.xf_index, xf.parent_style_index)
1008 check_colour_indexes_in_obj(self, xf, xf.xf_index)
1009 if xf.format_key not in self.format_map:
1010 msg = "WARNING *** XF[%d] unknown (raw) format key (%d, 0x%04x)\n"
1011 if self.verbosity:
1012 fprintf(self.logfile, msg,
1013 xf.xf_index, xf.format_key, xf.format_key)
1014 xf.format_key = 0
1016def xf_epilogue(self):
1017 # self is a Book instance.
1018 self._xf_epilogue_done = 1
1019 num_xfs = len(self.xf_list)
1020 blah = DEBUG or self.verbosity >= 3
1021 blah1 = DEBUG or self.verbosity >= 1
1022 if blah:
1023 fprintf(self.logfile, "xf_epilogue called ...\n")
1025 def check_same(book_arg, xf_arg, parent_arg, attr):
1026 # the _arg caper is to avoid a Warning msg from Python 2.1 :-(
1027 if getattr(xf_arg, attr) != getattr(parent_arg, attr):
1028 fprintf(book_arg.logfile,
1029 "NOTE !!! XF[%d] parent[%d] %s different\n",
1030 xf_arg.xf_index, parent_arg.xf_index, attr)
1032 for xfx in xrange(num_xfs):
1033 xf = self.xf_list[xfx]
1035 try:
1036 fmt = self.format_map[xf.format_key]
1037 cellty = _cellty_from_fmtty[fmt.type]
1038 except KeyError:
1039 cellty = XL_CELL_TEXT
1040 self._xf_index_to_xl_type_map[xf.xf_index] = cellty
1041 # Now for some assertions etc
1042 if not self.formatting_info:
1043 continue
1044 if xf.is_style:
1045 continue
1046 if not(0 <= xf.parent_style_index < num_xfs):
1047 if blah1:
1048 fprintf(self.logfile,
1049 "WARNING *** XF[%d]: is_style=%d but parent_style_index=%d\n",
1050 xf.xf_index, xf.is_style, xf.parent_style_index)
1051 # make it conform
1052 xf.parent_style_index = 0
1053 if self.biff_version >= 30:
1054 if blah1:
1055 if xf.parent_style_index == xf.xf_index:
1056 fprintf(self.logfile,
1057 "NOTE !!! XF[%d]: parent_style_index is also %d\n",
1058 xf.xf_index, xf.parent_style_index)
1059 elif not self.xf_list[xf.parent_style_index].is_style:
1060 fprintf(self.logfile,
1061 "NOTE !!! XF[%d]: parent_style_index is %d; style flag not set\n",
1062 xf.xf_index, xf.parent_style_index)
1063 if blah1 and xf.parent_style_index > xf.xf_index:
1064 fprintf(self.logfile,
1065 "NOTE !!! XF[%d]: parent_style_index is %d; out of order?\n",
1066 xf.xf_index, xf.parent_style_index)
1067 parent = self.xf_list[xf.parent_style_index]
1068 if not xf._alignment_flag and not parent._alignment_flag:
1069 if blah1: check_same(self, xf, parent, 'alignment')
1070 if not xf._background_flag and not parent._background_flag:
1071 if blah1: check_same(self, xf, parent, 'background')
1072 if not xf._border_flag and not parent._border_flag:
1073 if blah1: check_same(self, xf, parent, 'border')
1074 if not xf._protection_flag and not parent._protection_flag:
1075 if blah1: check_same(self, xf, parent, 'protection')
1076 if not xf._format_flag and not parent._format_flag:
1077 if blah1 and xf.format_key != parent.format_key:
1078 fprintf(self.logfile,
1079 "NOTE !!! XF[%d] fmtk=%d, parent[%d] fmtk=%r\n%r / %r\n",
1080 xf.xf_index, xf.format_key, parent.xf_index, parent.format_key,
1081 self.format_map[xf.format_key].format_str,
1082 self.format_map[parent.format_key].format_str)
1083 if not xf._font_flag and not parent._font_flag:
1084 if blah1 and xf.font_index != parent.font_index:
1085 fprintf(self.logfile,
1086 "NOTE !!! XF[%d] fontx=%d, parent[%d] fontx=%r\n",
1087 xf.xf_index, xf.font_index, parent.xf_index, parent.font_index)
1089def initialise_book(book):
1090 initialise_colour_map(book)
1091 book._xf_epilogue_done = 0
1092 methods = (
1093 handle_font,
1094 handle_efont,
1095 handle_format,
1096 is_date_format_string,
1097 handle_palette,
1098 palette_epilogue,
1099 handle_style,
1100 handle_xf,
1101 xf_epilogue,
1102 )
1103 for method in methods:
1104 setattr(book.__class__, method.__name__, method)
1106class XFBorder(BaseObject, EqNeAttrs):
1107 """
1108 A collection of the border-related attributes of an ``XF`` record.
1109 Items correspond to those in the Excel UI's Format -> Cells -> Border tab.
1111 An explanations of "colour index" is given in :ref:`palette`.
1113 There are five line style attributes; possible values and the
1114 associated meanings are::
1116 0 = No line,
1117 1 = Thin,
1118 2 = Medium,
1119 3 = Dashed,
1120 4 = Dotted,
1121 5 = Thick,
1122 6 = Double,
1123 7 = Hair,
1124 8 = Medium dashed,
1125 9 = Thin dash-dotted,
1126 10 = Medium dash-dotted,
1127 11 = Thin dash-dot-dotted,
1128 12 = Medium dash-dot-dotted,
1129 13 = Slanted medium dash-dotted.
1131 The line styles 8 to 13 appear in BIFF8 files (Excel 97 and later) only.
1132 For pictures of the line styles, refer to OOo docs s3.10 (p22)
1133 "Line Styles for Cell Borders (BIFF3-BIFF8)".</p>
1135 .. versionadded:: 0.6.1
1136 """
1138 #: The colour index for the cell's top line
1139 top_colour_index = 0
1140 #: The colour index for the cell's bottom line
1141 bottom_colour_index = 0
1143 #: The colour index for the cell's left line
1144 left_colour_index = 0
1146 #: The colour index for the cell's right line
1147 right_colour_index = 0
1149 #: The colour index for the cell's diagonal lines, if any
1150 diag_colour_index = 0
1152 #: The line style for the cell's top line
1153 top_line_style = 0
1155 #: The line style for the cell's bottom line
1156 bottom_line_style = 0
1158 #: The line style for the cell's left line
1159 left_line_style = 0
1161 #: The line style for the cell's right line
1162 right_line_style = 0
1164 #: The line style for the cell's diagonal lines, if any
1165 diag_line_style = 0
1167 #: 1 = draw a diagonal from top left to bottom right
1168 diag_down = 0
1170 #: 1 = draw a diagonal from bottom left to top right
1171 diag_up = 0
1173class XFBackground(BaseObject, EqNeAttrs):
1174 """
1175 A collection of the background-related attributes of an ``XF`` record.
1176 Items correspond to those in the Excel UI's Format -> Cells -> Patterns tab.
1178 An explanations of "colour index" is given in :ref:`palette`.
1180 .. versionadded:: 0.6.1
1181 """
1183 #: See section 3.11 of the OOo docs.
1184 fill_pattern = 0
1186 #: See section 3.11 of the OOo docs.
1187 background_colour_index = 0
1189 #: See section 3.11 of the OOo docs.
1190 pattern_colour_index = 0
1193class XFAlignment(BaseObject, EqNeAttrs):
1194 """
1195 A collection of the alignment and similar attributes of an ``XF`` record.
1196 Items correspond to those in the Excel UI's Format -> Cells -> Alignment tab.
1198 .. versionadded:: 0.6.1
1199 """
1201 #: Values: section 6.115 (p 214) of OOo docs
1202 hor_align = 0
1204 #: Values: section 6.115 (p 215) of OOo docs
1205 vert_align = 0
1207 #: Values: section 6.115 (p 215) of OOo docs.
1208 #:
1209 #: .. note::
1210 #: file versions BIFF7 and earlier use the documented
1211 #: :attr:`orientation` attribute; this will be mapped (without loss)
1212 #: into :attr:`rotation`.
1213 rotation = 0
1215 #: 1 = text is wrapped at right margin
1216 text_wrapped = 0
1218 #: A number in ``range(15)``.
1219 indent_level = 0
1221 #: 1 = shrink font size to fit text into cell.
1222 shrink_to_fit = 0
1224 #: 0 = according to context; 1 = left-to-right; 2 = right-to-left
1225 text_direction = 0
1227class XFProtection(BaseObject, EqNeAttrs):
1228 """
1229 A collection of the protection-related attributes of an ``XF`` record.
1230 Items correspond to those in the Excel UI's Format -> Cells -> Protection tab.
1231 Note the OOo docs include the "cell or style" bit in this bundle of
1232 attributes. This is incorrect; the bit is used in determining which bundles
1233 to use.
1235 .. versionadded:: 0.6.1
1236 """
1238 #: 1 = Cell is prevented from being changed, moved, resized, or deleted
1239 #: (only if the sheet is protected).
1240 cell_locked = 0
1242 #: 1 = Hide formula so that it doesn't appear in the formula bar when
1243 #: the cell is selected (only if the sheet is protected).
1244 formula_hidden = 0
1246class XF(BaseObject):
1247 """
1248 eXtended Formatting information for cells, rows, columns and styles.
1250 Each of the 6 flags below describes the validity of
1251 a specific group of attributes.
1253 In cell XFs:
1255 - ``flag==0`` means the attributes of the parent style ``XF`` are
1256 used, (but only if the attributes are valid there);
1258 - ``flag==1`` means the attributes of this ``XF`` are used.
1260 In style XFs:
1262 - ``flag==0`` means the attribute setting is valid;
1263 - ``flag==1`` means the attribute should be ignored.
1265 .. note::
1266 the API provides both "raw" XFs and "computed" XFs. In the latter case,
1267 cell XFs have had the above inheritance mechanism applied.
1269 .. versionadded:: 0.6.1
1270 """
1272 #: 0 = cell XF, 1 = style XF
1273 is_style = 0
1275 #: cell XF: Index into Book.xf_list of this XF's style XF
1276 #:
1277 #: style XF: 0xFFF
1278 parent_style_index = 0
1280 #
1281 _format_flag = 0
1283 #
1284 _font_flag = 0
1286 #
1287 _alignment_flag = 0
1289 #
1290 _border_flag = 0
1292 #
1293 _background_flag = 0
1295 _protection_flag = 0
1297 #: Index into :attr:`~xlrd.book.Book.xf_list`
1298 xf_index = 0
1300 #: Index into :attr:`~xlrd.book.Book.font_list`
1301 font_index = 0
1303 #: Key into :attr:`~xlrd.book.Book.format_map`
1304 #:
1305 #: .. warning::
1306 #: OOo docs on the XF record call this "Index to FORMAT record".
1307 #: It is not an index in the Python sense. It is a key to a map.
1308 #: It is true *only* for Excel 4.0 and earlier files
1309 #: that the key into format_map from an XF instance
1310 #: is the same as the index into format_list, and *only*
1311 #: if the index is less than 164.
1312 format_key = 0
1314 #: An instance of an :class:`XFProtection` object.
1315 protection = None
1317 #: An instance of an :class:`XFBackground` object.
1318 background = None
1320 #: An instance of an :class:`XFAlignment` object.
1321 alignment = None
1323 #: An instance of an :class:`XFBorder` object.
1324 border = None