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