xmlwriter.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*****************************************************************************
  2. * xmlwriter - A base library for libxlsxwriter libraries.
  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 <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include "xlsxwriter/xmlwriter.h"
  13. #define LXW_AMP "&amp;"
  14. #define LXW_LT "&lt;"
  15. #define LXW_GT "&gt;"
  16. #define LXW_QUOT "&quot;"
  17. /* Defines. */
  18. #define LXW_MAX_ENCODED_ATTRIBUTE_LENGTH (LXW_MAX_ATTRIBUTE_LENGTH*6)
  19. /* Forward declarations. */
  20. STATIC char *_escape_attributes(struct xml_attribute *attribute);
  21. char *lxw_escape_data(const char *data);
  22. STATIC void _fprint_escaped_attributes(FILE * xmlfile,
  23. struct xml_attribute_list *attributes);
  24. STATIC void _fprint_escaped_data(FILE * xmlfile, const char *data);
  25. /*
  26. * Write the XML declaration.
  27. */
  28. void
  29. lxw_xml_declaration(FILE * xmlfile)
  30. {
  31. fprintf(xmlfile, "<?xml version=\"1.0\" "
  32. "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
  33. }
  34. /*
  35. * Write an XML start tag with optional attributes.
  36. */
  37. void
  38. lxw_xml_start_tag(FILE * xmlfile,
  39. const char *tag, struct xml_attribute_list *attributes)
  40. {
  41. fprintf(xmlfile, "<%s", tag);
  42. _fprint_escaped_attributes(xmlfile, attributes);
  43. fprintf(xmlfile, ">");
  44. }
  45. /*
  46. * Write an XML start tag with optional, unencoded, attributes.
  47. * This is a minor speed optimization for elements that don't need encoding.
  48. */
  49. void
  50. lxw_xml_start_tag_unencoded(FILE * xmlfile,
  51. const char *tag,
  52. struct xml_attribute_list *attributes)
  53. {
  54. struct xml_attribute *attribute;
  55. fprintf(xmlfile, "<%s", tag);
  56. if (attributes) {
  57. STAILQ_FOREACH(attribute, attributes, list_entries) {
  58. fprintf(xmlfile, " %s=\"%s\"", attribute->key, attribute->value);
  59. }
  60. }
  61. fprintf(xmlfile, ">");
  62. }
  63. /*
  64. * Write an XML end tag.
  65. */
  66. void
  67. lxw_xml_end_tag(FILE * xmlfile, const char *tag)
  68. {
  69. fprintf(xmlfile, "</%s>", tag);
  70. }
  71. /*
  72. * Write an empty XML tag with optional attributes.
  73. */
  74. void
  75. lxw_xml_empty_tag(FILE * xmlfile,
  76. const char *tag, struct xml_attribute_list *attributes)
  77. {
  78. fprintf(xmlfile, "<%s", tag);
  79. _fprint_escaped_attributes(xmlfile, attributes);
  80. fprintf(xmlfile, "/>");
  81. }
  82. /*
  83. * Write an XML start tag with optional, unencoded, attributes.
  84. * This is a minor speed optimization for elements that don't need encoding.
  85. */
  86. void
  87. lxw_xml_empty_tag_unencoded(FILE * xmlfile,
  88. const char *tag,
  89. struct xml_attribute_list *attributes)
  90. {
  91. struct xml_attribute *attribute;
  92. fprintf(xmlfile, "<%s", tag);
  93. if (attributes) {
  94. STAILQ_FOREACH(attribute, attributes, list_entries) {
  95. fprintf(xmlfile, " %s=\"%s\"", attribute->key, attribute->value);
  96. }
  97. }
  98. fprintf(xmlfile, "/>");
  99. }
  100. /*
  101. * Write an XML element containing data with optional attributes.
  102. */
  103. void
  104. lxw_xml_data_element(FILE * xmlfile,
  105. const char *tag,
  106. const char *data, struct xml_attribute_list *attributes)
  107. {
  108. fprintf(xmlfile, "<%s", tag);
  109. _fprint_escaped_attributes(xmlfile, attributes);
  110. fprintf(xmlfile, ">");
  111. _fprint_escaped_data(xmlfile, data);
  112. fprintf(xmlfile, "</%s>", tag);
  113. }
  114. /*
  115. * Escape XML characters in attributes.
  116. */
  117. STATIC char *
  118. _escape_attributes(struct xml_attribute *attribute)
  119. {
  120. char *encoded = (char *) calloc(LXW_MAX_ENCODED_ATTRIBUTE_LENGTH, 1);
  121. char *p_encoded = encoded;
  122. char *p_attr = attribute->value;
  123. while (*p_attr) {
  124. switch (*p_attr) {
  125. case '&':
  126. strncat(p_encoded, LXW_AMP, sizeof(LXW_AMP) - 1);
  127. p_encoded += sizeof(LXW_AMP) - 1;
  128. break;
  129. case '<':
  130. strncat(p_encoded, LXW_LT, sizeof(LXW_LT) - 1);
  131. p_encoded += sizeof(LXW_LT) - 1;
  132. break;
  133. case '>':
  134. strncat(p_encoded, LXW_GT, sizeof(LXW_GT) - 1);
  135. p_encoded += sizeof(LXW_GT) - 1;
  136. break;
  137. case '"':
  138. strncat(p_encoded, LXW_QUOT, sizeof(LXW_QUOT) - 1);
  139. p_encoded += sizeof(LXW_QUOT) - 1;
  140. break;
  141. default:
  142. *p_encoded = *p_attr;
  143. p_encoded++;
  144. break;
  145. }
  146. p_attr++;
  147. }
  148. return encoded;
  149. }
  150. /*
  151. * Escape XML characters in data sections of tags.
  152. * Note, this is different from _escape_attributes()
  153. * in that double quotes are not escaped by Excel.
  154. */
  155. char *
  156. lxw_escape_data(const char *data)
  157. {
  158. size_t encoded_len = (strlen(data) * 5 + 1);
  159. char *encoded = (char *) calloc(encoded_len, 1);
  160. char *p_encoded = encoded;
  161. while (*data) {
  162. switch (*data) {
  163. case '&':
  164. strncat(p_encoded, LXW_AMP, sizeof(LXW_AMP) - 1);
  165. p_encoded += sizeof(LXW_AMP) - 1;
  166. break;
  167. case '<':
  168. strncat(p_encoded, LXW_LT, sizeof(LXW_LT) - 1);
  169. p_encoded += sizeof(LXW_LT) - 1;
  170. break;
  171. case '>':
  172. strncat(p_encoded, LXW_GT, sizeof(LXW_GT) - 1);
  173. p_encoded += sizeof(LXW_GT) - 1;
  174. break;
  175. default:
  176. *p_encoded = *data;
  177. p_encoded++;
  178. break;
  179. }
  180. data++;
  181. }
  182. return encoded;
  183. }
  184. /*
  185. * Escape control characters in strings with with _xHHHH_.
  186. */
  187. char *
  188. lxw_escape_control_characters(const char *string)
  189. {
  190. size_t escape_len = sizeof("_xHHHH_") - 1;
  191. size_t encoded_len = (strlen(string) * escape_len + 1);
  192. char *encoded = (char *) calloc(encoded_len, 1);
  193. char *p_encoded = encoded;
  194. while (*string) {
  195. switch (*string) {
  196. case '\x01':
  197. case '\x02':
  198. case '\x03':
  199. case '\x04':
  200. case '\x05':
  201. case '\x06':
  202. case '\x07':
  203. case '\x08':
  204. case '\x0B':
  205. case '\x0C':
  206. case '\x0D':
  207. case '\x0E':
  208. case '\x0F':
  209. case '\x10':
  210. case '\x11':
  211. case '\x12':
  212. case '\x13':
  213. case '\x14':
  214. case '\x15':
  215. case '\x16':
  216. case '\x17':
  217. case '\x18':
  218. case '\x19':
  219. case '\x1A':
  220. case '\x1B':
  221. case '\x1C':
  222. case '\x1D':
  223. case '\x1E':
  224. case '\x1F':
  225. lxw_snprintf(p_encoded, escape_len + 1, "_x%04X_", *string);
  226. p_encoded += escape_len;
  227. break;
  228. default:
  229. *p_encoded = *string;
  230. p_encoded++;
  231. break;
  232. }
  233. string++;
  234. }
  235. return encoded;
  236. }
  237. /* Write out escaped attributes. */
  238. STATIC void
  239. _fprint_escaped_attributes(FILE * xmlfile,
  240. struct xml_attribute_list *attributes)
  241. {
  242. struct xml_attribute *attribute;
  243. if (attributes) {
  244. STAILQ_FOREACH(attribute, attributes, list_entries) {
  245. fprintf(xmlfile, " %s=", attribute->key);
  246. if (!strpbrk(attribute->value, "&<>\"")) {
  247. fprintf(xmlfile, "\"%s\"", attribute->value);
  248. }
  249. else {
  250. char *encoded = _escape_attributes(attribute);
  251. if (encoded) {
  252. fprintf(xmlfile, "\"%s\"", encoded);
  253. free(encoded);
  254. }
  255. }
  256. }
  257. }
  258. }
  259. /* Write out escaped XML data. */
  260. STATIC void
  261. _fprint_escaped_data(FILE * xmlfile, const char *data)
  262. {
  263. /* Escape the data section of the XML element. */
  264. if (!strpbrk(data, "&<>")) {
  265. fprintf(xmlfile, "%s", data);
  266. }
  267. else {
  268. char *encoded = lxw_escape_data(data);
  269. if (encoded) {
  270. fprintf(xmlfile, "%s", encoded);
  271. free(encoded);
  272. }
  273. }
  274. }
  275. /* Create a new string XML attribute. */
  276. struct xml_attribute *
  277. lxw_new_attribute_str(const char *key, const char *value)
  278. {
  279. struct xml_attribute *attribute = malloc(sizeof(struct xml_attribute));
  280. LXW_ATTRIBUTE_COPY(attribute->key, key);
  281. LXW_ATTRIBUTE_COPY(attribute->value, value);
  282. return attribute;
  283. }
  284. /* Create a new integer XML attribute. */
  285. struct xml_attribute *
  286. lxw_new_attribute_int(const char *key, uint32_t value)
  287. {
  288. struct xml_attribute *attribute = malloc(sizeof(struct xml_attribute));
  289. LXW_ATTRIBUTE_COPY(attribute->key, key);
  290. lxw_snprintf(attribute->value, LXW_MAX_ATTRIBUTE_LENGTH, "%d", value);
  291. return attribute;
  292. }
  293. /* Create a new double XML attribute. */
  294. struct xml_attribute *
  295. lxw_new_attribute_dbl(const char *key, double value)
  296. {
  297. struct xml_attribute *attribute = malloc(sizeof(struct xml_attribute));
  298. LXW_ATTRIBUTE_COPY(attribute->key, key);
  299. lxw_sprintf_dbl(attribute->value, value);
  300. return attribute;
  301. }