/***************************************************************************** * vml - A library for creating Excel XLSX vml files. * * Used in conjunction with the libxlsxwriter library. * * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org. See LICENSE.txt. * */ #include "xlsxwriter/xmlwriter.h" #include "xlsxwriter/vml.h" #include "xlsxwriter/utility.h" /* * Forward declarations. */ /***************************************************************************** * * Private functions. * ****************************************************************************/ /* * Create a new vml object. */ lxw_vml * lxw_vml_new(void) { lxw_vml *vml = calloc(1, sizeof(lxw_vml)); GOTO_LABEL_ON_MEM_ERROR(vml, mem_error); return vml; mem_error: lxw_vml_free(vml); return NULL; } /* * Free a vml object. */ void lxw_vml_free(lxw_vml *vml) { if (!vml) return; free(vml); } /***************************************************************************** * * XML functions. * ****************************************************************************/ /* * Write the element. */ STATIC void _vml_write_visible(lxw_vml *self) { lxw_xml_empty_tag(self->file, "x:Visible", NULL); } /* * Write the element. */ STATIC void _vml_write_formula(lxw_vml *self, char *equation) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("eqn", equation); lxw_xml_empty_tag(self->file, "v:f", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_formulas(lxw_vml *self) { lxw_xml_start_tag(self->file, "v:formulas", NULL); _vml_write_formula(self, "if lineDrawn pixelLineWidth 0"); _vml_write_formula(self, "sum @0 1 0"); _vml_write_formula(self, "sum 0 0 @1"); _vml_write_formula(self, "prod @2 1 2"); _vml_write_formula(self, "prod @3 21600 pixelWidth"); _vml_write_formula(self, "prod @3 21600 pixelHeight"); _vml_write_formula(self, "sum @0 0 1"); _vml_write_formula(self, "prod @6 1 2"); _vml_write_formula(self, "prod @7 21600 pixelWidth"); _vml_write_formula(self, "sum @8 21600 0"); _vml_write_formula(self, "prod @7 21600 pixelHeight"); _vml_write_formula(self, "sum @10 21600 0"); lxw_xml_end_tag(self->file, "v:formulas"); } /* * Write the element. */ STATIC void _vml_write_text_halign(lxw_vml *self) { lxw_xml_data_element(self->file, "x:TextHAlign", "Center", NULL); } /* * Write the element. */ STATIC void _vml_write_text_valign(lxw_vml *self) { lxw_xml_data_element(self->file, "x:TextVAlign", "Center", NULL); } /* * Write the element. */ STATIC void _vml_write_fmla_macro(lxw_vml *self) { lxw_xml_data_element(self->file, "x:FmlaMacro", "[0]!Button1_Click", NULL); } /* * Write the element. */ STATIC void _vml_write_print_object(lxw_vml *self) { lxw_xml_data_element(self->file, "x:PrintObject", "False", NULL); } /* * Write the element. */ STATIC void _vml_write_aspect_ratio_lock(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); LXW_PUSH_ATTRIBUTES_STR("aspectratio", "t"); lxw_xml_empty_tag(self->file, "o:lock", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_rotation_lock(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); LXW_PUSH_ATTRIBUTES_STR("rotation", "t"); lxw_xml_empty_tag(self->file, "o:lock", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_column(lxw_vml *self, lxw_vml_obj *comment_obj) { char data[LXW_ATTR_32]; lxw_snprintf(data, LXW_ATTR_32, "%d", comment_obj->col); lxw_xml_data_element(self->file, "x:Column", data, NULL); } /* * Write the element. */ STATIC void _vml_write_row(lxw_vml *self, lxw_vml_obj *comment_obj) { char data[LXW_ATTR_32]; lxw_snprintf(data, LXW_ATTR_32, "%d", comment_obj->row); lxw_xml_data_element(self->file, "x:Row", data, NULL); } /* * Write the element. */ STATIC void _vml_write_auto_fill(lxw_vml *self) { lxw_xml_data_element(self->file, "x:AutoFill", "False", NULL); } /* * Write the element. */ STATIC void _vml_write_anchor(lxw_vml *self, lxw_vml_obj *comment_obj) { char anchor_data[LXW_MAX_ATTRIBUTE_LENGTH]; lxw_snprintf(anchor_data, LXW_MAX_ATTRIBUTE_LENGTH, "%d, %d, %d, %d, %d, %d, %d, %d", comment_obj->from.col, (uint32_t) comment_obj->from.col_offset, comment_obj->from.row, (uint32_t) comment_obj->from.row_offset, comment_obj->to.col, (uint32_t) comment_obj->to.col_offset, comment_obj->to.row, (uint32_t) comment_obj->to.row_offset); lxw_xml_data_element(self->file, "x:Anchor", anchor_data, NULL); } /* * Write the element. */ STATIC void _vml_write_size_with_cells(lxw_vml *self) { lxw_xml_empty_tag(self->file, "x:SizeWithCells", NULL); } /* * Write the element. */ STATIC void _vml_write_move_with_cells(lxw_vml *self) { lxw_xml_empty_tag(self->file, "x:MoveWithCells", NULL); } /* * Write the element. */ STATIC void _vml_write_shadow(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("on", "t"); LXW_PUSH_ATTRIBUTES_STR("color", "black"); LXW_PUSH_ATTRIBUTES_STR("obscured", "t"); lxw_xml_empty_tag(self->file, "v:shadow", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_stroke(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("joinstyle", "miter"); lxw_xml_empty_tag(self->file, "v:stroke", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_shapetype_lock(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); LXW_PUSH_ATTRIBUTES_STR("shapetype", "t"); lxw_xml_empty_tag(self->file, "o:lock", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_font(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("face", "Calibri"); LXW_PUSH_ATTRIBUTES_STR("size", "220"); LXW_PUSH_ATTRIBUTES_STR("color", "#000000"); lxw_xml_data_element(self->file, "font", "Button 1", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_imagedata(lxw_vml *self, uint32_t rel_index, char *name) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char rel_id[LXW_ATTR_32]; lxw_snprintf(rel_id, LXW_ATTR_32, "rId%d", rel_index); LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("o:relid", rel_id); LXW_PUSH_ATTRIBUTES_STR("o:title", name); lxw_xml_empty_tag(self->file, "v:imagedata", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_image_path(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("o:extrusionok", "f"); LXW_PUSH_ATTRIBUTES_STR("gradientshapeok", "t"); LXW_PUSH_ATTRIBUTES_STR("o:connecttype", "rect"); lxw_xml_empty_tag(self->file, "v:path", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_image_shape(lxw_vml *self, uint32_t vml_shape_id, uint32_t z_index, lxw_vml_obj *image_obj) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char width_str[LXW_ATTR_32]; char height_str[LXW_ATTR_32]; char style[LXW_MAX_ATTRIBUTE_LENGTH]; char o_spid[LXW_ATTR_32]; char type[] = "#_x0000_t75"; double width; double height; /* Scale the height/width by the resolution, relative to 72dpi. */ width = image_obj->width * (72.0 / image_obj->x_dpi); height = image_obj->height * (72.0 / image_obj->y_dpi); /* Excel uses a rounding based around 72 and 96 dpi. */ width = 72.0 / 96.0 * (uint32_t) (width * 96.0 / 72 + 0.25); height = 72.0 / 96.0 * (uint32_t) (height * 96.0 / 72 + 0.25); lxw_sprintf_dbl(width_str, width); lxw_sprintf_dbl(height_str, height); lxw_snprintf(o_spid, LXW_ATTR_32, "_x0000_s%d", vml_shape_id); lxw_snprintf(style, LXW_MAX_ATTRIBUTE_LENGTH, "position:absolute;" "margin-left:0;" "margin-top:0;" "width:%spt;" "height:%spt;" "z-index:%d", width_str, height_str, z_index); LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("id", image_obj->image_position); LXW_PUSH_ATTRIBUTES_STR("o:spid", o_spid); LXW_PUSH_ATTRIBUTES_STR("type", type); LXW_PUSH_ATTRIBUTES_STR("style", style); lxw_xml_start_tag(self->file, "v:shape", &attributes); /* Write the v:imagedata element. */ _vml_write_imagedata(self, image_obj->rel_index, image_obj->name); /* Write the o:lock element. */ _vml_write_rotation_lock(self); lxw_xml_end_tag(self->file, "v:shape"); LXW_FREE_ATTRIBUTES(); } /* * Write the element for images. */ STATIC void _vml_write_image_shapetype(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char id[] = "_x0000_t75"; char coordsize[] = "21600,21600"; char o_spt[] = "75"; char o_preferrelative[] = "t"; char path[] = "m@4@5l@4@11@9@11@9@5xe"; char filled[] = "f"; char stroked[] = "f"; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("id", id); LXW_PUSH_ATTRIBUTES_STR("coordsize", coordsize); LXW_PUSH_ATTRIBUTES_STR("o:spt", o_spt); LXW_PUSH_ATTRIBUTES_STR("o:preferrelative", o_preferrelative); LXW_PUSH_ATTRIBUTES_STR("path", path); LXW_PUSH_ATTRIBUTES_STR("filled", filled); LXW_PUSH_ATTRIBUTES_STR("stroked", stroked); lxw_xml_start_tag(self->file, "v:shapetype", &attributes); /* Write the v:stroke element. */ _vml_write_stroke(self); /* Write the v:formulas element. */ _vml_write_formulas(self); /* Write the v:path element. */ _vml_write_image_path(self); /* Write the o:lock element. */ _vml_write_aspect_ratio_lock(self); lxw_xml_end_tag(self->file, "v:shapetype"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_button_client_data(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("ObjectType", "Button"); lxw_xml_start_tag(self->file, "x:ClientData", &attributes); /* Write the element. */ _vml_write_anchor(self, NULL); /* Write the x:PrintObject element. */ _vml_write_print_object(self); /* Write the x:AutoFill element. */ _vml_write_auto_fill(self); /* Write the x:FmlaMacro element. */ _vml_write_fmla_macro(self); /* Write the x:TextHAlign element. */ _vml_write_text_halign(self); /* Write the x:TextVAlign element. */ _vml_write_text_valign(self); lxw_xml_end_tag(self->file, "x:ClientData"); LXW_FREE_ATTRIBUTES(); } /* * Write the
element. */ STATIC void _vml_write_button_div(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("style", "text-align:center"); lxw_xml_start_tag(self->file, "div", &attributes); /* Write the font element. */ _vml_write_font(self); lxw_xml_end_tag(self->file, "div"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_button_textbox(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("style", "mso-direction-alt:auto"); LXW_PUSH_ATTRIBUTES_STR("o:singleclick", "f"); lxw_xml_start_tag(self->file, "v:textbox", &attributes); /* Write the div element. */ _vml_write_button_div(self); lxw_xml_end_tag(self->file, "v:textbox"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_button_fill(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("color2", "buttonFace [67]"); LXW_PUSH_ATTRIBUTES_STR("o:detectmouseclick", "t"); lxw_xml_empty_tag(self->file, "v:fill", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element for buttons. */ STATIC void _vml_write_button_path(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("shadowok", "f"); LXW_PUSH_ATTRIBUTES_STR("o:extrusionok", "f"); LXW_PUSH_ATTRIBUTES_STR("strokeok", "f"); LXW_PUSH_ATTRIBUTES_STR("fillok", "f"); LXW_PUSH_ATTRIBUTES_STR("o:connecttype", "rect"); lxw_xml_empty_tag(self->file, "v:path", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element for buttons. */ STATIC void _vml_write_button_shape(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char id[] = "_x0000_s1025"; char type[] = "#_x0000_t201"; char style[] = "position:absolute;margin-left:96pt;margin-top:15pt;" "width:48pt;height:15pt;z-index:1;mso-wrap-style:tight"; char o_button[] = "t"; char fillcolor[] = "buttonFace [67]"; char strokecolor[] = "windowText [64]"; char o_insetmode[] = "auto"; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("id", id); LXW_PUSH_ATTRIBUTES_STR("type", type); LXW_PUSH_ATTRIBUTES_STR("style", style); LXW_PUSH_ATTRIBUTES_STR("o:button", o_button); LXW_PUSH_ATTRIBUTES_STR("fillcolor", fillcolor); LXW_PUSH_ATTRIBUTES_STR("strokecolor", strokecolor); LXW_PUSH_ATTRIBUTES_STR("o:insetmode", o_insetmode); lxw_xml_start_tag(self->file, "v:shape", &attributes); /* Write the v:fill element. */ _vml_write_button_fill(self); /* Write the o:lock element. */ _vml_write_rotation_lock(self); /* Write the v:textbox element. */ _vml_write_button_textbox(self); /* Write the x:ClientData element. */ _vml_write_button_client_data(self); lxw_xml_end_tag(self->file, "v:shape"); LXW_FREE_ATTRIBUTES(); } /* * Write the element for buttons. */ STATIC void _vml_write_button_shapetype(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char id[] = "_x0000_t201"; char coordsize[] = "21600,21600"; char o_spt[] = "201"; char path[] = "m,l,21600r21600,l21600,xe"; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("id", id); LXW_PUSH_ATTRIBUTES_STR("coordsize", coordsize); LXW_PUSH_ATTRIBUTES_STR("o:spt", o_spt); LXW_PUSH_ATTRIBUTES_STR("path", path); lxw_xml_start_tag(self->file, "v:shapetype", &attributes); /* Write the v:stroke element. */ _vml_write_stroke(self); /* Write the v:path element. */ _vml_write_button_path(self); /* Write the o:lock element. */ _vml_write_shapetype_lock(self); lxw_xml_end_tag(self->file, "v:shapetype"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_comment_client_data(lxw_vml *self, lxw_vml_obj *comment_obj) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("ObjectType", "Note"); lxw_xml_start_tag(self->file, "x:ClientData", &attributes); /* Write the element. */ _vml_write_move_with_cells(self); /* Write the element. */ _vml_write_size_with_cells(self); /* Write the element. */ _vml_write_anchor(self, comment_obj); /* Write the element. */ _vml_write_auto_fill(self); /* Write the element. */ _vml_write_row(self, comment_obj); /* Write the element. */ _vml_write_column(self, comment_obj); /* Write the x:Visible element. */ if (comment_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE) _vml_write_visible(self); lxw_xml_end_tag(self->file, "x:ClientData"); LXW_FREE_ATTRIBUTES(); } /* * Write the
element. */ STATIC void _vml_write_comment_div(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("style", "text-align:left"); lxw_xml_start_tag(self->file, "div", &attributes); lxw_xml_end_tag(self->file, "div"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_comment_textbox(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("style", "mso-direction-alt:auto"); lxw_xml_start_tag(self->file, "v:textbox", &attributes); /* Write the div element. */ _vml_write_comment_div(self); lxw_xml_end_tag(self->file, "v:textbox"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_comment_fill(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("color2", "#ffffe1"); lxw_xml_empty_tag(self->file, "v:fill", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_comment_path(lxw_vml *self, uint8_t has_gradient, char *type) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); if (has_gradient) LXW_PUSH_ATTRIBUTES_STR("gradientshapeok", "t"); LXW_PUSH_ATTRIBUTES_STR("o:connecttype", type); lxw_xml_empty_tag(self->file, "v:path", &attributes); LXW_FREE_ATTRIBUTES(); } /* * Write the element for comments. */ STATIC void _vml_write_comment_shape(lxw_vml *self, uint32_t vml_shape_id, uint32_t z_index, lxw_vml_obj *comment_obj) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char id[LXW_ATTR_32]; char margin_left[LXW_ATTR_32]; char margin_top[LXW_ATTR_32]; char width[LXW_ATTR_32]; char height[LXW_ATTR_32]; char visible[LXW_ATTR_32]; char fillcolor[LXW_ATTR_32]; char style[LXW_MAX_ATTRIBUTE_LENGTH]; char type[] = "#_x0000_t202"; char o_insetmode[] = "auto"; lxw_sprintf_dbl(margin_left, comment_obj->col_absolute * 0.75); lxw_sprintf_dbl(margin_top, comment_obj->row_absolute * 0.75); lxw_sprintf_dbl(width, comment_obj->width * 0.75); lxw_sprintf_dbl(height, comment_obj->height * 0.75); lxw_snprintf(id, LXW_ATTR_32, "_x0000_s%d", vml_shape_id); if (comment_obj->visible == LXW_COMMENT_DISPLAY_DEFAULT) comment_obj->visible = self->comment_display_default; if (comment_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE) lxw_snprintf(visible, LXW_ATTR_32, "visible"); else lxw_snprintf(visible, LXW_ATTR_32, "hidden"); if (comment_obj->color) lxw_snprintf(fillcolor, LXW_ATTR_32, "#%06x", comment_obj->color & LXW_COLOR_MASK); else lxw_snprintf(fillcolor, LXW_ATTR_32, "#%06x", 0xffffe1); lxw_snprintf(style, LXW_MAX_ATTRIBUTE_LENGTH, "position:absolute;" "margin-left:%spt;" "margin-top:%spt;" "width:%spt;" "height:%spt;" "z-index:%d;" "visibility:%s", margin_left, margin_top, width, height, z_index, visible); LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("id", id); LXW_PUSH_ATTRIBUTES_STR("type", type); LXW_PUSH_ATTRIBUTES_STR("style", style); LXW_PUSH_ATTRIBUTES_STR("fillcolor", fillcolor); LXW_PUSH_ATTRIBUTES_STR("o:insetmode", o_insetmode); lxw_xml_start_tag(self->file, "v:shape", &attributes); /* Write the v:fill element. */ _vml_write_comment_fill(self); /* Write the v:shadow element. */ _vml_write_shadow(self); /* Write the v:path element. */ _vml_write_comment_path(self, LXW_FALSE, "none"); /* Write the v:textbox element. */ _vml_write_comment_textbox(self); /* Write the x:ClientData element. */ _vml_write_comment_client_data(self, comment_obj); lxw_xml_end_tag(self->file, "v:shape"); LXW_FREE_ATTRIBUTES(); } /* * Write the element for comments. */ STATIC void _vml_write_comment_shapetype(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char id[] = "_x0000_t202"; char coordsize[] = "21600,21600"; char o_spt[] = "202"; char path[] = "m,l,21600r21600,l21600,xe"; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("id", id); LXW_PUSH_ATTRIBUTES_STR("coordsize", coordsize); LXW_PUSH_ATTRIBUTES_STR("o:spt", o_spt); LXW_PUSH_ATTRIBUTES_STR("path", path); lxw_xml_start_tag(self->file, "v:shapetype", &attributes); /* Write the v:stroke element. */ _vml_write_stroke(self); /* Write the v:path element. */ _vml_write_comment_path(self, LXW_TRUE, "rect"); lxw_xml_end_tag(self->file, "v:shapetype"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_idmap(lxw_vml *self) { /* Since the vml_data_id_str may exceed the LXW_MAX_ATTRIBUTE_LENGTH we * write it directly without the xml helper functions. */ fprintf(self->file, "", self->vml_data_id_str); } /* * Write the element. */ STATIC void _vml_write_shapelayout(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); lxw_xml_start_tag(self->file, "o:shapelayout", &attributes); /* Write the o:idmap element. */ _vml_write_idmap(self); lxw_xml_end_tag(self->file, "o:shapelayout"); LXW_FREE_ATTRIBUTES(); } /* * Write the element. */ STATIC void _vml_write_xml_namespace(lxw_vml *self) { struct xml_attribute_list attributes; struct xml_attribute *attribute; char xmlns_v[] = "urn:schemas-microsoft-com:vml"; char xmlns_o[] = "urn:schemas-microsoft-com:office:office"; char xmlns_x[] = "urn:schemas-microsoft-com:office:excel"; LXW_INIT_ATTRIBUTES(); LXW_PUSH_ATTRIBUTES_STR("xmlns:v", xmlns_v); LXW_PUSH_ATTRIBUTES_STR("xmlns:o", xmlns_o); LXW_PUSH_ATTRIBUTES_STR("xmlns:x", xmlns_x); lxw_xml_start_tag(self->file, "xml", &attributes); LXW_FREE_ATTRIBUTES(); } /***************************************************************************** * * XML file assembly functions. * ****************************************************************************/ /* * Assemble and write the XML file. */ void lxw_vml_assemble_xml_file(lxw_vml *self) { lxw_vml_obj *comment_obj; lxw_vml_obj *button_obj; lxw_vml_obj *image_obj; uint32_t z_index = 1; /* Write the xml namespace element. Note, the VML files have no * XML declaration.*/ _vml_write_xml_namespace(self); /* Write the o:shapelayout element. */ _vml_write_shapelayout(self); if (self->comment_objs) { /* Write the element. */ _vml_write_comment_shapetype(self); STAILQ_FOREACH(comment_obj, self->comment_objs, list_pointers) { self->vml_shape_id++; /* Write the element. */ _vml_write_comment_shape(self, self->vml_shape_id, z_index, comment_obj); z_index++; } } if (self->button_objs) { /* Write the element. */ _vml_write_button_shapetype(self); STAILQ_FOREACH(button_obj, self->button_objs, list_pointers) { /* Write the element. */ _vml_write_button_shape(self); } } if (self->image_objs) { /* Write the element. */ _vml_write_image_shapetype(self); STAILQ_FOREACH(image_obj, self->image_objs, list_pointers) { self->vml_shape_id++; /* Write the element. */ _vml_write_image_shape(self, self->vml_shape_id, z_index, image_obj); z_index++; } } lxw_xml_end_tag(self->file, "xml"); } /***************************************************************************** * * Public functions. * ****************************************************************************/