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

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""" 

10 

11from __future__ import print_function 

12 

13import re 

14from struct import unpack 

15 

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 * 

22 

23DEBUG = 0 

24 

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} 

32 

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) 

49 

50excel_default_palette_b2 = excel_default_palette_b5[:16] 

51 

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) 

70 

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} 

81 

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] 

104 

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 

127 

128 

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 

153 

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 """ 

159 

160 def __eq__(self, other): 

161 return self.__dict__ == other.__dict__ 

162 

163 def __ne__(self, other): 

164 return self.__dict__ != other.__dict__ 

165 

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. 

171 

172 .. versionadded:: 0.6.1 

173 """ 

174 

175 #: 1 = Characters are bold. Redundant; see "weight" attribute. 

176 bold = 0 

177 

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 

201 

202 #: An explanation of "colour index" is given in :ref:`palette`. 

203 colour_index = 0 

204 

205 #: 1 = Superscript, 2 = Subscript. 

206 escapement = 0 

207 

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 

218 

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 

222 

223 #: Height of the font (in twips). A twip = 1/20 of a point. 

224 height = 0 

225 

226 #: 1 = Characters are italic. 

227 italic = 0 

228 

229 #: The name of the font. Example: ``"Arial"``. 

230 name = UNICODE_LITERAL("") 

231 

232 #: 1 = Characters are struck out. 

233 struck_out = 0 

234 

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 

242 

243 #: 1 = Characters are underlined. Redundant; see 

244 #: :attr:`underline_type` attribute. 

245 underlined = 0 

246 

247 #: Font weight (100-1000). Standard values are 400 for normal text 

248 #: and 700 for bold text. 

249 weight = 400 

250 

251 #: 1 = Font is outline style (Macintosh only) 

252 outline = 0 

253 

254 #: 1 = Font is shadow style (Macintosh only) 

255 shadow = 0 

256 

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] 

261 

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 ) 

332 

333# === "Number formats" === 

334 

335class Format(BaseObject, EqNeAttrs): 

336 """ 

337 "Number format" information from a ``FORMAT`` record. 

338 

339 .. versionadded:: 0.6.1 

340 """ 

341 

342 #: The key into :attr:`~xlrd.book.Book.format_map` 

343 format_key = 0 

344 

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 

355 

356 #: The format string 

357 format_str = UNICODE_LITERAL('') 

358 

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 

363 

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} 

405 

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] 

423 

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 

429 

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 

435 

436skip_char_dict = {} 

437for _c in UNICODE_LITERAL('$-+/(): '): 

438 skip_char_dict[_c] = 1 

439 

440num_char_dict = { 

441 UNICODE_LITERAL('0'): 5, 

442 UNICODE_LITERAL('#'): 5, 

443 UNICODE_LITERAL('?'): 5, 

444} 

445 

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} 

454 

455fmt_bracketed_sub = re.compile(r'\[[^]]*\]').sub 

456 

457# Boolean format strings (actual cases) 

458# '"Yes";"Yes";"No"' 

459# '"True";"True";"False"' 

460# '"On";"On";"Off"' 

461 

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 = '' 

474 

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 

524 

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) 

574 

575# ============================================================================= 

576 

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) 

612 

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) 

632 

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) 

675 

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) 

688 

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 

699 

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) 

986 

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 

1002 

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 

1015 

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") 

1024 

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) 

1031 

1032 for xfx in xrange(num_xfs): 

1033 xf = self.xf_list[xfx] 

1034 

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) 

1088 

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) 

1105 

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. 

1110 

1111 An explanations of "colour index" is given in :ref:`palette`. 

1112 

1113 There are five line style attributes; possible values and the 

1114 associated meanings are:: 

1115 

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. 

1130 

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> 

1134 

1135 .. versionadded:: 0.6.1 

1136 """ 

1137 

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 

1142 

1143 #: The colour index for the cell's left line 

1144 left_colour_index = 0 

1145 

1146 #: The colour index for the cell's right line 

1147 right_colour_index = 0 

1148 

1149 #: The colour index for the cell's diagonal lines, if any 

1150 diag_colour_index = 0 

1151 

1152 #: The line style for the cell's top line 

