1 /*****************************************************************************
2  * format - A library for creating Excel XLSX format 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/format.h"
12 #include "xlsxwriter/utility.h"
13 
14 /*****************************************************************************
15  *
16  * Private functions.
17  *
18  ****************************************************************************/
19 
20 /*
21  * Create a new format object.
22  */
23 lxw_format *
lxw_format_new(void)24 lxw_format_new(void)
25 {
26     lxw_format *format = calloc(1, sizeof(lxw_format));
27     GOTO_LABEL_ON_MEM_ERROR(format, mem_error);
28 
29     format->xf_format_indices = NULL;
30     format->dxf_format_indices = NULL;
31 
32     format->xf_index = LXW_PROPERTY_UNSET;
33     format->dxf_index = LXW_PROPERTY_UNSET;
34     format->xf_id = 0;
35 
36     format->font_name[0] = '\0';
37     format->font_scheme[0] = '\0';
38     format->num_format[0] = '\0';
39     format->num_format_index = 0;
40     format->font_index = 0;
41     format->has_font = LXW_FALSE;
42     format->has_dxf_font = LXW_FALSE;
43     format->font_size = 11.0;
44     format->bold = LXW_FALSE;
45     format->italic = LXW_FALSE;
46     format->font_color = LXW_COLOR_UNSET;
47     format->underline = LXW_UNDERLINE_NONE;
48     format->font_strikeout = LXW_FALSE;
49     format->font_outline = LXW_FALSE;
50     format->font_shadow = LXW_FALSE;
51     format->font_script = LXW_FALSE;
52     format->font_family = LXW_DEFAULT_FONT_FAMILY;
53     format->font_charset = LXW_FALSE;
54     format->font_condense = LXW_FALSE;
55     format->font_extend = LXW_FALSE;
56     format->theme = 0;
57     format->hyperlink = LXW_FALSE;
58 
59     format->hidden = LXW_FALSE;
60     format->locked = LXW_TRUE;
61 
62     format->text_h_align = LXW_ALIGN_NONE;
63     format->text_wrap = LXW_FALSE;
64     format->text_v_align = LXW_ALIGN_NONE;
65     format->text_justlast = LXW_FALSE;
66     format->rotation = 0;
67 
68     format->fg_color = LXW_COLOR_UNSET;
69     format->bg_color = LXW_COLOR_UNSET;
70     format->pattern = LXW_PATTERN_NONE;
71     format->has_fill = LXW_FALSE;
72     format->has_dxf_fill = LXW_FALSE;
73     format->fill_index = 0;
74     format->fill_count = 0;
75 
76     format->border_index = 0;
77     format->has_border = LXW_FALSE;
78     format->has_dxf_border = LXW_FALSE;
79     format->border_count = 0;
80 
81     format->bottom = LXW_BORDER_NONE;
82     format->left = LXW_BORDER_NONE;
83     format->right = LXW_BORDER_NONE;
84     format->top = LXW_BORDER_NONE;
85     format->diag_border = LXW_BORDER_NONE;
86     format->diag_type = LXW_BORDER_NONE;
87     format->bottom_color = LXW_COLOR_UNSET;
88     format->left_color = LXW_COLOR_UNSET;
89     format->right_color = LXW_COLOR_UNSET;
90     format->top_color = LXW_COLOR_UNSET;
91     format->diag_color = LXW_COLOR_UNSET;
92 
93     format->indent = 0;
94     format->shrink = LXW_FALSE;
95     format->merge_range = LXW_FALSE;
96     format->reading_order = 0;
97     format->just_distrib = LXW_FALSE;
98     format->color_indexed = LXW_FALSE;
99     format->font_only = LXW_FALSE;
100 
101     return format;
102 
103 mem_error:
104     lxw_format_free(format);
105     return NULL;
106 }
107 
108 /*
109  * Free a format object.
110  */
111 void
lxw_format_free(lxw_format * format)112 lxw_format_free(lxw_format *format)
113 {
114     if (!format)
115         return;
116 
117     free(format);
118     format = NULL;
119 }
120 
121 /*
122  * Check a user input border.
123  */
124 STATIC uint8_t
_check_border(uint8_t border)125 _check_border(uint8_t border)
126 {
127     if (border >= LXW_BORDER_THIN && border <= LXW_BORDER_SLANT_DASH_DOT)
128         return border;
129     else
130         return LXW_BORDER_NONE;
131 }
132 
133 /*****************************************************************************
134  *
135  * Public functions.
136  *
137  ****************************************************************************/
138 
139 /*
140  * Returns a format struct suitable for hashing as a lookup key. This is
141  * mainly a memcpy with any pointer members set to NULL.
142  */
143 STATIC lxw_format *
_get_format_key(lxw_format * self)144 _get_format_key(lxw_format *self)
145 {
146     lxw_format *key = calloc(1, sizeof(lxw_format));
147     GOTO_LABEL_ON_MEM_ERROR(key, mem_error);
148 
149     memcpy(key, self, sizeof(lxw_format));
150 
151     /* Set pointer members to NULL since they aren't part of the comparison. */
152     key->xf_format_indices = NULL;
153     key->dxf_format_indices = NULL;
154     key->num_xf_formats = NULL;
155     key->num_dxf_formats = NULL;
156     key->list_pointers.stqe_next = NULL;
157 
158     return key;
159 
160 mem_error:
161     return NULL;
162 }
163 
164 /*
165  * Returns a font struct suitable for hashing as a lookup key.
166  */
167 lxw_font *
lxw_format_get_font_key(lxw_format * self)168 lxw_format_get_font_key(lxw_format *self)
169 {
170     lxw_font *key = calloc(1, sizeof(lxw_font));
171     GOTO_LABEL_ON_MEM_ERROR(key, mem_error);
172 
173     LXW_FORMAT_FIELD_COPY(key->font_name, self->font_name);
174     key->font_size = self->font_size;
175     key->bold = self->bold;
176     key->italic = self->italic;
177     key->underline = self->underline;
178     key->theme = self->theme;
179     key->font_color = self->font_color;
180     key->font_strikeout = self->font_strikeout;
181     key->font_outline = self->font_outline;
182     key->font_shadow = self->font_shadow;
183     key->font_script = self->font_script;
184     key->font_family = self->font_family;
185     key->font_charset = self->font_charset;
186     key->font_condense = self->font_condense;
187     key->font_extend = self->font_extend;
188 
189     return key;
190 
191 mem_error:
192     return NULL;
193 }
194 
195 /*
196  * Returns a border struct suitable for hashing as a lookup key.
197  */
198 lxw_border *
lxw_format_get_border_key(lxw_format * self)199 lxw_format_get_border_key(lxw_format *self)
200 {
201     lxw_border *key = calloc(1, sizeof(lxw_border));
202     GOTO_LABEL_ON_MEM_ERROR(key, mem_error);
203 
204     key->bottom = self->bottom;
205     key->left = self->left;
206     key->right = self->right;
207     key->top = self->top;
208     key->diag_border = self->diag_border;
209     key->diag_type = self->diag_type;
210     key->bottom_color = self->bottom_color;
211     key->left_color = self->left_color;
212     key->right_color = self->right_color;
213     key->top_color = self->top_color;
214     key->diag_color = self->diag_color;
215 
216     return key;
217 
218 mem_error:
219     return NULL;
220 }
221 
222 /*
223  * Returns a pattern fill struct suitable for hashing as a lookup key.
224  */
225 lxw_fill *
lxw_format_get_fill_key(lxw_format * self)226 lxw_format_get_fill_key(lxw_format *self)
227 {
228     lxw_fill *key = calloc(1, sizeof(lxw_fill));
229     GOTO_LABEL_ON_MEM_ERROR(key, mem_error);
230 
231     key->fg_color = self->fg_color;
232     key->bg_color = self->bg_color;
233     key->pattern = self->pattern;
234 
235     return key;
236 
237 mem_error:
238     return NULL;
239 }
240 
241 /*
242  * Returns the XF index number used by Excel to identify a format.
243  */
244 int32_t
lxw_format_get_xf_index(lxw_format * self)245 lxw_format_get_xf_index(lxw_format *self)
246 {
247     lxw_format *format_key;
248     lxw_format *existing_format;
249     lxw_hash_element *hash_element;
250     lxw_hash_table *formats_hash_table = self->xf_format_indices;
251     int32_t index;
252 
253     /* Note: The formats_hash_table/xf_format_indices contains the unique and
254      * more importantly the *used* formats in the workbook.
255      */
256 
257     /* Format already has an index number so return it. */
258     if (self->xf_index != LXW_PROPERTY_UNSET) {
259         return self->xf_index;
260     }
261 
262     /* Otherwise, the format doesn't have an index number so we assign one.
263      * First generate a unique key to identify the format in the hash table.
264      */
265     format_key = _get_format_key(self);
266 
267     /* Return the default format index if the key generation failed. */
268     if (!format_key)
269         return 0;
270 
271     /* Look up the format in the hash table. */
272     hash_element =
273         lxw_hash_key_exists(formats_hash_table, format_key,
274                             sizeof(lxw_format));
275 
276     if (hash_element) {
277         /* Format matches existing format with an index. */
278         free(format_key);
279         existing_format = hash_element->value;
280         return existing_format->xf_index;
281     }
282     else {
283         /* New format requiring an index. */
284         index = formats_hash_table->unique_count;
285         self->xf_index = index;
286         lxw_insert_hash_element(formats_hash_table, format_key, self,
287                                 sizeof(lxw_format));
288         return index;
289     }
290 }
291 
292 /*
293  * Returns the DXF index number used by Excel to identify a format.
294  */
295 int32_t
lxw_format_get_dxf_index(lxw_format * self)296 lxw_format_get_dxf_index(lxw_format *self)
297 {
298     lxw_format *format_key;
299     lxw_format *existing_format;
300     lxw_hash_element *hash_element;
301     lxw_hash_table *formats_hash_table = self->dxf_format_indices;
302     int32_t index;
303 
304     /* Note: The formats_hash_table/dxf_format_indices contains the unique and
305      * more importantly the *used* formats in the workbook.
306      */
307 
308     /* Format already has an index number so return it. */
309     if (self->dxf_index != LXW_PROPERTY_UNSET) {
310         return self->dxf_index;
311     }
312 
313     /* Otherwise, the format doesn't have an index number so we assign one.
314      * First generate a unique key to identify the format in the hash table.
315      */
316     format_key = _get_format_key(self);
317 
318     /* Return the default format index if the key generation failed. */
319     if (!format_key)
320         return 0;
321 
322     /* Look up the format in the hash table. */
323     hash_element =
324         lxw_hash_key_exists(formats_hash_table, format_key,
325                             sizeof(lxw_format));
326 
327     if (hash_element) {
328         /* Format matches existing format with an index. */
329         free(format_key);
330         existing_format = hash_element->value;
331         return existing_format->dxf_index;
332     }
333     else {
334         /* New format requiring an index. */
335         index = formats_hash_table->unique_count;
336         self->dxf_index = index;
337         lxw_insert_hash_element(formats_hash_table, format_key, self,
338                                 sizeof(lxw_format));
339         return index;
340     }
341 }
342 
343 /*
344  * Set the font_name property.
345  */
346 void
format_set_font_name(lxw_format * self,const char * font_name)347 format_set_font_name(lxw_format *self, const char *font_name)
348 {
349     LXW_FORMAT_FIELD_COPY(self->font_name, font_name);
350 }
351 
352 /*
353  * Set the font_size property.
354  */
355 void
format_set_font_size(lxw_format * self,double size)356 format_set_font_size(lxw_format *self, double size)
357 {
358 
359     if (size >= LXW_MIN_FONT_SIZE && size <= LXW_MAX_FONT_SIZE)
360         self->font_size = size;
361 }
362 
363 /*
364  * Set the font_color property.
365  */
366 void
format_set_font_color(lxw_format * self,lxw_color_t color)367 format_set_font_color(lxw_format *self, lxw_color_t color)
368 {
369     self->font_color = color;
370 }
371 
372 /*
373  * Set the bold property.
374  */
375 void
format_set_bold(lxw_format * self)376 format_set_bold(lxw_format *self)
377 {
378     self->bold = LXW_TRUE;
379 }
380 
381 /*
382  * Set the italic property.
383  */
384 
385 void
format_set_italic(lxw_format * self)386 format_set_italic(lxw_format *self)
387 {
388     self->italic = LXW_TRUE;
389 }
390 
391 /*
392  * Set the underline property.
393  */
394 void
format_set_underline(lxw_format * self,uint8_t style)395 format_set_underline(lxw_format *self, uint8_t style)
396 {
397     if (style >= LXW_UNDERLINE_SINGLE
398         && style <= LXW_UNDERLINE_DOUBLE_ACCOUNTING)
399         self->underline = style;
400 }
401 
402 /*
403  * Set the font_strikeout property.
404  */
405 void
format_set_font_strikeout(lxw_format * self)406 format_set_font_strikeout(lxw_format *self)
407 {
408     self->font_strikeout = LXW_TRUE;
409 }
410 
411 /*
412  * Set the font_script property.
413  */
414 void
format_set_font_script(lxw_format * self,uint8_t style)415 format_set_font_script(lxw_format *self, uint8_t style)
416 {
417     if (style >= LXW_FONT_SUPERSCRIPT && style <= LXW_FONT_SUBSCRIPT)
418         self->font_script = style;
419 }
420 
421 /*
422  * Set the font_outline property.
423  */
424 void
format_set_font_outline(lxw_format * self)425 format_set_font_outline(lxw_format *self)
426 {
427     self->font_outline = LXW_TRUE;
428 }
429 
430 /*
431  * Set the font_shadow property.
432  */
433 void
format_set_font_shadow(lxw_format * self)434 format_set_font_shadow(lxw_format *self)
435 {
436     self->font_shadow = LXW_TRUE;
437 }
438 
439 /*
440  * Set the num_format property.
441  */
442 void
format_set_num_format(lxw_format * self,const char * num_format)443 format_set_num_format(lxw_format *self, const char *num_format)
444 {
445     LXW_FORMAT_FIELD_COPY(self->num_format, num_format);
446 }
447 
448 /*
449  * Set the unlocked property.
450  */
451 void
format_set_unlocked(lxw_format * self)452 format_set_unlocked(lxw_format *self)
453 {
454     self->locked = LXW_FALSE;
455 }
456 
457 /*
458  * Set the hidden property.
459  */
460 void
format_set_hidden(lxw_format * self)461 format_set_hidden(lxw_format *self)
462 {
463     self->hidden = LXW_TRUE;
464 }
465 
466 /*
467  * Set the align property.
468  */
469 void
format_set_align(lxw_format * self,uint8_t value)470 format_set_align(lxw_format *self, uint8_t value)
471 {
472     if (value >= LXW_ALIGN_LEFT && value <= LXW_ALIGN_DISTRIBUTED) {
473         self->text_h_align = value;
474     }
475 
476     if (value >= LXW_ALIGN_VERTICAL_TOP
477         && value <= LXW_ALIGN_VERTICAL_DISTRIBUTED) {
478         self->text_v_align = value;
479     }
480 }
481 
482 /*
483  * Set the text_wrap property.
484  */
485 void
format_set_text_wrap(lxw_format * self)486 format_set_text_wrap(lxw_format *self)
487 {
488     self->text_wrap = LXW_TRUE;
489 }
490 
491 /*
492  * Set the rotation property.
493  */
494 void
format_set_rotation(lxw_format * self,int16_t angle)495 format_set_rotation(lxw_format *self, int16_t angle)
496 {
497     /* Convert user angle to Excel angle. */
498     if (angle == 270) {
499         self->rotation = 255;
500     }
501     else if (angle >= -90 && angle <= 90) {
502         if (angle < 0)
503             angle = -angle + 90;
504 
505         self->rotation = angle;
506     }
507     else {
508         LXW_WARN("Rotation rotation outside range: -90 <= angle <= 90.");
509         self->rotation = 0;
510     }
511 }
512 
513 /*
514  * Set the indent property.
515  */
516 void
format_set_indent(lxw_format * self,uint8_t value)517 format_set_indent(lxw_format *self, uint8_t value)
518 {
519     self->indent = value;
520 }
521 
522 /*
523  * Set the shrink property.
524  */
525 void
format_set_shrink(lxw_format * self)526 format_set_shrink(lxw_format *self)
527 {
528     self->shrink = LXW_TRUE;
529 }
530 
531 /*
532  * Set the text_justlast property.
533  */
534 void
format_set_text_justlast(lxw_format * self)535 format_set_text_justlast(lxw_format *self)
536 {
537     self->text_justlast = LXW_TRUE;
538 }
539 
540 /*
541  * Set the pattern property.
542  */
543 void
format_set_pattern(lxw_format * self,uint8_t value)544 format_set_pattern(lxw_format *self, uint8_t value)
545 {
546     self->pattern = value;
547 }
548 
549 /*
550  * Set the bg_color property.
551  */
552 void
format_set_bg_color(lxw_format * self,lxw_color_t color)553 format_set_bg_color(lxw_format *self, lxw_color_t color)
554 {
555     self->bg_color = color;
556 }
557 
558 /*
559  * Set the fg_color property.
560  */
561 void
format_set_fg_color(lxw_format * self,lxw_color_t color)562 format_set_fg_color(lxw_format *self, lxw_color_t color)
563 {
564     self->fg_color = color;
565 }
566 
567 /*
568  * Set the border property.
569  */
570 void
format_set_border(lxw_format * self,uint8_t style)571 format_set_border(lxw_format *self, uint8_t style)
572 {
573     style = _check_border(style);
574     self->bottom = style;
575     self->top = style;
576     self->left = style;
577     self->right = style;
578 }
579 
580 /*
581  * Set the border_color property.
582  */
583 void
format_set_border_color(lxw_format * self,lxw_color_t color)584 format_set_border_color(lxw_format *self, lxw_color_t color)
585 {
586     self->bottom_color = color;
587     self->top_color = color;
588     self->left_color = color;
589     self->right_color = color;
590 }
591 
592 /*
593  * Set the bottom property.
594  */
595 void
format_set_bottom(lxw_format * self,uint8_t style)596 format_set_bottom(lxw_format *self, uint8_t style)
597 {
598     self->bottom = _check_border(style);
599 }
600 
601 /*
602  * Set the bottom_color property.
603  */
604 void
format_set_bottom_color(lxw_format * self,lxw_color_t color)605 format_set_bottom_color(lxw_format *self, lxw_color_t color)
606 {
607     self->bottom_color = color;
608 }
609 
610 /*
611  * Set the left property.
612  */
613 void
format_set_left(lxw_format * self,uint8_t style)614 format_set_left(lxw_format *self, uint8_t style)
615 {
616     self->left = _check_border(style);
617 }
618 
619 /*
620  * Set the left_color property.
621  */
622 void
format_set_left_color(lxw_format * self,lxw_color_t color)623 format_set_left_color(lxw_format *self, lxw_color_t color)
624 {
625     self->left_color = color;
626 }
627 
628 /*
629  * Set the right property.
630  */
631 void
format_set_right(lxw_format * self,uint8_t style)632 format_set_right(lxw_format *self, uint8_t style)
633 {
634     self->right = _check_border(style);
635 }
636 
637 /*
638  * Set the right_color property.
639  */
640 void
format_set_right_color(lxw_format * self,lxw_color_t color)641 format_set_right_color(lxw_format *self, lxw_color_t color)
642 {
643     self->right_color = color;
644 }
645 
646 /*
647  * Set the top property.
648  */
649 void
format_set_top(lxw_format * self,uint8_t style)650 format_set_top(lxw_format *self, uint8_t style)
651 {
652     self->top = _check_border(style);
653 }
654 
655 /*
656  * Set the top_color property.
657  */
658 void
format_set_top_color(lxw_format * self,lxw_color_t color)659 format_set_top_color(lxw_format *self, lxw_color_t color)
660 {
661     self->top_color = color;
662 }
663 
664 /*
665  * Set the diag_type property.
666  */
667 void
format_set_diag_type(lxw_format * self,uint8_t type)668 format_set_diag_type(lxw_format *self, uint8_t type)
669 {
670     if (type >= LXW_DIAGONAL_BORDER_UP && type <= LXW_DIAGONAL_BORDER_UP_DOWN)
671         self->diag_type = type;
672 }
673 
674 /*
675  * Set the diag_color property.
676  */
677 void
format_set_diag_color(lxw_format * self,lxw_color_t color)678 format_set_diag_color(lxw_format *self, lxw_color_t color)
679 {
680     self->diag_color = color;
681 }
682 
683 /*
684  * Set the diag_border property.
685  */
686 void
format_set_diag_border(lxw_format * self,uint8_t style)687 format_set_diag_border(lxw_format *self, uint8_t style)
688 {
689     self->diag_border = style;
690 }
691 
692 /*
693  * Set the num_format_index property.
694  */
695 void
format_set_num_format_index(lxw_format * self,uint8_t value)696 format_set_num_format_index(lxw_format *self, uint8_t value)
697 {
698     self->num_format_index = value;
699 }
700 
701 /*
702  * Set the valign property.
703  */
704 void
format_set_valign(lxw_format * self,uint8_t value)705 format_set_valign(lxw_format *self, uint8_t value)
706 {
707     self->text_v_align = value;
708 }
709 
710 /*
711  * Set the reading_order property.
712  */
713 void
format_set_reading_order(lxw_format * self,uint8_t value)714 format_set_reading_order(lxw_format *self, uint8_t value)
715 {
716     self->reading_order = value;
717 }
718 
719 /*
720  * Set the font_family property.
721  */
722 void
format_set_font_family(lxw_format * self,uint8_t value)723 format_set_font_family(lxw_format *self, uint8_t value)
724 {
725     self->font_family = value;
726 }
727 
728 /*
729  * Set the font_charset property.
730  */
731 void
format_set_font_charset(lxw_format * self,uint8_t value)732 format_set_font_charset(lxw_format *self, uint8_t value)
733 {
734     self->font_charset = value;
735 }
736 
737 /*
738  * Set the font_scheme property.
739  */
740 void
format_set_font_scheme(lxw_format * self,const char * font_scheme)741 format_set_font_scheme(lxw_format *self, const char *font_scheme)
742 {
743     LXW_FORMAT_FIELD_COPY(self->font_scheme, font_scheme);
744 }
745 
746 /*
747  * Set the font_condense property.
748  */
749 void
format_set_font_condense(lxw_format * self)750 format_set_font_condense(lxw_format *self)
751 {
752     self->font_condense = LXW_TRUE;
753 }
754 
755 /*
756  * Set the font_extend property.
757  */
758 void
format_set_font_extend(lxw_format * self)759 format_set_font_extend(lxw_format *self)
760 {
761     self->font_extend = LXW_TRUE;
762 }
763 
764 /*
765  * Set the theme property.
766  */
767 void
format_set_theme(lxw_format * self,uint8_t value)768 format_set_theme(lxw_format *self, uint8_t value)
769 {
770     self->theme = value;
771 }
772 
773 /*
774  * Set the color_indexed property.
775  */
776 void
format_set_color_indexed(lxw_format * self,uint8_t value)777 format_set_color_indexed(lxw_format *self, uint8_t value)
778 {
779     self->color_indexed = value;
780 }
781 
782 /*
783  * Set the font_only property.
784  */
785 void
format_set_font_only(lxw_format * self)786 format_set_font_only(lxw_format *self)
787 {
788     self->font_only = LXW_TRUE;
789 }
790 
791 /*
792  * Set the theme property.
793  */
794 void
format_set_hyperlink(lxw_format * self)795 format_set_hyperlink(lxw_format *self)
796 {
797     self->hyperlink = LXW_TRUE;
798     self->xf_id = 1;
799     self->underline = LXW_UNDERLINE_SINGLE;
800     self->theme = 10;
801 }
802