content_types.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*****************************************************************************
  2. * content_types - A library for creating Excel XLSX content_types files.
  3. *
  4. * Used in conjunction with the libxlsxwriter library.
  5. *
  6. * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
  7. *
  8. */
  9. #include "xlsxwriter/xmlwriter.h"
  10. #include "xlsxwriter/content_types.h"
  11. #include "xlsxwriter/utility.h"
  12. /*
  13. * Forward declarations.
  14. */
  15. /*****************************************************************************
  16. *
  17. * Private functions.
  18. *
  19. ****************************************************************************/
  20. /*
  21. * Create a new content_types object.
  22. */
  23. lxw_content_types *
  24. lxw_content_types_new()
  25. {
  26. lxw_content_types *content_types = calloc(1, sizeof(lxw_content_types));
  27. GOTO_LABEL_ON_MEM_ERROR(content_types, mem_error);
  28. content_types->default_types = calloc(1, sizeof(struct lxw_tuples));
  29. GOTO_LABEL_ON_MEM_ERROR(content_types->default_types, mem_error);
  30. STAILQ_INIT(content_types->default_types);
  31. content_types->overrides = calloc(1, sizeof(struct lxw_tuples));
  32. GOTO_LABEL_ON_MEM_ERROR(content_types->overrides, mem_error);
  33. STAILQ_INIT(content_types->overrides);
  34. lxw_ct_add_default(content_types, "rels",
  35. LXW_APP_PACKAGE "relationships+xml");
  36. lxw_ct_add_default(content_types, "xml", "application/xml");
  37. lxw_ct_add_override(content_types, "/docProps/app.xml",
  38. LXW_APP_DOCUMENT "extended-properties+xml");
  39. lxw_ct_add_override(content_types, "/docProps/core.xml",
  40. LXW_APP_PACKAGE "core-properties+xml");
  41. lxw_ct_add_override(content_types, "/xl/styles.xml",
  42. LXW_APP_DOCUMENT "spreadsheetml.styles+xml");
  43. lxw_ct_add_override(content_types, "/xl/theme/theme1.xml",
  44. LXW_APP_DOCUMENT "theme+xml");
  45. lxw_ct_add_override(content_types, "/xl/workbook.xml",
  46. LXW_APP_DOCUMENT "spreadsheetml.sheet.main+xml");
  47. return content_types;
  48. mem_error:
  49. lxw_content_types_free(content_types);
  50. return NULL;
  51. }
  52. /*
  53. * Free a content_types object.
  54. */
  55. void
  56. lxw_content_types_free(lxw_content_types *content_types)
  57. {
  58. lxw_tuple *default_type;
  59. lxw_tuple *override;
  60. if (!content_types)
  61. return;
  62. if (content_types->default_types) {
  63. while (!STAILQ_EMPTY(content_types->default_types)) {
  64. default_type = STAILQ_FIRST(content_types->default_types);
  65. STAILQ_REMOVE_HEAD(content_types->default_types, list_pointers);
  66. free(default_type->key);
  67. free(default_type->value);
  68. free(default_type);
  69. }
  70. free(content_types->default_types);
  71. }
  72. if (content_types->overrides) {
  73. while (!STAILQ_EMPTY(content_types->overrides)) {
  74. override = STAILQ_FIRST(content_types->overrides);
  75. STAILQ_REMOVE_HEAD(content_types->overrides, list_pointers);
  76. free(override->key);
  77. free(override->value);
  78. free(override);
  79. }
  80. free(content_types->overrides);
  81. }
  82. free(content_types);
  83. }
  84. /*****************************************************************************
  85. *
  86. * XML functions.
  87. *
  88. ****************************************************************************/
  89. /*
  90. * Write the XML declaration.
  91. */
  92. STATIC void
  93. _content_types_xml_declaration(lxw_content_types *self)
  94. {
  95. lxw_xml_declaration(self->file);
  96. }
  97. /*
  98. * Write the <Types> element.
  99. */
  100. STATIC void
  101. _write_types(lxw_content_types *self)
  102. {
  103. struct xml_attribute_list attributes;
  104. struct xml_attribute *attribute;
  105. LXW_INIT_ATTRIBUTES();
  106. LXW_PUSH_ATTRIBUTES_STR("xmlns", LXW_SCHEMA_CONTENT);
  107. lxw_xml_start_tag(self->file, "Types", &attributes);
  108. LXW_FREE_ATTRIBUTES();
  109. }
  110. /*
  111. * Write the <Default> element.
  112. */
  113. STATIC void
  114. _write_default(lxw_content_types *self, const char *ext, const char *type)
  115. {
  116. struct xml_attribute_list attributes;
  117. struct xml_attribute *attribute;
  118. LXW_INIT_ATTRIBUTES();
  119. LXW_PUSH_ATTRIBUTES_STR("Extension", ext);
  120. LXW_PUSH_ATTRIBUTES_STR("ContentType", type);
  121. lxw_xml_empty_tag(self->file, "Default", &attributes);
  122. LXW_FREE_ATTRIBUTES();
  123. }
  124. /*
  125. * Write the <Override> element.
  126. */
  127. STATIC void
  128. _write_override(lxw_content_types *self, const char *part_name,
  129. const char *type)
  130. {
  131. struct xml_attribute_list attributes;
  132. struct xml_attribute *attribute;
  133. LXW_INIT_ATTRIBUTES();
  134. LXW_PUSH_ATTRIBUTES_STR("PartName", part_name);
  135. LXW_PUSH_ATTRIBUTES_STR("ContentType", type);
  136. lxw_xml_empty_tag(self->file, "Override", &attributes);
  137. LXW_FREE_ATTRIBUTES();
  138. }
  139. /*****************************************************************************
  140. *
  141. * XML file assembly functions.
  142. *
  143. ****************************************************************************/
  144. /*
  145. * Write out all of the <Default> types.
  146. */
  147. STATIC void
  148. _write_defaults(lxw_content_types *self)
  149. {
  150. lxw_tuple *tuple;
  151. STAILQ_FOREACH(tuple, self->default_types, list_pointers) {
  152. _write_default(self, tuple->key, tuple->value);
  153. }
  154. }
  155. /*
  156. * Write out all of the <Override> types.
  157. */
  158. STATIC void
  159. _write_overrides(lxw_content_types *self)
  160. {
  161. lxw_tuple *tuple;
  162. STAILQ_FOREACH(tuple, self->overrides, list_pointers) {
  163. _write_override(self, tuple->key, tuple->value);
  164. }
  165. }
  166. /*
  167. * Assemble and write the XML file.
  168. */
  169. void
  170. lxw_content_types_assemble_xml_file(lxw_content_types *self)
  171. {
  172. /* Write the XML declaration. */
  173. _content_types_xml_declaration(self);
  174. _write_types(self);
  175. _write_defaults(self);
  176. _write_overrides(self);
  177. /* Close the content_types tag. */
  178. lxw_xml_end_tag(self->file, "Types");
  179. }
  180. /*****************************************************************************
  181. *
  182. * Public functions.
  183. *
  184. ****************************************************************************/
  185. /*
  186. * Add elements to the ContentTypes defaults.
  187. */
  188. void
  189. lxw_ct_add_default(lxw_content_types *self, const char *key,
  190. const char *value)
  191. {
  192. lxw_tuple *tuple;
  193. if (!key || !value)
  194. return;
  195. tuple = calloc(1, sizeof(lxw_tuple));
  196. GOTO_LABEL_ON_MEM_ERROR(tuple, mem_error);
  197. tuple->key = lxw_strdup(key);
  198. GOTO_LABEL_ON_MEM_ERROR(tuple->key, mem_error);
  199. tuple->value = lxw_strdup(value);
  200. GOTO_LABEL_ON_MEM_ERROR(tuple->value, mem_error);
  201. STAILQ_INSERT_TAIL(self->default_types, tuple, list_pointers);
  202. return;
  203. mem_error:
  204. if (tuple) {
  205. free(tuple->key);
  206. free(tuple->value);
  207. free(tuple);
  208. }
  209. }
  210. /*
  211. * Add elements to the ContentTypes overrides.
  212. */
  213. void
  214. lxw_ct_add_override(lxw_content_types *self, const char *key,
  215. const char *value)
  216. {
  217. lxw_tuple *tuple;
  218. if (!key || !value)
  219. return;
  220. tuple = calloc(1, sizeof(lxw_tuple));
  221. GOTO_LABEL_ON_MEM_ERROR(tuple, mem_error);
  222. tuple->key = lxw_strdup(key);
  223. GOTO_LABEL_ON_MEM_ERROR(tuple->key, mem_error);
  224. tuple->value = lxw_strdup(value);
  225. GOTO_LABEL_ON_MEM_ERROR(tuple->value, mem_error);
  226. STAILQ_INSERT_TAIL(self->overrides, tuple, list_pointers);
  227. return;
  228. mem_error:
  229. if (tuple) {
  230. free(tuple->key);
  231. free(tuple->value);
  232. free(tuple);
  233. }
  234. }
  235. /*
  236. * Add the name of a worksheet to the ContentTypes overrides.
  237. */
  238. void
  239. lxw_ct_add_worksheet_name(lxw_content_types *self, const char *name)
  240. {
  241. lxw_ct_add_override(self, name,
  242. LXW_APP_DOCUMENT "spreadsheetml.worksheet+xml");
  243. }
  244. /*
  245. * Add the name of a chart to the ContentTypes overrides.
  246. */
  247. void
  248. lxw_ct_add_chart_name(lxw_content_types *self, const char *name)
  249. {
  250. lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawingml.chart+xml");
  251. }
  252. /*
  253. * Add the name of a drawing to the ContentTypes overrides.
  254. */
  255. void
  256. lxw_ct_add_drawing_name(lxw_content_types *self, const char *name)
  257. {
  258. lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawing+xml");
  259. }
  260. /*
  261. * Add the sharedStrings link to the ContentTypes overrides.
  262. */
  263. void
  264. lxw_ct_add_shared_strings(lxw_content_types *self)
  265. {
  266. lxw_ct_add_override(self, "/xl/sharedStrings.xml",
  267. LXW_APP_DOCUMENT "spreadsheetml.sharedStrings+xml");
  268. }
  269. /*
  270. * Add the calcChain link to the ContentTypes overrides.
  271. */
  272. void
  273. lxw_ct_add_calc_chain(lxw_content_types *self)
  274. {
  275. lxw_ct_add_override(self, "/xl/calcChain.xml",
  276. LXW_APP_DOCUMENT "spreadsheetml.calcChain+xml");
  277. }
  278. /*
  279. * Add the custom properties to the ContentTypes overrides.
  280. */
  281. void
  282. lxw_ct_add_custom_properties(lxw_content_types *self)
  283. {
  284. lxw_ct_add_override(self, "/docProps/custom.xml",
  285. LXW_APP_DOCUMENT "custom-properties+xml");
  286. }