1153 top_line_style = 0 

1154 

1155 #: The line style for the cell's bottom line 

1156 bottom_line_style = 0 

1157 

1158 #: The line style for the cell's left line 

1159 left_line_style = 0 

1160 

1161 #: The line style for the cell's right line 

1162 right_line_style = 0 

1163 

1164 #: The line style for the cell's diagonal lines, if any 

1165 diag_line_style = 0 

1166 

1167 #: 1 = draw a diagonal from top left to bottom right 

1168 diag_down = 0 

1169 

1170 #: 1 = draw a diagonal from bottom left to top right 

1171 diag_up = 0 

1172 

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. 

1177 

1178 An explanations of "colour index" is given in :ref:`palette`. 

1179 

1180 .. versionadded:: 0.6.1 

1181 """ 

1182 

1183 #: See section 3.11 of the OOo docs. 

1184 fill_pattern = 0 

1185 

1186 #: See section 3.11 of the OOo docs. 

1187 background_colour_index = 0 

1188 

1189 #: See section 3.11 of the OOo docs. 

1190 pattern_colour_index = 0 

1191 

1192 

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. 

1197 

1198 .. versionadded:: 0.6.1 

1199 """ 

1200 

1201 #: Values: section 6.115 (p 214) of OOo docs 

1202 hor_align = 0 

1203 

1204 #: Values: section 6.115 (p 215) of OOo docs 

1205 vert_align = 0 

1206 

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 

1214 

1215 #: 1 = text is wrapped at right margin 

1216 text_wrapped = 0 

1217 

1218 #: A number in ``range(15)``. 

1219 indent_level = 0 

1220 

1221 #: 1 = shrink font size to fit text into cell. 

1222 shrink_to_fit = 0 

1223 

1224 #: 0 = according to context; 1 = left-to-right; 2 = right-to-left 

1225 text_direction = 0 

1226 

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. 

1234 

1235 .. versionadded:: 0.6.1 

1236 """ 

1237 

1238 #: 1 = Cell is prevented from being changed, moved, resized, or deleted 

1239 #: (only if the sheet is protected). 

1240 cell_locked = 0 

1241 

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 

1245 

1246class XF(BaseObject): 

1247 """ 

1248 eXtended Formatting information for cells, rows, columns and styles. 

1249 

1250 Each of the 6 flags below describes the validity of 

1251 a specific group of attributes. 

1252 

1253 In cell XFs: 

1254 

1255 - ``flag==0`` means the attributes of the parent style ``XF`` are 

1256 used, (but only if the attributes are valid there); 

1257 

1258 - ``flag==1`` means the attributes of this ``XF`` are used. 

1259 

1260 In style XFs: 

1261 

1262 - ``flag==0`` means the attribute setting is valid; 

1263 - ``flag==1`` means the attribute should be ignored. 

1264 

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. 

1268 

1269 .. versionadded:: 0.6.1 

1270 """ 

1271 

1272 #: 0 = cell XF, 1 = style XF 

1273 is_style = 0 

1274 

1275 #: cell XF: Index into Book.xf_list of this XF's style XF 

1276 #: 

1277 #: style XF: 0xFFF 

1278 parent_style_index = 0 

1279 

1280 # 

1281 _format_flag = 0 

1282 

1283 # 

1284 _font_flag = 0 

1285 

1286 # 

1287 _alignment_flag = 0 

1288 

1289 # 

1290 _border_flag = 0 

1291 

1292 # 

1293 _background_flag = 0 

1294 

1295 _protection_flag = 0 

1296 

1297 #: Index into :attr:`~xlrd.book.Book.xf_list` 

1298 xf_index = 0 

1299 

1300 #: Index into :attr:`~xlrd.book.Book.font_list` 

1301 font_index = 0 

1302 

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 

1313 

1314 #: An instance of an :class:`XFProtection` object. 

1315 protection = None 

1316 

1317 #: An instance of an :class:`XFBackground` object. 

1318 background = None 

1319 

1320 #: An instance of an :class:`XFAlignment` object. 

1321 alignment = None 

1322 

1323 #: An instance of an :class:`XFBorder` object. 

1324 border = None