1 /*****************************************************************************
2  * drawing - A library for creating Excel XLSX drawing 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/common.h"
12 #include "xlsxwriter/drawing.h"
13 #include "xlsxwriter/worksheet.h"
14 #include "xlsxwriter/utility.h"
15 
16 #define LXW_OBJ_NAME_LENGTH 14  /* "Picture 65536", or "Chart 65536" */
17 /*
18  * Forward declarations.
19  */
20 
21 /*****************************************************************************
22  *
23  * Private functions.
24  *
25  ****************************************************************************/
26 
27 /*
28  * Create a new drawing collection.
29  */
30 lxw_drawing *
lxw_drawing_new(void)31 lxw_drawing_new(void)
32 {
33     lxw_drawing *drawing = calloc(1, sizeof(lxw_drawing));
34     GOTO_LABEL_ON_MEM_ERROR(drawing, mem_error);
35 
36     drawing->drawing_objects = calloc(1, sizeof(struct lxw_drawing_objects));
37     GOTO_LABEL_ON_MEM_ERROR(drawing->drawing_objects, mem_error);
38 
39     STAILQ_INIT(drawing->drawing_objects);
40 
41     return drawing;
42 
43 mem_error:
44     lxw_drawing_free(drawing);
45     return NULL;
46 }
47 
48 /*
49  * Free a drawing object.
50  */
51 void
lxw_free_drawing_object(lxw_drawing_object * drawing_object)52 lxw_free_drawing_object(lxw_drawing_object *drawing_object)
53 {
54     if (!drawing_object)
55         return;
56 
57     free(drawing_object->description);
58     free(drawing_object->tip);
59 
60     free(drawing_object);
61 }
62 
63 /*
64  * Free a drawing collection.
65  */
66 void
lxw_drawing_free(lxw_drawing * drawing)67 lxw_drawing_free(lxw_drawing *drawing)
68 {
69     lxw_drawing_object *drawing_object;
70 
71     if (!drawing)
72         return;
73 
74     if (drawing->drawing_objects) {
75         while (!STAILQ_EMPTY(drawing->drawing_objects)) {
76             drawing_object = STAILQ_FIRST(drawing->drawing_objects);
77             STAILQ_REMOVE_HEAD(drawing->drawing_objects, list_pointers);
78             lxw_free_drawing_object(drawing_object);
79         }
80 
81         free(drawing->drawing_objects);
82     }
83 
84     free(drawing);
85 }
86 
87 /*
88  * Add a drawing object to the drawing collection.
89  */
90 void
lxw_add_drawing_object(lxw_drawing * drawing,lxw_drawing_object * drawing_object)91 lxw_add_drawing_object(lxw_drawing *drawing,
92                        lxw_drawing_object *drawing_object)
93 {
94     STAILQ_INSERT_TAIL(drawing->drawing_objects, drawing_object,
95                        list_pointers);
96 }
97 
98 /*****************************************************************************
99  *
100  * XML functions.
101  *
102  ****************************************************************************/
103 
104 /*
105  * Write the XML declaration.
106  */
107 STATIC void
_drawing_xml_declaration(lxw_drawing * self)108 _drawing_xml_declaration(lxw_drawing *self)
109 {
110     lxw_xml_declaration(self->file);
111 }
112 
113 /*
114  * Write the <xdr:wsDr> element.
115  */
116 STATIC void
_write_drawing_workspace(lxw_drawing * self)117 _write_drawing_workspace(lxw_drawing *self)
118 {
119     struct xml_attribute_list attributes;
120     struct xml_attribute *attribute;
121     char xmlns_xdr[] = LXW_SCHEMA_DRAWING "/spreadsheetDrawing";
122     char xmlns_a[] = LXW_SCHEMA_DRAWING "/main";
123 
124     LXW_INIT_ATTRIBUTES();
125 
126     LXW_PUSH_ATTRIBUTES_STR("xmlns:xdr", xmlns_xdr);
127     LXW_PUSH_ATTRIBUTES_STR("xmlns:a", xmlns_a);
128 
129     lxw_xml_start_tag(self->file, "xdr:wsDr", &attributes);
130 
131     LXW_FREE_ATTRIBUTES();
132 }
133 
134 /*
135  * Write the <xdr:col> element.
136  */
137 STATIC void
_drawing_write_col(lxw_drawing * self,char * data)138 _drawing_write_col(lxw_drawing *self, char *data)
139 {
140     lxw_xml_data_element(self->file, "xdr:col", data, NULL);
141 }
142 
143 /*
144  * Write the <xdr:colOff> element.
145  */
146 STATIC void
_drawing_write_col_off(lxw_drawing * self,char * data)147 _drawing_write_col_off(lxw_drawing *self, char *data)
148 {
149     lxw_xml_data_element(self->file, "xdr:colOff", data, NULL);
150 }
151 
152 /*
153  * Write the <xdr:row> element.
154  */
155 STATIC void
_drawing_write_row(lxw_drawing * self,char * data)156 _drawing_write_row(lxw_drawing *self, char *data)
157 {
158     lxw_xml_data_element(self->file, "xdr:row", data, NULL);
159 }
160 
161 /*
162  * Write the <xdr:rowOff> element.
163  */
164 STATIC void
_drawing_write_row_off(lxw_drawing * self,char * data)165 _drawing_write_row_off(lxw_drawing *self, char *data)
166 {
167     lxw_xml_data_element(self->file, "xdr:rowOff", data, NULL);
168 }
169 
170 /*
171  * Write the main part of the <xdr:from> and <xdr:to> elements.
172  */
173 STATIC void
_drawing_write_coords(lxw_drawing * self,lxw_drawing_coords * coords)174 _drawing_write_coords(lxw_drawing *self, lxw_drawing_coords *coords)
175 {
176     char data[LXW_UINT32_T_LENGTH];
177 
178     lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u", coords->col);
179     _drawing_write_col(self, data);
180 
181     lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u",
182                  (uint32_t) coords->col_offset);
183     _drawing_write_col_off(self, data);
184 
185     lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u", coords->row);
186     _drawing_write_row(self, data);
187 
188     lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u",
189                  (uint32_t) coords->row_offset);
190     _drawing_write_row_off(self, data);
191 }
192 
193 /*
194  * Write the <xdr:from> element.
195  */
196 STATIC void
_drawing_write_from(lxw_drawing * self,lxw_drawing_coords * coords)197 _drawing_write_from(lxw_drawing *self, lxw_drawing_coords *coords)
198 {
199     lxw_xml_start_tag(self->file, "xdr:from", NULL);
200 
201     _drawing_write_coords(self, coords);
202 
203     lxw_xml_end_tag(self->file, "xdr:from");
204 }
205 
206 /*
207  * Write the <xdr:to> element.
208  */
209 STATIC void
_drawing_write_to(lxw_drawing * self,lxw_drawing_coords * coords)210 _drawing_write_to(lxw_drawing *self, lxw_drawing_coords *coords)
211 {
212     lxw_xml_start_tag(self->file, "xdr:to", NULL);
213 
214     _drawing_write_coords(self, coords);
215 
216     lxw_xml_end_tag(self->file, "xdr:to");
217 }
218 
219 /*
220  * Write the <a:hlinkClick> element.
221  */
222 STATIC void
_drawing_write_a_hlink_click(lxw_drawing * self,uint32_t rel_index,char * tip)223 _drawing_write_a_hlink_click(lxw_drawing *self, uint32_t rel_index, char *tip)
224 {
225     struct xml_attribute_list attributes;
226     struct xml_attribute *attribute;
227     char xmlns_r[] = "http://schemas.openxmlformats.org/"
228         "officeDocument/2006/relationships";
229     char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
230 
231     lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", rel_index);
232 
233     LXW_INIT_ATTRIBUTES();
234     LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
235     LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
236 
237     if (tip)
238         LXW_PUSH_ATTRIBUTES_STR("tooltip", tip);
239 
240     lxw_xml_empty_tag(self->file, "a:hlinkClick", &attributes);
241 
242     LXW_FREE_ATTRIBUTES();
243 }
244 
245 /*
246  * Write the <a16:creationId> element.
247  */
248 STATIC void
_drawing_write_a16_creation_id(lxw_drawing * self)249 _drawing_write_a16_creation_id(lxw_drawing *self)
250 {
251     struct xml_attribute_list attributes;
252     struct xml_attribute *attribute;
253     char xmlns[] = "http://schemas.microsoft.com/office/drawing/2014/main";
254 
255     LXW_INIT_ATTRIBUTES();
256     LXW_PUSH_ATTRIBUTES_STR("xmlns:a16", xmlns);
257     LXW_PUSH_ATTRIBUTES_STR("id", "{00000000-0008-0000-0000-000002000000}");
258 
259     lxw_xml_empty_tag(self->file, "a16:creationId", &attributes);
260 
261     LXW_FREE_ATTRIBUTES();
262 }
263 
264 /*
265  * Write the <adec:decorative> element.
266  */
267 STATIC void
_workbook_write_adec_decorative(lxw_drawing * self)268 _workbook_write_adec_decorative(lxw_drawing *self)
269 {
270     struct xml_attribute_list attributes;
271     struct xml_attribute *attribute;
272     char xmlns[] =
273         "http://schemas.microsoft.com/office/drawing/2017/decorative";
274 
275     LXW_INIT_ATTRIBUTES();
276     LXW_PUSH_ATTRIBUTES_STR("xmlns:adec", xmlns);
277     LXW_PUSH_ATTRIBUTES_STR("val", "1");
278 
279     lxw_xml_empty_tag(self->file, "adec:decorative", &attributes);
280 
281     LXW_FREE_ATTRIBUTES();
282 }
283 
284 /*
285  * Write the <a:ext> element.
286  */
287 STATIC void
_drawing_write_uri_ext(lxw_drawing * self,char * uri)288 _drawing_write_uri_ext(lxw_drawing *self, char *uri)
289 {
290     struct xml_attribute_list attributes;
291     struct xml_attribute *attribute;
292 
293     LXW_INIT_ATTRIBUTES();
294     LXW_PUSH_ATTRIBUTES_STR("uri", uri);
295 
296     lxw_xml_start_tag(self->file, "a:ext", &attributes);
297 
298     LXW_FREE_ATTRIBUTES();
299 }
300 
301 /*
302  * Write the decorative elements.
303  */
304 STATIC void
_workbook_write_decorative(lxw_drawing * self)305 _workbook_write_decorative(lxw_drawing *self)
306 {
307     lxw_xml_start_tag(self->file, "a:extLst", NULL);
308 
309     _drawing_write_uri_ext(self, "{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}");
310     _drawing_write_a16_creation_id(self);
311     lxw_xml_end_tag(self->file, "a:ext");
312 
313     _drawing_write_uri_ext(self, "{C183D7F6-B498-43B3-948B-1728B52AA6E4}");
314     _workbook_write_adec_decorative(self);
315     lxw_xml_end_tag(self->file, "a:ext");
316 
317     lxw_xml_end_tag(self->file, "a:extLst");
318 }
319 
320 /*
321  * Write the <xdr:cNvPr> element.
322  */
323 STATIC void
_drawing_write_c_nv_pr(lxw_drawing * self,char * object_name,uint32_t index,lxw_drawing_object * drawing_object)324 _drawing_write_c_nv_pr(lxw_drawing *self, char *object_name, uint32_t index,
325                        lxw_drawing_object *drawing_object)
326 {
327     struct xml_attribute_list attributes;
328     struct xml_attribute *attribute;
329 
330     char name[LXW_OBJ_NAME_LENGTH];
331     lxw_snprintf(name, LXW_OBJ_NAME_LENGTH, "%s %d", object_name, index);
332 
333     LXW_INIT_ATTRIBUTES();
334 
335     LXW_PUSH_ATTRIBUTES_INT("id", index + 1);
336     LXW_PUSH_ATTRIBUTES_STR("name", name);
337 
338     if (drawing_object && drawing_object->description
339         && strlen(drawing_object->description)
340         && !drawing_object->decorative) {
341 
342         LXW_PUSH_ATTRIBUTES_STR("descr", drawing_object->description);
343     }
344 
345     if (drawing_object
346         && (drawing_object->url_rel_index || drawing_object->decorative)) {
347         lxw_xml_start_tag(self->file, "xdr:cNvPr", &attributes);
348 
349         if (drawing_object->url_rel_index) {
350             /* Write the a:hlinkClick element. */
351             _drawing_write_a_hlink_click(self,
352                                          drawing_object->url_rel_index,
353                                          drawing_object->tip);
354         }
355 
356         if (drawing_object->decorative) {
357             _workbook_write_decorative(self);
358         }
359 
360         lxw_xml_end_tag(self->file, "xdr:cNvPr");
361     }
362     else {
363         lxw_xml_empty_tag(self->file, "xdr:cNvPr", &attributes);
364     }
365 
366     LXW_FREE_ATTRIBUTES();
367 }
368 
369 /*
370  * Write the <a:picLocks> element.
371  */
372 STATIC void
_drawing_write_a_pic_locks(lxw_drawing * self)373 _drawing_write_a_pic_locks(lxw_drawing *self)
374 {
375     struct xml_attribute_list attributes;
376     struct xml_attribute *attribute;
377 
378     LXW_INIT_ATTRIBUTES();
379     LXW_PUSH_ATTRIBUTES_STR("noChangeAspect", "1");
380 
381     lxw_xml_empty_tag(self->file, "a:picLocks", &attributes);
382 
383     LXW_FREE_ATTRIBUTES();
384 }
385 
386 /*
387  * Write the <xdr:cNvPicPr> element.
388  */
389 STATIC void
_drawing_write_c_nv_pic_pr(lxw_drawing * self)390 _drawing_write_c_nv_pic_pr(lxw_drawing *self)
391 {
392     lxw_xml_start_tag(self->file, "xdr:cNvPicPr", NULL);
393 
394     /* Write the a:picLocks element. */
395     _drawing_write_a_pic_locks(self);
396 
397     lxw_xml_end_tag(self->file, "xdr:cNvPicPr");
398 }
399 
400 /*
401  * Write the <xdr:nvPicPr> element.
402  */
403 STATIC void
_drawing_write_nv_pic_pr(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)404 _drawing_write_nv_pic_pr(lxw_drawing *self, uint32_t index,
405                          lxw_drawing_object *drawing_object)
406 {
407     lxw_xml_start_tag(self->file, "xdr:nvPicPr", NULL);
408 
409     /* Write the xdr:cNvPr element. */
410     _drawing_write_c_nv_pr(self, "Picture", index, drawing_object);
411 
412     /* Write the xdr:cNvPicPr element. */
413     _drawing_write_c_nv_pic_pr(self);
414 
415     lxw_xml_end_tag(self->file, "xdr:nvPicPr");
416 }
417 
418 /*
419  * Write the <a:blip> element.
420  */
421 STATIC void
_drawing_write_a_blip(lxw_drawing * self,uint32_t index)422 _drawing_write_a_blip(lxw_drawing *self, uint32_t index)
423 {
424     struct xml_attribute_list attributes;
425     struct xml_attribute *attribute;
426     char xmlns_r[] = LXW_SCHEMA_OFFICEDOC "/relationships";
427     char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
428 
429     lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", index);
430 
431     LXW_INIT_ATTRIBUTES();
432     LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
433     LXW_PUSH_ATTRIBUTES_STR("r:embed", r_id);
434 
435     lxw_xml_empty_tag(self->file, "a:blip", &attributes);
436 
437     LXW_FREE_ATTRIBUTES();
438 }
439 
440 /*
441  * Write the <a:fillRect> element.
442  */
443 STATIC void
_drawing_write_a_fill_rect(lxw_drawing * self)444 _drawing_write_a_fill_rect(lxw_drawing *self)
445 {
446     lxw_xml_empty_tag(self->file, "a:fillRect", NULL);
447 }
448 
449 /*
450  * Write the <a:stretch> element.
451  */
452 STATIC void
_drawing_write_a_stretch(lxw_drawing * self)453 _drawing_write_a_stretch(lxw_drawing *self)
454 {
455     lxw_xml_start_tag(self->file, "a:stretch", NULL);
456 
457     /* Write the a:fillRect element. */
458     _drawing_write_a_fill_rect(self);
459 
460     lxw_xml_end_tag(self->file, "a:stretch");
461 }
462 
463 /*
464  * Write the <xdr:blipFill> element.
465  */
466 STATIC void
_drawing_write_blip_fill(lxw_drawing * self,uint32_t index)467 _drawing_write_blip_fill(lxw_drawing *self, uint32_t index)
468 {
469     lxw_xml_start_tag(self->file, "xdr:blipFill", NULL);
470 
471     /* Write the a:blip element. */
472     _drawing_write_a_blip(self, index);
473 
474     /* Write the a:stretch element. */
475     _drawing_write_a_stretch(self);
476 
477     lxw_xml_end_tag(self->file, "xdr:blipFill");
478 }
479 
480 /*
481  * Write the <a:ext> element.
482  */
483 STATIC void
_drawing_write_a_ext(lxw_drawing * self,lxw_drawing_object * drawing_object)484 _drawing_write_a_ext(lxw_drawing *self, lxw_drawing_object *drawing_object)
485 {
486     struct xml_attribute_list attributes;
487     struct xml_attribute *attribute;
488 
489     LXW_INIT_ATTRIBUTES();
490     LXW_PUSH_ATTRIBUTES_INT("cx", drawing_object->width);
491     LXW_PUSH_ATTRIBUTES_INT("cy", drawing_object->height);
492 
493     lxw_xml_empty_tag(self->file, "a:ext", &attributes);
494 
495     LXW_FREE_ATTRIBUTES();
496 }
497 
498 /*
499  * Write the <a:off> element.
500  */
501 STATIC void
_drawing_write_a_off(lxw_drawing * self,lxw_drawing_object * drawing_object)502 _drawing_write_a_off(lxw_drawing *self, lxw_drawing_object *drawing_object)
503 {
504     struct xml_attribute_list attributes;
505     struct xml_attribute *attribute;
506 
507     LXW_INIT_ATTRIBUTES();
508     LXW_PUSH_ATTRIBUTES_INT("x", drawing_object->col_absolute);
509     LXW_PUSH_ATTRIBUTES_INT("y", drawing_object->row_absolute);
510 
511     lxw_xml_empty_tag(self->file, "a:off", &attributes);
512 
513     LXW_FREE_ATTRIBUTES();
514 }
515 
516 /*
517  * Write the <a:xfrm> element.
518  */
519 STATIC void
_drawing_write_a_xfrm(lxw_drawing * self,lxw_drawing_object * drawing_object)520 _drawing_write_a_xfrm(lxw_drawing *self, lxw_drawing_object *drawing_object)
521 {
522     lxw_xml_start_tag(self->file, "a:xfrm", NULL);
523 
524     /* Write the a:off element. */
525     _drawing_write_a_off(self, drawing_object);
526 
527     /* Write the a:ext element. */
528     _drawing_write_a_ext(self, drawing_object);
529 
530     lxw_xml_end_tag(self->file, "a:xfrm");
531 }
532 
533 /*
534  * Write the <a:avLst> element.
535  */
536 STATIC void
_drawing_write_a_av_lst(lxw_drawing * self)537 _drawing_write_a_av_lst(lxw_drawing *self)
538 {
539     lxw_xml_empty_tag(self->file, "a:avLst", NULL);
540 }
541 
542 /*
543  * Write the <a:prstGeom> element.
544  */
545 STATIC void
_drawing_write_a_prst_geom(lxw_drawing * self)546 _drawing_write_a_prst_geom(lxw_drawing *self)
547 {
548     struct xml_attribute_list attributes;
549     struct xml_attribute *attribute;
550 
551     LXW_INIT_ATTRIBUTES();
552     LXW_PUSH_ATTRIBUTES_STR("prst", "rect");
553 
554     lxw_xml_start_tag(self->file, "a:prstGeom", &attributes);
555 
556     /* Write the a:avLst element. */
557     _drawing_write_a_av_lst(self);
558 
559     lxw_xml_end_tag(self->file, "a:prstGeom");
560 
561     LXW_FREE_ATTRIBUTES();
562 }
563 
564 /*
565  * Write the <xdr:spPr> element.
566  */
567 STATIC void
_drawing_write_sp_pr(lxw_drawing * self,lxw_drawing_object * drawing_object)568 _drawing_write_sp_pr(lxw_drawing *self, lxw_drawing_object *drawing_object)
569 {
570     lxw_xml_start_tag(self->file, "xdr:spPr", NULL);
571 
572     /* Write the a:xfrm element. */
573     _drawing_write_a_xfrm(self, drawing_object);
574 
575     /* Write the a:prstGeom element. */
576     _drawing_write_a_prst_geom(self);
577 
578     lxw_xml_end_tag(self->file, "xdr:spPr");
579 }
580 
581 /*
582  * Write the <xdr:pic> element.
583  */
584 STATIC void
_drawing_write_pic(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)585 _drawing_write_pic(lxw_drawing *self, uint32_t index,
586                    lxw_drawing_object *drawing_object)
587 {
588     lxw_xml_start_tag(self->file, "xdr:pic", NULL);
589 
590     /* Write the xdr:nvPicPr element. */
591     _drawing_write_nv_pic_pr(self, index, drawing_object);
592 
593     /* Write the xdr:blipFill element. */
594     _drawing_write_blip_fill(self, drawing_object->rel_index);
595 
596     /* Write the xdr:spPr element. */
597     _drawing_write_sp_pr(self, drawing_object);
598 
599     lxw_xml_end_tag(self->file, "xdr:pic");
600 }
601 
602 /*
603  * Write the <xdr:clientData> element.
604  */
605 STATIC void
_drawing_write_client_data(lxw_drawing * self)606 _drawing_write_client_data(lxw_drawing *self)
607 {
608     lxw_xml_empty_tag(self->file, "xdr:clientData", NULL);
609 }
610 
611 /*
612  * Write the <a:graphicFrameLocks> element.
613  */
614 STATIC void
_drawing_write_a_graphic_frame_locks(lxw_drawing * self)615 _drawing_write_a_graphic_frame_locks(lxw_drawing *self)
616 {
617     struct xml_attribute_list attributes;
618     struct xml_attribute *attribute;
619 
620     LXW_INIT_ATTRIBUTES();
621     LXW_PUSH_ATTRIBUTES_INT("noGrp", 1);
622 
623     lxw_xml_empty_tag(self->file, "a:graphicFrameLocks", &attributes);
624 
625     LXW_FREE_ATTRIBUTES();
626 }
627 
628 /*
629  * Write the <xdr:cNvGraphicFramePr> element.
630  */
631 STATIC void
_drawing_write_c_nv_graphic_frame_pr(lxw_drawing * self)632 _drawing_write_c_nv_graphic_frame_pr(lxw_drawing *self)
633 {
634     if (self->embedded) {
635         lxw_xml_empty_tag(self->file, "xdr:cNvGraphicFramePr", NULL);
636     }
637     else {
638         lxw_xml_start_tag(self->file, "xdr:cNvGraphicFramePr", NULL);
639 
640         /* Write the a:graphicFrameLocks element. */
641         _drawing_write_a_graphic_frame_locks(self);
642 
643         lxw_xml_end_tag(self->file, "xdr:cNvGraphicFramePr");
644     }
645 }
646 
647 /*
648  * Write the <xdr:nvGraphicFramePr> element.
649  */
650 STATIC void
_drawing_write_nv_graphic_frame_pr(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)651 _drawing_write_nv_graphic_frame_pr(lxw_drawing *self, uint32_t index,
652                                    lxw_drawing_object *drawing_object)
653 {
654     lxw_xml_start_tag(self->file, "xdr:nvGraphicFramePr", NULL);
655 
656     /* Write the xdr:cNvPr element. */
657     _drawing_write_c_nv_pr(self, "Chart", index, drawing_object);
658 
659     /* Write the xdr:cNvGraphicFramePr element. */
660     _drawing_write_c_nv_graphic_frame_pr(self);
661 
662     lxw_xml_end_tag(self->file, "xdr:nvGraphicFramePr");
663 }
664 
665 /*
666  * Write the <a:off> element.
667  */
668 STATIC void
_drawing_write_xfrm_offset(lxw_drawing * self)669 _drawing_write_xfrm_offset(lxw_drawing *self)
670 {
671     struct xml_attribute_list attributes;
672     struct xml_attribute *attribute;
673 
674     LXW_INIT_ATTRIBUTES();
675     LXW_PUSH_ATTRIBUTES_STR("x", "0");
676     LXW_PUSH_ATTRIBUTES_STR("y", "0");
677 
678     lxw_xml_empty_tag(self->file, "a:off", &attributes);
679 
680     LXW_FREE_ATTRIBUTES();
681 }
682 
683 /*
684  * Write the <a:ext> element.
685  */
686 STATIC void
_drawing_write_xfrm_extension(lxw_drawing * self)687 _drawing_write_xfrm_extension(lxw_drawing *self)
688 {
689     struct xml_attribute_list attributes;
690     struct xml_attribute *attribute;
691 
692     LXW_INIT_ATTRIBUTES();
693     LXW_PUSH_ATTRIBUTES_STR("cx", "0");
694     LXW_PUSH_ATTRIBUTES_STR("cy", "0");
695 
696     lxw_xml_empty_tag(self->file, "a:ext", &attributes);
697 
698     LXW_FREE_ATTRIBUTES();
699 }
700 
701 /*
702  * Write the <xdr:xfrm> element.
703  */
704 STATIC void
_drawing_write_xfrm(lxw_drawing * self)705 _drawing_write_xfrm(lxw_drawing *self)
706 {
707     lxw_xml_start_tag(self->file, "xdr:xfrm", NULL);
708 
709     /* Write the a:off element. */
710     _drawing_write_xfrm_offset(self);
711 
712     /* Write the a:ext element. */
713     _drawing_write_xfrm_extension(self);
714 
715     lxw_xml_end_tag(self->file, "xdr:xfrm");
716 }
717 
718 /*
719  * Write the <c:chart> element.
720  */
721 STATIC void
_drawing_write_chart(lxw_drawing * self,uint32_t index)722 _drawing_write_chart(lxw_drawing *self, uint32_t index)
723 {
724     struct xml_attribute_list attributes;
725     struct xml_attribute *attribute;
726     char xmlns_c[] = LXW_SCHEMA_DRAWING "/chart";
727     char xmlns_r[] = LXW_SCHEMA_OFFICEDOC "/relationships";
728     char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
729 
730     lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", index);
731 
732     LXW_INIT_ATTRIBUTES();
733     LXW_PUSH_ATTRIBUTES_STR("xmlns:c", xmlns_c);
734     LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
735     LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
736 
737     lxw_xml_empty_tag(self->file, "c:chart", &attributes);
738 
739     LXW_FREE_ATTRIBUTES();
740 }
741 
742 /*
743  * Write the <a:graphicData> element.
744  */
745 STATIC void
_drawing_write_a_graphic_data(lxw_drawing * self,uint32_t index)746 _drawing_write_a_graphic_data(lxw_drawing *self, uint32_t index)
747 {
748     struct xml_attribute_list attributes;
749     struct xml_attribute *attribute;
750     char uri[] = LXW_SCHEMA_DRAWING "/chart";
751 
752     LXW_INIT_ATTRIBUTES();
753     LXW_PUSH_ATTRIBUTES_STR("uri", uri);
754 
755     lxw_xml_start_tag(self->file, "a:graphicData", &attributes);
756 
757     /* Write the c:chart element. */
758     _drawing_write_chart(self, index);
759 
760     lxw_xml_end_tag(self->file, "a:graphicData");
761 
762     LXW_FREE_ATTRIBUTES();
763 }
764 
765 /*
766  * Write the <a:graphic> element.
767  */
768 STATIC void
_drawing_write_a_graphic(lxw_drawing * self,uint32_t index)769 _drawing_write_a_graphic(lxw_drawing *self, uint32_t index)
770 {
771 
772     lxw_xml_start_tag(self->file, "a:graphic", NULL);
773 
774     /* Write the a:graphicData element. */
775     _drawing_write_a_graphic_data(self, index);
776 
777     lxw_xml_end_tag(self->file, "a:graphic");
778 }
779 
780 /*
781  * Write the <xdr:graphicFrame> element.
782  */
783 STATIC void
_drawing_write_graphic_frame(lxw_drawing * self,uint32_t index,uint32_t rel_index,lxw_drawing_object * drawing_object)784 _drawing_write_graphic_frame(lxw_drawing *self, uint32_t index,
785                              uint32_t rel_index,
786                              lxw_drawing_object *drawing_object)
787 {
788     struct xml_attribute_list attributes;
789     struct xml_attribute *attribute;
790 
791     LXW_INIT_ATTRIBUTES();
792     LXW_PUSH_ATTRIBUTES_STR("macro", "");
793 
794     lxw_xml_start_tag(self->file, "xdr:graphicFrame", &attributes);
795 
796     /* Write the xdr:nvGraphicFramePr element. */
797     _drawing_write_nv_graphic_frame_pr(self, index, drawing_object);
798 
799     /* Write the xdr:xfrm element. */
800     _drawing_write_xfrm(self);
801 
802     /* Write the a:graphic element. */
803     _drawing_write_a_graphic(self, rel_index);
804 
805     lxw_xml_end_tag(self->file, "xdr:graphicFrame");
806 
807     LXW_FREE_ATTRIBUTES();
808 }
809 
810 /*
811  * Write the <xdr:twoCellAnchor> element.
812  */
813 STATIC void
_drawing_write_two_cell_anchor(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)814 _drawing_write_two_cell_anchor(lxw_drawing *self, uint32_t index,
815                                lxw_drawing_object *drawing_object)
816 {
817     struct xml_attribute_list attributes;
818     struct xml_attribute *attribute;
819 
820     LXW_INIT_ATTRIBUTES();
821 
822     if (drawing_object->anchor == LXW_OBJECT_MOVE_DONT_SIZE)
823         LXW_PUSH_ATTRIBUTES_STR("editAs", "oneCell");
824     else if (drawing_object->anchor == LXW_OBJECT_DONT_MOVE_DONT_SIZE)
825         LXW_PUSH_ATTRIBUTES_STR("editAs", "absolute");
826 
827     lxw_xml_start_tag(self->file, "xdr:twoCellAnchor", &attributes);
828 
829     _drawing_write_from(self, &drawing_object->from);
830     _drawing_write_to(self, &drawing_object->to);
831 
832     if (drawing_object->type == LXW_DRAWING_CHART) {
833         /* Write the xdr:graphicFrame element for charts. */
834         _drawing_write_graphic_frame(self, index, drawing_object->rel_index,
835                                      drawing_object);
836     }
837     else if (drawing_object->type == LXW_DRAWING_IMAGE) {
838         /* Write the xdr:pic element. */
839         _drawing_write_pic(self, index, drawing_object);
840     }
841     else {
842         /* Write the xdr:sp element for shapes. */
843         /* _drawing_write_sp(self, index, col_absolute, row_absolute, width,
844            height,  shape); */
845     }
846 
847     /* Write the xdr:clientData element. */
848     _drawing_write_client_data(self);
849 
850     lxw_xml_end_tag(self->file, "xdr:twoCellAnchor");
851 
852     LXW_FREE_ATTRIBUTES();
853 }
854 
855 /*
856  * Write the <xdr:ext> element.
857  */
858 STATIC void
_drawing_write_ext(lxw_drawing * self,uint32_t cx,uint32_t cy)859 _drawing_write_ext(lxw_drawing *self, uint32_t cx, uint32_t cy)
860 {
861     struct xml_attribute_list attributes;
862     struct xml_attribute *attribute;
863 
864     LXW_INIT_ATTRIBUTES();
865     LXW_PUSH_ATTRIBUTES_INT("cx", cx);
866     LXW_PUSH_ATTRIBUTES_INT("cy", cy);
867 
868     lxw_xml_empty_tag(self->file, "xdr:ext", &attributes);
869 
870     LXW_FREE_ATTRIBUTES();
871 }
872 
873 /*
874  * Write the <xdr:pos> element.
875  */
876 STATIC void
_drawing_write_pos(lxw_drawing * self,int32_t x,int32_t y)877 _drawing_write_pos(lxw_drawing *self, int32_t x, int32_t y)
878 {
879     struct xml_attribute_list attributes;
880     struct xml_attribute *attribute;
881 
882     LXW_INIT_ATTRIBUTES();
883     LXW_PUSH_ATTRIBUTES_INT("x", x);
884     LXW_PUSH_ATTRIBUTES_INT("y", y);
885 
886     lxw_xml_empty_tag(self->file, "xdr:pos", &attributes);
887 
888     LXW_FREE_ATTRIBUTES();
889 }
890 
891 /*
892  * Write the <xdr:absoluteAnchor> element.
893  */
894 STATIC void
_drawing_write_absolute_anchor(lxw_drawing * self,uint32_t frame_index)895 _drawing_write_absolute_anchor(lxw_drawing *self, uint32_t frame_index)
896 {
897     lxw_xml_start_tag(self->file, "xdr:absoluteAnchor", NULL);
898 
899     if (self->orientation == LXW_LANDSCAPE) {
900         /* Write the xdr:pos element. */
901         _drawing_write_pos(self, 0, 0);
902 
903         /* Write the xdr:ext element. */
904         _drawing_write_ext(self, 9308969, 6078325);
905     }
906     else {
907         /* Write the xdr:pos element. */
908         _drawing_write_pos(self, 0, -47625);
909 
910         /* Write the xdr:ext element. */
911         _drawing_write_ext(self, 6162675, 6124575);
912     }
913 
914     _drawing_write_graphic_frame(self, frame_index, frame_index, NULL);
915 
916     /* Write the xdr:clientData element. */
917     _drawing_write_client_data(self);
918 
919     lxw_xml_end_tag(self->file, "xdr:absoluteAnchor");
920 }
921 
922 /*****************************************************************************
923  *
924  * XML file assembly functions.
925  *
926  ****************************************************************************/
927 
928 /*
929  * Assemble and write the XML file.
930  */
931 void
lxw_drawing_assemble_xml_file(lxw_drawing * self)932 lxw_drawing_assemble_xml_file(lxw_drawing *self)
933 {
934     uint32_t index;
935     lxw_drawing_object *drawing_object;
936 
937     /* Write the XML declaration. */
938     _drawing_xml_declaration(self);
939 
940     /* Write the xdr:wsDr element. */
941     _write_drawing_workspace(self);
942 
943     if (self->embedded) {
944         index = 1;
945 
946         STAILQ_FOREACH(drawing_object, self->drawing_objects, list_pointers) {
947             _drawing_write_two_cell_anchor(self, index, drawing_object);
948             index++;
949         }
950     }
951     else {
952         /* Write the xdr:absoluteAnchor element. Mainly for chartsheets. */
953         _drawing_write_absolute_anchor(self, 1);
954     }
955 
956     lxw_xml_end_tag(self->file, "xdr:wsDr");
957 }
958 
959 /*****************************************************************************
960  *
961  * Public functions.
962  *
963  ****************************************************************************/
964