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