1 /*
2 * libwbxml, the WBXML Library.
3 * Copyright (C) 2002-2008 Aymerick Jehanne <aymerick@jehanne.org>
4 * Copyright (C) 2011 Michael Bell <michael.bell@opensync.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 * LGPL v2.1: http://www.gnu.org/copyleft/lesser.txt
21 *
22 * Contact: aymerick@jehanne.org
23 * Home: http://libwbxml.aymerick.com
24 */
25
26 /**
27 * @file wbxml_conv.c
28 * @ingroup wbxml_conv
29 *
30 * @author Aymerick Jehanne <aymerick@jehanne.org>
31 * @date 03/02/23
32 *
33 * @brief WBXML Convertion Library (XML to WBXML, and WBXML to XML)
34 */
35
36 #include "wbxml_conv.h"
37 #include "wbxml_tree.h"
38 #include "wbxml_log.h"
39
40 /****************************
41 * converter objects *
42 ****************************
43 */
44
45 struct WBXMLConvWBXML2XML_s {
46 WBXMLGenXMLType gen_type; /**< WBXML_GEN_XML_COMPACT | WBXML_GEN_XML_INDENT | WBXML_GEN_XML_CANONICAL (Default: WBXML_GEN_XML_INDENT) */
47 WBXMLLanguage lang; /**< Force document Language (overwrite document Public ID) */
48 WBXMLCharsetMIBEnum charset; /**< Set document Language (does not overwrite document character set) */
49 WB_UTINY indent; /**< Indentation Delta, when using WBXML_GEN_XML_INDENT Generation Type (Default: 0) */
50 WB_BOOL keep_ignorable_ws; /**< Keep Ignorable Whitespaces (Default: FALSE) */
51 };
52
53 struct WBXMLConvXML2WBXML_s {
54 WBXMLVersion wbxml_version; /**< WBXML Version */
55 WB_BOOL keep_ignorable_ws; /**< Keep Ignorable Whitespaces (Default: FALSE) */
56 WB_BOOL use_strtbl; /**< Generate String Table (Default: TRUE) */
57 WB_BOOL produce_anonymous; /**< Produce an anonymous document (Default: FALSE) */
58 };
59
60 /****************************
61 * Public Functions *
62 ****************************
63 */
64
wbxml_conv_wbxml2xml_create(WBXMLConvWBXML2XML ** conv)65 WBXML_DECLARE(WBXMLError) wbxml_conv_wbxml2xml_create(WBXMLConvWBXML2XML **conv)
66 {
67 if (conv == NULL) {
68 return WBXML_ERROR_BAD_PARAMETER;
69 }
70
71 *conv = wbxml_malloc(sizeof(WBXMLConvWBXML2XML));
72 if (*conv == NULL) {
73 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
74 }
75
76 (*conv)->gen_type = WBXML_GEN_XML_INDENT;
77 (*conv)->lang = WBXML_LANG_UNKNOWN;
78 (*conv)->charset = WBXML_CHARSET_UNKNOWN;
79 (*conv)->indent = 0;
80 (*conv)->keep_ignorable_ws = FALSE;
81
82 return WBXML_OK;
83 }
84
85 /**
86 * @brief Set the XML generation type (default: WBXML_GEN_XML_INDENT).
87 * @param conv [in] the converter
88 * @param gen_type [in] generation type
89 */
wbxml_conv_wbxml2xml_set_gen_type(WBXMLConvWBXML2XML * conv,WBXMLGenXMLType gen_type)90 WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_gen_type(WBXMLConvWBXML2XML *conv, WBXMLGenXMLType gen_type)
91 {
92 conv->gen_type = gen_type;
93 }
94
95 /**
96 * @brief Set the used WBXML language.
97 * The language is usually detected by the specified public ID in the document.
98 * If the public ID is set then it overrides the language.
99 * @param conv [in] the converter
100 * @param lang [in] language (e.g. SYNCML12)
101 */
wbxml_conv_wbxml2xml_set_language(WBXMLConvWBXML2XML * conv,WBXMLLanguage lang)102 WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_language(WBXMLConvWBXML2XML *conv, WBXMLLanguage lang)
103 {
104 conv->lang = lang;
105 }
106
107 /**
108 * @brief Set the used character set.
109 * The default character set is UTF-8.
110 * If the document specifies a character set by it own
111 * then this character set overrides the parameter charset.
112 * @param conv [in] the converter
113 * @param charset [in] the character set
114 */
wbxml_conv_wbxml2xml_set_charset(WBXMLConvWBXML2XML * conv,WBXMLCharsetMIBEnum charset)115 WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_charset(WBXMLConvWBXML2XML *conv, WBXMLCharsetMIBEnum charset)
116 {
117 conv->charset = charset;
118 }
119
120 /**
121 * @brief Set the indent of the generated XML document (please see EXPAT default).
122 * @param conv [in] the converter
123 * @param indent [in] the number of blanks
124 */
wbxml_conv_wbxml2xml_set_indent(WBXMLConvWBXML2XML * conv,WB_UTINY indent)125 WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_indent(WBXMLConvWBXML2XML *conv, WB_UTINY indent)
126 {
127 conv->indent = indent;
128 }
129
130 /**
131 * @brief Enable whitespace preservation (default: FALSE).
132 * @param conv [in] the converter
133 */
wbxml_conv_wbxml2xml_enable_preserve_whitespaces(WBXMLConvWBXML2XML * conv)134 WBXML_DECLARE(void) wbxml_conv_wbxml2xml_enable_preserve_whitespaces(WBXMLConvWBXML2XML *conv)
135 {
136 conv->keep_ignorable_ws = TRUE;
137 }
138
139 /**
140 * @brief Convert WBXML to XML
141 * @param conv [in] the converter
142 * @param wbxml [in] WBXML Document to convert
143 * @param wbxml_len [in] Length of WBXML Document
144 * @param xml [out] Resulting XML Document
145 * @param xml_len [out] XML Document length
146 * @return WBXML_OK if conversion succeeded, an Error Code otherwise
147 */
wbxml_conv_wbxml2xml_run(WBXMLConvWBXML2XML * conv,WB_UTINY * wbxml,WB_ULONG wbxml_len,WB_UTINY ** xml,WB_ULONG * xml_len)148 WBXML_DECLARE(WBXMLError) wbxml_conv_wbxml2xml_run(WBXMLConvWBXML2XML *conv,
149 WB_UTINY *wbxml,
150 WB_ULONG wbxml_len,
151 WB_UTINY **xml,
152 WB_ULONG *xml_len)
153 {
154 WBXMLGenXMLParams params;
155 WBXMLTree *wbxml_tree = NULL;
156 WB_ULONG dummy_len = 0;
157 WBXMLError ret = WBXML_OK;
158
159 /* Copy options */
160 params.gen_type = conv->gen_type;
161 params.lang = conv->lang;
162 params.charset = conv->charset;
163 params.keep_ignorable_ws = conv->keep_ignorable_ws;
164 params.indent = conv->indent;
165
166 /* Check Parameters (we allow 'xml_len' to be NULL for backward compatibility) */
167 if ((wbxml == NULL) || (wbxml_len == 0) || (xml == NULL))
168 return WBXML_ERROR_BAD_PARAMETER;
169
170 if (xml_len == NULL)
171 xml_len = &dummy_len;
172
173 *xml = NULL;
174 *xml_len = 0;
175
176 /* Parse WBXML to WBXML Tree */
177 ret = wbxml_tree_from_wbxml(wbxml, wbxml_len, conv->lang, conv->charset, &wbxml_tree);
178 if (ret != WBXML_OK) {
179 WBXML_ERROR((WBXML_CONV, "wbxml2xml conversion failed - WBXML Parser Error: %s",
180 wbxml_errors_string(ret)));
181
182 return ret;
183 }
184 else {
185 /* Convert Tree to XML */
186 ret = wbxml_tree_to_xml(wbxml_tree, xml, xml_len, ¶ms);
187 if (ret != WBXML_OK) {
188 WBXML_ERROR((WBXML_CONV, "wbxml2xml conversion failed - WBXML Encoder Error: %s",
189 wbxml_errors_string(ret)));
190 }
191
192 /* Clean-up */
193 wbxml_tree_destroy(wbxml_tree);
194
195 return ret;
196 }
197 }
198
199 /**
200 * @brief Destroy the converter object.
201 * @param [in] the converter
202 */
wbxml_conv_wbxml2xml_destroy(WBXMLConvWBXML2XML * conv)203 WBXML_DECLARE(void) wbxml_conv_wbxml2xml_destroy(WBXMLConvWBXML2XML *conv)
204 {
205 wbxml_free(conv);
206 }
207
208 /**
209 * @brief Create a new WBXML to XML converter with the default configuration.
210 * @param conv [out] a reference to the pointer of the new converter
211 * @return WBXML_OK if conversion succeeded, an Error Code otherwise
212 */
wbxml_conv_xml2wbxml_create(WBXMLConvXML2WBXML ** conv)213 WBXML_DECLARE(WBXMLError) wbxml_conv_xml2wbxml_create(WBXMLConvXML2WBXML **conv)
214 {
215 if (conv == NULL) {
216 return WBXML_ERROR_BAD_PARAMETER;
217 }
218
219 *conv = wbxml_malloc(sizeof(WBXMLConvXML2WBXML));
220 if (*conv == NULL) {
221 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
222 }
223
224 (*conv)->wbxml_version = WBXML_VERSION_13;
225 (*conv)->keep_ignorable_ws = FALSE;
226 (*conv)->use_strtbl = TRUE;
227 (*conv)->produce_anonymous = FALSE;
228
229 return WBXML_OK;
230 }
231
232 /**
233 * @brief Set the WBXML version (default: 1.3).
234 * @param conv [in] the converter
235 * @param indent [in] the number of blanks
236 */
wbxml_conv_xml2wbxml_set_version(WBXMLConvXML2WBXML * conv,WBXMLVersion wbxml_version)237 WBXML_DECLARE(void) wbxml_conv_xml2wbxml_set_version(WBXMLConvXML2WBXML *conv,
238 WBXMLVersion wbxml_version)
239 {
240 conv->wbxml_version = wbxml_version;
241 }
242
243 /**
244 * @brief Enable whitespace preservation (default: FALSE/DISABLED).
245 * @param conv [in] the converter
246 */
wbxml_conv_xml2wbxml_enable_preserve_whitespaces(WBXMLConvXML2WBXML * conv)247 WBXML_DECLARE(void) wbxml_conv_xml2wbxml_enable_preserve_whitespaces(WBXMLConvXML2WBXML *conv)
248 {
249 conv->keep_ignorable_ws = TRUE;
250 }
251
252 /**
253 * @brief Disable string table (default: TRUE/ENABLED).
254 * @param conv [in] the converter
255 */
wbxml_conv_xml2wbxml_disable_string_table(WBXMLConvXML2WBXML * conv)256 WBXML_DECLARE(void) wbxml_conv_xml2wbxml_disable_string_table(WBXMLConvXML2WBXML *conv)
257 {
258 conv->use_strtbl = FALSE;
259 }
260
261 /**
262 * @brief Disable public ID (default: TRUE/ENABLED).
263 * @param conv [in] the converter
264 */
wbxml_conv_xml2wbxml_disable_public_id(WBXMLConvXML2WBXML * conv)265 WBXML_DECLARE(void) wbxml_conv_xml2wbxml_disable_public_id(WBXMLConvXML2WBXML *conv)
266 {
267 conv->produce_anonymous = TRUE;
268 }
269
270 /**
271 * @brief Convert XML to WBXML
272 * @param conv [in] the converter
273 * @param xml [in] XML Document to convert
274 * @param xml_len [in] Length of XML Document
275 * @param wbxml [out] Resulting WBXML Document
276 * @param wbxml_len [out] Length of resulting WBXML Document
277 * @return WBXML_OK if conversion succeeded, an Error Code otherwise
278 */
wbxml_conv_xml2wbxml_run(WBXMLConvXML2WBXML * conv,WB_UTINY * xml,WB_ULONG xml_len,WB_UTINY ** wbxml,WB_ULONG * wbxml_len)279 WBXML_DECLARE(WBXMLError) wbxml_conv_xml2wbxml_run(WBXMLConvXML2WBXML *conv,
280 WB_UTINY *xml,
281 WB_ULONG xml_len,
282 WB_UTINY **wbxml,
283 WB_ULONG *wbxml_len)
284 {
285 WBXMLTree *wbxml_tree = NULL;
286 WBXMLError ret = WBXML_OK;
287 WBXMLGenWBXMLParams params;
288
289 /* Check Parameters */
290 if ((xml == NULL) || (xml_len == 0) || (wbxml == NULL) || (wbxml_len == NULL))
291 return WBXML_ERROR_BAD_PARAMETER;
292
293 /* copy options */
294 params.wbxml_version = conv->wbxml_version;
295 params.keep_ignorable_ws = conv->keep_ignorable_ws;
296 params.use_strtbl = conv->use_strtbl;
297 params.produce_anonymous = conv->produce_anonymous;
298
299 *wbxml = NULL;
300 *wbxml_len = 0;
301
302 /* Parse XML to WBXML Tree */
303 ret = wbxml_tree_from_xml(xml, xml_len, &wbxml_tree);
304 if (ret != WBXML_OK) {
305 WBXML_ERROR((WBXML_CONV, "xml2wbxml conversion failed - Error: %s",
306 wbxml_errors_string(ret)));
307
308 return ret;
309 }
310 else {
311 /* Convert Tree to WBXML */
312 ret = wbxml_tree_to_wbxml(wbxml_tree, wbxml, wbxml_len, ¶ms);
313 if (ret != WBXML_OK) {
314 WBXML_ERROR((WBXML_CONV, "xml2wbxml conversion failed - WBXML Encoder Error: %s",
315 wbxml_errors_string(ret)));
316 }
317
318 /* Clean-up */
319 wbxml_tree_destroy(wbxml_tree);
320
321 return ret;
322 }
323 }
324
325
326 /**
327 * @brief Destroy the converter object.
328 * @param [in] the converter
329 */
wbxml_conv_xml2wbxml_destroy(WBXMLConvXML2WBXML * conv)330 WBXML_DECLARE(void) wbxml_conv_xml2wbxml_destroy(WBXMLConvXML2WBXML *conv)
331 {
332 wbxml_free(conv);
333 }
334
335 /**************************************
336 * Public Functions - DEPRECATED in API
337 */
338
wbxml_conv_wbxml2xml_withlen(WB_UTINY * wbxml,WB_ULONG wbxml_len,WB_UTINY ** xml,WB_ULONG * xml_len,WBXMLGenXMLParams * params)339 WBXML_DECLARE(WBXMLError) wbxml_conv_wbxml2xml_withlen(WB_UTINY *wbxml,
340 WB_ULONG wbxml_len,
341 WB_UTINY **xml,
342 WB_ULONG *xml_len,
343 WBXMLGenXMLParams *params)
344 {
345 WBXMLConvWBXML2XML *conv = NULL;
346 WBXMLError ret = WBXML_OK;
347
348 ret = wbxml_conv_wbxml2xml_create(&conv);
349 if (ret != WBXML_OK)
350 return ret;
351
352 wbxml_conv_wbxml2xml_set_gen_type(conv, params->gen_type);
353 wbxml_conv_wbxml2xml_set_language(conv, params->lang);
354 wbxml_conv_wbxml2xml_set_charset(conv, params->charset);
355 wbxml_conv_wbxml2xml_set_indent(conv, params->indent);
356 if (params->keep_ignorable_ws)
357 wbxml_conv_wbxml2xml_enable_preserve_whitespaces(conv);
358 ret = wbxml_conv_wbxml2xml_run(conv, wbxml, wbxml_len, xml, xml_len);
359 wbxml_conv_wbxml2xml_destroy(conv);
360 return ret;
361 }
362
wbxml_conv_xml2wbxml_withlen(WB_UTINY * xml,WB_ULONG xml_len,WB_UTINY ** wbxml,WB_ULONG * wbxml_len,WBXMLGenWBXMLParams * params)363 WBXML_DECLARE(WBXMLError) wbxml_conv_xml2wbxml_withlen(WB_UTINY *xml,
364 WB_ULONG xml_len,
365 WB_UTINY **wbxml,
366 WB_ULONG *wbxml_len,
367 WBXMLGenWBXMLParams *params)
368 {
369 WBXMLConvXML2WBXML *conv = NULL;
370 WBXMLError ret = WBXML_OK;
371
372 ret = wbxml_conv_xml2wbxml_create(&conv);
373 if (ret != WBXML_OK)
374 return ret;
375
376 wbxml_conv_xml2wbxml_set_version(conv, params->wbxml_version);
377 if (params->keep_ignorable_ws)
378 wbxml_conv_xml2wbxml_enable_preserve_whitespaces(conv);
379 if (!params->use_strtbl)
380 wbxml_conv_xml2wbxml_disable_string_table(conv);
381 if (params->produce_anonymous)
382 wbxml_conv_xml2wbxml_disable_public_id(conv);
383 ret = wbxml_conv_xml2wbxml_run(conv, xml, xml_len, wbxml, wbxml_len);
384 wbxml_conv_xml2wbxml_destroy(conv);
385 return ret;
386 }
387