1 /*****************************************************************************
2 * styles - A library for creating Excel XLSX styles files.
3 *
4 * Used in conjunction with the libxlsxwriter library.
5 *
6 * Copyright 2014-2021, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7 *
8 */
9
10 #include "xlsxwriter/xmlwriter.h"
11 #include "xlsxwriter/styles.h"
12 #include "xlsxwriter/utility.h"
13
14 /*
15 * Forward declarations.
16 */
17 STATIC void _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
18 uint8_t is_rich_string);
19
20 /*****************************************************************************
21 *
22 * Private functions.
23 *
24 ****************************************************************************/
25
26 /*
27 * Create a new styles object.
28 */
29 lxw_styles *
lxw_styles_new(void)30 lxw_styles_new(void)
31 {
32 lxw_styles *styles = calloc(1, sizeof(lxw_styles));
33 GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
34
35 styles->xf_formats = calloc(1, sizeof(struct lxw_formats));
36 GOTO_LABEL_ON_MEM_ERROR(styles->xf_formats, mem_error);
37 STAILQ_INIT(styles->xf_formats);
38
39 styles->dxf_formats = calloc(1, sizeof(struct lxw_formats));
40 GOTO_LABEL_ON_MEM_ERROR(styles->dxf_formats, mem_error);
41 STAILQ_INIT(styles->dxf_formats);
42
43 return styles;
44
45 mem_error:
46 lxw_styles_free(styles);
47 return NULL;
48 }
49
50 /*
51 * Free a styles object.
52 */
53 void
lxw_styles_free(lxw_styles * styles)54 lxw_styles_free(lxw_styles *styles)
55 {
56 lxw_format *format;
57
58 if (!styles)
59 return;
60
61 /* Free the xf formats in the styles. */
62 if (styles->xf_formats) {
63 while (!STAILQ_EMPTY(styles->xf_formats)) {
64 format = STAILQ_FIRST(styles->xf_formats);
65 STAILQ_REMOVE_HEAD(styles->xf_formats, list_pointers);
66 free(format);
67 }
68 free(styles->xf_formats);
69 }
70
71 /* Free the dxf formats in the styles. */
72 if (styles->dxf_formats) {
73 while (!STAILQ_EMPTY(styles->dxf_formats)) {
74 format = STAILQ_FIRST(styles->dxf_formats);
75 STAILQ_REMOVE_HEAD(styles->dxf_formats, list_pointers);
76 free(format);
77 }
78 free(styles->dxf_formats);
79 }
80
81 free(styles);
82 }
83
84 /*
85 * Write the <t> element for rich strings.
86 */
87 void
lxw_styles_write_string_fragment(lxw_styles * self,char * string)88 lxw_styles_write_string_fragment(lxw_styles *self, char *string)
89 {
90 struct xml_attribute_list attributes;
91 struct xml_attribute *attribute;
92
93 LXW_INIT_ATTRIBUTES();
94
95 /* Add attribute to preserve leading or trailing whitespace. */
96 if (isspace((unsigned char) string[0])
97 || isspace((unsigned char) string[strlen(string) - 1]))
98 LXW_PUSH_ATTRIBUTES_STR("xml:space", "preserve");
99
100 lxw_xml_data_element(self->file, "t", string, &attributes);
101
102 LXW_FREE_ATTRIBUTES();
103 }
104
105 void
lxw_styles_write_rich_font(lxw_styles * self,lxw_format * format)106 lxw_styles_write_rich_font(lxw_styles *self, lxw_format *format)
107 {
108
109 _write_font(self, format, LXW_FALSE, LXW_TRUE);
110 }
111
112 /*****************************************************************************
113 *
114 * XML functions.
115 *
116 ****************************************************************************/
117
118 /*
119 * Write the XML declaration.
120 */
121 STATIC void
_styles_xml_declaration(lxw_styles * self)122 _styles_xml_declaration(lxw_styles *self)
123 {
124 lxw_xml_declaration(self->file);
125 }
126
127 /*
128 * Write the <styleSheet> element.
129 */
130 STATIC void
_write_style_sheet(lxw_styles * self)131 _write_style_sheet(lxw_styles *self)
132 {
133 struct xml_attribute_list attributes;
134 struct xml_attribute *attribute;
135 LXW_INIT_ATTRIBUTES();
136 LXW_PUSH_ATTRIBUTES_STR("xmlns",
137 "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
138
139 lxw_xml_start_tag(self->file, "styleSheet", &attributes);
140
141 LXW_FREE_ATTRIBUTES();
142 }
143
144 /*
145 * Write the <numFmt> element.
146 */
147 STATIC void
_write_num_fmt(lxw_styles * self,uint16_t num_fmt_id,char * format_code)148 _write_num_fmt(lxw_styles *self, uint16_t num_fmt_id, char *format_code)
149 {
150 struct xml_attribute_list attributes;
151 struct xml_attribute *attribute;
152 char *format_codes[] = {
153 "General",
154 "0",
155 "0.00",
156 "#,##0",
157 "#,##0.00",
158 "($#,##0_);($#,##0)",
159 "($#,##0_);[Red]($#,##0)",
160 "($#,##0.00_);($#,##0.00)",
161 "($#,##0.00_);[Red]($#,##0.00)",
162 "0%",
163 "0.00%",
164 "0.00E+00",
165 "# ?/?",
166 "# ?" "?/?" "?", /* Split string to avoid unintentional trigraph. */
167 "m/d/yy",
168 "d-mmm-yy",
169 "d-mmm",
170 "mmm-yy",
171 "h:mm AM/PM",
172 "h:mm:ss AM/PM",
173 "h:mm",
174 "h:mm:ss",
175 "m/d/yy h:mm",
176 "General",
177 "General",
178 "General",
179 "General",
180 "General",
181 "General",
182 "General",
183 "General",
184 "General",
185 "General",
186 "General",
187 "General",
188 "General",
189 "General",
190 "(#,##0_);(#,##0)",
191 "(#,##0_);[Red](#,##0)",
192 "(#,##0.00_);(#,##0.00)",
193 "(#,##0.00_);[Red](#,##0.00)",
194 "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
195 "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
196 "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
197 "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
198 "mm:ss",
199 "[h]:mm:ss",
200 "mm:ss.0",
201 "##0.0E+0",
202 "@"
203 };
204
205 LXW_INIT_ATTRIBUTES();
206 LXW_PUSH_ATTRIBUTES_INT("numFmtId", num_fmt_id);
207
208 if (num_fmt_id < 50)
209 LXW_PUSH_ATTRIBUTES_STR("formatCode", format_codes[num_fmt_id]);
210 else if (num_fmt_id < 164)
211 LXW_PUSH_ATTRIBUTES_STR("formatCode", "General");
212 else
213 LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
214
215 lxw_xml_empty_tag(self->file, "numFmt", &attributes);
216
217 LXW_FREE_ATTRIBUTES();
218 }
219
220 /*
221 * Write the <numFmts> element.
222 */
223 STATIC void
_write_num_fmts(lxw_styles * self)224 _write_num_fmts(lxw_styles *self)
225 {
226 struct xml_attribute_list attributes;
227 struct xml_attribute *attribute;
228 lxw_format *format;
229 uint16_t last_format_index = 0;
230
231 if (!self->num_format_count)
232 return;
233
234 LXW_INIT_ATTRIBUTES();
235 LXW_PUSH_ATTRIBUTES_INT("count", self->num_format_count);
236
237 lxw_xml_start_tag(self->file, "numFmts", &attributes);
238
239 /* Write the numFmts elements. */
240 STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
241
242 /* Ignore built-in number formats, i.e., < 164. */
243 if (format->num_format_index < 164)
244 continue;
245
246 /* Ignore duplicates which have an already used index. */
247 if (format->num_format_index <= last_format_index)
248 continue;
249
250 _write_num_fmt(self, format->num_format_index, format->num_format);
251
252 last_format_index = format->num_format_index;
253 }
254
255 lxw_xml_end_tag(self->file, "numFmts");
256
257 LXW_FREE_ATTRIBUTES();
258 }
259
260 /*
261 * Write the <sz> element.
262 */
263 STATIC void
_write_font_size(lxw_styles * self,double font_size)264 _write_font_size(lxw_styles *self, double font_size)
265 {
266 struct xml_attribute_list attributes;
267 struct xml_attribute *attribute;
268
269 LXW_INIT_ATTRIBUTES();
270 LXW_PUSH_ATTRIBUTES_DBL("val", font_size);
271
272 lxw_xml_empty_tag(self->file, "sz", &attributes);
273
274 LXW_FREE_ATTRIBUTES();
275 }
276
277 /*
278 * Write the <color> element for themes.
279 */
280 STATIC void
_write_font_color_theme(lxw_styles * self,uint8_t theme)281 _write_font_color_theme(lxw_styles *self, uint8_t theme)
282 {
283 struct xml_attribute_list attributes;
284 struct xml_attribute *attribute;
285
286 LXW_INIT_ATTRIBUTES();
287 LXW_PUSH_ATTRIBUTES_INT("theme", theme);
288
289 lxw_xml_empty_tag(self->file, "color", &attributes);
290
291 LXW_FREE_ATTRIBUTES();
292 }
293
294 /*
295 * Write the <color> element for RGB colors.
296 */
297 STATIC void
_write_font_color_rgb(lxw_styles * self,int32_t rgb)298 _write_font_color_rgb(lxw_styles *self, int32_t rgb)
299 {
300 struct xml_attribute_list attributes;
301 struct xml_attribute *attribute;
302 char rgb_str[LXW_ATTR_32];
303
304 lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", rgb & LXW_COLOR_MASK);
305
306 LXW_INIT_ATTRIBUTES();
307 LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
308
309 lxw_xml_empty_tag(self->file, "color", &attributes);
310
311 LXW_FREE_ATTRIBUTES();
312 }
313
314 /*
315 * Write the <color> element for indexed colors.
316 */
317 STATIC void
_write_font_color_indexed(lxw_styles * self,uint8_t index)318 _write_font_color_indexed(lxw_styles *self, uint8_t index)
319 {
320 struct xml_attribute_list attributes;
321 struct xml_attribute *attribute;
322
323 LXW_INIT_ATTRIBUTES();
324 LXW_PUSH_ATTRIBUTES_INT("indexed", index);
325
326 lxw_xml_empty_tag(self->file, "color", &attributes);
327
328 LXW_FREE_ATTRIBUTES();
329 }
330
331 /*
332 * Write the <name> element.
333 */
334 STATIC void
_write_font_name(lxw_styles * self,const char * font_name,uint8_t is_rich_string)335 _write_font_name(lxw_styles *self, const char *font_name,
336 uint8_t is_rich_string)
337 {
338 struct xml_attribute_list attributes;
339 struct xml_attribute *attribute;
340
341 LXW_INIT_ATTRIBUTES();
342
343 if (*font_name)
344 LXW_PUSH_ATTRIBUTES_STR("val", font_name);
345 else
346 LXW_PUSH_ATTRIBUTES_STR("val", LXW_DEFAULT_FONT_NAME);
347
348 if (is_rich_string)
349 lxw_xml_empty_tag(self->file, "rFont", &attributes);
350 else
351 lxw_xml_empty_tag(self->file, "name", &attributes);
352
353 LXW_FREE_ATTRIBUTES();
354 }
355
356 /*
357 * Write the <family> element.
358 */
359 STATIC void
_write_font_family(lxw_styles * self,uint8_t font_family)360 _write_font_family(lxw_styles *self, uint8_t font_family)
361 {
362 struct xml_attribute_list attributes;
363 struct xml_attribute *attribute;
364
365 LXW_INIT_ATTRIBUTES();
366 LXW_PUSH_ATTRIBUTES_INT("val", font_family);
367
368 lxw_xml_empty_tag(self->file, "family", &attributes);
369
370 LXW_FREE_ATTRIBUTES();
371 }
372
373 /*
374 * Write the <scheme> element.
375 */
376 STATIC void
_write_font_scheme(lxw_styles * self,const char * font_scheme)377 _write_font_scheme(lxw_styles *self, const char *font_scheme)
378 {
379 struct xml_attribute_list attributes;
380 struct xml_attribute *attribute;
381
382 LXW_INIT_ATTRIBUTES();
383
384 if (*font_scheme)
385 LXW_PUSH_ATTRIBUTES_STR("val", font_scheme);
386 else
387 LXW_PUSH_ATTRIBUTES_STR("val", "minor");
388
389 lxw_xml_empty_tag(self->file, "scheme", &attributes);
390
391 LXW_FREE_ATTRIBUTES();
392 }
393
394 /*
395 * Write the underline font element.
396 */
397 STATIC void
_write_font_underline(lxw_styles * self,uint8_t underline)398 _write_font_underline(lxw_styles *self, uint8_t underline)
399 {
400 struct xml_attribute_list attributes;
401 struct xml_attribute *attribute;
402
403 LXW_INIT_ATTRIBUTES();
404
405 /* Handle the underline variants. */
406 if (underline == LXW_UNDERLINE_DOUBLE)
407 LXW_PUSH_ATTRIBUTES_STR("val", "double");
408 else if (underline == LXW_UNDERLINE_SINGLE_ACCOUNTING)
409 LXW_PUSH_ATTRIBUTES_STR("val", "singleAccounting");
410 else if (underline == LXW_UNDERLINE_DOUBLE_ACCOUNTING)
411 LXW_PUSH_ATTRIBUTES_STR("val", "doubleAccounting");
412 /* Default to single underline. */
413
414 lxw_xml_empty_tag(self->file, "u", &attributes);
415
416 LXW_FREE_ATTRIBUTES();
417
418 }
419
420 /*
421 * Write the font <condense> element.
422 */
423 STATIC void
_write_font_condense(lxw_styles * self)424 _write_font_condense(lxw_styles *self)
425 {
426 struct xml_attribute_list attributes;
427 struct xml_attribute *attribute;
428
429 LXW_INIT_ATTRIBUTES();
430 LXW_PUSH_ATTRIBUTES_STR("val", "0");
431
432 lxw_xml_empty_tag(self->file, "condense", &attributes);
433
434 LXW_FREE_ATTRIBUTES();
435 }
436
437 /*
438 * Write the font <extend> element.
439 */
440 STATIC void
_write_font_extend(lxw_styles * self)441 _write_font_extend(lxw_styles *self)
442 {
443 struct xml_attribute_list attributes;
444 struct xml_attribute *attribute;
445
446 LXW_INIT_ATTRIBUTES();
447 LXW_PUSH_ATTRIBUTES_STR("val", "0");
448
449 lxw_xml_empty_tag(self->file, "extend", &attributes);
450
451 LXW_FREE_ATTRIBUTES();
452 }
453
454 /*
455 * Write the <vertAlign> font sub-element.
456 */
457 STATIC void
_write_font_vert_align(lxw_styles * self,const char * align)458 _write_font_vert_align(lxw_styles *self, const char *align)
459 {
460 struct xml_attribute_list attributes;
461 struct xml_attribute *attribute;
462
463 LXW_INIT_ATTRIBUTES();
464 LXW_PUSH_ATTRIBUTES_STR("val", align);
465
466 lxw_xml_empty_tag(self->file, "vertAlign", &attributes);
467
468 LXW_FREE_ATTRIBUTES();
469 }
470
471 /*
472 * Write the <font> element.
473 */
474 STATIC void
_write_font(lxw_styles * self,lxw_format * format,uint8_t is_dxf,uint8_t is_rich_string)475 _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
476 uint8_t is_rich_string)
477 {
478 if (is_rich_string)
479 lxw_xml_start_tag(self->file, "rPr", NULL);
480 else
481 lxw_xml_start_tag(self->file, "font", NULL);
482
483 if (format->font_condense)
484 _write_font_condense(self);
485
486 if (format->font_extend)
487 _write_font_extend(self);
488
489 if (format->bold)
490 lxw_xml_empty_tag(self->file, "b", NULL);
491
492 if (format->italic)
493 lxw_xml_empty_tag(self->file, "i", NULL);
494
495 if (format->font_strikeout)
496 lxw_xml_empty_tag(self->file, "strike", NULL);
497
498 if (format->font_outline)
499 lxw_xml_empty_tag(self->file, "outline", NULL);
500
501 if (format->font_shadow)
502 lxw_xml_empty_tag(self->file, "shadow", NULL);
503
504 if (format->underline)
505 _write_font_underline(self, format->underline);
506
507 if (format->font_script == LXW_FONT_SUPERSCRIPT)
508 _write_font_vert_align(self, "superscript");
509
510 if (format->font_script == LXW_FONT_SUBSCRIPT)
511 _write_font_vert_align(self, "subscript");
512
513 if (!is_dxf && format->font_size > 0.0)
514 _write_font_size(self, format->font_size);
515
516 if (format->theme)
517 _write_font_color_theme(self, format->theme);
518 else if (format->color_indexed)
519 _write_font_color_indexed(self, format->color_indexed);
520 else if (format->font_color != LXW_COLOR_UNSET)
521 _write_font_color_rgb(self, format->font_color);
522 else if (!is_dxf)
523 _write_font_color_theme(self, LXW_DEFAULT_FONT_THEME);
524
525 if (!is_dxf) {
526 _write_font_name(self, format->font_name, is_rich_string);
527 _write_font_family(self, format->font_family);
528
529 /* Only write the scheme element for the default font type if it
530 * is a hyperlink. */
531 if ((!*format->font_name
532 || strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
533 && !format->hyperlink) {
534 _write_font_scheme(self, format->font_scheme);
535 }
536 }
537
538 if (format->hyperlink) {
539 self->has_hyperlink = LXW_TRUE;
540
541 if (self->hyperlink_font_id == 0)
542 self->hyperlink_font_id = format->font_index;
543 }
544
545 if (is_rich_string)
546 lxw_xml_end_tag(self->file, "rPr");
547 else
548 lxw_xml_end_tag(self->file, "font");
549 }
550
551 /*
552 * Write the <font> element for comments.
553 */
554 STATIC void
_write_comment_font(lxw_styles * self)555 _write_comment_font(lxw_styles *self)
556 {
557 lxw_xml_start_tag(self->file, "font", NULL);
558
559 _write_font_size(self, 8);
560 _write_font_color_indexed(self, 81);
561 _write_font_name(self, "Tahoma", LXW_FALSE);
562 _write_font_family(self, 2);
563
564 lxw_xml_end_tag(self->file, "font");
565 }
566
567 /*
568 * Write the <fonts> element.
569 */
570 STATIC void
_write_fonts(lxw_styles * self)571 _write_fonts(lxw_styles *self)
572 {
573 struct xml_attribute_list attributes;
574 struct xml_attribute *attribute;
575 lxw_format *format;
576 uint32_t count;
577
578 LXW_INIT_ATTRIBUTES();
579
580 count = self->font_count;
581 if (self->has_comments)
582 count++;
583
584 LXW_PUSH_ATTRIBUTES_INT("count", count);
585
586 lxw_xml_start_tag(self->file, "fonts", &attributes);
587
588 STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
589 if (format->has_font)
590 _write_font(self, format, LXW_FALSE, LXW_FALSE);
591 }
592
593 if (self->has_comments)
594 _write_comment_font(self);
595
596 lxw_xml_end_tag(self->file, "fonts");
597
598 LXW_FREE_ATTRIBUTES();
599 }
600
601 /*
602 * Write the default <fill> element.
603 */
604 STATIC void
_write_default_fill(lxw_styles * self,const char * pattern)605 _write_default_fill(lxw_styles *self, const char *pattern)
606 {
607 struct xml_attribute_list attributes;
608 struct xml_attribute *attribute;
609
610 LXW_INIT_ATTRIBUTES();
611 LXW_PUSH_ATTRIBUTES_STR("patternType", pattern);
612
613 lxw_xml_start_tag(self->file, "fill", NULL);
614 lxw_xml_empty_tag(self->file, "patternFill", &attributes);
615 lxw_xml_end_tag(self->file, "fill");
616
617 LXW_FREE_ATTRIBUTES();
618 }
619
620 /*
621 * Write the <fgColor> element.
622 */
623 STATIC void
_write_fg_color(lxw_styles * self,lxw_color_t color)624 _write_fg_color(lxw_styles *self, lxw_color_t color)
625 {
626 struct xml_attribute_list attributes;
627 struct xml_attribute *attribute;
628 char rgb_str[LXW_ATTR_32];
629
630 LXW_INIT_ATTRIBUTES();
631
632 lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
633 LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
634
635 lxw_xml_empty_tag(self->file, "fgColor", &attributes);
636
637 LXW_FREE_ATTRIBUTES();
638 }
639
640 /*
641 * Write the <bgColor> element.
642 */
643 STATIC void
_write_bg_color(lxw_styles * self,lxw_color_t color,uint8_t pattern)644 _write_bg_color(lxw_styles *self, lxw_color_t color, uint8_t pattern)
645 {
646 struct xml_attribute_list attributes;
647 struct xml_attribute *attribute;
648 char rgb_str[LXW_ATTR_32];
649
650 LXW_INIT_ATTRIBUTES();
651
652 if (color == LXW_COLOR_UNSET) {
653 if (pattern <= LXW_PATTERN_SOLID) {
654 LXW_PUSH_ATTRIBUTES_STR("indexed", "64");
655 lxw_xml_empty_tag(self->file, "bgColor", &attributes);
656 }
657 }
658 else {
659 lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
660 LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
661 lxw_xml_empty_tag(self->file, "bgColor", &attributes);
662 }
663
664 LXW_FREE_ATTRIBUTES();
665 }
666
667 /*
668 * Write the <fill> element.
669 */
670 STATIC void
_write_fill(lxw_styles * self,lxw_format * format,uint8_t is_dxf)671 _write_fill(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
672 {
673 struct xml_attribute_list attributes;
674 struct xml_attribute *attribute;
675
676 uint8_t pattern = format->pattern;
677 lxw_color_t bg_color = format->bg_color;
678 lxw_color_t fg_color = format->fg_color;
679
680 char *patterns[] = {
681 "none",
682 "solid",
683 "mediumGray",
684 "darkGray",
685 "lightGray",
686 "darkHorizontal",
687 "darkVertical",
688 "darkDown",
689 "darkUp",
690 "darkGrid",
691 "darkTrellis",
692 "lightHorizontal",
693 "lightVertical",
694 "lightDown",
695 "lightUp",
696 "lightGrid",
697 "lightTrellis",
698 "gray125",
699 "gray0625",
700 };
701
702 if (is_dxf) {
703 bg_color = format->dxf_bg_color;
704 fg_color = format->dxf_fg_color;
705 }
706
707 LXW_INIT_ATTRIBUTES();
708
709 /* Special handling for pattern only case. */
710 if (!bg_color && !fg_color && pattern) {
711 _write_default_fill(self, patterns[pattern]);
712 LXW_FREE_ATTRIBUTES();
713 return;
714 }
715
716 lxw_xml_start_tag(self->file, "fill", NULL);
717
718 /* None/Solid patterns are handled differently for dxf formats. */
719 if (pattern && !(is_dxf && pattern <= LXW_PATTERN_SOLID))
720 LXW_PUSH_ATTRIBUTES_STR("patternType", patterns[pattern]);
721
722 lxw_xml_start_tag(self->file, "patternFill", &attributes);
723
724 if (fg_color != LXW_COLOR_UNSET)
725 _write_fg_color(self, fg_color);
726
727 _write_bg_color(self, bg_color, pattern);
728
729 lxw_xml_end_tag(self->file, "patternFill");
730 lxw_xml_end_tag(self->file, "fill");
731
732 LXW_FREE_ATTRIBUTES();
733 }
734
735 /*
736 * Write the <fills> element.
737 */
738 STATIC void
_write_fills(lxw_styles * self)739 _write_fills(lxw_styles *self)
740 {
741 struct xml_attribute_list attributes;
742 struct xml_attribute *attribute;
743 lxw_format *format;
744
745 LXW_INIT_ATTRIBUTES();
746 LXW_PUSH_ATTRIBUTES_INT("count", self->fill_count);
747
748 lxw_xml_start_tag(self->file, "fills", &attributes);
749
750 /* Write the default fills. */
751 _write_default_fill(self, "none");
752 _write_default_fill(self, "gray125");
753
754 STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
755 if (format->has_fill)
756 _write_fill(self, format, LXW_FALSE);
757 }
758
759 lxw_xml_end_tag(self->file, "fills");
760
761 LXW_FREE_ATTRIBUTES();
762 }
763
764 /*
765 * Write the border <color> element.
766 */
767 STATIC void
_write_border_color(lxw_styles * self,lxw_color_t color)768 _write_border_color(lxw_styles *self, lxw_color_t color)
769 {
770 struct xml_attribute_list attributes;
771 struct xml_attribute *attribute;
772 char rgb_str[LXW_ATTR_32];
773
774 LXW_INIT_ATTRIBUTES();
775
776 if (color != LXW_COLOR_UNSET) {
777 lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
778 LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
779 }
780 else {
781 LXW_PUSH_ATTRIBUTES_STR("auto", "1");
782 }
783
784 lxw_xml_empty_tag(self->file, "color", &attributes);
785
786 LXW_FREE_ATTRIBUTES();
787 }
788
789 /*
790 * Write the <border> sub elements such as <right>, <top>, etc.
791 */
792 STATIC void
_write_sub_border(lxw_styles * self,const char * type,uint8_t style,lxw_color_t color)793 _write_sub_border(lxw_styles *self, const char *type, uint8_t style,
794 lxw_color_t color)
795 {
796 struct xml_attribute_list attributes;
797 struct xml_attribute *attribute;
798
799 char *border_styles[] = {
800 "none",
801 "thin",
802 "medium",
803 "dashed",
804 "dotted",
805 "thick",
806 "double",
807 "hair",
808 "mediumDashed",
809 "dashDot",
810 "mediumDashDot",
811 "dashDotDot",
812 "mediumDashDotDot",
813 "slantDashDot",
814 };
815
816 if (!style) {
817 lxw_xml_empty_tag(self->file, type, NULL);
818 return;
819 }
820
821 LXW_INIT_ATTRIBUTES();
822 LXW_PUSH_ATTRIBUTES_STR("style", border_styles[style]);
823
824 lxw_xml_start_tag(self->file, type, &attributes);
825
826 _write_border_color(self, color);
827
828 lxw_xml_end_tag(self->file, type);
829
830 LXW_FREE_ATTRIBUTES();
831 }
832
833 /*
834 * Write the <border> element.
835 */
836 STATIC void
_write_border(lxw_styles * self,lxw_format * format,uint8_t is_dxf)837 _write_border(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
838 {
839 struct xml_attribute_list attributes;
840 struct xml_attribute *attribute;
841
842 LXW_INIT_ATTRIBUTES();
843
844 /* Add attributes for diagonal borders. */
845 if (format->diag_type == LXW_DIAGONAL_BORDER_UP) {
846 LXW_PUSH_ATTRIBUTES_STR("diagonalUp", "1");
847 }
848 else if (format->diag_type == LXW_DIAGONAL_BORDER_DOWN) {
849 LXW_PUSH_ATTRIBUTES_STR("diagonalDown", "1");
850 }
851 else if (format->diag_type == LXW_DIAGONAL_BORDER_UP_DOWN) {
852 LXW_PUSH_ATTRIBUTES_STR("diagonalUp", "1");
853 LXW_PUSH_ATTRIBUTES_STR("diagonalDown", "1");
854 }
855
856 /* Ensure that a default diag border is set if the diag type is set. */
857 if (format->diag_type && !format->diag_border) {
858 format->diag_border = LXW_BORDER_THIN;
859 }
860
861 /* Write the start border tag. */
862 lxw_xml_start_tag(self->file, "border", &attributes);
863
864 /* Write the <border> sub elements. */
865 _write_sub_border(self, "left", format->left, format->left_color);
866 _write_sub_border(self, "right", format->right, format->right_color);
867 _write_sub_border(self, "top", format->top, format->top_color);
868 _write_sub_border(self, "bottom", format->bottom, format->bottom_color);
869
870 if (is_dxf) {
871 _write_sub_border(self, "vertical", 0, LXW_COLOR_UNSET);
872 _write_sub_border(self, "horizontal", 0, LXW_COLOR_UNSET);
873 }
874
875 /* Conditional DXF formats don't allow diagonal borders. */
876 if (!is_dxf)
877 _write_sub_border(self, "diagonal",
878 format->diag_border, format->diag_color);
879
880 lxw_xml_end_tag(self->file, "border");
881
882 LXW_FREE_ATTRIBUTES();
883 }
884
885 /*
886 * Write the <borders> element.
887 */
888 STATIC void
_write_borders(lxw_styles * self)889 _write_borders(lxw_styles *self)
890 {
891 struct xml_attribute_list attributes;
892 struct xml_attribute *attribute;
893 lxw_format *format;
894
895 LXW_INIT_ATTRIBUTES();
896 LXW_PUSH_ATTRIBUTES_INT("count", self->border_count);
897
898 lxw_xml_start_tag(self->file, "borders", &attributes);
899
900 STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
901 if (format->has_border)
902 _write_border(self, format, LXW_FALSE);
903 }
904
905 lxw_xml_end_tag(self->file, "borders");
906
907 LXW_FREE_ATTRIBUTES();
908 }
909
910 /*
911 * Write the <alignment> element for hyperlinks.
912 */
913 STATIC void
_write_hyperlink_alignment(lxw_styles * self)914 _write_hyperlink_alignment(lxw_styles *self)
915 {
916 struct xml_attribute_list attributes;
917 struct xml_attribute *attribute;
918
919 LXW_INIT_ATTRIBUTES();
920 LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
921
922 lxw_xml_empty_tag(self->file, "alignment", &attributes);
923
924 LXW_FREE_ATTRIBUTES();
925 }
926
927 /*
928 * Write the <protection> element for hyperlinks.
929 */
930 STATIC void
_write_hyperlink_protection(lxw_styles * self)931 _write_hyperlink_protection(lxw_styles *self)
932 {
933 struct xml_attribute_list attributes;
934 struct xml_attribute *attribute;
935
936 LXW_INIT_ATTRIBUTES();
937 LXW_PUSH_ATTRIBUTES_STR("locked", "0");
938
939 lxw_xml_empty_tag(self->file, "protection", &attributes);
940
941 LXW_FREE_ATTRIBUTES();
942 }
943
944 /*
945 * Write the <xf> element for styles.
946 */
947 STATIC void
_write_style_xf(lxw_styles * self,uint8_t has_hyperlink,uint16_t font_id)948 _write_style_xf(lxw_styles *self, uint8_t has_hyperlink, uint16_t font_id)
949 {
950 struct xml_attribute_list attributes;
951 struct xml_attribute *attribute;
952
953 LXW_INIT_ATTRIBUTES();
954 LXW_PUSH_ATTRIBUTES_STR("numFmtId", "0");
955 LXW_PUSH_ATTRIBUTES_INT("fontId", font_id);
956 LXW_PUSH_ATTRIBUTES_STR("fillId", "0");
957 LXW_PUSH_ATTRIBUTES_STR("borderId", "0");
958
959 if (has_hyperlink) {
960 LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "0");
961 LXW_PUSH_ATTRIBUTES_STR("applyFill", "0");
962 LXW_PUSH_ATTRIBUTES_STR("applyBorder", "0");
963 LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "0");
964 LXW_PUSH_ATTRIBUTES_STR("applyProtection", "0");
965
966 lxw_xml_start_tag(self->file, "xf", &attributes);
967 _write_hyperlink_alignment(self);
968 _write_hyperlink_protection(self);
969 lxw_xml_end_tag(self->file, "xf");
970 }
971 else {
972 lxw_xml_empty_tag(self->file, "xf", &attributes);
973 }
974
975 LXW_FREE_ATTRIBUTES();
976 }
977
978 /*
979 * Write the <cellStyleXfs> element.
980 */
981 STATIC void
_write_cell_style_xfs(lxw_styles * self)982 _write_cell_style_xfs(lxw_styles *self)
983 {
984 struct xml_attribute_list attributes;
985 struct xml_attribute *attribute;
986
987 LXW_INIT_ATTRIBUTES();
988
989 if (self->has_hyperlink)
990 LXW_PUSH_ATTRIBUTES_STR("count", "2");
991 else
992 LXW_PUSH_ATTRIBUTES_STR("count", "1");
993
994 lxw_xml_start_tag(self->file, "cellStyleXfs", &attributes);
995 _write_style_xf(self, LXW_FALSE, 0);
996
997 if (self->has_hyperlink)
998 _write_style_xf(self, self->has_hyperlink, self->hyperlink_font_id);
999
1000 lxw_xml_end_tag(self->file, "cellStyleXfs");
1001
1002 LXW_FREE_ATTRIBUTES();
1003 }
1004
1005 /*
1006 * Check if a format struct has alignment properties set and the
1007 * "applyAlignment" attribute should be set.
1008 */
1009 STATIC uint8_t
_apply_alignment(lxw_format * format)1010 _apply_alignment(lxw_format *format)
1011 {
1012 return format->text_h_align != LXW_ALIGN_NONE
1013 || format->text_v_align != LXW_ALIGN_NONE
1014 || format->indent != 0
1015 || format->rotation != 0
1016 || format->text_wrap != 0
1017 || format->shrink != 0 || format->reading_order != 0;
1018 }
1019
1020 /*
1021 * Check if a format struct has alignment properties set apart from the
1022 * LXW_ALIGN_VERTICAL_BOTTOM which Excel treats as a default.
1023 */
1024 STATIC uint8_t
_has_alignment(lxw_format * format)1025 _has_alignment(lxw_format *format)
1026 {
1027 return format->text_h_align != LXW_ALIGN_NONE
1028 || !(format->text_v_align == LXW_ALIGN_NONE ||
1029 format->text_v_align == LXW_ALIGN_VERTICAL_BOTTOM)
1030 || format->indent != 0
1031 || format->rotation != 0
1032 || format->text_wrap != 0
1033 || format->shrink != 0 || format->reading_order != 0;
1034 }
1035
1036 /*
1037 * Write the <alignment> element.
1038 */
1039 STATIC void
_write_alignment(lxw_styles * self,lxw_format * format)1040 _write_alignment(lxw_styles *self, lxw_format *format)
1041 {
1042 struct xml_attribute_list attributes;
1043 struct xml_attribute *attribute;
1044 int16_t rotation = format->rotation;
1045
1046 LXW_INIT_ATTRIBUTES();
1047
1048 /* Indent is only allowed for horizontal left, right and distributed. */
1049 /* If it is defined for any other alignment or no alignment has been */
1050 /* set then default to left alignment. */
1051 if (format->indent
1052 && format->text_h_align != LXW_ALIGN_LEFT
1053 && format->text_h_align != LXW_ALIGN_RIGHT
1054 && format->text_h_align != LXW_ALIGN_DISTRIBUTED) {
1055 format->text_h_align = LXW_ALIGN_LEFT;
1056 }
1057
1058 /* Check for properties that are mutually exclusive. */
1059 if (format->text_wrap)
1060 format->shrink = 0;
1061
1062 if (format->text_h_align == LXW_ALIGN_FILL)
1063 format->shrink = 0;
1064
1065 if (format->text_h_align == LXW_ALIGN_JUSTIFY)
1066 format->shrink = 0;
1067
1068 if (format->text_h_align == LXW_ALIGN_DISTRIBUTED)
1069 format->shrink = 0;
1070
1071 if (format->text_h_align != LXW_ALIGN_DISTRIBUTED)
1072 format->just_distrib = 0;
1073
1074 if (format->indent)
1075 format->just_distrib = 0;
1076
1077 if (format->text_h_align == LXW_ALIGN_LEFT)
1078 LXW_PUSH_ATTRIBUTES_STR("horizontal", "left");
1079
1080 if (format->text_h_align == LXW_ALIGN_CENTER)
1081 LXW_PUSH_ATTRIBUTES_STR("horizontal", "center");
1082
1083 if (format->text_h_align == LXW_ALIGN_RIGHT)
1084 LXW_PUSH_ATTRIBUTES_STR("horizontal", "right");
1085
1086 if (format->text_h_align == LXW_ALIGN_FILL)
1087 LXW_PUSH_ATTRIBUTES_STR("horizontal", "fill");
1088
1089 if (format->text_h_align == LXW_ALIGN_JUSTIFY)
1090 LXW_PUSH_ATTRIBUTES_STR("horizontal", "justify");
1091
1092 if (format->text_h_align == LXW_ALIGN_CENTER_ACROSS)
1093 LXW_PUSH_ATTRIBUTES_STR("horizontal", "centerContinuous");
1094
1095 if (format->text_h_align == LXW_ALIGN_DISTRIBUTED)
1096 LXW_PUSH_ATTRIBUTES_STR("horizontal", "distributed");
1097
1098 if (format->just_distrib)
1099 LXW_PUSH_ATTRIBUTES_STR("justifyLastLine", "1");
1100
1101 if (format->text_v_align == LXW_ALIGN_VERTICAL_TOP)
1102 LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
1103
1104 if (format->text_v_align == LXW_ALIGN_VERTICAL_CENTER)
1105 LXW_PUSH_ATTRIBUTES_STR("vertical", "center");
1106
1107 if (format->text_v_align == LXW_ALIGN_VERTICAL_JUSTIFY)
1108 LXW_PUSH_ATTRIBUTES_STR("vertical", "justify");
1109
1110 if (format->text_v_align == LXW_ALIGN_VERTICAL_DISTRIBUTED)
1111 LXW_PUSH_ATTRIBUTES_STR("vertical", "distributed");
1112
1113 if (format->indent)
1114 LXW_PUSH_ATTRIBUTES_INT("indent", format->indent);
1115
1116 /* Map rotation to Excel values. */
1117 if (rotation) {
1118 if (rotation == 270)
1119 rotation = 255;
1120 else if (rotation < 0)
1121 rotation = -rotation + 90;
1122
1123 LXW_PUSH_ATTRIBUTES_INT("textRotation", rotation);
1124 }
1125
1126 if (format->text_wrap)
1127 LXW_PUSH_ATTRIBUTES_STR("wrapText", "1");
1128
1129 if (format->shrink)
1130 LXW_PUSH_ATTRIBUTES_STR("shrinkToFit", "1");
1131
1132 if (format->reading_order == 1)
1133 LXW_PUSH_ATTRIBUTES_STR("readingOrder", "1");
1134
1135 if (format->reading_order == 2)
1136 LXW_PUSH_ATTRIBUTES_STR("readingOrder", "2");
1137
1138 if (!STAILQ_EMPTY(&attributes))
1139 lxw_xml_empty_tag(self->file, "alignment", &attributes);
1140
1141 LXW_FREE_ATTRIBUTES();
1142 }
1143
1144 /*
1145 * Write the <protection> element.
1146 */
1147 STATIC void
_write_protection(lxw_styles * self,lxw_format * format)1148 _write_protection(lxw_styles *self, lxw_format *format)
1149 {
1150 struct xml_attribute_list attributes;
1151 struct xml_attribute *attribute;
1152
1153 LXW_INIT_ATTRIBUTES();
1154
1155 if (!format->locked)
1156 LXW_PUSH_ATTRIBUTES_STR("locked", "0");
1157
1158 if (format->hidden)
1159 LXW_PUSH_ATTRIBUTES_STR("hidden", "1");
1160
1161 lxw_xml_empty_tag(self->file, "protection", &attributes);
1162
1163 LXW_FREE_ATTRIBUTES();
1164 }
1165
1166 /*
1167 * Write the <xf> element.
1168 */
1169 STATIC void
_write_xf(lxw_styles * self,lxw_format * format)1170 _write_xf(lxw_styles *self, lxw_format *format)
1171 {
1172 struct xml_attribute_list attributes;
1173 struct xml_attribute *attribute;
1174 uint8_t has_protection = (!format->locked) | format->hidden;
1175 uint8_t has_alignment = _has_alignment(format);
1176 uint8_t apply_alignment = _apply_alignment(format);
1177
1178 LXW_INIT_ATTRIBUTES();
1179 LXW_PUSH_ATTRIBUTES_INT("numFmtId", format->num_format_index);
1180 LXW_PUSH_ATTRIBUTES_INT("fontId", format->font_index);
1181 LXW_PUSH_ATTRIBUTES_INT("fillId", format->fill_index);
1182 LXW_PUSH_ATTRIBUTES_INT("borderId", format->border_index);
1183 LXW_PUSH_ATTRIBUTES_INT("xfId", format->xf_id);
1184
1185 if (format->num_format_index > 0)
1186 LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "1");
1187
1188 /* Add applyFont attribute if XF format uses a font element. */
1189 if (format->font_index > 0 && !format->hyperlink)
1190 LXW_PUSH_ATTRIBUTES_STR("applyFont", "1");
1191
1192 /* Add applyFill attribute if XF format uses a fill element. */
1193 if (format->fill_index > 0)
1194 LXW_PUSH_ATTRIBUTES_STR("applyFill", "1");
1195
1196 /* Add applyBorder attribute if XF format uses a border element. */
1197 if (format->border_index > 0)
1198 LXW_PUSH_ATTRIBUTES_STR("applyBorder", "1");
1199
1200 /* We can also have applyAlignment without a sub-element. */
1201 if (apply_alignment || format->hyperlink)
1202 LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "1");
1203
1204 if (has_protection || format->hyperlink)
1205 LXW_PUSH_ATTRIBUTES_STR("applyProtection", "1");
1206
1207 /* Write XF with sub-elements if required. */
1208 if (has_alignment || has_protection) {
1209 lxw_xml_start_tag(self->file, "xf", &attributes);
1210
1211 if (has_alignment)
1212 _write_alignment(self, format);
1213
1214 if (has_protection)
1215 _write_protection(self, format);
1216
1217 lxw_xml_end_tag(self->file, "xf");
1218 }
1219 else {
1220 lxw_xml_empty_tag(self->file, "xf", &attributes);
1221 }
1222
1223 LXW_FREE_ATTRIBUTES();
1224 }
1225
1226 /*
1227 * Write the <cellXfs> element.
1228 */
1229 STATIC void
_write_cell_xfs(lxw_styles * self)1230 _write_cell_xfs(lxw_styles *self)
1231 {
1232 struct xml_attribute_list attributes;
1233 struct xml_attribute *attribute;
1234 lxw_format *format;
1235 uint32_t count = self->xf_count;
1236 uint32_t i = 0;
1237
1238 /* If the last format is "font_only" it is for the comment font and
1239 * shouldn't be counted. This is a workaround to get the last object
1240 * in the list since STAILQ_LAST() requires __containerof and isn't
1241 * ANSI compatible. */
1242 STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
1243 i++;
1244 if (i == self->xf_count && format->font_only)
1245 count--;
1246 }
1247
1248 LXW_INIT_ATTRIBUTES();
1249 LXW_PUSH_ATTRIBUTES_INT("count", count);
1250
1251 lxw_xml_start_tag(self->file, "cellXfs", &attributes);
1252
1253 STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
1254 if (!format->font_only)
1255 _write_xf(self, format);
1256 }
1257
1258 lxw_xml_end_tag(self->file, "cellXfs");
1259
1260 LXW_FREE_ATTRIBUTES();
1261 }
1262
1263 /*
1264 * Write the <cellStyle> element.
1265 */
1266 STATIC void
_write_cell_style(lxw_styles * self,char * name,uint8_t xf_id,uint8_t builtin_id)1267 _write_cell_style(lxw_styles *self, char *name, uint8_t xf_id,
1268 uint8_t builtin_id)
1269 {
1270 struct xml_attribute_list attributes;
1271 struct xml_attribute *attribute;
1272
1273 LXW_INIT_ATTRIBUTES();
1274 LXW_PUSH_ATTRIBUTES_STR("name", name);
1275 LXW_PUSH_ATTRIBUTES_INT("xfId", xf_id);
1276 LXW_PUSH_ATTRIBUTES_INT("builtinId", builtin_id);
1277
1278 lxw_xml_empty_tag(self->file, "cellStyle", &attributes);
1279
1280 LXW_FREE_ATTRIBUTES();
1281 }
1282
1283 /*
1284 * Write the <cellStyles> element.
1285 */
1286 STATIC void
_write_cell_styles(lxw_styles * self)1287 _write_cell_styles(lxw_styles *self)
1288 {
1289 struct xml_attribute_list attributes;
1290 struct xml_attribute *attribute;
1291 LXW_INIT_ATTRIBUTES();
1292
1293 if (self->has_hyperlink)
1294 LXW_PUSH_ATTRIBUTES_STR("count", "2");
1295 else
1296 LXW_PUSH_ATTRIBUTES_STR("count", "1");
1297
1298 lxw_xml_start_tag(self->file, "cellStyles", &attributes);
1299
1300 if (self->has_hyperlink)
1301 _write_cell_style(self, "Hyperlink", 1, 8);
1302
1303 _write_cell_style(self, "Normal", 0, 0);
1304
1305 lxw_xml_end_tag(self->file, "cellStyles");
1306
1307 LXW_FREE_ATTRIBUTES();
1308 }
1309
1310 /*
1311 * Write the <dxfs> element.
1312 *
1313 */
1314 STATIC void
_write_dxfs(lxw_styles * self)1315 _write_dxfs(lxw_styles *self)
1316 {
1317 struct xml_attribute_list attributes;
1318 struct xml_attribute *attribute;
1319 lxw_format *format;
1320 uint32_t count = self->dxf_count;
1321
1322 LXW_INIT_ATTRIBUTES();
1323 LXW_PUSH_ATTRIBUTES_INT("count", count);
1324
1325 if (count) {
1326 lxw_xml_start_tag(self->file, "dxfs", &attributes);
1327
1328 STAILQ_FOREACH(format, self->dxf_formats, list_pointers) {
1329 lxw_xml_start_tag(self->file, "dxf", NULL);
1330
1331 if (format->has_dxf_font)
1332 _write_font(self, format, LXW_TRUE, LXW_FALSE);
1333
1334 if (format->num_format_index)
1335 _write_num_fmt(self, format->num_format_index,
1336 format->num_format);
1337
1338 if (format->has_dxf_fill)
1339 _write_fill(self, format, LXW_TRUE);
1340
1341 if (format->has_dxf_border)
1342 _write_border(self, format, LXW_TRUE);
1343
1344 lxw_xml_end_tag(self->file, "dxf");
1345 }
1346
1347 lxw_xml_end_tag(self->file, "dxfs");
1348 }
1349 else {
1350 lxw_xml_empty_tag(self->file, "dxfs", &attributes);
1351 }
1352 LXW_FREE_ATTRIBUTES();
1353 }
1354
1355 /*
1356 * Write the <tableStyles> element.
1357 */
1358 STATIC void
_write_table_styles(lxw_styles * self)1359 _write_table_styles(lxw_styles *self)
1360 {
1361 struct xml_attribute_list attributes;
1362 struct xml_attribute *attribute;
1363
1364 LXW_INIT_ATTRIBUTES();
1365 LXW_PUSH_ATTRIBUTES_STR("count", "0");
1366 LXW_PUSH_ATTRIBUTES_STR("defaultTableStyle", "TableStyleMedium9");
1367 LXW_PUSH_ATTRIBUTES_STR("defaultPivotStyle", "PivotStyleLight16");
1368
1369 lxw_xml_empty_tag(self->file, "tableStyles", &attributes);
1370
1371 LXW_FREE_ATTRIBUTES();
1372 }
1373
1374 /*****************************************************************************
1375 *
1376 * XML file assembly functions.
1377 *
1378 ****************************************************************************/
1379
1380 /*
1381 * Assemble and write the XML file.
1382 */
1383 void
lxw_styles_assemble_xml_file(lxw_styles * self)1384 lxw_styles_assemble_xml_file(lxw_styles *self)
1385 {
1386 /* Write the XML declaration. */
1387 _styles_xml_declaration(self);
1388
1389 /* Add the style sheet. */
1390 _write_style_sheet(self);
1391
1392 /* Write the number formats. */
1393 _write_num_fmts(self);
1394
1395 /* Write the fonts. */
1396 _write_fonts(self);
1397
1398 /* Write the fills. */
1399 _write_fills(self);
1400
1401 /* Write the borders element. */
1402 _write_borders(self);
1403
1404 /* Write the cellStyleXfs element. */
1405 _write_cell_style_xfs(self);
1406
1407 /* Write the cellXfs element. */
1408 _write_cell_xfs(self);
1409
1410 /* Write the cellStyles element. */
1411 _write_cell_styles(self);
1412
1413 /* Write the dxfs element. */
1414 _write_dxfs(self);
1415
1416 /* Write the tableStyles element. */
1417 _write_table_styles(self);
1418
1419 /* Close the style sheet tag. */
1420 lxw_xml_end_tag(self->file, "styleSheet");
1421 }
1422
1423 /*****************************************************************************
1424 *
1425 * Public functions.
1426 *
1427 ****************************************************************************/
1428