1 /*
2  * libwbxml, the WBXML Library.
3  * Copyright (C) 2002-2008 Aymerick Jehanne <aymerick@jehanne.org>
4  * Copyright (C) 2008-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_encoder.c
28  * @ingroup wbxml_encoder
29  *
30  * @author Aymerick Jehanne <aymerick@jehanne.org>
31  * @date 11/11/02
32  *
33  * @brief WBXML Encoder - Encodes a WBXML Tree to WBXML or to XML
34  *
35  * @note Inspired from kannel WML Encoder (http://www.kannel.org)
36  *
37  * @note [OMA WV 1.1] : OMA-WV-CSP_WBXML-V1_1-20021001-A.pdf
38  *
39  * @todo Parse CDDATA
40  * @todo Parse PI
41  * @todo Handle Charsets Encoding
42  * @todo Really generate ENTITY tokens
43  * @todo Handle Namespaces !
44  * @todo For canonical XML output: Sort the Attributes
45  * @todo When adding string to String Table, check that this is not a Content Text that will be tokenized
46  * @todo For Wireless-Village CSP :
47  *              - Encode "Date and Time" in OPAQUE (OMA-WV-CSP_WBXML-V1_1-20021001-A.pdf - 6.6)
48  *
49  * @todo Review the canonical XML generation:
50  *       - http://www.jclark.com/xml/canonxml.html
51 *        - http://www.w3.org/TR/2004/REC-xml-20040204/
52  */
53 
54 #include <ctype.h> /* For isdigit() */
55 
56 #include "wbxml_encoder.h"
57 #include "wbxml_log.h"
58 #include "wbxml_internals.h"
59 #include "wbxml_base64.h"
60 
61 
62 /**
63  * Compilation Flag: WBXML_ENCODER_USE_STRTBL
64  * -----------------
65  * Do We Use String Table when Encoding to WBXML ?
66  * (NOTE: We still use String Table for Unknown Public ID, even if this flag is not set)
67  */
68 
69 /* WBXML Header:    version     publicid    charset     length
70  *                  u_int8      mb_u_int32  mb_u_int32  mb_u_int32
71  *                  1 octet     5 octets    5 octets    5 octets   :  16 octets
72  * mb_u_int32: 5 octets (to handle continuation bits)
73  */
74 #define WBXML_HEADER_MAX_LEN 16
75 
76 /* Memory management related defines */
77 #define WBXML_ENCODER_XML_DOC_MALLOC_BLOCK 5000
78 #define WBXML_ENCODER_WBXML_DOC_MALLOC_BLOCK 1000
79 
80 #define WBXML_ENCODER_XML_HEADER_MALLOC_BLOCK 250
81 #define WBXML_ENCODER_WBXML_HEADER_MALLOC_BLOCK WBXML_HEADER_MAX_LEN
82 
83 /* WBXML Default Charset: UTF-8 (106) */
84 #define WBXML_ENCODER_DEFAULT_CHARSET 0x6a
85 
86 /* String Terminating NULL Char */
87 #define WBXML_STR_END '\0'
88 
89 /* Minimum String Size needed for String Table - @note Set to '3' for Prov 1.0 */
90 #define WBXML_ENCODER_STRING_TABLE_MIN 3
91 
92 /**
93  * Default charset of the outputed WBXML document. Used only in this case :
94  *  - No charset was indicated thanks to the function 'wbxml_encoder_set_output_charset()'
95  *  - and the WBXML Tree field 'orig_charset' is set to WBXML_CHARSET_UNKNOWN (ie. charset
96  *    information not found in original document)
97  */
98 #define WBXML_ENCODER_WBXML_DEFAULT_CHARSET WBXML_CHARSET_UTF_8
99 
100 /**
101  * Default charset of the outputed XML document. Used only in this case :
102  *  - No charset was indicated thanks to the function 'wbxml_encoder_set_output_charset()'
103  *  - and the WBXML Tree field 'orig_charset' is set to WBXML_CHARSET_UNKNOWN (ie. charset
104  *    information not found in original document)
105  */
106 #define WBXML_ENCODER_XML_DEFAULT_CHARSET WBXML_CHARSET_UTF_8
107 
108 /**
109  * If defined, generate empty XML elements (eg: &lt;foo /&gt;), else generate
110  * full "end element" (eg: &lt;foo&gt;&lt;/foo&gt;)
111  *
112  * @todo This must be a 'WBXMLGenXMLParams' parameter
113  */
114 #define WBXML_ENCODER_XML_GEN_EMPTY_ELT
115 
116 /**
117  * If defined, do not indent elements that have no element child (eg: &lt;foo&gt;bar&lt;/foo&gt;),
118  * else indent anyway (eg: &lt;foo&gt;
119  *                           bar
120  *                         &lt;/foo&gt;)
121  *
122  * @todo This must be a 'WBXMLGenXMLParams' parameter
123  */
124 #define WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT
125 
126 
127 /**
128  * @warning For now 'current_tag' field is only used for WV Content Encoding. And for this use, it works.
129  *          But this field is reset after End Tag, and as there is no Linked List mecanism, this is bad for
130  *          cascading elements: we don't fill this field with parent Tag when parsing End Tag.
131  *
132  * @warning For now 'current_text_parent' field is only used for DRM REL Content Encoding. It should not be
133  *          used for another purpose.
134  *
135  * @warning For now 'current_node' field is a hack. It is reset after End Tag, and as there is no Linked List
136  *          mecanism, this is bad for cascading elements: we don't fill this field with parent Tag
137  *          when parsing End Tag.
138  */
139 struct WBXMLEncoder_s {
140     WBXMLTree *tree;                        /**< WBXML Tree to Encode */
141     const WBXMLLangEntry *lang;             /**< Language table to use */
142     WBXMLBuffer *output;                    /**< The output (wbxml or xml) we are producing */
143     WBXMLBuffer *output_header;             /**< The output header (used if Flow Mode encoding is activated) */
144     const WBXMLTagEntry *current_tag;       /**< Current Tag (See The Warning For This Field !) */
145     const WBXMLTreeNode *current_text_parent; /**< Text parent of current Node (See The Warning For This Field !) */
146     const WBXMLAttrEntry *current_attr;     /**< Current Attribute */
147     WBXMLTreeNode *current_node;            /**< Current Node (See The Warning For This Field !) */
148     WB_UTINY tagCodePage;                   /**< Current Tag Code Page */
149     WB_UTINY attrCodePage;                  /**< Current Attribute Code Page */
150     WB_BOOL ignore_empty_text;              /**< Do we ignore empty text nodes (ie: ignorable whitespaces)? */
151     WB_BOOL remove_text_blanks;             /**< Do we remove leading and trailing blanks in text nodes ? */
152     WBXMLEncoderOutputType output_type;     /**< Output Type */
153     WBXMLGenXMLType xml_gen_type;           /**< XML Generation Type */
154     WB_UTINY indent_delta;                  /**< Indent Delta (number of spaces) */
155     WB_UTINY indent;                        /**< Current Indent */
156     WB_BOOL in_content;                     /**< We are in Content Text (used for indentation when generating XML output) */
157     WB_BOOL in_cdata;                       /**< We are in a CDATA section (and so, content must be generaed "as is") */
158     WBXMLBuffer *cdata;                     /**< Current CDATA Buffer */
159 #if defined( WBXML_ENCODER_USE_STRTBL )
160     WBXMLList *strstbl;                     /**< String Table we are creating */
161     WB_ULONG strstbl_len;                   /**< String Table Length */
162     WB_BOOL use_strtbl;                     /**< Do we use String Table when generating WBXML output ? (default: YES) */
163 #endif /* WBXML_ENCODER_USE_STRTBL */
164     WB_BOOL xml_encode_header;              /**< Do we generate XML Header ? */
165     WB_BOOL produce_anonymous;              /**< Do we produce anonymous documents? (default: NO) */
166     WBXMLVersion wbxml_version;             /**< WBXML Version to use (when generating WBXML output) */
167     WBXMLCharsetMIBEnum output_charset;     /**< Output charset encoding */
168     WB_BOOL flow_mode;                      /**< Is Flow Mode encoding activated ? */
169     WB_ULONG pre_last_node_len;             /**< Output buffer length before last node encoding */
170     WB_BOOL textual_publicid;               /**< Generate textual Public ID instead of token (when generating WBXML output) */
171 };
172 
173 #if defined( WBXML_ENCODER_USE_STRTBL )
174 /**
175  * @brief The WBXML String Table Element
176  */
177 typedef struct WBXMLStringTableElement_t {
178     WBXMLBuffer *string; /**< String */
179     WB_ULONG offset;     /**< Offset of String in String Table */
180     WB_ULONG count;      /**< Number of times this String is referenced in the XML Document */
181     WB_BOOL stat;        /**< If set to TRUE, this is a static String that we must not destroy in wbxml_strtbl_element_destroy() function */
182 } WBXMLStringTableElement;
183 #endif /* WBXML_ENCODER_USE_STRTBL */
184 
185 /**
186  * @brief WBXML Value Element Context: In Content or in Attribute Value
187  */
188 typedef enum WBXMLValueElementCtx_e {
189     WBXML_VALUE_ELEMENT_CTX_CONTENT = 0,    /**< Text Content */
190     WBXML_VALUE_ELEMENT_CTX_ATTR            /**< Attribute Value */
191 } WBXMLValueElementCtx;
192 
193 /**
194  * @brief WBXML Value Element Type: string / tableref / extension / opaque
195  */
196 typedef enum WBXMLValueElementType_e {
197     WBXML_VALUE_ELEMENT_STRING = 0, /**< Inline String */
198     WBXML_VALUE_ELEMENT_EXTENSION,  /**< Extension Token */
199     WBXML_VALUE_ELEMENT_OPAQUE,     /**< Opaque Buffer */
200     WBXML_VALUE_ELEMENT_ATTR_TOKEN /**< Attribute Value Token */
201 #if defined( WBXML_ENCODER_USE_STRTBL )
202     , WBXML_VALUE_ELEMENT_TABLEREF   /**< String Table Reference */
203 #endif /* WBXML_ENCODER_USE_STRTBL */
204 } WBXMLValueElementType;
205 
206 /**
207  * @brief WBXML Value Element Structure
208  */
209 typedef struct WBXMLValueElement_t {
210     WBXMLValueElementType type;     /**< Cf WBXMLValueElementType enum */
211     union {
212         WBXMLBuffer *str;                   /**< WBXML_VALUE_ELEMENT_STRING */
213         const WBXMLExtValueEntry *ext;      /**< WBXML_VALUE_ELEMENT_EXTENSION */
214         WBXMLBuffer *buff;                  /**< WBXML_VALUE_ELEMENT_OPAQUE */
215         const WBXMLAttrValueEntry *attr;    /**< WBXML_VALUE_ELEMENT_ATTR_TOKEN */
216 #if defined( WBXML_ENCODER_USE_STRTBL )
217         WB_ULONG    index;                  /**< WBXML_VALUE_ELEMENT_TABLEREF */
218 #endif /* WBXML_ENCODER_USE_STRTBL */
219     } u;
220 } WBXMLValueElement;
221 
222 
223 /***************************************************
224  *    Private Functions prototypes
225  */
226 
227 /*******************************
228  * Common Functions
229  */
230 
231 #if 0
232 static WB_BOOL convert_char_to_ucs4(WB_UTINY ch, WB_ULONG *result);
233 #endif /* 0 */
234 
235 static WBXMLEncoder *encoder_duplicate(WBXMLEncoder *encoder);
236 static WBXMLError encoder_encode_tree(WBXMLEncoder *encoder);
237 static WB_BOOL encoder_init_output(WBXMLEncoder *encoder);
238 
239 
240 /*******************************
241  * WBXML Tree Parsing Functions
242  */
243 
244 static WBXMLError parse_node(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL enc_end);
245 static WBXMLError parse_element(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content);
246 static WBXMLError parse_element_end(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content);
247 static WBXMLError parse_attribute(WBXMLEncoder *encoder, WBXMLAttribute *attribute);
248 static WBXMLError parse_text(WBXMLEncoder *encoder, WBXMLTreeNode *node);
249 static WBXMLError parse_cdata(WBXMLEncoder *encoder);
250 static WBXMLError parse_pi(WBXMLEncoder *encoder, WBXMLTreeNode *node);
251 static WBXMLError parse_tree(WBXMLEncoder *encoder, WBXMLTreeNode *node);
252 
253 
254 /*******************************
255  * WBXML Output Functions
256  */
257 
258 /* Build WBXML Result */
259 static WBXMLError wbxml_build_result(WBXMLEncoder *encoder, WB_UTINY **wbxml, WB_ULONG *wbxml_len);
260 static WBXMLError wbxml_fill_header(WBXMLEncoder *encoder, WBXMLBuffer *header);
261 
262 /* WBXML Encoding Functions */
263 static WBXMLError wbxml_encode_end(WBXMLEncoder *encoder);
264 
265 static WBXMLError wbxml_encode_tag(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content);
266 static WBXMLError wbxml_encode_tag_literal(WBXMLEncoder *encoder, const WB_UTINY *tag, WB_UTINY mask);
267 static WBXMLError wbxml_encode_tag_token(WBXMLEncoder *encoder, WB_UTINY token, WB_UTINY page);
268 
269 static WBXMLError wbxml_encode_attr(WBXMLEncoder *encoder, WBXMLAttribute *attribute);
270 static WBXMLError wbxml_encode_attr_start(WBXMLEncoder *encoder, WBXMLAttribute *attribute, WB_UTINY **value);
271 static WBXMLError wbxml_encode_value_element_buffer(WBXMLEncoder *encoder, WB_UTINY *value, WBXMLValueElementCtx ctx);
272 static WBXMLError wbxml_encode_value_element_list(WBXMLEncoder *encoder, WBXMLList *list);
273 static WBXMLError wbxml_encode_attr_start_literal(WBXMLEncoder *encoder, const WB_UTINY *attr);
274 static WBXMLError wbxml_encode_attr_token(WBXMLEncoder *encoder, WB_UTINY token, WB_UTINY page);
275 
276 static WBXMLError wbxml_encode_inline_string(WBXMLEncoder *encoder, WBXMLBuffer *str);
277 static WBXMLError wbxml_encode_inline_integer_extension_token(WBXMLEncoder *encoder, WB_UTINY ext, WB_UTINY value);
278 #if 0
279 static WBXMLError wbxml_encode_entity(WBXMLEncoder *encoder, WB_ULONG value);
280 #endif /* 0 */
281 static WBXMLError wbxml_encode_opaque(WBXMLEncoder *encoder, WBXMLBuffer *buff);
282 static WBXMLError wbxml_encode_opaque_data(WBXMLEncoder *encoder, WB_UTINY *data, WB_ULONG data_len);
283 #if defined( WBXML_ENCODER_USE_STRTBL )
284 static WBXMLError wbxml_encode_tableref(WBXMLEncoder *encoder, WB_ULONG offset);
285 #endif /* WBXML_ENCODER_USE_STRTBL */
286 
287 static WBXMLValueElement *wbxml_value_element_create(void);
288 static void wbxml_value_element_destroy(WBXMLValueElement *elt);
289 static void wbxml_value_element_destroy_item(void *elt);
290 
291 static WBXMLError wbxml_encode_tree(WBXMLEncoder *encoder, WBXMLTree *tree);
292 
293 #if ( defined( WBXML_SUPPORT_SI ) || defined( WBXML_SUPPORT_EMN ) )
294 static WBXMLError wbxml_encode_datetime(WBXMLEncoder *encoder, WB_UTINY *buffer);
295 #endif /* WBXML_SUPPORT_SI || WBXML_SUPPORT_EMN */
296 
297 #if defined( WBXML_SUPPORT_WV )
298 static WBXMLError wbxml_encode_wv_content(WBXMLEncoder *encoder, WB_UTINY *buffer);
299 static WBXMLError wbxml_encode_wv_integer(WBXMLEncoder *encoder, WB_UTINY *buffer);
300 static WBXMLError wbxml_encode_wv_datetime(WBXMLEncoder *encoder, WB_UTINY *buffer);
301 #endif /* WBXML_SUPPORT_WV */
302 
303 #if defined( WBXML_SUPPORT_DRMREL )
304 static WBXMLError wbxml_encode_drmrel_content(WBXMLEncoder *encoder, WB_UTINY *buffer);
305 #endif /* WBXML_SUPPORT_DRMREL */
306 
307 #if defined( WBXML_SUPPORT_OTA_SETTINGS )
308 static WBXMLError wbxml_encode_ota_nokia_icon(WBXMLEncoder *encoder, WB_UTINY *buffer);
309 #endif /* WBXML_SUPPORT_OTA_SETTINGS */
310 
311 #if defined( WBXML_ENCODER_USE_STRTBL )
312 /* WBXML String Table Functions */
313 static WBXMLStringTableElement *wbxml_strtbl_element_create(WBXMLBuffer *string, WB_BOOL is_stat);
314 static void wbxml_strtbl_element_destroy(WBXMLStringTableElement *element);
315 static void wbxml_strtbl_element_destroy_item(void *element);
316 
317 static WBXMLError wbxml_strtbl_initialize(WBXMLEncoder *encoder, WBXMLTreeNode *root);
318 static void wbxml_strtbl_collect_strings(WBXMLEncoder *encoder, WBXMLTreeNode *node, WBXMLList *strings);
319 static WBXMLError wbxml_strtbl_collect_words(WBXMLList *elements, WBXMLList **result);
320 static WBXMLError wbxml_strtbl_construct(WBXMLBuffer *buff, WBXMLList *strstbl);
321 static WBXMLError wbxml_strtbl_check_references(WBXMLEncoder *encoder, WBXMLList **strings, WBXMLList **one_ref, WB_BOOL stat_buff);
322 static WB_BOOL wbxml_strtbl_add_element(WBXMLEncoder *encoder, WBXMLStringTableElement *elt, WB_ULONG *index, WB_BOOL *added);
323 #endif /* WBXML_ENCODER_USE_STRTBL */
324 
325 
326 /*******************************
327  * XML Output Functions
328  */
329 
330 /** New Line */
331 #define WBXML_ENCODER_XML_NEW_LINE ((WB_UTINY *)"\n")
332 
333 /* XML Header Macros */
334 #define WBXML_ENCODER_XML_HEADER "<?xml version=\"1.0\"?>"
335 #define WBXML_ENCODER_XML_DOCTYPE "<!DOCTYPE "
336 #define WBXML_ENCODER_XML_PUBLIC_START " PUBLIC \""
337 #define WBXML_ENCODER_XML_PUBLIC_END "\""
338 #define WBXML_ENCODER_XML_SYSTEM " SYSTEM"
339 #define WBXML_ENCODER_XML_DTD " \""
340 #define WBXML_ENCODER_XML_END_DTD "\">"
341 
342 /* Global vars for XML Normalization */
343 const WB_UTINY xml_lt[5]     = "&lt;";   /**< &lt; */
344 const WB_UTINY xml_gt[5]     = "&gt;";   /**< &gt; */
345 const WB_UTINY xml_amp[6]    = "&amp;";  /**< &amp; */
346 const WB_UTINY xml_quot[7]   = "&quot;"; /**< &quot; */
347 const WB_UTINY xml_apos[7]   = "&apos;"; /**< &apos; */
348 const WB_UTINY xml_slashr[6] = "&#13;";  /**< &#13; */
349 const WB_UTINY xml_slashn[6] = "&#10;";  /**< &#10; */
350 const WB_UTINY xml_tab[5]    = "&#9;";   /**< &#9; */
351 
352 /* Build XML Result */
353 static WBXMLError xml_build_result(WBXMLEncoder *encoder, WB_UTINY **xml, WB_ULONG *xml_len);
354 static WBXMLError xml_fill_header(WBXMLEncoder *encoder, WBXMLBuffer *header);
355 
356 /* XML Encoding Functions */
357 static WBXMLError xml_encode_tag(WBXMLEncoder *encoer, WBXMLTreeNode *node);
358 static WBXMLError xml_encode_end_tag(WBXMLEncoder *encoder, WBXMLTreeNode *node);
359 
360 static WBXMLError xml_encode_attr(WBXMLEncoder *encoder, WBXMLAttribute *attribute);
361 static WBXMLError xml_encode_end_attrs(WBXMLEncoder *encoder, WBXMLTreeNode *node);
362 
363 static WBXMLError xml_encode_text(WBXMLEncoder *encoder, WBXMLTreeNode *node);
364 static WBXMLError xml_encode_text_entities(WBXMLEncoder *encoder, WBXMLBuffer *buff);
365 static WB_BOOL xml_encode_new_line(WBXMLBuffer *buff);
366 
367 static WBXMLError xml_encode_cdata(WBXMLEncoder *encoder);
368 static WBXMLError xml_encode_end_cdata(WBXMLEncoder *encoder);
369 
370 static WBXMLError xml_encode_tree(WBXMLEncoder *encoder, WBXMLTree *tree);
371 
372 
373 /***************************************************
374  *    Public Functions
375  */
376 
wbxml_encoder_create_real(void)377 WBXML_DECLARE(WBXMLEncoder *) wbxml_encoder_create_real(void)
378 {
379     WBXMLEncoder *encoder = NULL;
380 
381     encoder = wbxml_malloc(sizeof(WBXMLEncoder));
382     if (encoder == NULL) {
383         return NULL;
384     }
385 
386 #if defined( WBXML_ENCODER_USE_STRTBL )
387     if ((encoder->strstbl = wbxml_list_create()) == NULL) {
388         wbxml_free(encoder);
389         return NULL;
390     }
391     encoder->use_strtbl = TRUE;
392     encoder->strstbl_len = 0;
393 #endif /* WBXML_ENCODER_USE_STRTBL */
394 
395     encoder->tree = NULL;
396     encoder->lang = NULL;
397     encoder->output = NULL;
398     encoder->output_header = NULL;
399 
400     encoder->current_tag = NULL;
401     encoder->current_text_parent = NULL;
402     encoder->current_attr = NULL;
403     encoder->current_node = NULL;
404 
405     encoder->tagCodePage = 0;
406     encoder->attrCodePage = 0;
407 
408     encoder->ignore_empty_text = FALSE;
409     encoder->remove_text_blanks = FALSE;
410 
411     encoder->output_type = WBXML_ENCODER_OUTPUT_WBXML;
412     encoder->xml_gen_type = WBXML_GEN_XML_COMPACT;
413 
414     encoder->indent_delta = 1;
415     encoder->indent = 0;
416     encoder->in_content = FALSE;
417     encoder->in_cdata = FALSE;
418     encoder->cdata = NULL;
419 
420     encoder->xml_encode_header = TRUE;
421     encoder->produce_anonymous = FALSE;
422 
423     /* Default Version: WBXML 1.3 */
424     encoder->wbxml_version = WBXML_VERSION_13;
425 
426     /**
427      * Default Output Charset Encoding is the one found in WBXML Tree,
428      * so set it as 'unknown' for now.
429      */
430     encoder->output_charset = WBXML_CHARSET_UNKNOWN;
431 
432     encoder->flow_mode = FALSE;
433     encoder->pre_last_node_len = 0;
434     encoder->textual_publicid = FALSE;
435 
436     return encoder;
437 }
438 
439 
wbxml_encoder_destroy(WBXMLEncoder * encoder)440 WBXML_DECLARE(void) wbxml_encoder_destroy(WBXMLEncoder *encoder)
441 {
442     if (encoder == NULL)
443         return;
444 
445     wbxml_buffer_destroy(encoder->output);
446     wbxml_buffer_destroy(encoder->output_header);
447     wbxml_buffer_destroy(encoder->cdata);
448 
449 #if defined( WBXML_ENCODER_USE_STRTBL )
450     wbxml_list_destroy(encoder->strstbl, wbxml_strtbl_element_destroy_item);
451 #endif /* WBXML_ENCODER_USE_STRTBL */
452 
453     wbxml_free(encoder);
454 }
455 
456 
wbxml_encoder_reset(WBXMLEncoder * encoder)457 WBXML_DECLARE(void) wbxml_encoder_reset(WBXMLEncoder *encoder)
458 {
459     if (encoder == NULL)
460         return;
461 
462     encoder->tree = NULL;
463 
464     wbxml_buffer_destroy(encoder->output);
465     encoder->output = NULL;
466 
467     wbxml_buffer_destroy(encoder->output_header);
468     encoder->output_header = NULL;
469 
470     encoder->current_tag = NULL;
471     encoder->current_attr = NULL;
472     encoder->current_node = NULL;
473 
474     encoder->tagCodePage = 0;
475     encoder->attrCodePage = 0;
476 
477     encoder->in_content = FALSE;
478     encoder->in_cdata = FALSE;
479 
480     wbxml_buffer_destroy(encoder->cdata);
481     encoder->cdata = NULL;
482 
483     encoder->pre_last_node_len = 0;
484 
485 #if defined( WBXML_ENCODER_USE_STRTBL )
486     wbxml_list_destroy(encoder->strstbl, wbxml_strtbl_element_destroy_item);
487     encoder->strstbl = NULL;
488     encoder->strstbl_len = 0;
489 #endif /* WBXML_ENCODER_USE_STRTBL */
490 }
491 
492 
wbxml_encoder_set_ignore_empty_text(WBXMLEncoder * encoder,WB_BOOL set_ignore)493 WBXML_DECLARE(void) wbxml_encoder_set_ignore_empty_text(WBXMLEncoder *encoder, WB_BOOL set_ignore)
494 {
495     if (encoder == NULL)
496         return;
497 
498     encoder->ignore_empty_text = set_ignore;
499 }
500 
501 
wbxml_encoder_set_remove_text_blanks(WBXMLEncoder * encoder,WB_BOOL set_remove)502 WBXML_DECLARE(void) wbxml_encoder_set_remove_text_blanks(WBXMLEncoder *encoder, WB_BOOL set_remove)
503 {
504     if (encoder == NULL)
505         return;
506 
507     encoder->remove_text_blanks = set_remove;
508 }
509 
510 
wbxml_encoder_set_output_charset(WBXMLEncoder * encoder,WBXMLCharsetMIBEnum charset)511 WBXML_DECLARE(void) wbxml_encoder_set_output_charset(WBXMLEncoder *encoder, WBXMLCharsetMIBEnum charset)
512 {
513   if (encoder == NULL)
514     return;
515 
516   /* Tell which Output Charset Encoding to use (this overides the Charset Encoding found in WBXML Tree) */
517   encoder->output_charset = charset;
518 }
519 
520 
wbxml_encoder_set_use_strtbl(WBXMLEncoder * encoder,WB_BOOL use_strtbl)521 WBXML_DECLARE(void) wbxml_encoder_set_use_strtbl(WBXMLEncoder *encoder, WB_BOOL use_strtbl)
522 {
523 #if defined( WBXML_ENCODER_USE_STRTBL )
524     if (encoder == NULL)
525         return;
526 
527     encoder->use_strtbl = use_strtbl;
528 #endif /* WBXML_ENCODER_USE_STRTBL */
529 }
530 
531 
wbxml_encoder_set_produce_anonymous(WBXMLEncoder * encoder,WB_BOOL set_anonymous)532 WBXML_DECLARE(void) wbxml_encoder_set_produce_anonymous(WBXMLEncoder *encoder, WB_BOOL set_anonymous)
533 {
534     if (encoder == NULL)
535         return;
536 
537     encoder->produce_anonymous = set_anonymous;
538 }
539 
540 
wbxml_encoder_set_wbxml_version(WBXMLEncoder * encoder,WBXMLVersion version)541 WBXML_DECLARE(void) wbxml_encoder_set_wbxml_version(WBXMLEncoder *encoder, WBXMLVersion version)
542 {
543     if (encoder == NULL)
544         return;
545 
546     if (version != WBXML_VERSION_UNKNOWN)
547         encoder->wbxml_version = version;
548 }
549 
550 
wbxml_encoder_set_xml_gen_type(WBXMLEncoder * encoder,WBXMLGenXMLType gen_type)551 WBXML_DECLARE(void) wbxml_encoder_set_xml_gen_type(WBXMLEncoder *encoder, WBXMLGenXMLType gen_type)
552 {
553     if (encoder == NULL)
554         return;
555 
556     encoder->xml_gen_type = gen_type;
557 }
558 
559 
wbxml_encoder_set_indent(WBXMLEncoder * encoder,WB_UTINY indent)560 WBXML_DECLARE(void) wbxml_encoder_set_indent(WBXMLEncoder *encoder, WB_UTINY indent)
561 {
562     if (encoder == NULL)
563         return;
564 
565     encoder->indent_delta = indent;
566 }
567 
568 
wbxml_encoder_set_tree(WBXMLEncoder * encoder,WBXMLTree * tree)569 WBXML_DECLARE(void) wbxml_encoder_set_tree(WBXMLEncoder *encoder, WBXMLTree *tree)
570 {
571     if (encoder == NULL)
572         return;
573 
574     encoder->tree = tree;
575 }
576 
577 
wbxml_encoder_encode_tree_to_wbxml(WBXMLEncoder * encoder,WB_UTINY ** wbxml,WB_ULONG * wbxml_len)578 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_tree_to_wbxml(WBXMLEncoder *encoder, WB_UTINY **wbxml, WB_ULONG *wbxml_len)
579 {
580     WBXMLError ret = WBXML_OK;
581 
582     /* Check Parameters */
583     if (encoder == NULL)
584         return WBXML_ERROR_BAD_PARAMETER;
585 
586     /* Init ret values */
587     *wbxml = NULL;
588     *wbxml_len = 0;
589 
590     /* We output WBXML */
591     wbxml_encoder_set_output_type(encoder, WBXML_ENCODER_OUTPUT_WBXML);
592 
593     /* Encode */
594     if ((ret = encoder_encode_tree(encoder)) != WBXML_OK)
595         return ret;
596 
597     /* Get result */
598     return wbxml_encoder_get_output(encoder, wbxml, wbxml_len);
599 }
600 
601 
wbxml_encoder_encode_tree_to_xml(WBXMLEncoder * encoder,WB_UTINY ** xml,WB_ULONG * xml_len)602 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_tree_to_xml(WBXMLEncoder *encoder, WB_UTINY **xml, WB_ULONG *xml_len)
603 {
604     WBXMLError ret = WBXML_OK;
605 
606     /* Check Parameters */
607     if (encoder == NULL)
608         return WBXML_ERROR_BAD_PARAMETER;
609 
610     /* Init ret values */
611     *xml = NULL;
612     *xml_len = 0;
613 
614     /* We output WBXML */
615     wbxml_encoder_set_output_type(encoder, WBXML_ENCODER_OUTPUT_XML);
616 
617     /* Encode */
618     if ((ret = encoder_encode_tree(encoder)) != WBXML_OK)
619         return ret;
620 
621     /* Get result */
622     return wbxml_encoder_get_output(encoder, xml, xml_len);
623 }
624 
625 
wbxml_encoder_set_flow_mode(WBXMLEncoder * encoder,WB_BOOL flow_mode)626 WBXML_DECLARE(WBXMLError) wbxml_encoder_set_flow_mode(WBXMLEncoder *encoder, WB_BOOL flow_mode)
627 {
628     if (encoder == NULL)
629         return WBXML_ERROR_BAD_PARAMETER;
630 
631     encoder->flow_mode = flow_mode;
632 
633     /* The string tables must only be disabled during flow mode. */
634     if (flow_mode)
635     {
636         /* Don't use String Tables */
637         wbxml_encoder_set_use_strtbl(encoder, FALSE);
638     }
639 
640     return WBXML_OK;
641 }
642 
643 
wbxml_encoder_set_output_type(WBXMLEncoder * encoder,WBXMLEncoderOutputType output_type)644 WBXML_DECLARE(void) wbxml_encoder_set_output_type(WBXMLEncoder *encoder, WBXMLEncoderOutputType output_type)
645 {
646     if (encoder == NULL)
647         return;
648 
649     encoder->output_type = output_type;
650 }
651 
652 
wbxml_encoder_set_lang(WBXMLEncoder * encoder,WBXMLLanguage lang)653 WBXML_DECLARE(void) wbxml_encoder_set_lang(WBXMLEncoder *encoder, WBXMLLanguage lang)
654 {
655     if (encoder == NULL)
656         return;
657 
658     encoder->lang = wbxml_tables_get_table(lang);
659 }
660 
661 
wbxml_encoder_set_text_public_id(WBXMLEncoder * encoder,WB_BOOL gen_text)662 WBXML_DECLARE(void) wbxml_encoder_set_text_public_id(WBXMLEncoder *encoder, WB_BOOL gen_text)
663 {
664     if (encoder == NULL)
665         return;
666 
667     encoder->textual_publicid = gen_text;
668 }
669 
670 
wbxml_encoder_encode_node(WBXMLEncoder * encoder,WBXMLTreeNode * node)671 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_node(WBXMLEncoder *encoder, WBXMLTreeNode *node)
672 {
673     if (encoder->flow_mode == FALSE) {
674         WBXML_WARNING((WBXML_ENCODER, "You should NOT call wbxml_encoder_encode_node() if you are not in Flow Mode encoding ! (use wbxml_encoder_set_flow_mode(encoder, TRUE))"));
675     }
676 
677     return wbxml_encoder_encode_node_with_elt_end(encoder, node, TRUE);
678 }
679 
680 
wbxml_encoder_encode_node_with_elt_end(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL enc_end)681 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_node_with_elt_end(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL enc_end)
682 {
683     WB_ULONG   prev_len = 0;
684     WBXMLError ret      = WBXML_OK;
685 
686     if ((encoder == NULL) || (node == NULL))
687         return WBXML_ERROR_BAD_PARAMETER;
688 
689     /* Check that language table has been set */
690     if (encoder->lang == NULL)
691         return WBXML_ERROR_BAD_PARAMETER;
692 
693     /* Init Output Buffer if needed */
694     if (!encoder_init_output(encoder))
695         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
696 
697     /* Backup length */
698     prev_len = wbxml_buffer_len(encoder->output);
699 
700     /* Check if result header is not already built */
701     if ((encoder->flow_mode == TRUE) && (encoder->output_header == NULL) &&
702         !((encoder->xml_encode_header == FALSE) && (encoder->output_type == WBXML_ENCODER_OUTPUT_XML)))
703     {
704         /* Build result header */
705         switch (encoder->output_type) {
706         case WBXML_ENCODER_OUTPUT_XML:
707             if ((encoder->output_header = wbxml_buffer_create("", 0, WBXML_ENCODER_XML_HEADER_MALLOC_BLOCK)) == NULL)
708                 ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
709             else
710                 ret = xml_fill_header(encoder, encoder->output_header);
711             break;
712 
713         case WBXML_ENCODER_OUTPUT_WBXML:
714             if ((encoder->output_header = wbxml_buffer_create("", 0, WBXML_ENCODER_WBXML_HEADER_MALLOC_BLOCK)) == NULL)
715                 ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
716             else
717                 ret = wbxml_fill_header(encoder, encoder->output_header);
718             break;
719 
720         default:
721             ret = WBXML_ERROR_BAD_PARAMETER;
722             break;
723         }
724     }
725 
726     if (ret != WBXML_OK)
727         return ret;
728 
729     if ((ret = parse_node(encoder, node, enc_end)) == WBXML_OK)
730         encoder->pre_last_node_len = prev_len;
731 
732     return ret;
733 }
734 
735 
wbxml_encoder_encode_tree(WBXMLEncoder * encoder,WBXMLTree * tree)736 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_tree(WBXMLEncoder *encoder, WBXMLTree *tree)
737 {
738     const WBXMLLangEntry *lang = NULL;
739     WBXMLError            ret  = WBXML_OK;
740 
741     if ((encoder == NULL) || (tree == NULL))
742         return WBXML_ERROR_BAD_PARAMETER;
743 
744     /* Backup encoder lang */
745     lang = encoder->lang;
746 
747     /* Set Tree lang to encoder */
748     encoder->lang = tree->lang;
749 
750     /* Encode root node */
751     ret = wbxml_encoder_encode_node(encoder, tree->root);
752 
753     /* Revert encoder lang */
754     encoder->lang = lang;
755 
756     return ret;
757 }
758 
759 
wbxml_encoder_encode_raw_elt_start(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL has_content)760 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_raw_elt_start(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content)
761 {
762     /* Init Output Buffer if needed */
763     if (!encoder_init_output(encoder))
764         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
765 
766     return parse_element(encoder, node, has_content);
767 }
768 
769 
wbxml_encoder_encode_raw_elt_end(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL has_content)770 WBXML_DECLARE(WBXMLError) wbxml_encoder_encode_raw_elt_end(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content)
771 {
772     /* Init Output Buffer if needed */
773     if (!encoder_init_output(encoder))
774         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
775 
776     return parse_element_end(encoder, node, has_content);
777 }
778 
779 
wbxml_encoder_get_output(WBXMLEncoder * encoder,WB_UTINY ** result,WB_ULONG * result_len)780 WBXML_DECLARE(WBXMLError) wbxml_encoder_get_output(WBXMLEncoder *encoder, WB_UTINY **result, WB_ULONG *result_len)
781 {
782     if ((encoder == NULL) || (result == NULL) || (result_len == NULL))
783         return WBXML_ERROR_BAD_PARAMETER;
784 
785     switch (encoder->output_type) {
786     case WBXML_ENCODER_OUTPUT_XML:
787         return xml_build_result(encoder, result, result_len);
788 
789     case WBXML_ENCODER_OUTPUT_WBXML:
790         return wbxml_build_result(encoder, result, result_len);
791 
792     default:
793         return WBXML_ERROR_BAD_PARAMETER;
794     }
795 }
796 
797 
wbxml_encoder_get_output_len(WBXMLEncoder * encoder)798 WBXML_DECLARE(WB_ULONG) wbxml_encoder_get_output_len(WBXMLEncoder *encoder)
799 {
800     if (encoder == NULL)
801         return 0;
802 
803     return wbxml_buffer_len(encoder->output_header) + wbxml_buffer_len(encoder->output);
804 }
805 
806 
wbxml_encoder_delete_output_bytes(WBXMLEncoder * encoder,WB_ULONG nb)807 WBXML_DECLARE(void) wbxml_encoder_delete_output_bytes(WBXMLEncoder *encoder, WB_ULONG nb)
808 {
809     if (encoder == NULL)
810         return;
811 
812     wbxml_buffer_delete(encoder->output, wbxml_buffer_len(encoder->output) - nb, nb);
813 }
814 
815 
wbxml_encoder_delete_last_node(WBXMLEncoder * encoder)816 WBXML_DECLARE(void) wbxml_encoder_delete_last_node(WBXMLEncoder *encoder)
817 {
818     if (encoder == NULL)
819         return;
820 
821     wbxml_encoder_delete_output_bytes(encoder, wbxml_buffer_len(encoder->output) - encoder->pre_last_node_len);
822 }
823 
824 
825 /***************************************************
826  *    Private Functions
827  */
828 
829 /****************************
830  * Common Functions
831  */
832 
833 #if 0
834 /**
835  * @brief Convert a char to UCS-4
836  * @param ch [in] The character to convert
837  * @param result [out] The UCS-4 code
838  * @return TRUE if convertion succeeded, FALSE otherwise
839  */
840 static WB_BOOL convert_char_to_ucs4(WB_UTINY ch, WB_ULONG *result)
841 {
842     /** @todo convert_char_to_ucs4() */
843 
844     return FALSE;
845 }
846 #endif /* 0 */
847 
848 /**
849  * @brief Duplicate a WBXML Encoder
850  * @param encoder [in] The WBXML Encoder to Duplicate
851  * @return The duplicated WBXML Encoder, or NULL if error
852  * @note Only options (parameters) fields are duplicated, others are reset
853  */
encoder_duplicate(WBXMLEncoder * encoder)854 static WBXMLEncoder *encoder_duplicate(WBXMLEncoder *encoder)
855 {
856     WBXMLEncoder *result = NULL;
857 
858     if ((result = wbxml_encoder_create()) == NULL)
859         return NULL;
860 
861     result->ignore_empty_text = encoder->ignore_empty_text;
862     result->remove_text_blanks = encoder->remove_text_blanks;
863 
864     result->output_type = encoder->output_type;
865     result->xml_gen_type = encoder->xml_gen_type;
866 
867     result->indent_delta = encoder->indent_delta;
868     result->indent = encoder->indent;
869 
870 #if defined( WBXML_ENCODER_USE_STRTBL )
871     result->use_strtbl = encoder->use_strtbl;
872 #endif /* WBXML_ENCODER_USE_STRTBL */
873 
874     /* Do NOT generate XML Header */
875     result->xml_encode_header = FALSE;
876 
877     result->wbxml_version = encoder->wbxml_version;
878 
879     return result;
880 }
881 
882 
encoder_encode_tree(WBXMLEncoder * encoder)883 static WBXMLError encoder_encode_tree(WBXMLEncoder *encoder)
884 {
885     WBXMLError ret = WBXML_OK;
886 
887     /* Check Parameters */
888     if ((encoder == NULL) || (encoder->tree == NULL) || ((encoder->lang == NULL) && (encoder->tree->lang == NULL)) ||
889         ((encoder->output_type != WBXML_ENCODER_OUTPUT_XML) && (encoder->output_type != WBXML_ENCODER_OUTPUT_WBXML)))
890     {
891         return WBXML_ERROR_BAD_PARAMETER;
892     }
893 
894     if (encoder->lang == NULL)
895         encoder->lang = encoder->tree->lang;
896 
897     /* Choose Output Charset */
898     if (encoder->output_charset == WBXML_CHARSET_UNKNOWN) {
899         /* User has not choosen the Output Charset Encoding */
900         if (encoder->tree->orig_charset != WBXML_CHARSET_UNKNOWN) {
901             /* Use the original Charset Encoding found when we have parsed the original document */
902             encoder->output_charset = encoder->tree->orig_charset;
903         }
904         else {
905             /* Use default charset */
906             encoder->output_charset = WBXML_ENCODER_XML_DEFAULT_CHARSET;
907         }
908     }
909 
910     /* Init Output Buffer */
911     if (!encoder_init_output(encoder)) {
912         wbxml_encoder_destroy(encoder);
913         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
914     }
915 
916 #if defined( WBXML_ENCODER_USE_STRTBL )
917 
918     if (encoder->output_type == WBXML_ENCODER_OUTPUT_WBXML) {
919         /* Choose if we will use String Table */
920         switch (encoder->lang->langID)
921         {
922     #if defined( WBXML_SUPPORT_WV )
923         /* Wireless-Village CSP 1.1 / 1.2: content can be tokenized, so we mustn't interfere with String Table stuff */
924         case WBXML_LANG_WV_CSP11:
925         case WBXML_LANG_WV_CSP12:
926             encoder->use_strtbl = FALSE;
927             break;
928     #endif /* WBXML_SUPPORT_WV */
929 
930     #if defined( WBXML_SUPPORT_OTA_SETTINGS )
931         /* Nokia Ericsson OTA Settings : string tables are not supported */
932         case WBXML_LANG_OTA_SETTINGS:
933             encoder->use_strtbl = FALSE;
934             break;
935     #endif /* WBXML_SUPPORT_OTA_SETTINGS */
936 
937         default:
938             /* Use Default Value */
939             break;
940         }
941 
942         /* Init String Table */
943         if (encoder->use_strtbl) {
944             /**
945              * @bug If 'output_charset' is different from UTF-8, the string table initialization
946              *      also is erroneous !!!
947              */
948             if ((ret = wbxml_strtbl_initialize(encoder, encoder->tree->root)) != WBXML_OK)
949                 return ret;
950         }
951     }
952 
953 #endif /* WBXML_ENCODER_USE_STRTBL */
954 
955     /* Let's begin WBXML Tree Parsing */
956     return parse_node(encoder, encoder->tree->root, TRUE);
957 }
958 
959 
encoder_init_output(WBXMLEncoder * encoder)960 static WB_BOOL encoder_init_output(WBXMLEncoder *encoder)
961 {
962     WB_ULONG malloc_block = 0;
963 
964     if (encoder == NULL)
965         return FALSE;
966 
967     /* Check if output already inited */
968     if (encoder->output != NULL)
969         return TRUE;
970 
971     /* Get malloc block */
972     if (encoder->output_type == WBXML_ENCODER_OUTPUT_WBXML)
973         malloc_block = WBXML_ENCODER_WBXML_DOC_MALLOC_BLOCK;
974     else
975         malloc_block = WBXML_ENCODER_XML_DOC_MALLOC_BLOCK;
976 
977     /* Init Output Buffer */
978     encoder->output = wbxml_buffer_create("", 0, malloc_block);
979     if (encoder->output == NULL)
980         return FALSE;
981 
982     return TRUE;
983 }
984 
985 
986 /*********************************
987  * WBXML Tree Parsing Functions
988  */
989 
990 /**
991  * @brief Parse an XML Node
992  * @param encoder The WBXML Encoder
993  * @param node    The node to parse
994  * @param enc_end If node is an element, do we encoded its end ?
995  * @return WBXML_OK if parsing is OK, an error code otherwise
996  * @note We have recurrency in this function
997  */
parse_node(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL enc_end)998 static WBXMLError parse_node(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL enc_end)
999 {
1000     WBXMLError ret = WBXML_OK;
1001 
1002     /* Set current node */
1003     encoder->current_node = node;
1004 
1005     /* Parse this node */
1006     switch (node->type) {
1007         case WBXML_TREE_ELEMENT_NODE:
1008             ret = parse_element(encoder, node, node->children != NULL);
1009             break;
1010         case WBXML_TREE_TEXT_NODE:
1011             ret = parse_text(encoder, node);
1012             break;
1013         case WBXML_TREE_CDATA_NODE:
1014             ret = parse_cdata(encoder);
1015             break;
1016         case WBXML_TREE_PI_NODE:
1017             ret = parse_pi(encoder, node);
1018             break;
1019         case WBXML_TREE_TREE_NODE:
1020             ret = parse_tree(encoder, node);
1021             break;
1022         default:
1023             return WBXML_ERROR_XML_NODE_NOT_ALLOWED;
1024     }
1025 
1026     if (ret != WBXML_OK)
1027         return ret;
1028 
1029     /* Check if node has children */
1030     if (node->children != NULL) {
1031         /* Parse Child */
1032         if ((ret = parse_node(encoder, node->children, TRUE)) != WBXML_OK)
1033             return ret;
1034     }
1035 
1036     /* Handle end of Element or CDATA section */
1037     switch (node->type) {
1038     case WBXML_TREE_ELEMENT_NODE:
1039         if (enc_end) {
1040             switch(encoder->output_type) {
1041             case WBXML_ENCODER_OUTPUT_XML:
1042 #if defined( WBXML_ENCODER_XML_GEN_EMPTY_ELT )
1043                 if (node->children != NULL) {
1044 #endif /* WBXML_ENCODER_XML_GEN_EMPTY_ELT */
1045 
1046                     /* Encode end tag */
1047                     if ((ret = xml_encode_end_tag(encoder, node)) != WBXML_OK)
1048                         return ret;
1049 
1050                     WBXML_DEBUG((WBXML_ENCODER, "End Element"));
1051 
1052 #if defined( WBXML_ENCODER_XML_GEN_EMPTY_ELT )
1053                 }
1054 #endif /* WBXML_ENCODER_XML_GEN_EMPTY_ELT */
1055                 break;
1056 
1057             case WBXML_ENCODER_OUTPUT_WBXML:
1058                 if (node->children != NULL) {
1059                     /* Add a WBXML End tag */
1060                     if ((ret = wbxml_encode_end(encoder)) != WBXML_OK)
1061                         return ret;
1062 
1063                     WBXML_DEBUG((WBXML_ENCODER, "End Element"));
1064                 }
1065                 break;
1066 
1067             default:
1068                 /* hu ? */
1069                 break;
1070             } /* switch */
1071         } /* if */
1072         break;
1073 
1074     case WBXML_TREE_CDATA_NODE:
1075         /* End of CDATA section */
1076         encoder->in_cdata = FALSE;
1077 
1078         WBXML_DEBUG((WBXML_ENCODER, "End CDATA"));
1079 
1080         switch(encoder->output_type) {
1081         case WBXML_ENCODER_OUTPUT_XML:
1082             /* Encode XML "End of CDATA section" */
1083             if ((ret = xml_encode_end_cdata(encoder)) != WBXML_OK)
1084                 return ret;
1085             break;
1086 
1087         case WBXML_ENCODER_OUTPUT_WBXML:
1088             if (encoder->cdata == NULL) {
1089                 /* Must never happen */
1090                 return WBXML_ERROR_INTERNAL;
1091             }
1092 
1093             /* Encode CDATA Buffer into Opaque */
1094             /* NOTE: A CDATA section is not necessarily opaque data.
1095              * NOTE: CDATA is only character data which can be NULL terminated.
1096              * NOTE: Nevertheless it is not wrong to handle it like opaque data.
1097              */
1098             if (wbxml_buffer_len(encoder->cdata) > 0) {
1099                 if ((ret = wbxml_encode_opaque(encoder, encoder->cdata)) != WBXML_OK)
1100                     return ret;
1101             }
1102 
1103             /* Reset CDATA Buffer */
1104             wbxml_buffer_destroy(encoder->cdata);
1105             encoder->cdata = NULL;
1106             break;
1107 
1108         default:
1109             /* hu ? */
1110             break;
1111         } /* switch */
1112         break;
1113 
1114     default:
1115         /* NOP */
1116         break;
1117     }
1118 
1119     /* Reset Current Tag and Current Node */
1120     encoder->current_tag = NULL;
1121     encoder->current_node = NULL;
1122 
1123     /* Parse next node */
1124     if (node->next != NULL)
1125         return parse_node(encoder, node->next, TRUE);
1126     else
1127         return WBXML_OK;
1128 }
1129 
1130 
1131 /**
1132  * @brief Parse an XML Element
1133  * @param encoder The WBXML Encoder
1134  * @param node The element to parse
1135  * @param has_content Does the element has content ?
1136  * @return WBXML_OK if parsing is OK, an error code otherwise
1137  */
parse_element(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL has_content)1138 static WBXMLError parse_element(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content)
1139 {
1140     WB_ULONG i = 0;
1141     WBXMLError ret = WBXML_OK;
1142     WBXMLAttribute *attr = NULL;
1143 
1144     WBXML_DEBUG((WBXML_ENCODER, "Element: <%s>", wbxml_tag_get_xml_name(node->name)));
1145 
1146     /* Encode: Element Name */
1147     switch (encoder->output_type) {
1148     case WBXML_ENCODER_OUTPUT_WBXML:
1149         if ((ret = wbxml_encode_tag(encoder, node, has_content)) != WBXML_OK)
1150             return ret;
1151         break;
1152 
1153     case WBXML_ENCODER_OUTPUT_XML:
1154         if ((ret = xml_encode_tag(encoder, node)) != WBXML_OK)
1155             return ret;
1156         break;
1157 
1158     default:
1159         return WBXML_ERROR_INTERNAL;
1160     }
1161 
1162     /** @todo Check handling of Namespaces */
1163 
1164     /** @todo For Canonical XML Output: Attributes MUST be sorted */
1165 
1166     /* Parse: Attributes List */
1167     if (node->attrs != NULL)
1168     {
1169         for (i = 0; i < wbxml_list_len(node->attrs); i++) {
1170             /* Parse: Attribute */
1171             attr = wbxml_list_get(node->attrs, i);
1172             if (attr == NULL)
1173             	return WBXML_ERROR_INTERNAL;
1174             if ((ret = parse_attribute(encoder, attr)) != WBXML_OK)
1175                 return ret;
1176         }
1177     }
1178 
1179     /* Encode: End of attributes */
1180     switch (encoder->output_type) {
1181     case WBXML_ENCODER_OUTPUT_WBXML:
1182         /** @todo Check if the attributes will really be tokenized. There can be ignored attributes, and so NO attribute
1183          *        tokenized at all.
1184          */
1185         if ((node->attrs != NULL) && (encoder->lang->attrTable != NULL) /** @todo Fast patch for SyncML (change this) */) {
1186             if ((ret = wbxml_encode_end(encoder)) != WBXML_OK)
1187                 return ret;
1188 
1189             WBXML_DEBUG((WBXML_ENCODER, "End Attributes"));
1190         }
1191         break;
1192 
1193     case WBXML_ENCODER_OUTPUT_XML:
1194         /* Encode end of attributes */
1195         if ((ret = xml_encode_end_attrs(encoder, node)) != WBXML_OK)
1196             return ret;
1197 
1198         WBXML_DEBUG((WBXML_ENCODER, "End Attributes"));
1199         break;
1200 
1201     default:
1202         return WBXML_ERROR_INTERNAL;
1203     }
1204 
1205     return WBXML_OK;
1206 }
1207 
1208 
1209 /**
1210  * @brief Parse an Element End
1211  * @param encoder The WBXML Encoder
1212  * @param node The element to parse
1213  * @param has_content Does the element has content ?
1214  * @return WBXML_OK if parsing is OK, an error code otherwise
1215  */
parse_element_end(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL has_content)1216 static WBXMLError parse_element_end(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content)
1217 {
1218     WBXMLError ret = WBXML_OK;
1219 
1220     if (encoder->output_type == WBXML_ENCODER_OUTPUT_XML) {
1221 #if defined( WBXML_ENCODER_XML_GEN_EMPTY_ELT )
1222         if (has_content) {
1223 #endif /* WBXML_ENCODER_XML_GEN_EMPTY_ELT */
1224 
1225             /* Encode end tag */
1226             ret = xml_encode_end_tag(encoder, node);
1227 
1228             WBXML_DEBUG((WBXML_ENCODER, "End Element"));
1229 
1230 #if defined( WBXML_ENCODER_XML_GEN_EMPTY_ELT )
1231         }
1232 #endif /* WBXML_ENCODER_XML_GEN_EMPTY_ELT */
1233     }
1234     else if (encoder->output_type == WBXML_ENCODER_OUTPUT_WBXML) {
1235         if (has_content) {
1236             /* Add a WBXML End tag */
1237             ret = wbxml_encode_end(encoder);
1238 
1239             WBXML_DEBUG((WBXML_ENCODER, "End Element"));
1240         }
1241     }
1242 
1243     return ret;
1244 }
1245 
1246 
1247 /**
1248  * @brief Parse an XML Attribute
1249  * @param encoder The WBXML Encoder
1250  * @param attribute The XML Attribute to parse
1251  * @return WBXML_OK if parsing is OK, an error code otherwise
1252  */
parse_attribute(WBXMLEncoder * encoder,WBXMLAttribute * attribute)1253 static WBXMLError parse_attribute(WBXMLEncoder *encoder, WBXMLAttribute *attribute)
1254 {
1255     if (encoder->lang == NULL)
1256         return WBXML_ERROR_LANG_TABLE_UNDEFINED;
1257 
1258     if (encoder->lang->attrTable == NULL)
1259         return WBXML_OK;
1260 
1261     /* Check that this attribute has a name */
1262     if (attribute->name == NULL)
1263         return WBXML_ERROR_XML_NULL_ATTR_NAME;
1264 
1265     WBXML_DEBUG((WBXML_ENCODER, "Attribute: %s = %s", wbxml_attribute_get_xml_name(attribute), wbxml_attribute_get_xml_value(attribute)));
1266 
1267     /* Encode: Attribute */
1268     switch (encoder->output_type) {
1269     case WBXML_ENCODER_OUTPUT_WBXML:
1270         return wbxml_encode_attr(encoder, attribute);
1271 
1272     case WBXML_ENCODER_OUTPUT_XML:
1273         return xml_encode_attr(encoder, attribute);
1274 
1275     default:
1276         return WBXML_ERROR_INTERNAL;
1277     }
1278 }
1279 
1280 
1281 /**
1282  * @brief Parse an XML Text
1283  * @param encoder The WBXML Encoder
1284  * @param node The text to parse
1285  * @return WBXML_OK if parsing is OK, an error code otherwise
1286  */
parse_text(WBXMLEncoder * encoder,WBXMLTreeNode * node)1287 static WBXMLError parse_text(WBXMLEncoder *encoder, WBXMLTreeNode *node)
1288 {
1289     WBXMLError ret = WBXML_OK;
1290 
1291     /* Some elements should be transferred as opaque data */
1292     if (encoder->output_type == WBXML_ENCODER_OUTPUT_WBXML &&
1293         encoder->current_tag != NULL &&
1294         encoder->current_tag->options & WBXML_TAG_OPTION_BINARY)
1295     {
1296         return wbxml_encode_opaque(encoder, node->content);
1297     }
1298 
1299     /* Do not modify text inside a CDATA section */
1300     /* Do not modify text inside a BINARY section */
1301     if (!encoder->in_cdata &&
1302         ! (encoder->current_tag != NULL && encoder->current_tag->options & WBXML_TAG_OPTION_BINARY)) {
1303         /* If Canonical Form: "Ignorable white space is considered significant and is treated equivalently to data" */
1304         if ((encoder->output_type != WBXML_ENCODER_OUTPUT_XML) || (encoder->xml_gen_type != WBXML_GEN_XML_CANONICAL)) {
1305             /* Ignore blank nodes */
1306             if ((encoder->ignore_empty_text) && (wbxml_buffer_contains_only_whitespaces(node->content)))
1307                 return WBXML_OK;
1308 
1309             /* Strip Blanks */
1310             if (encoder->remove_text_blanks)
1311                 wbxml_buffer_strip_blanks(node->content);
1312         }
1313     }
1314 
1315     WBXML_DEBUG((WBXML_ENCODER, "Text: <%s>", wbxml_buffer_get_cstr(node->content)));
1316 
1317     /* Encode Text */
1318     switch (encoder->output_type) {
1319     case WBXML_ENCODER_OUTPUT_WBXML:
1320         if (encoder->in_cdata) {
1321             if (encoder->cdata == NULL) {
1322                 /* Must never happen */
1323                 return WBXML_ERROR_INTERNAL;
1324             }
1325 
1326 #if defined( WBXML_SUPPORT_SYNCML )
1327 
1328             if ((encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML10) ||
1329                 (encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML11) ||
1330                 (encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML12))
1331             {
1332                 /** @todo We suppose that Opaque Data in SyncML messages can only be vCard or vCal documents. CHANGE THAT ! */
1333                 if (node->content != NULL) {
1334                     if (wbxml_buffer_get_cstr(node->content)[0] == 0x0a && wbxml_buffer_len(node->content) == 1) {
1335                         wbxml_buffer_insert_cstr(node->content, (WB_UTINY*) "\r", 0);
1336                     }
1337                 }
1338             }
1339 
1340 #endif /* WBXML_SUPPORT_SYNCML */
1341 
1342             /* Add text into CDATA Buffer */
1343             if (!wbxml_buffer_append(encoder->cdata, node->content))
1344                 return WBXML_ERROR_ENCODER_APPEND_DATA;
1345 
1346             return WBXML_OK;
1347         }
1348         else {
1349             /* Encode text */
1350             encoder->current_text_parent = node->parent;
1351             ret = wbxml_encode_value_element_buffer(encoder, wbxml_buffer_get_cstr(node->content), WBXML_VALUE_ELEMENT_CTX_CONTENT);
1352             encoder->current_text_parent = NULL;
1353             return ret;
1354         }
1355 
1356     case WBXML_ENCODER_OUTPUT_XML:
1357         return xml_encode_text(encoder, node);
1358 
1359     default:
1360         return WBXML_ERROR_INTERNAL;
1361     }
1362 }
1363 
1364 
1365 /**
1366  * @brief Parse an XML CDATA
1367  * @param encoder The WBXML Encoder
1368  * @return WBXML_OK if parsing is OK, an error code otherwise
1369  * @note There is no node parameter because the content is not
1370  *       handled by this function and CDATA has no "attributes".
1371  */
parse_cdata(WBXMLEncoder * encoder)1372 static WBXMLError parse_cdata(WBXMLEncoder *encoder)
1373 {
1374     WBXML_DEBUG((WBXML_ENCODER, "CDATA Begin"));
1375 
1376     /* Keep in mind that we are in a CDATA section */
1377     encoder->in_cdata = TRUE;
1378 
1379     /* Encode CDATA */
1380     switch (encoder->output_type) {
1381     case WBXML_ENCODER_OUTPUT_WBXML:
1382         if (encoder->cdata != NULL) {
1383             /* Must never happend */
1384             return WBXML_ERROR_INTERNAL;
1385         }
1386 
1387         /* Create a new CDATA Buffer */
1388         if ((encoder->cdata = wbxml_buffer_create("", 0, 0)) == NULL) {
1389             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1390         }
1391 
1392         return WBXML_OK;
1393     case WBXML_ENCODER_OUTPUT_XML:
1394         return xml_encode_cdata(encoder);
1395     default:
1396         return WBXML_ERROR_INTERNAL;
1397     }
1398 }
1399 
1400 
1401 /**
1402  * @brief Parse an XML PI
1403  * @param encoder The WBXML Encoder
1404  * @param node The PI to parse
1405  * @return WBXML_OK if parsing is OK, an error code otherwise
1406  */
parse_pi(WBXMLEncoder * encoder,WBXMLTreeNode * node)1407 static WBXMLError parse_pi(WBXMLEncoder *encoder, WBXMLTreeNode *node)
1408 {
1409     /** @todo parse_pi() */
1410 
1411     return WBXML_ERROR_NOT_IMPLEMENTED;
1412 }
1413 
1414 
1415 /**
1416  * @brief Parse a WBXML Tree
1417  * @param encoder The WBXML Encoder
1418  * @param node The WBXML Tree to parse
1419  * @return WBXML_OK if parsing is OK, an error code otherwise
1420  */
parse_tree(WBXMLEncoder * encoder,WBXMLTreeNode * node)1421 static WBXMLError parse_tree(WBXMLEncoder *encoder, WBXMLTreeNode *node)
1422 {
1423     switch (encoder->output_type) {
1424     case WBXML_ENCODER_OUTPUT_WBXML:
1425         return wbxml_encode_tree(encoder, node->tree);
1426     case WBXML_ENCODER_OUTPUT_XML:
1427         return xml_encode_tree(encoder, node->tree);
1428     default:
1429         return WBXML_ERROR_INTERNAL;
1430     }
1431 }
1432 
1433 
1434 /*****************************************
1435  *  WBXML Output Functions
1436  */
1437 
1438 /****************************
1439  * Build WBXML Result
1440  */
1441 
1442 /**
1443  * @brief Build WBXML Result
1444  * @param encoder [in] The WBXML Encoder
1445  * @param wbxml [out] Resulting WBXML document
1446  * @param wbxml_len [out] The resulting WBXML document length
1447  * @return WBXML_OK if built is OK, an error code otherwise
1448  * @note WBXML Header = version publicid charset length
1449  */
wbxml_build_result(WBXMLEncoder * encoder,WB_UTINY ** wbxml,WB_ULONG * wbxml_len)1450 static WBXMLError wbxml_build_result(WBXMLEncoder *encoder, WB_UTINY **wbxml, WB_ULONG *wbxml_len)
1451 {
1452     WBXMLBuffer *header = NULL;
1453     WBXMLError ret = WBXML_OK;
1454 
1455     if (encoder->flow_mode == TRUE) {
1456         /* Header already built */
1457         header = encoder->output_header;
1458     }
1459     else {
1460         /* Create WBXML Header buffer */
1461         if ((header = wbxml_buffer_create("", 0, WBXML_ENCODER_WBXML_HEADER_MALLOC_BLOCK)) == NULL)
1462             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1463 
1464         /* Fill Header Buffer */
1465         if ((ret = wbxml_fill_header(encoder, header)) != WBXML_OK) {
1466             wbxml_buffer_destroy(header);
1467             return ret;
1468         }
1469     }
1470 
1471     /* Result Buffer Length */
1472     *wbxml_len = wbxml_buffer_len(header) + wbxml_buffer_len(encoder->output);
1473 
1474     /* Create Result Buffer */
1475     *wbxml = wbxml_malloc(*wbxml_len * sizeof(WB_UTINY));
1476     if (*wbxml == NULL) {
1477         if (encoder->flow_mode == FALSE)
1478             wbxml_buffer_destroy(header);
1479 
1480         *wbxml_len = 0;
1481         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1482     }
1483 
1484     /* Copy WBXML Header */
1485     memcpy(*wbxml, wbxml_buffer_get_cstr(header), wbxml_buffer_len(header));
1486 
1487     /* Copy WBXML Buffer */
1488     memcpy(*wbxml + wbxml_buffer_len(header), wbxml_buffer_get_cstr(encoder->output), wbxml_buffer_len(encoder->output));
1489 
1490     if (encoder->flow_mode == FALSE)
1491         wbxml_buffer_destroy(header);
1492 
1493     return WBXML_OK;
1494 }
1495 
1496 
wbxml_fill_header(WBXMLEncoder * encoder,WBXMLBuffer * header)1497 static WBXMLError wbxml_fill_header(WBXMLEncoder *encoder, WBXMLBuffer *header)
1498 {
1499     WBXMLBuffer *pid = NULL;
1500     WB_ULONG public_id = 0, public_id_index = 0, strstbl_len = 0;
1501     WB_BOOL pi_in_strtbl = FALSE;
1502     WBXMLError ret = WBXML_OK;
1503 
1504 #if defined( WBXML_ENCODER_USE_STRTBL )
1505     WBXMLStringTableElement *elt = NULL;
1506     WB_BOOL added = FALSE;
1507 #endif /* WBXML_ENCODER_USE_STRTBL */
1508 
1509     if ((encoder == NULL) || (encoder->lang == NULL) || (encoder->lang->publicID == NULL) || (header == NULL))
1510         return WBXML_ERROR_BAD_PARAMETER;
1511 
1512 #if defined( WBXML_ENCODER_USE_STRTBL )
1513     strstbl_len = encoder->strstbl_len;
1514 #endif /* WBXML_ENCODER_USE_STRTBL */
1515 
1516     /* WBXML Public ID */
1517     public_id = encoder->lang->publicID->wbxmlPublicID;
1518 
1519     /* Encode WBXML Version */
1520     if (!wbxml_buffer_append_char(header, (WB_UTINY) encoder->wbxml_version))
1521         return WBXML_ERROR_ENCODER_APPEND_DATA;
1522 
1523     /* Prepare string table - adding Public ID */
1524     /* If WBXML Public Id is '0x01' (unknown), or we forced it, add the XML Public ID in the String Table */
1525     if ((encoder->textual_publicid || (public_id == WBXML_PUBLIC_ID_UNKNOWN)) &&
1526         !encoder->produce_anonymous)
1527     {
1528         if (encoder->lang->publicID->xmlPublicID != NULL)
1529         {
1530             if ((pid = wbxml_buffer_create(encoder->lang->publicID->xmlPublicID,
1531                                            WBXML_STRLEN(encoder->lang->publicID->xmlPublicID),
1532                                            WBXML_STRLEN(encoder->lang->publicID->xmlPublicID))) == NULL)
1533             {
1534                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1535             }
1536 
1537 #if defined( WBXML_ENCODER_USE_STRTBL )
1538             if (encoder->use_strtbl) {
1539                 if ((elt = wbxml_strtbl_element_create(pid, FALSE)) == NULL)
1540                 {
1541                     wbxml_buffer_destroy(pid);
1542                     return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1543                 }
1544 
1545                 if (!wbxml_strtbl_add_element(encoder,
1546                                               elt,
1547                                               &public_id_index,
1548                                               &added))
1549                 {
1550                     wbxml_strtbl_element_destroy(elt);
1551                     if (pid) wbxml_buffer_destroy(pid);
1552                     return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1553                 }
1554 
1555                 /* "added" means that pid was consumed by encoder.
1556                  * So never free pid if added is TRUE.
1557                  */
1558                 if (!added)
1559                     wbxml_strtbl_element_destroy(elt);
1560 
1561                 strstbl_len = encoder->strstbl_len;
1562             }
1563             else {
1564 #endif /* WBXML_ENCODER_USE_STRTBL */
1565                 /* Length of String Table is length of XML Public ID (plus the NULL char) */
1566                 strstbl_len = wbxml_buffer_len(pid) + 1;
1567 
1568                 /* There is only the XML Public ID in String Table */
1569                 public_id_index = 0;
1570 #if defined( WBXML_ENCODER_USE_STRTBL )
1571             }
1572 #endif /* WBXML_ENCODER_USE_STRTBL */
1573 
1574             pi_in_strtbl = TRUE;
1575         }
1576     }
1577 
1578     /* Encode Public ID */
1579     /* publicid = mb_u_int32 | ( zero index ) */
1580     if (pi_in_strtbl) {
1581         /* Encode XML Public ID String Table index */
1582         if (!wbxml_buffer_append_char(header, 0x00) ||
1583             !wbxml_buffer_append_mb_uint_32(header, public_id_index))
1584         {
1585             if (pid && !added) wbxml_buffer_destroy(pid);
1586             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1587         }
1588     }
1589     else {
1590         /* Encode WBXML Public ID */
1591         if (!wbxml_buffer_append_mb_uint_32(header, public_id))
1592         {
1593             return WBXML_ERROR_ENCODER_APPEND_DATA;
1594         }
1595     }
1596 
1597     /* Encode Charset (default: UTF-8) and String Table Length */
1598     /** @todo Handle correctly the charset */
1599     if (!wbxml_buffer_append_mb_uint_32(header, WBXML_ENCODER_DEFAULT_CHARSET) ||
1600         !wbxml_buffer_append_mb_uint_32(header, strstbl_len))
1601     {
1602         if (pid && !added) wbxml_buffer_destroy(pid);
1603         return WBXML_ERROR_ENCODER_APPEND_DATA;
1604     }
1605 
1606     /* Encode WBXML String Table */
1607 #if defined( WBXML_ENCODER_USE_STRTBL )
1608     if (encoder->use_strtbl) {
1609         if ((ret = wbxml_strtbl_construct(header,(WBXMLList *) encoder->strstbl)) != WBXML_OK)
1610         {
1611             if (pid && !added) wbxml_buffer_destroy(pid);
1612             return ret;
1613         }
1614     }
1615     else {
1616 #endif /* WBXML_ENCODER_USE_STRTBL */
1617 
1618         if (pid != NULL) {
1619             if (!wbxml_buffer_append(header, pid))
1620             {
1621                 wbxml_buffer_destroy(pid);
1622                 return WBXML_ERROR_ENCODER_APPEND_DATA;
1623             }
1624 
1625             if (!wbxml_buffer_append_char(header, WBXML_STR_END))
1626             {
1627                 wbxml_buffer_destroy(pid);
1628                 return WBXML_ERROR_ENCODER_APPEND_DATA;
1629             }
1630 
1631             /* Clean up */
1632             wbxml_buffer_destroy(pid);
1633             pid = NULL;
1634         }
1635 
1636 #if defined( WBXML_ENCODER_USE_STRTBL )
1637     }
1638     if (pid && !added) wbxml_buffer_destroy(pid);
1639 #endif /* WBXML_ENCODER_USE_STRTBL */
1640 
1641     return WBXML_OK;
1642 }
1643 
1644 
1645 /****************************
1646  * WBXML Encoding Functions
1647  */
1648 
1649 /**
1650  * @brief Encode a WBXML End Token
1651  * @param encoder The WBXML Encoder
1652  * @return WBXML_OK if encoding is OK, an error code otherwise
1653  */
wbxml_encode_end(WBXMLEncoder * encoder)1654 static WBXMLError wbxml_encode_end(WBXMLEncoder *encoder)
1655 {
1656     /* Append END */
1657     if (!wbxml_buffer_append_char(encoder->output, WBXML_END))
1658         return WBXML_ERROR_ENCODER_APPEND_DATA;
1659 
1660     return WBXML_OK;
1661 }
1662 
1663 
1664 /**
1665  * @brief Encode a WBXML Tag
1666  * @param encoder The WBXML Encoder
1667  * @param node The element to encode
1668  * @param has_content Does the element has content ?
1669  * @return WBXML_OK if encoding is OK, an error code otherwise
1670  */
wbxml_encode_tag(WBXMLEncoder * encoder,WBXMLTreeNode * node,WB_BOOL has_content)1671 static WBXMLError wbxml_encode_tag(WBXMLEncoder *encoder, WBXMLTreeNode *node, WB_BOOL has_content)
1672 {
1673     const WBXMLTagEntry *tag = NULL;
1674     WB_UTINY token = 0x00, page = 0x00;
1675 
1676     if (!node || !node->name) {
1677     	return WBXML_ERROR_UNKNOWN_TAG;
1678     }
1679     if (node->name->type == WBXML_VALUE_TOKEN) {
1680         token = node->name->u.token->wbxmlToken;
1681         page = node->name->u.token->wbxmlCodePage;
1682 
1683         /* Current Tag */
1684         encoder->current_tag = node->name->u.token;
1685     }
1686     else {
1687         /* Search tag in Tags Table */
1688         if ((tag = wbxml_tables_get_tag_from_xml(encoder->lang, encoder->tagCodePage, wbxml_tag_get_xml_name(node->name))) != NULL)
1689         {
1690             token = tag->wbxmlToken;
1691             page = tag->wbxmlCodePage;
1692 
1693             /* Current Tag */
1694             encoder->current_tag = tag;
1695         }
1696         else
1697             encoder->current_tag = NULL;
1698     }
1699 
1700     /* Check if this element has content */
1701     if (has_content)
1702         token |= WBXML_TOKEN_WITH_CONTENT;
1703 
1704     /* Check if this element has attributes */
1705     /** @todo Check if the attributes will really be tokenized. There can be ignored attributes, and so NO attribute
1706      *        tokenized at all.
1707      */
1708     if ((node->attrs != NULL) && (encoder->lang->attrTable != NULL) /** @todo Fast patch for SyncML (change this) */)
1709         token |= WBXML_TOKEN_WITH_ATTRS;
1710 
1711     /* Encode Token */
1712     if ((token & WBXML_TOKEN_MASK) == 0x00)
1713         return wbxml_encode_tag_literal(encoder, (WB_UTINY *) wbxml_tag_get_xml_name(node->name), token);
1714     else
1715         return wbxml_encode_tag_token(encoder, token, page);
1716 }
1717 
1718 
1719 /**
1720  * @brief Encode a WBXML Literal Token
1721  * @param encoder The WBXML Encoder
1722  * @param tag The literal tag to encode
1723  * @param mask The WBXML Mask for this tag
1724  * @return WBXML_OK if encoding is OK, an error code otherwise
1725  * @note    stag = (literalTag index)
1726  *          literalTag = LITERAL | LITERAL_A | LITERAL_C | LITERAL_AC
1727  *          index = mb_u_int32
1728  */
wbxml_encode_tag_literal(WBXMLEncoder * encoder,const WB_UTINY * tag,WB_UTINY mask)1729 static WBXMLError wbxml_encode_tag_literal(WBXMLEncoder *encoder, const WB_UTINY *tag, WB_UTINY mask)
1730 {
1731 #if defined( WBXML_ENCODER_USE_STRTBL )
1732     WBXMLStringTableElement *elt = NULL;
1733     WBXMLBuffer *buff = NULL;
1734     WB_ULONG index = 0;
1735     WB_BOOL added = FALSE;
1736 
1737     /* If String Table generation is disabled, we can't generate this Literal Tag */
1738     if (!encoder->use_strtbl)
1739         return WBXML_ERROR_STRTBL_DISABLED;
1740 
1741     /* Add tag in String Table */
1742     if (((buff = wbxml_buffer_create(tag, WBXML_STRLEN(tag), WBXML_STRLEN(tag))) == NULL) ||
1743         ((elt = wbxml_strtbl_element_create(buff, FALSE)) == NULL) ||
1744         (!wbxml_strtbl_add_element(encoder, elt, &index, &added)))
1745     {
1746         wbxml_strtbl_element_destroy(elt);
1747         wbxml_buffer_destroy(buff);
1748         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
1749     }
1750 
1751     /* If already exists in String Table: clean-up */
1752     if (!added)
1753         wbxml_strtbl_element_destroy(elt);
1754 
1755     /* Encode literalTag index */
1756     if ((!wbxml_buffer_append_char(encoder->output, (WB_UTINY) (WBXML_LITERAL | mask))) ||
1757         (!wbxml_buffer_append_mb_uint_32(encoder->output, index)))
1758     {
1759         return WBXML_ERROR_ENCODER_APPEND_DATA;
1760     }
1761 
1762     return WBXML_OK;
1763 #else
1764     /* No String Table Support */
1765     return WBXML_ERROR_STRTBL_DISABLED;
1766 #endif /* WBXML_ENCODER_USE_STRTBL */
1767 }
1768 
1769 
1770 /**
1771  * @brief Encode a WBXML Tag Token
1772  * @param encoder The WBXML Encoder
1773  * @param token The WBXML Tag Token to encode
1774  * @param page The WBXML CodePage for this Token
1775  * @return WBXML_OK if encoding is OK, an error code otherwise
1776  * @note    element = ([switchPage] stag)
1777  *          switchPage = SWITCH_PAGE pageindex
1778  *          stag = TAG
1779  *          pageindex = u_int8
1780  */
wbxml_encode_tag_token(WBXMLEncoder * encoder,WB_UTINY token,WB_UTINY page)1781 static WBXMLError wbxml_encode_tag_token(WBXMLEncoder *encoder, WB_UTINY token, WB_UTINY page)
1782 {
1783     /* Switch Page if needed */
1784     if (encoder->tagCodePage != page)
1785     {
1786         if ((!wbxml_buffer_append_char(encoder->output, WBXML_SWITCH_PAGE)) ||
1787             (!wbxml_buffer_append_char(encoder->output, page)))
1788         {
1789             return WBXML_ERROR_ENCODER_APPEND_DATA;
1790         }
1791 
1792         encoder->tagCodePage = page;
1793     }
1794 
1795     /* Add Token */
1796     if (!wbxml_buffer_append_char(encoder->output, token))
1797         return WBXML_ERROR_ENCODER_APPEND_DATA;
1798 
1799     return WBXML_OK;
1800 }
1801 
1802 
1803 /**
1804  * @brief Encode a WBXML Attribute
1805  * @param encoder [in] The WBXML Encoder
1806  * @param attribute [in] The Attribute to encode
1807  * @return WBXML_OK if encoding is OK, an error code otherwise
1808  * @note    attribute = attrStart *attrValue
1809  */
wbxml_encode_attr(WBXMLEncoder * encoder,WBXMLAttribute * attribute)1810 static WBXMLError wbxml_encode_attr(WBXMLEncoder *encoder, WBXMLAttribute *attribute)
1811 {
1812     WB_UTINY *value = NULL;
1813     WBXMLError ret = WBXML_OK;
1814 
1815     /* Encode Attribute Start */
1816     if ((ret = wbxml_encode_attr_start(encoder, attribute, &value)) != WBXML_OK)
1817         return ret;
1818 
1819     /* Encode Attribute Value */
1820     if (value != NULL) {
1821         if ((ret = wbxml_encode_value_element_buffer(encoder, value, WBXML_VALUE_ELEMENT_CTX_ATTR)) != WBXML_OK)
1822             return ret;
1823     }
1824 
1825     /* Reset Current Attribute */
1826     encoder->current_attr = NULL;
1827 
1828     return WBXML_OK;
1829 }
1830 
1831 
1832 /**
1833  * @brief Encode a WBXML Attribute Start
1834  * @param encoder [in] The WBXML Encoder
1835  * @param attribute [in] The Attribute
1836  * @param value [out] Pointer to the value to encode
1837  * @return WBXML_OK if encoding is OK, an error code otherwise
1838  * @note The 'value' result correspond to the value there is still to encode
1839  *       For example, in Wireless-Village, to encode:
1840  *              xmlns="http://www.wireless-village.org/CSP1.1"
1841  *       We first encode:
1842  *              xmlns="http://www.wireless-village.org/CSP (start token: 0x05)
1843  *       Then:
1844  *              "1.1" as an inline string
1845  */
wbxml_encode_attr_start(WBXMLEncoder * encoder,WBXMLAttribute * attribute,WB_UTINY ** value)1846 static WBXMLError wbxml_encode_attr_start(WBXMLEncoder *encoder, WBXMLAttribute *attribute, WB_UTINY **value)
1847 {
1848     const WBXMLAttrEntry *attr = NULL;
1849     WB_UTINY *value_left = NULL;
1850     WB_UTINY token = 0x00, page = 0x00;
1851 
1852     *value = wbxml_buffer_get_cstr(attribute->value);
1853 
1854     if (attribute->name->type == WBXML_VALUE_TOKEN) {
1855         /* We already have Token / Page pair for this Attribute Start */
1856         token = attribute->name->u.token->wbxmlToken;
1857         page = attribute->name->u.token->wbxmlCodePage;
1858 
1859         /* Current Attribute */
1860         encoder->current_attr = attribute->name->u.token;
1861 
1862         /* If there is a Start Value associated to the Attribute Name token... */
1863         if (attribute->name->u.token->xmlValue != NULL)
1864         {
1865             /* ... Check that we have it at start of full Attribute Value */
1866             if (WBXML_STRNCMP(wbxml_buffer_get_cstr(attribute->value),
1867                               attribute->name->u.token->xmlValue,
1868                               WBXML_STRLEN(attribute->name->u.token->xmlValue)) == 0)
1869             {
1870                 /* Check if you have still a part in the Attribute Value to encode */
1871                 if (wbxml_buffer_len(attribute->value) > WBXML_STRLEN(attribute->name->u.token->xmlValue))
1872                 {
1873                     /* There is still a part in the Value to encode */
1874                     *value = wbxml_buffer_get_cstr(attribute->value) + WBXML_STRLEN(attribute->name->u.token->xmlValue);
1875                 }
1876                 else
1877                     *value = NULL;
1878             }
1879             else {
1880                 /** @todo Should we stop everything and generate an error ? */
1881                 WBXML_WARNING((WBXML_ENCODER, "wbxml_encode_attr_start() => Attribute Value doesn't match Attribute Token"));
1882 
1883                 /* Current Attribute */
1884                 encoder->current_attr = NULL;
1885 
1886                 /* Encode Attribute Literal */
1887                 return wbxml_encode_attr_start_literal(encoder, wbxml_attribute_get_xml_name(attribute));
1888             }
1889         }
1890 
1891         /* Encode Attribute Token */
1892         return wbxml_encode_attr_token(encoder, token, page);
1893     }
1894     else {
1895         /* Search in Attribute table */
1896         if ((attr = wbxml_tables_get_attr_from_xml(encoder->lang,
1897                                                    (WB_UTINY *)attribute->name->u.token->xmlName,
1898                                                    wbxml_buffer_get_cstr(attribute->value),
1899                                                    &value_left)) != NULL)
1900         {
1901             token = attr->wbxmlToken;
1902             page = attr->wbxmlCodePage;
1903 
1904             /* Current Attribute */
1905             encoder->current_attr = attr;
1906 
1907             /* If there is still a part in Attribute Value to encode */
1908             *value = value_left;
1909 
1910             /* Encode Attribute Token */
1911             return wbxml_encode_attr_token(encoder, token, page);
1912         }
1913         else {
1914             /* Current Attribute */
1915             encoder->current_attr = NULL;
1916 
1917             /* Encode Attribute Literal */
1918             return wbxml_encode_attr_start_literal(encoder, wbxml_attribute_get_xml_name(attribute));
1919         }
1920     }
1921 }
1922 
1923 
1924 /**
1925  * @brief Encode a WBXML Attribute Value
1926  * @param encoder The WBXML Encoder
1927  * @param buffer The Value Element Buffer to encode
1928  * @param ctx Value Element Context (Attribute Value or Content)
1929  * @return WBXML_OK if encoding is OK, an error code otherwise
1930  * @note    attrStart = *attrValue
1931  *          attrValue = string | extension | entity | opaque
1932  *
1933  *   AND:   element = *content
1934  *          content = string | extension | entity | opaque
1935  */
wbxml_encode_value_element_buffer(WBXMLEncoder * encoder,WB_UTINY * buffer,WBXMLValueElementCtx ctx)1936 static WBXMLError wbxml_encode_value_element_buffer(WBXMLEncoder *encoder, WB_UTINY *buffer, WBXMLValueElementCtx ctx)
1937 {
1938     WBXMLList *lresult = NULL;
1939     WBXMLBuffer *buff = NULL;
1940     WBXMLValueElement *elt = NULL, *new_elt = NULL;
1941     WB_ULONG i = 0, j = 0, index = 0;
1942     WB_UTINY *the_buffer = buffer;
1943     WBXMLError ret = WBXML_OK;
1944 
1945 #if defined( WBXML_ENCODER_USE_STRTBL )
1946     WBXMLStringTableElement *strtbl_elt = NULL;
1947 #endif /* WBXML_ENCODER_USE_STRTBL */
1948 
1949     if ((buffer == NULL) || (*buffer == '\0'))
1950         return WBXML_OK;
1951 
1952 
1953     /*********************************************************
1954      *  Encoder Language Specific Attribute Values
1955      */
1956 
1957     if (ctx == WBXML_VALUE_ELEMENT_CTX_ATTR) {
1958         switch (encoder->lang->langID) {
1959 #if defined( WBXML_SUPPORT_SI )
1960         case WBXML_LANG_SI10:
1961             /* SI 1.0: Encode date for 'created' and 'si-expires' attributes */
1962             if (encoder->current_attr == NULL)
1963                 break;
1964 
1965             if ((encoder->current_attr->wbxmlCodePage == 0x00) &&
1966                 ((encoder->current_attr->wbxmlToken == 0x0a) || (encoder->current_attr->wbxmlToken == 0x10)))
1967             {
1968                 return wbxml_encode_datetime(encoder, buffer);
1969             }
1970             break;
1971 #endif /* WBXML_SUPPORT_SI */
1972 
1973 #if defined( WBXML_SUPPORT_EMN )
1974         case WBXML_LANG_EMN10:
1975             /* EMN 1.0: Encode date for 'timestamp' attribute */
1976             if (encoder->current_attr == NULL)
1977                 break;
1978 
1979             if ((encoder->current_attr->wbxmlCodePage == 0x00) && (encoder->current_attr->wbxmlToken == 0x05))
1980             {
1981                 return wbxml_encode_datetime(encoder, buffer);
1982             }
1983             break;
1984 #endif /* WBXML_SUPPORT_EMN */
1985 
1986 #if defined( WBXML_SUPPORT_OTA_SETTINGS )
1987         case WBXML_LANG_OTA_SETTINGS:
1988             /**
1989              * Nokia OTA Settings support for the ICON value in bookmarks.
1990              * The encoding is done using base64 encoded images in XML, and encoding it as OPAQUE data in the WBXML.
1991              * The icon is embedded using an PARM element with name ICON.
1992              */
1993             if ((encoder->current_attr->wbxmlCodePage == 0x00) &&
1994                 (encoder->current_attr->wbxmlToken == 0x11))
1995             {
1996                 if ((ret = wbxml_encode_ota_nokia_icon(encoder, buffer)) != WBXML_NOT_ENCODED)
1997                     return ret;
1998             }
1999             break;
2000 #endif /* WBXML_SUPPORT_OTA_SETTINGS */
2001 
2002         default:
2003             break;
2004         }
2005     }
2006 
2007 
2008     /*********************************************************
2009      *  Encoder Language Specific Content Text Values
2010      */
2011 
2012     /* If this is a Text Content (not in a CDATA section) */
2013     if ((ctx == WBXML_VALUE_ELEMENT_CTX_CONTENT) && (!encoder->in_cdata))
2014     {
2015 #if defined( WBXML_SUPPORT_WV )
2016         /* If this is a Wireless-Village 1.1 / 1.2 document */
2017         if ((encoder->lang->langID == WBXML_LANG_WV_CSP11) ||
2018             (encoder->lang->langID == WBXML_LANG_WV_CSP12))
2019         {
2020             /* Here we try to encode Specific WV Content. If this buffer is not a WV Data Type buffer, or
2021              * if it can't be FULLY encoded as an Extension Token, then this function returns WBXML_NOT_ENCODED.
2022              * If so, the buffer will be encoded as String latter.
2023              */
2024             if ((ret = wbxml_encode_wv_content(encoder, buffer)) != WBXML_NOT_ENCODED)
2025                 return ret;
2026         }
2027 #endif /* WBXML_SUPPORT_WV */
2028 
2029 #if defined( WBXML_SUPPORT_DRMREL )
2030         /* If this is a DRMREL 1.0 document */
2031         if (encoder->lang->langID == WBXML_LANG_DRMREL10)
2032         {
2033             /* Here we try to encode Specific DRMREL Content. If this buffer is not a DRMREL Data Type buffer
2034              * this function returns WBXML_NOT_ENCODED.
2035              * If so, the buffer will be encoded as String latter.
2036              */
2037             if ((ret = wbxml_encode_drmrel_content(encoder, buffer)) != WBXML_NOT_ENCODED)
2038                 return ret;
2039         }
2040 #endif /* WBXML_SUPPORT_DRMREL */
2041 
2042 #if defined( WBXML_SUPPORT_SYNCML )
2043         /* If this is a SyncML document ? */
2044         if ((encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML10) ||
2045             (encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML11) ||
2046             (encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML12))
2047         {
2048             /** @todo We must check too if we are in a <Type> */
2049 
2050             /* Change text in <Type> from "application/vnd.syncml-devinf+xml" to "application/vnd.syncml-devinf+wbxml" */
2051             if (WBXML_STRCASECMP(buffer, "application/vnd.syncml-devinf+xml") == 0) {
2052                 the_buffer = (WB_UTINY*) "application/vnd.syncml-devinf+wbxml";
2053             }
2054             /* Change text in <Type> from "application/vnd.syncml.dmtnds+xml" to "application/vnd.syncml.dmtnds+wbxml" */
2055             if (WBXML_STRCASECMP(buffer, "application/vnd.syncml.dmtnds+xml") == 0) {
2056                 the_buffer = (WB_UTINY*) "application/vnd.syncml.dmtnds+wbxml";
2057             }
2058         }
2059 #endif /* WBXML_SUPPORT_SYNCML */
2060     }
2061 
2062 
2063     /*********************************************************
2064      * @todo Search first for simple cases !
2065      */
2066 
2067 
2068     /*********************************************************
2069      *  We search the list of Value Elements that represents
2070      *  this Value buffer
2071      */
2072 
2073     /* Create Result List */
2074     if ((lresult = wbxml_list_create()) == NULL)
2075         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2076 
2077     /* Create primary Buffer */
2078     if ((buff = wbxml_buffer_create_from_cstr(the_buffer)) == NULL) {
2079         wbxml_list_destroy(lresult, NULL);
2080         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2081     }
2082 
2083     /* Create Value Element for this buffer */
2084     if ((elt = wbxml_value_element_create()) == NULL) {
2085         wbxml_buffer_destroy(buff);
2086         wbxml_list_destroy(lresult, NULL);
2087         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2088     }
2089 
2090     elt->type = WBXML_VALUE_ELEMENT_STRING;
2091     elt->u.str = buff;
2092 
2093     /* Append this Buffer to Result List */
2094     if (!wbxml_list_append(lresult, elt)) {
2095         wbxml_value_element_destroy(elt);
2096         wbxml_list_destroy(lresult, NULL);
2097         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2098     }
2099 
2100     /* If this is an Attribute Value */
2101     if (ctx == WBXML_VALUE_ELEMENT_CTX_ATTR)
2102     {
2103         /*********************************************************
2104          *  Search for Attribute Value Tokens
2105          */
2106 
2107         if (encoder->lang->attrValueTable != NULL) {
2108             /* For each Attribute Value Token */
2109             j = 0;
2110             while (encoder->lang->attrValueTable[j].xmlName != NULL)
2111             {
2112                 /* For each Value Element */
2113                 for (i = 0; i < wbxml_list_len(lresult); i++) {
2114                     if ((elt = (WBXMLValueElement *) wbxml_list_get(lresult, i)) == NULL)
2115                         continue;
2116 
2117                     if (elt->type != WBXML_VALUE_ELEMENT_STRING)
2118                         continue;
2119 
2120                     /* Is this Attribute Value contained in this Buffer ? */
2121                     if (wbxml_buffer_search_cstr(elt->u.str, (WB_UTINY *)encoder->lang->attrValueTable[j].xmlName, 0, &index)) {
2122                         /* Create new Value Element */
2123                         if ((new_elt = wbxml_value_element_create()) == NULL) {
2124                             wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2125                             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2126                         }
2127 
2128                         new_elt->type = WBXML_VALUE_ELEMENT_ATTR_TOKEN;
2129                         new_elt->u.attr = &(encoder->lang->attrValueTable[j]);
2130 
2131                         /* Insert new Value Element in List */
2132                         if (!wbxml_list_insert(lresult, (void *) new_elt, i + 1)) {
2133                             wbxml_value_element_destroy(new_elt);
2134                             wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2135                             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2136                         }
2137 
2138                         /* Check if there is still the end of the String to encode */
2139                         if (index + WBXML_STRLEN(encoder->lang->attrValueTable[j].xmlName) < wbxml_buffer_len(elt->u.str)) {
2140                             /* Create new Value Element */
2141                             if ((new_elt = wbxml_value_element_create()) == NULL) {
2142                                 wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2143                                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2144                             }
2145 
2146                             new_elt->type = WBXML_VALUE_ELEMENT_STRING;
2147                             new_elt->u.str = wbxml_buffer_create_from_cstr(wbxml_buffer_get_cstr(elt->u.str) + index + WBXML_STRLEN(encoder->lang->attrValueTable[j].xmlName));
2148 
2149                             /* Insert new Value Element in List */
2150                             if ((new_elt->u.str == NULL) ||
2151                                 !wbxml_list_insert(lresult, (void *) new_elt, i + 2))
2152                             {
2153                                 wbxml_value_element_destroy(new_elt);
2154                                 wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2155                                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2156                             }
2157                         }
2158 
2159                         /* Remove the Attribute Value found in Value Element */
2160                         wbxml_buffer_delete(elt->u.str, index, wbxml_buffer_len(elt->u.str) - index);
2161                     } /* if */
2162                 } /* for */
2163                 j++;
2164             } /* while */
2165         } /* if */
2166     }
2167 
2168     /* If this is a Text Content (not in a CDATA section) */
2169     if ((ctx == WBXML_VALUE_ELEMENT_CTX_CONTENT) && (!encoder->in_cdata))
2170     {
2171         /*********************************************************
2172          *  Search for Extension Tokens
2173          */
2174 
2175         /** @todo Finish Extension Tokens Search */
2176 
2177         if (encoder->lang->extValueTable != NULL) {
2178             /* For each Extension Token */
2179             j = 0;
2180             while (encoder->lang->extValueTable[j].xmlName != NULL)
2181             {
2182                 /* For each Value Element */
2183                 for (i = 0; i < wbxml_list_len(lresult); i++) {
2184                     if ((elt = (WBXMLValueElement *) wbxml_list_get(lresult, i)) == NULL)
2185                         continue;
2186 
2187                     if (elt->type != WBXML_VALUE_ELEMENT_STRING)
2188                         continue;
2189 
2190                     /* Ignores the "1 char Extension Tokens" */
2191                     if (WBXML_STRLEN(encoder->lang->extValueTable[j].xmlName) < 2)
2192                         continue;
2193 
2194                     /* Is this Extension Token contained in this Buffer ?
2195 		     *
2196 		     * The Extension Token must start at the beginning of
2197 		     * the buffer. Otherwise we can damage normal text
2198 		     * entities like 'My IM-application.' If 'IM' is an
2199 		     * Extension Token.
2200 		     *
2201 		     * Assumption: The buffer is already normalized.
2202 		     */
2203                     if (wbxml_buffer_compare_cstr(elt->u.str, (WB_TINY *) encoder->lang->extValueTable[j].xmlName) == 0)
2204                     {
2205                         /* Create new Value Element */
2206                         if ((new_elt = wbxml_value_element_create()) == NULL) {
2207                             wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2208                             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2209                         }
2210 
2211                         new_elt->type = WBXML_VALUE_ELEMENT_EXTENSION;
2212                         new_elt->u.ext = &(encoder->lang->extValueTable[j]);
2213 
2214                         /* Insert new Value Element in List */
2215                         if (!wbxml_list_insert(lresult, (void *) new_elt, i + 1)) {
2216                             wbxml_value_element_destroy(new_elt);
2217                             wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2218                             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2219                         }
2220 
2221                         /* Check if there is still the end of the String to encode */
2222                         if (index + WBXML_STRLEN(encoder->lang->extValueTable[j].xmlName) < wbxml_buffer_len(elt->u.str)) {
2223                             /* Create new Value Element */
2224                             if ((new_elt = wbxml_value_element_create()) == NULL) {
2225                                 wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2226                                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2227                             }
2228 
2229                             new_elt->type = WBXML_VALUE_ELEMENT_STRING;
2230                             new_elt->u.str = wbxml_buffer_create_from_cstr(wbxml_buffer_get_cstr(elt->u.str) + index + WBXML_STRLEN(encoder->lang->extValueTable[j].xmlName));
2231 
2232                             /* Insert new Value Element in List */
2233                             if ((new_elt->u.str == NULL) ||
2234                                 !wbxml_list_insert(lresult, (void *) new_elt, i + 2))
2235                             {
2236                                 wbxml_value_element_destroy(new_elt);
2237                                 wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2238                                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2239                             }
2240                         }
2241 
2242                         /* Remove the Attribute Value found in Value Element */
2243                         wbxml_buffer_delete(elt->u.str, index, wbxml_buffer_len(elt->u.str) - index);
2244                     } /* if */
2245                 } /* for */
2246                 j++;
2247             } /* while */
2248         } /* if */
2249     }
2250 
2251 
2252 #if defined( WBXML_ENCODER_USE_STRTBL )
2253 
2254     /***********************************************************************
2255      *  Search for String Table References
2256      *  (except if this is a Content string and we are in a CDATA section)
2257      */
2258 
2259     if (encoder->use_strtbl && !(encoder->in_cdata && (ctx == WBXML_VALUE_ELEMENT_CTX_CONTENT))) {
2260         /* For each String Table Element */
2261         for (j = 0; j < wbxml_list_len(encoder->strstbl); j++) {
2262             if ((strtbl_elt = (WBXMLStringTableElement *) wbxml_list_get(encoder->strstbl, j)) == NULL)
2263                 continue;
2264 
2265             /* For each Value Element */
2266             for (i = 0; i < wbxml_list_len(lresult); i++) {
2267                 if ((elt = (WBXMLValueElement *) wbxml_list_get(lresult, i)) == NULL)
2268                     continue;
2269 
2270                 if (elt->type != WBXML_VALUE_ELEMENT_STRING)
2271                     continue;
2272 
2273                 /* Is the String Table Element contained in this Buffer ? */
2274                 if (wbxml_buffer_search(elt->u.str, strtbl_elt->string, 0, &index)) {
2275                     /* Create new Value Element */
2276                     if ((new_elt = wbxml_value_element_create()) == NULL) {
2277                         wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2278                         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2279                     }
2280 
2281                     new_elt->type = WBXML_VALUE_ELEMENT_TABLEREF;
2282                     new_elt->u.index = strtbl_elt->offset;
2283 
2284                     /* Insert new Value Element in List */
2285                     if (!wbxml_list_insert(lresult, (void *) new_elt, i + 1)) {
2286                         wbxml_value_element_destroy(new_elt);
2287                         wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2288                         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2289                     }
2290 
2291                     /* Check if there is still the end of the String to encode */
2292                     if (index + wbxml_buffer_len(strtbl_elt->string) < wbxml_buffer_len(elt->u.str)) {
2293                         /* Create new Value Element */
2294                         if ((new_elt = wbxml_value_element_create()) == NULL) {
2295                             wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2296                             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2297                         }
2298 
2299                         new_elt->type = WBXML_VALUE_ELEMENT_STRING;
2300                         new_elt->u.str = wbxml_buffer_create_from_cstr(wbxml_buffer_get_cstr(elt->u.str) + index + wbxml_buffer_len(strtbl_elt->string));
2301 
2302                         /* Insert new Value Element in List */
2303                         if ((new_elt->u.str == NULL) ||
2304                             !wbxml_list_insert(lresult, (void *) new_elt, i + 2))
2305                         {
2306                             wbxml_value_element_destroy(new_elt);
2307                             wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2308                             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2309                         }
2310                     }
2311 
2312                     /* Remove the Attribute Value found in Value Element */
2313                     wbxml_buffer_delete(elt->u.str, index, wbxml_buffer_len(elt->u.str) - index);
2314                 } /* if */
2315             } /* for */
2316         } /* for */
2317     } /* if */
2318 
2319 #endif /* WBXML_ENCODER_USE_STRTBL */
2320 
2321 
2322     /*********************************************************
2323      *  Encode Value Element Buffer
2324      */
2325 
2326     ret = wbxml_encode_value_element_list(encoder, lresult);
2327 
2328     /* Clean-up */
2329     wbxml_list_destroy(lresult, wbxml_value_element_destroy_item);
2330 
2331     return ret;
2332 }
2333 
2334 
2335 /**
2336  * @brief Encode a WBXML Value Element List
2337  * @param encoder The WBXML Encoder
2338  * @param list The Value Element list
2339  * @return WBXML_OK if encoding is OK, an error code otherwise
2340  */
wbxml_encode_value_element_list(WBXMLEncoder * encoder,WBXMLList * list)2341 static WBXMLError wbxml_encode_value_element_list(WBXMLEncoder *encoder, WBXMLList *list)
2342 {
2343     WBXMLValueElement *elt = NULL;
2344     WB_ULONG i = 0;
2345     WBXMLError ret = WBXML_OK;
2346 
2347     if (encoder == NULL)
2348         return WBXML_ERROR_INTERNAL;
2349 
2350     if (list == NULL)
2351         return WBXML_OK;
2352 
2353     for (i = 0; i < wbxml_list_len(list); i++) {
2354         if ((elt = (WBXMLValueElement *) wbxml_list_get(list, i)) == NULL)
2355             continue;
2356 
2357         switch (elt->type) {
2358         case WBXML_VALUE_ELEMENT_STRING:
2359             /* Inline String */
2360             if (wbxml_buffer_len(elt->u.str) > 0) {
2361                 if ((ret = wbxml_encode_inline_string(encoder, elt->u.str)) != WBXML_OK)
2362                     return ret;
2363             }
2364             break;
2365 
2366 #if defined( WBXML_ENCODER_USE_STRTBL )
2367         case WBXML_VALUE_ELEMENT_TABLEREF:
2368             /* String Table Reference */
2369             if ((ret = wbxml_encode_tableref(encoder, elt->u.index)) != WBXML_OK)
2370                 return ret;
2371             break;
2372 #endif /* WBXML_ENCODER_USE_STRTBL */
2373 
2374         case WBXML_VALUE_ELEMENT_EXTENSION:
2375             /* Encode Extension Token */
2376             if ((ret = wbxml_encode_inline_integer_extension_token(encoder, WBXML_EXT_T_0, elt->u.ext->wbxmlToken)) != WBXML_OK)
2377                 return ret;
2378             break;
2379 
2380         case WBXML_VALUE_ELEMENT_OPAQUE:
2381             /** @todo Opaque */
2382             break;
2383 
2384         case WBXML_VALUE_ELEMENT_ATTR_TOKEN:
2385             /* Attribute Value Token */
2386             if ((ret = wbxml_encode_attr_token(encoder, elt->u.attr->wbxmlToken,  elt->u.attr->wbxmlCodePage)) != WBXML_OK)
2387                 return ret;
2388             break;
2389 
2390         default:
2391             return WBXML_ERROR_INTERNAL;
2392         }
2393     }
2394 
2395     return WBXML_OK;
2396 }
2397 
2398 
2399 /**
2400  * @brief Encode a WBXML Literal Attribute Start
2401  * @param encoder The WBXML Encoder
2402  * @param attr The literal attr name to encode
2403  * @return WBXML_OK if encoding is OK, an error code otherwise
2404  * @note    attrStart = (LITERAL index)
2405  *          index = mb_u_int32
2406  */
wbxml_encode_attr_start_literal(WBXMLEncoder * encoder,const WB_UTINY * attr)2407 static WBXMLError wbxml_encode_attr_start_literal(WBXMLEncoder *encoder, const WB_UTINY *attr)
2408 {
2409 #if defined( WBXML_ENCODER_USE_STRTBL )
2410     WBXMLStringTableElement *elt = NULL;
2411     WBXMLBuffer *buff = NULL;
2412     WB_ULONG index = 0;
2413     WB_BOOL added = FALSE;
2414 
2415     /* If String Table generation is disabled, we can't generate this Literal */
2416     if (!encoder->use_strtbl)
2417         return WBXML_ERROR_STRTBL_DISABLED;
2418 
2419     /* Add tag in String Table */
2420     if (((buff = wbxml_buffer_create(attr, WBXML_STRLEN(attr), WBXML_STRLEN(attr))) == NULL) ||
2421         ((elt = wbxml_strtbl_element_create(buff, FALSE)) == NULL) ||
2422         (!wbxml_strtbl_add_element(encoder, elt, &index, &added)))
2423     {
2424         wbxml_strtbl_element_destroy(elt);
2425         wbxml_buffer_destroy(buff);
2426         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2427     }
2428 
2429     /* If already exists in String Table: clean-up */
2430     if (!added)
2431         wbxml_strtbl_element_destroy(elt);
2432 
2433     /* Encode LITERAL index */
2434     if ((!wbxml_buffer_append_char(encoder->output, WBXML_LITERAL)) ||
2435         (!wbxml_buffer_append_mb_uint_32(encoder->output, index)))
2436     {
2437         return WBXML_ERROR_ENCODER_APPEND_DATA;
2438     }
2439 
2440     return WBXML_OK;
2441 #else
2442     /* No String Table Support */
2443     return WBXML_ERROR_STRTBL_DISABLED;
2444 #endif /* WBXML_ENCODER_USE_STRTBL */
2445 }
2446 
2447 
2448 /**
2449  * @brief Encode a WBXML Attribute Token
2450  * @param encoder The WBXML Encoder
2451  * @param token The WBXML Attribute Token to encode
2452  * @param page The WBXML CodePage for this Token
2453  * @return WBXML_OK if encoding is OK, an error code otherwise
2454  * @note    attrStart = ([switchPage] ATTRSTART)
2455  *          switchPage = SWITCH_PAGE pageindex
2456  *          pageindex = u_int8
2457  *
2458  *  And:    attrValue = ([switchPage] ATTRVALUE)
2459  */
wbxml_encode_attr_token(WBXMLEncoder * encoder,WB_UTINY token,WB_UTINY page)2460 static WBXMLError wbxml_encode_attr_token(WBXMLEncoder *encoder, WB_UTINY token, WB_UTINY page)
2461 {
2462     /* Switch Page if needed */
2463     if (encoder->attrCodePage != page)
2464     {
2465         if ((!wbxml_buffer_append_char(encoder->output, WBXML_SWITCH_PAGE)) ||
2466             (!wbxml_buffer_append_char(encoder->output, page)))
2467         {
2468             return WBXML_ERROR_ENCODER_APPEND_DATA;
2469         }
2470 
2471         encoder->attrCodePage = page;
2472     }
2473 
2474     /* Add Token */
2475     if (!wbxml_buffer_append_char(encoder->output, token))
2476         return WBXML_ERROR_ENCODER_APPEND_DATA;
2477 
2478     return WBXML_OK;
2479 }
2480 
2481 
2482 /**
2483  * @brief Encode a WBXML Inline String
2484  * @param encoder The WBXML Encoder
2485  * @param str The String to encode
2486  * @return WBXML_OK if encoding is OK, an error code otherwise
2487  */
wbxml_encode_inline_string(WBXMLEncoder * encoder,WBXMLBuffer * str)2488 static WBXMLError wbxml_encode_inline_string(WBXMLEncoder *encoder, WBXMLBuffer *str)
2489 {
2490     /* Add STR_I */
2491     if (!wbxml_buffer_append_char(encoder->output, WBXML_STR_I))
2492         return WBXML_ERROR_ENCODER_APPEND_DATA;
2493 
2494     /* Add String */
2495     if (!wbxml_buffer_append(encoder->output, str))
2496         return WBXML_ERROR_ENCODER_APPEND_DATA;
2497 
2498     /* Add Null Termination */
2499     if (!wbxml_buffer_append_char(encoder->output, WBXML_STR_END))
2500         return WBXML_ERROR_ENCODER_APPEND_DATA;
2501 
2502     return WBXML_OK;
2503 }
2504 
2505 
2506 /**
2507  * @brief Encode a WBXML Inline Integer Extension Token
2508  * @param encoder The WBXML Encoder
2509  * @param ext Extension Type (WBXML_EXT_T_0, WBXML_EXT_T_1 or WBXML_EXT_T_2)
2510  * @param value The Extension Token Value
2511  * @return WBXML_OK if encoding is OK, an error code otherwise
2512  * @note  (WBXML 1.3 - 5.8.4.2) Inline integrer extension token = EXT_T* mb_u_int32
2513  */
wbxml_encode_inline_integer_extension_token(WBXMLEncoder * encoder,WB_UTINY ext,WB_UTINY value)2514 static WBXMLError wbxml_encode_inline_integer_extension_token(WBXMLEncoder *encoder, WB_UTINY ext, WB_UTINY value)
2515 {
2516     /* Add EXT_T* */
2517     if (!wbxml_buffer_append_char(encoder->output, ext))
2518         return WBXML_ERROR_ENCODER_APPEND_DATA;
2519 
2520     /* Add Value */
2521     if (!wbxml_buffer_append_mb_uint_32(encoder->output, (WB_ULONG) value))
2522         return WBXML_ERROR_ENCODER_APPEND_DATA;
2523 
2524     return WBXML_OK;
2525 }
2526 
2527 
2528 #if 0
2529 /**
2530  * @brief Encode a WBXML Entity
2531  * @param encoder The WBXML Encoder
2532  * @param value The Entity to encode
2533  * @return WBXML_OK if encoding is OK, an error code otherwise
2534  * @note  (WBXML 1.3 - 5.8.4.3) entity = ENTITY entcode
2535  *                              entcode = mb_u_int32
2536  */
2537 static WBXMLError wbxml_encode_entity(WBXMLEncoder *encoder, WB_ULONG value)
2538 {
2539     /* Add ENTITY */
2540     if (!wbxml_buffer_append_char(encoder->output, WBXML_ENTITY))
2541         return WBXML_ERROR_ENCODER_APPEND_DATA;
2542 
2543     /* Add entcode */
2544     if (!wbxml_buffer_append_mb_uint_32(encoder->output, value))
2545         return WBXML_ERROR_ENCODER_APPEND_DATA;
2546 
2547     return WBXML_OK;
2548 }
2549 #endif /* 0 */
2550 
2551 
2552 /**
2553  * @brief Encode a WBXML Opaque, given a Buffer
2554  * @param encoder The WBXML Encoder
2555  * @param buff The Buffer to encode
2556  * @return WBXML_OK if encoding is OK, an error code otherwise
2557  * @note This function is simple a wrapper to wbxml_encode_opaque_data()
2558  */
wbxml_encode_opaque(WBXMLEncoder * encoder,WBXMLBuffer * buff)2559 static WBXMLError wbxml_encode_opaque(WBXMLEncoder *encoder, WBXMLBuffer *buff)
2560 {
2561     return wbxml_encode_opaque_data(encoder, wbxml_buffer_get_cstr(buff), wbxml_buffer_len(buff));
2562 }
2563 
2564 
2565 /**
2566  * @brief Encode a WBXML Opaque
2567  * @param encoder The WBXML Encoder
2568  * @param data The data to encode
2569  * @param data_len The data length to encode
2570  * @return WBXML_OK if encoding is OK, an error code otherwise
2571  * @note  opaque = OPAQUE length *byte
2572  *        length = mb_u_int32
2573  */
wbxml_encode_opaque_data(WBXMLEncoder * encoder,WB_UTINY * data,WB_ULONG data_len)2574 static WBXMLError wbxml_encode_opaque_data(WBXMLEncoder *encoder, WB_UTINY *data, WB_ULONG data_len)
2575 {
2576     /* Add WBXML_OPAQUE */
2577     if (!wbxml_buffer_append_char(encoder->output, WBXML_OPAQUE))
2578         return WBXML_ERROR_ENCODER_APPEND_DATA;
2579 
2580     /* Add Length */
2581     if (!wbxml_buffer_append_mb_uint_32(encoder->output, data_len))
2582         return WBXML_ERROR_ENCODER_APPEND_DATA;
2583 
2584     /* Add Buffer */
2585     if (!wbxml_buffer_append_data(encoder->output, data, data_len))
2586         return WBXML_ERROR_ENCODER_APPEND_DATA;
2587 
2588     return WBXML_OK;
2589 }
2590 
2591 
2592 #if defined( WBXML_ENCODER_USE_STRTBL )
2593 /**
2594  * @brief Encode a WBXML String Table Reference
2595  * @param encoder The WBXML Encoder
2596  * @param offset The String Table offset
2597  * @return WBXML_OK if encoding is OK, an error code otherwise
2598  * @note tableref = STR_T index
2599  */
wbxml_encode_tableref(WBXMLEncoder * encoder,WB_ULONG offset)2600 static WBXMLError wbxml_encode_tableref(WBXMLEncoder *encoder, WB_ULONG offset)
2601 {
2602     /* Add WBXML_STR_T */
2603     if (!wbxml_buffer_append_char(encoder->output, WBXML_STR_T))
2604         return WBXML_ERROR_ENCODER_APPEND_DATA;
2605 
2606     /* Add String */
2607     if (!wbxml_buffer_append_mb_uint_32(encoder->output, offset))
2608         return WBXML_ERROR_ENCODER_APPEND_DATA;
2609 
2610     return WBXML_OK;
2611 }
2612 #endif /* WBXML_ENCODER_USE_STRTBL */
2613 
2614 
2615 /**
2616  * @brief Create a WBXMLValueElement structure
2617  * @return The newly created WBXMLValueElement structure, or NULL if not enough memory
2618  */
wbxml_value_element_create(void)2619 static WBXMLValueElement *wbxml_value_element_create(void)
2620 {
2621     WBXMLValueElement *elt = NULL;
2622 
2623     if ((elt = wbxml_malloc(sizeof(WBXMLValueElement))) == NULL)
2624         return NULL;
2625 
2626     elt->type = WBXML_VALUE_ELEMENT_STRING;
2627     elt->u.str = NULL;
2628 
2629     return elt;
2630 }
2631 
2632 
2633 /**
2634  * @brief Destroy a WBXMLValueElement structure
2635  * @param elt The WBXMLValueElement structure to destroy
2636  */
wbxml_value_element_destroy(WBXMLValueElement * elt)2637 static void wbxml_value_element_destroy(WBXMLValueElement *elt)
2638 {
2639     if (elt == NULL)
2640         return;
2641 
2642     switch (elt->type) {
2643     case WBXML_VALUE_ELEMENT_STRING:
2644         wbxml_buffer_destroy(elt->u.str);
2645         break;
2646     case WBXML_VALUE_ELEMENT_OPAQUE:
2647         wbxml_buffer_destroy(elt->u.buff);
2648         break;
2649     default:
2650         /* Nothing to destroy */
2651         break;
2652     }
2653 
2654     wbxml_free((void*) elt);
2655 }
2656 
2657 
2658 /**
2659  * @brief Destroy a WBXMLValueElement structure (for wbxml_list_destroy() function)
2660  * @param elt The WBXMLValueElement structure to destroy
2661  */
wbxml_value_element_destroy_item(void * elt)2662 static void wbxml_value_element_destroy_item(void *elt)
2663 {
2664     wbxml_value_element_destroy((WBXMLValueElement *) elt);
2665 }
2666 
2667 
2668 /**
2669  * @brief Encode an encapsulated WBXML Tree to WBXML
2670  * @param encoder [in] The WBXML Encoder
2671  * @param tree    [in] The WBXML Tree to encode
2672  * @return WBXML_OK if encoding is OK, an error code otherwise
2673  */
wbxml_encode_tree(WBXMLEncoder * encoder,WBXMLTree * tree)2674 static WBXMLError wbxml_encode_tree(WBXMLEncoder *encoder, WBXMLTree *tree)
2675 {
2676     WBXMLEncoder *new_encoder = NULL;
2677     WB_UTINY *wbxml = NULL;
2678     WB_ULONG wbxml_len = 0;
2679     WBXMLError ret = WBXML_OK;
2680 
2681     if ((new_encoder = encoder_duplicate(encoder)) == NULL)
2682         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2683 
2684     /* Set Tree */
2685     new_encoder->tree = tree;
2686 
2687     /* Encode to WBXML */
2688     if ((ret = wbxml_encoder_encode_tree_to_wbxml(new_encoder, &wbxml, &wbxml_len)) != WBXML_OK) {
2689         wbxml_encoder_destroy(new_encoder);
2690         return ret;
2691     }
2692 
2693     /* Clean-up */
2694     wbxml_encoder_destroy(new_encoder);
2695 
2696     /* Add WBXML_OPAQUE */
2697     if (!wbxml_buffer_append_char(encoder->output, WBXML_OPAQUE)) {
2698         wbxml_free(wbxml);
2699         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2700     }
2701 
2702     /* Add Length */
2703     if (!wbxml_buffer_append_mb_uint_32(encoder->output, wbxml_len)) {
2704         wbxml_free(wbxml);
2705         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2706     }
2707 
2708     /* Append wbxml to output */
2709     if (!wbxml_buffer_append_data(encoder->output, wbxml, wbxml_len)) {
2710         wbxml_free(wbxml);
2711         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2712     }
2713 
2714     /* Clean-up */
2715     wbxml_free(wbxml);
2716 
2717     return WBXML_OK;
2718 }
2719 
2720 
2721 /****************************************
2722  * Language Specific Encoding Functions
2723  */
2724 
2725 #if ( defined( WBXML_SUPPORT_SI ) || defined( WBXML_SUPPORT_EMN ) )
2726 
2727 /*******************
2728  * SI 1.0 / EMN 1.0
2729  */
2730 
2731 /**
2732  * @brief Encode SI %Datetime attribute value
2733  * @param encoder The WBXML Encoder
2734  * @param buffer The %Datetime value to encode
2735  * @return WBXML_OK if encoded, another error code otherwise
2736  * @note [SI] - 8.2.2. Encoding of %Datetime
2737  */
wbxml_encode_datetime(WBXMLEncoder * encoder,WB_UTINY * buffer)2738 static WBXMLError wbxml_encode_datetime(WBXMLEncoder *encoder, WB_UTINY *buffer)
2739 {
2740     WBXMLBuffer *tmp = NULL;
2741     WB_ULONG i = 0;
2742     WB_UTINY ch = 0;
2743     WBXMLError ret = WBXML_OK;
2744 
2745 
2746     if ((tmp = wbxml_buffer_create_from_cstr(buffer)) == NULL)
2747         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
2748 
2749     /* Remove non-digit characters */
2750     while (i < wbxml_buffer_len(tmp)) {
2751         /* Get char */
2752         if (!wbxml_buffer_get_char(tmp, i, &ch)) {
2753             wbxml_buffer_destroy(tmp);
2754             return WBXML_ERROR_INTERNAL;
2755         }
2756 
2757         if (!WBXML_ISDIGIT(ch)) {
2758             if ((ch != 'T') && (ch != 'Z') && (ch != '-') && (ch != ':')) {
2759                 wbxml_buffer_destroy(tmp);
2760                 return WBXML_ERROR_BAD_DATETIME;
2761             }
2762 
2763             /* Remove it */
2764             wbxml_buffer_delete(tmp, i, 1);
2765         }
2766         else
2767             i++;
2768     }
2769 
2770     /* Convert Ascii to Binary buffer */
2771     wbxml_buffer_hex_to_binary(tmp);
2772 
2773     /* Remove trailing zero */
2774     wbxml_buffer_remove_trailing_zeros(tmp);
2775 
2776     /* Encode it to Opaque */
2777     ret = wbxml_encode_opaque(encoder, tmp);
2778 
2779     wbxml_buffer_destroy(tmp);
2780 
2781     return ret;
2782 }
2783 
2784 #endif /* WBXML_SUPPORT_SI || WBXML_SUPPORT_EMN */
2785 
2786 
2787 #if defined( WBXML_SUPPORT_WV )
2788 
2789 /*******************
2790  * WV 1.1 / WV 1.2
2791  */
2792 
2793 /**
2794  * @brief Encode a Wireless-Village Content buffer
2795  * @param encoder The WBXML Encoder
2796  * @param buffer The buffer to encode
2797  * @return WBXML_OK if encoded, WBXML_NOT_ENCODED if not encoded, another error code otherwise
2798  * @note This function encodes a Specific WV Data Type content, or an exact Extension Token.
2799  *       If not found, this is not encoded... and it will be encoded latter as an Inline String
2800  *       in wbxml_encode_value_element_buffer(). We don't deal here if this buffer CONTAINS
2801  *       Extension Tokens.
2802  */
wbxml_encode_wv_content(WBXMLEncoder * encoder,WB_UTINY * buffer)2803 static WBXMLError wbxml_encode_wv_content(WBXMLEncoder *encoder, WB_UTINY *buffer)
2804 {
2805     const WBXMLExtValueEntry *ext = NULL;
2806     WBXMLWVDataType data_type = WBXML_WV_DATA_TYPE_STRING;
2807     /* WB_ULONG ucs4_ch = 0; */
2808 
2809     /*
2810      *  Specific Data Type Elements:
2811      *
2812      *        Boolean:
2813      *            Acceptance (0x00 / 0x05)
2814      *            InUse (0x00 / 0x18)
2815      *            Poll (0x00 / 0x21)
2816      *            AllFunctionsRequest (0x01 / 0x06)
2817      *            CapabilityRequest (0x01 / 0x0B)
2818      *            CompletionFlag (0x01 / 0x34)
2819      *            ReceiveList (0x01 / 0x36) [WV 1.2]
2820      *            AnyContent (0x03 / 0x09)
2821      *            DefaultList (0x04 / 0x0B)
2822      *            Auto-Subscribe (0x04 / 0x1E) [WV 1.2]
2823      *            DeliveryReport (0x06 / 0x08)
2824      *            JoinGroup (0x07 / 0x21)
2825      *            JoinedRequest (0x07 / 0x10)
2826      *            SubscribeNotification (0x07 / 0x22)
2827      *            CIR (0x09 / 0x05) [WV 1.2]
2828      *
2829      *        Integer:
2830      *            Code (0x00 / 0x0B)
2831      *            ContentSize (0x00 / 0x0F)
2832      *            MessageCount (0x00 / 0x1A)
2833      *            Validity (0x00 / 0x3C)
2834      *            KeepAliveTime (0x01 / 0x1C)
2835      *            SearchFindings (0x01 / 0x25)
2836      *            SearchID (0x01 / 0x26)
2837      *            SearchIndex (0x01 / 0x27)
2838      *            SearchLimit (0x01 / 0x28)
2839      *            TimeToLive (0x01 / 0x32)
2840      *            AcceptedCharSet (0x03 / 0x05)
2841      *            AcceptedContentLength (0x03 / 0x06)
2842      *            MultiTrans (0x03 / 0x0C)
2843      *            ParserSize (0x03 / 0x0D)
2844      *            ServerPollMin (0x03 / 0x0E)
2845      *            TCPPort (0x03 / 0x12)
2846      *            UDPPort (0x03 / 0x13)
2847      *            HistoryPeriod (0x09 / 0x08) [WV 1.2]
2848      *            MaxWatcherList (0x09 / 0x0A) [WV 1.2]
2849      *
2850      *        Date and Time:
2851      *            DateTime (0x00 / 0x11)
2852      *            DeliveryTime (0x06 / 0x1A)
2853      *
2854      *        Binary:
2855      *            ContentData (0x00 / 0x0D) (only if we have a: "<ContentEncoding>BASE64</ContentEncoding>" associated)
2856      */
2857 
2858     /****************************************
2859      * Get the Data Type of Current Element
2860      */
2861 
2862     if (encoder->current_tag != NULL)
2863     {
2864         switch (encoder->current_tag->wbxmlCodePage) {
2865         case 0x00:
2866             /* Code Page: 0x00 */
2867             switch (encoder->current_tag->wbxmlToken) {
2868             case 0x05: /* Acceptance */
2869             case 0x18: /* InUse */
2870             case 0x21: /* Poll */
2871                 /* BOOLEAN */
2872                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
2873                 break;
2874             case 0x0B: /* Code */
2875             case 0x0F: /* ContentSize */
2876             case 0x1A: /* MessageCount */
2877             case 0x3C: /* Validity */
2878                 /* INTEGER */
2879                 data_type = WBXML_WV_DATA_TYPE_INTEGER;
2880                 break;
2881             case 0x11: /* DateTime */
2882                 /* DATE_AND_TIME */
2883                 data_type = WBXML_WV_DATA_TYPE_DATE_AND_TIME;
2884                 break;
2885             case 0x0D: /* ContentData */
2886                 /* BINARY */
2887                 /** @todo Check if we have a: "<ContentEncoding>BASE64</ContentEncoding>" associated */
2888                 /*
2889                 if (base64_encoded)
2890                     data_type = WBXML_WV_DATA_TYPE_BINARY;
2891                 else
2892                 */
2893                     data_type = WBXML_WV_DATA_TYPE_STRING;
2894                 break;
2895             default:
2896                 /* STRING */
2897                 data_type = WBXML_WV_DATA_TYPE_STRING;
2898                 break;
2899             }
2900             break;
2901         case 0x01:
2902             /* Code Page: 0x01 */
2903             switch (encoder->current_tag->wbxmlToken) {
2904             case 0x06: /* AllFunctionsRequest */
2905             case 0x0B: /* CapabilityRequest */
2906             case 0x34: /* CompletionFlag */
2907             case 0x36: /* ReceiveList */
2908                 /* BOOLEAN */
2909                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
2910                 break;
2911             case 0x1C: /* KeepAliveTime */
2912             case 0x25: /* SearchFindings */
2913             case 0x26: /* SearchID */
2914             case 0x27: /* SearchIndex */
2915             case 0x28: /* SearchLimit */
2916             case 0x32: /* TimeToLive */
2917                 /* INTEGER */
2918                 data_type = WBXML_WV_DATA_TYPE_INTEGER;
2919                 break;
2920             default:
2921                 /* STRING */
2922                 data_type = WBXML_WV_DATA_TYPE_STRING;
2923                 break;
2924             }
2925             break;
2926         case 0x03:
2927             /* Code Page: 0x03 */
2928             switch (encoder->current_tag->wbxmlToken) {
2929             case 0x09: /* AnyContent */
2930                 /* BOOLEAN */
2931                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
2932                 break;
2933             case 0x05: /* AcceptedCharSet */
2934             case 0x06: /* AcceptedContentLength */
2935             case 0x0C: /* MultiTrans */
2936             case 0x0D: /* ParserSize */
2937             case 0x0E: /* ServerPollMin */
2938             case 0x12: /* TCPPort */
2939             case 0x13: /* UDPPort */
2940                 /* INTEGER */
2941                 data_type = WBXML_WV_DATA_TYPE_INTEGER;
2942                 break;
2943             default:
2944                 /* STRING */
2945                 data_type = WBXML_WV_DATA_TYPE_STRING;
2946                 break;
2947             }
2948             break;
2949         case 0x04:
2950             /* Code Page: 0x04 */
2951             switch (encoder->current_tag->wbxmlToken) {
2952             case 0x0B: /* DefaultList */
2953             case 0x1E: /* Auto-Subscribe */
2954                 /* BOOLEAN */
2955                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
2956                 break;
2957             default:
2958                 /* STRING */
2959                 data_type = WBXML_WV_DATA_TYPE_STRING;
2960                 break;
2961             }
2962             break;
2963         case 0x06:
2964             /* Code Page: 0x06 */
2965             switch (encoder->current_tag->wbxmlToken) {
2966             case 0x08: /* DeliveryReport */
2967                 /* BOOLEAN */
2968                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
2969                 break;
2970             case 0x1A: /* DeliveryTime */
2971                 /* DATE AND TIME */
2972                 data_type = WBXML_WV_DATA_TYPE_DATE_AND_TIME;
2973                 break;
2974             default:
2975                 /* STRING */
2976                 data_type = WBXML_WV_DATA_TYPE_STRING;
2977                 break;
2978             }
2979             break;
2980         case 0x07:
2981             /* Code Page: 0x07 */
2982             switch (encoder->current_tag->wbxmlToken) {
2983             case 0x21: /* JoinGroup */
2984             case 0x10: /* JoinedRequest */
2985             case 0x22: /* SubscribeNotification */
2986                 /* BOOLEAN */
2987                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
2988                 break;
2989             default:
2990                 /* STRING */
2991                 data_type = WBXML_WV_DATA_TYPE_STRING;
2992                 break;
2993             }
2994             break;
2995         case 0x09:
2996             /* Code Page: 0x09 */
2997             switch (encoder->current_tag->wbxmlToken) {
2998             case 0x05: /* CIR */
2999                 /* BOOLEAN */
3000                 data_type = WBXML_WV_DATA_TYPE_BOOLEAN;
3001                 break;
3002             case 0x08: /* HistoryPeriod */
3003             case 0x0A: /* MaxWatcherList */
3004                 /* INTEGER */
3005                 data_type = WBXML_WV_DATA_TYPE_INTEGER;
3006                 break;
3007             default:
3008                 /* STRING */
3009                 data_type = WBXML_WV_DATA_TYPE_STRING;
3010                 break;
3011             }
3012             break;
3013         default:
3014             data_type = WBXML_WV_DATA_TYPE_STRING;
3015             break;
3016         }
3017     }
3018 
3019 
3020     /****************************************
3021      * Encode, given the Data Type
3022      */
3023 
3024     switch (data_type) {
3025     case WBXML_WV_DATA_TYPE_INTEGER:
3026         /* Integer: Encode it */
3027         return wbxml_encode_wv_integer(encoder, buffer);
3028         break;
3029     case WBXML_WV_DATA_TYPE_DATE_AND_TIME:
3030         /* Date and time can be encoded as OPAQUE data or as a string as specified in [ISO8601]. */
3031         return wbxml_encode_wv_datetime(encoder, buffer);
3032         break;
3033     case WBXML_WV_DATA_TYPE_BINARY:
3034         /** @todo Binary Encoding !! */
3035         break;
3036     case WBXML_WV_DATA_TYPE_BOOLEAN:
3037         /* Booleans are handled by the "T" and "F" extension tokens */
3038     case WBXML_WV_DATA_TYPE_STRING:
3039         /* Check if this buffer is an EXACT Extension Token */
3040         if ((ext = wbxml_tables_get_ext_from_xml(encoder->lang, buffer)) != NULL)
3041             return wbxml_encode_inline_integer_extension_token(encoder, WBXML_EXT_T_0, ext->wbxmlToken);
3042         else {
3043             if (WBXML_STRLEN(buffer) == 1)
3044             {
3045                 /**
3046                  * @todo [OMA WV 1.1] - 6.1 : A single character can be encoded as ENTITY (0x02) followed
3047                  *                           by a mb_u_int32 containing the entity number.
3048                  */
3049 
3050                 /*
3051                 if (convert_char_to_ucs4(*buffer, &ucs4_ch))
3052                     return wbxml_encode_entity(encoder, ucs4_ch);
3053                 */
3054             }
3055 
3056             /* Else: noting encoded... this will be latter as an inline string */
3057         }
3058         break;
3059     default:
3060         /* Hu ? */
3061         break;
3062     }
3063 
3064     return WBXML_NOT_ENCODED;
3065 }
3066 
3067 
3068 /**
3069  * @brief Encode a Wireless-Village Integer
3070  * @param encoder The WBXML Encoder
3071  * @param buffer The buffer that contains the string representation of the integer to encode
3072  * @return WBXML_OK if OK, another error code otherwise
3073  */
wbxml_encode_wv_integer(WBXMLEncoder * encoder,WB_UTINY * buffer)3074 static WBXMLError wbxml_encode_wv_integer(WBXMLEncoder *encoder, WB_UTINY *buffer)
3075 {
3076     WB_UTINY octets[4];
3077     WB_ULONG the_int = 0, start = 0;
3078     WB_LONG i = 0;
3079 
3080     if ((encoder == NULL) || (buffer == NULL))
3081         return WBXML_ERROR_INTERNAL;
3082 
3083     if (buffer[1] == 'x' || buffer[1] == 'X') {
3084         the_int = (WB_ULONG) strtol((const WB_TINY *) buffer , NULL , 16);
3085     } else {
3086         the_int = (WB_ULONG) atol((const WB_TINY *) buffer);
3087     }
3088 
3089 
3090     for (i = 3; the_int > 0 && i >= 0; i--) {
3091         octets[i] = (WB_UTINY)(the_int & 0xff);
3092         the_int >>= 8;
3093     }
3094 
3095     start = i + 1;
3096 
3097     /* Add WBXML_OPAQUE */
3098     if (!wbxml_buffer_append_char(encoder->output, WBXML_OPAQUE))
3099         return WBXML_ERROR_ENCODER_APPEND_DATA;
3100 
3101     /* Add Integer Length */
3102     if (!wbxml_buffer_append_mb_uint_32(encoder->output, 4 - start))
3103         return WBXML_ERROR_ENCODER_APPEND_DATA;
3104 
3105     /* Add Integer */
3106     if (!wbxml_buffer_append_data(encoder->output, octets + start, (WB_UTINY)(4 - start)))
3107         return WBXML_ERROR_ENCODER_APPEND_DATA;
3108 
3109     return WBXML_OK;
3110 }
3111 
3112 
3113 /**
3114  * @brief Encode inline WV Date and Time content value
3115  * @param encoder The WBXML Encoder
3116  * @param buffer The ISO 8601 Date and Time value to encode
3117  * @return WBXML_OK if encoded, another error code otherwise
3118  * @note [WV] - 6.6 Date and Time
3119  * @note
3120  *  Encoded Format:
3121  *      - ISO 8601 string (see expected format)
3122  *
3123  *  Expected Format (ISO 8601):
3124  *      20011019T0950Z
3125  *      20011019T095031Z
3126  *      2001-10-19T09:50:31Z (with number seperators)
3127  *      2001-10-19T09:50:31+01:00 (with explicit positive time zone)
3128  *      2001-10-19T09:50:31+05:00 (with explicit negative time zone)
3129  */
wbxml_encode_wv_datetime_inline(WBXMLEncoder * encoder,WB_UTINY * buffer)3130 static WBXMLError wbxml_encode_wv_datetime_inline(WBXMLEncoder *encoder, WB_UTINY *buffer)
3131 {
3132     WBXMLError result = WBXML_OK;
3133     WBXMLBuffer *tmp = NULL;
3134 
3135     /* Create temp Buffer */
3136     if ((tmp = wbxml_buffer_create_from_cstr(buffer)) == NULL) {
3137         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3138     }
3139 
3140     /* Add buffer to encoder */
3141     result = wbxml_encode_inline_string(encoder, tmp);
3142 
3143     /* Cleanup buffer */
3144     wbxml_buffer_destroy(tmp);
3145 
3146     return result;
3147 }
3148 
3149 
3150 /**
3151  * @brief Encode opaque WV Date and Time content value
3152  * @param encoder The WBXML Encoder
3153  * @param buffer The ISO 8601 Date and Time value to encode
3154  * @return WBXML_OK if encoded, another error code otherwise
3155  * @note [WV] - 6.6 Date and Time
3156  * @note
3157  *  Encoded Format: (6 octets)
3158  *      - The first 2 bits are reserved, and both must be 0.
3159  *      - Year is encoded by 12 bits (0 to 4095)
3160  *      - Month is encoded by 4 bits (1 to 12)
3161  *      - Day is encoded by 5 bits (1 to 31)
3162  *      - Hour is encoded by 5 bits (0 to 23)
3163  *      - Minute is encoded by 6 bits (0 to 59)
3164  *      - Second is encoded by 6 bits (0 to 59)
3165  *      - Time zone is encoded in 1 byte [ISO8601].
3166  *
3167  *      eg:
3168  *          Binary:  00 011111010001 1010 10011 01001 110010 011111 01011010
3169  *          Octets:  (-------)(-------)(--------)(-------)(-------) (------)
3170  *
3171  *  Expected Format (ISO 8601):
3172  *      20011019T0950 (missing seconds and time zone)
3173  *      20011019T0950Z (missing seconds)
3174  *      20011019T095031 (missing time zone)
3175  *      20011019T095031Z
3176  *      20011019T095031A (UTC+1)
3177  */
wbxml_encode_wv_datetime_opaque(WBXMLEncoder * encoder,WB_UTINY * buffer)3178 static WBXMLError wbxml_encode_wv_datetime_opaque(WBXMLEncoder *encoder, WB_UTINY *buffer)
3179 {
3180     WBXMLBuffer *tmp = NULL;
3181     WB_ULONG i = 0, len = 0;
3182     WB_UTINY ch = 0;
3183     WBXMLError ret = WBXML_OK;
3184     WB_UTINY octets[6];
3185     WBXMLBuffer *component = NULL;
3186 
3187     /* definitions first ... or some compilers don't like it */
3188     unsigned int year, month, day, hour, minute, second;
3189 
3190     len = WBXML_STRLEN(buffer);
3191 
3192     /* Create temp Buffer */
3193     if ((tmp = wbxml_buffer_create_from_cstr(buffer)) == NULL) {
3194         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3195         goto error;
3196     }
3197 
3198     /* Check Length */
3199     if ((len == 13) || (len == 14)) {
3200         /* This is illegal but we can tolerate datetimes
3201          * which forget the seconds.
3202          */
3203         WBXML_WARNING((WBXML_CONV, "The WV datetime %s is missing the seconds.", buffer));
3204         if (len == 13) {
3205             wbxml_buffer_append_cstr(tmp, "00");
3206         } else {
3207             wbxml_buffer_insert_cstr(tmp, (WB_UTINY *) "00", 13);
3208         }
3209         len = wbxml_buffer_len(tmp);
3210     }
3211     if ((len != 15) && (len != 16)) {
3212         WBXML_ERROR((WBXML_CONV, "The length of a WV datetime must be 15 or 16."));
3213         ret = WBXML_ERROR_WV_DATETIME_FORMAT;
3214         goto error;
3215     }
3216 
3217     /* Check position of 'T' */
3218     if (*(buffer+8) != 'T') {
3219         WBXML_ERROR((WBXML_CONV, "The 9th character of a WV datetime must be 'T'."));
3220         ret = WBXML_ERROR_WV_DATETIME_FORMAT;
3221         goto error;
3222     }
3223 
3224     /* Check position of time zone */
3225     if (len == 16) {
3226         if (!wbxml_buffer_get_char(tmp, 15, &ch)) {
3227             ret = WBXML_ERROR_INTERNAL;
3228             goto error;
3229         }
3230         if (ch < 'A' || ch == 'J' || ch > 'Z') {
3231             WBXML_ERROR((WBXML_CONV, "If the length of a WV datetime is 16 then the last character must be the time zone."));
3232             ret = WBXML_ERROR_WV_DATETIME_FORMAT;
3233             goto error;
3234         }
3235 
3236         /* There is a time zone. */
3237         octets[5] = ch;
3238 
3239         /* delete time zone */
3240         wbxml_buffer_delete(tmp, 15, 1);
3241     } else {
3242         /* There is no time zone. */
3243         octets[5] = 0;
3244     }
3245 
3246     /* delete 'T' */
3247     wbxml_buffer_delete(tmp, 8, 1);
3248 
3249     /* Check if you have only digits characters */
3250     while (i < wbxml_buffer_len(tmp)) {
3251         /* Get char */
3252         if (!wbxml_buffer_get_char(tmp, i, &ch)) {
3253             ret = WBXML_ERROR_INTERNAL;
3254             goto error;
3255         }
3256 
3257         if (!WBXML_ISDIGIT(ch)) {
3258             ret = WBXML_ERROR_WV_DATETIME_FORMAT;
3259             goto error;
3260         }
3261         else
3262             i++;
3263     }
3264 
3265     WBXML_DEBUG((WBXML_CONV, "Starting WV datetime conversion ..."));
3266 
3267     /* Set Year */
3268     component = wbxml_buffer_duplicate(tmp);
3269     if (!component) {
3270         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3271         goto error;
3272     }
3273     wbxml_buffer_delete(component, 4, 10);
3274     year = strtoul((const char *)wbxml_buffer_get_cstr(component), NULL, 10);
3275     wbxml_buffer_destroy(component);
3276     octets[0] = (WB_UTINY) ((year & 0xfc0) >> 6); /* 6 bits */
3277     octets[1] = (WB_UTINY) (year & 0x3f);  /* 6 bits */
3278 
3279     /* Set Month */
3280     component = wbxml_buffer_duplicate(tmp);
3281     if (!component) {
3282         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3283         goto error;
3284     }
3285     wbxml_buffer_delete(component, 0, 4);
3286     wbxml_buffer_delete(component, 2, 8);
3287     month = strtoul((const char *)wbxml_buffer_get_cstr(component), NULL, 10);
3288     wbxml_buffer_destroy(component);
3289     octets[1] <<= 2;
3290     octets[1] += (WB_UTINY) ((month & 0xc) >> 2); /* 2 bits */
3291     octets[2] = (WB_UTINY) (month & 0x3); /* 2 bits */
3292 
3293     /* Set Day */
3294     component = wbxml_buffer_duplicate(tmp);
3295     if (!component) {
3296         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3297         goto error;
3298     }
3299     wbxml_buffer_delete(component, 0, 6);
3300     wbxml_buffer_delete(component, 2, 6);
3301     day = strtoul((const char *)wbxml_buffer_get_cstr(component), NULL, 10);
3302     wbxml_buffer_destroy(component);
3303     octets[2] <<= 5;
3304     octets[2] += (WB_UTINY) (day & 0x1f); /* 5 bits */
3305 
3306     /* Set Hour */
3307     component = wbxml_buffer_duplicate(tmp);
3308     if (!component) {
3309         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3310         goto error;
3311     }
3312     wbxml_buffer_delete(component, 0, 8);
3313     wbxml_buffer_delete(component, 2, 4);
3314     hour = strtoul((const char *)wbxml_buffer_get_cstr(component), NULL, 10);
3315     wbxml_buffer_destroy(component);
3316     octets[2] <<=1;
3317     octets[2] += (WB_UTINY) ((hour & 0x10) >> 4); /* 1 bit */
3318     octets[3] = (WB_UTINY) (hour & 0xf); /* 4 bits */
3319 
3320     /* Set Minute */
3321     component = wbxml_buffer_duplicate(tmp);
3322     if (!component) {
3323         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3324         goto error;
3325     }
3326     wbxml_buffer_delete(component, 0, 10);
3327     wbxml_buffer_delete(component, 2, 2);
3328     minute = strtoul((const char *)wbxml_buffer_get_cstr(component), NULL, 10);
3329     wbxml_buffer_destroy(component);
3330     octets[3] <<=4;
3331     octets[3] += (WB_UTINY) ((minute & 0x3c) >> 2); /* 4 bits */
3332     octets[4] = (WB_UTINY) (minute & 0x3); /* 2 bits */
3333 
3334     /* Set Second */
3335     component = wbxml_buffer_duplicate(tmp);
3336     if (!component) {
3337         ret = WBXML_ERROR_NOT_ENOUGH_MEMORY;
3338         goto error;
3339     }
3340     wbxml_buffer_delete(component, 0, 12);
3341     second = strtoul((const char *)wbxml_buffer_get_cstr(component), NULL, 10);
3342     wbxml_buffer_destroy(component);
3343     octets[4] <<=6;
3344     octets[4] += (WB_UTINY) (second & 0x3f); /* 6 bits */
3345 
3346     WBXML_DEBUG((WBXML_CONV, "WV datetime: %x %x %x %x %x %x", octets[0], octets[1], octets[2], octets[3], octets[4], octets[5]));
3347 
3348     /* Encode it to Opaque */
3349     ret = wbxml_encode_opaque_data(encoder, octets, 6);
3350 
3351 error:
3352     if (tmp)
3353         wbxml_buffer_destroy(tmp);
3354     return ret;
3355 }
3356 
3357 
3358 /**
3359  * @brief Encode WV Date and Time content value
3360  * @param encoder The WBXML Encoder
3361  * @param buffer The ISO 8601 Date and Time value to encode
3362  * @return WBXML_OK if encoded, another error code otherwise
3363  * @note [WV] - 6.6 Date and Time
3364  * @note This function only decides which kind of datetime
3365  *       encoding should be used and calls the appropriate
3366  *       function. Please see wbxml_encode_wv_datetime_opaque
3367  *       and wbxml_encode_wv_datetime_inline for more details.
3368  * @note Both encoding mechanisms were implemented to be able
3369  *       to test the parsing of both encoding scheme. This is
3370  *       necessary because other implementations can decide by
3371  *       their own which encoding scheme they use.
3372  */
wbxml_encode_wv_datetime(WBXMLEncoder * encoder,WB_UTINY * buffer)3373 static WBXMLError wbxml_encode_wv_datetime(WBXMLEncoder *encoder, WB_UTINY *buffer)
3374 {
3375     WB_BOOL use_inline = FALSE;
3376     WB_ULONG len = WBXML_STRLEN(buffer);
3377 
3378     /* long version of ISO 8601 should be inline encoded */
3379     if (strchr((WB_TINY *) buffer, '-'))
3380         use_inline = TRUE;
3381     if (strchr((WB_TINY *) buffer, '+'))
3382         use_inline = TRUE;
3383     if (strchr((WB_TINY *) buffer, ':'))
3384         use_inline = TRUE;
3385 
3386     /* timezone Z should be inline encoded */
3387     if (buffer[len - 1] == 'Z')
3388         use_inline = TRUE;
3389 
3390     if (use_inline) {
3391         WBXML_DEBUG((WBXML_CONV, "WV datetime conversion: INLINE"));
3392         return wbxml_encode_wv_datetime_inline(encoder, buffer);
3393     } else {
3394         WBXML_DEBUG((WBXML_CONV, "WV datetime conversion: OPAQUE"));
3395         return wbxml_encode_wv_datetime_opaque(encoder, buffer);
3396     }
3397 }
3398 
3399 #endif /* WBXML_SUPPORT_WV */
3400 
3401 
3402 #if defined( WBXML_SUPPORT_DRMREL )
3403 
3404 /*******************
3405  * DRMREL 1.0
3406  */
3407 
3408 /**
3409  * @brief Encode a DRMREL Content buffer
3410  * @param encoder The WBXML Encoder
3411  * @param buffer The buffer to encode
3412  * @return WBXML_OK if encoded, WBXML_NOT_ENCODED if not encoded, another error code otherwise
3413  * @note This function encodes a Specific DRMREL content.
3414  *       If not found, this is not encoded... and it will be encoded latter as an Inline String
3415  *       in wbxml_encode_value_element_buffer().
3416  */
wbxml_encode_drmrel_content(WBXMLEncoder * encoder,WB_UTINY * buffer)3417 static WBXMLError wbxml_encode_drmrel_content(WBXMLEncoder *encoder, WB_UTINY *buffer)
3418 {
3419     WB_UTINY *data = NULL;
3420     WB_LONG data_len = 0;
3421     const WBXMLTagEntry *current_tag = NULL;
3422 
3423     if ((encoder->current_text_parent != NULL) &&
3424         (encoder->current_text_parent->name != NULL) &&
3425         (encoder->current_text_parent->name->type == WBXML_VALUE_TOKEN))
3426     {
3427         current_tag = encoder->current_text_parent->name->u.token;
3428     }
3429 
3430     if (current_tag != NULL)
3431     {
3432         if ((current_tag->wbxmlCodePage == 0x00) &&
3433             (current_tag->wbxmlToken == 0x0C))
3434         {
3435             /* <ds:KeyValue> content: "Encoded in binary format, i.e., no base64 encoding" */
3436 
3437             /* Decode Base64 */
3438             if ((data_len = wbxml_base64_decode(buffer, -1, &data)) < 0)
3439                 return WBXML_NOT_ENCODED;
3440 
3441             /* Add WBXML_OPAQUE */
3442             if (!wbxml_buffer_append_char(encoder->output, WBXML_OPAQUE))
3443             {
3444                 wbxml_free(data);
3445                 return WBXML_ERROR_ENCODER_APPEND_DATA;
3446             }
3447 
3448             /* Add Data Length */
3449             if (!wbxml_buffer_append_mb_uint_32(encoder->output, (WB_ULONG) data_len))
3450             {
3451                 wbxml_free(data);
3452                 return WBXML_ERROR_ENCODER_APPEND_DATA;
3453             }
3454 
3455             /* Add Data */
3456             if (!wbxml_buffer_append_data(encoder->output, data, data_len))
3457             {
3458                 wbxml_free(data);
3459                 return WBXML_ERROR_ENCODER_APPEND_DATA;
3460             }
3461 
3462             /* Free Data */
3463             wbxml_free(data);
3464 
3465             return WBXML_OK;
3466         }
3467     }
3468 
3469     return WBXML_NOT_ENCODED;
3470 }
3471 
3472 #endif /* WBXML_SUPPORT_DRMREL */
3473 
3474 
3475 #if defined( WBXML_SUPPORT_OTA_SETTINGS )
3476 
3477 /*******************
3478  * OTA Settings
3479  */
3480 
3481 /**
3482  * @brief Encode a OTA ICON as opaque data
3483  * @param encoder The WBXML Encoder
3484  * @param buffer The buffer to encode
3485  * @return WBXML_OK if encoded, WBXML_NOT_ENCODED if not encoded, another error code otherwise
3486  * @note Nokia OTA Settings support for the ICON value in bookmarks.
3487  *
3488  * Nokia introduced a proprietary way of including icons in the old Nokia OTA Settings format when sending bookmarks.
3489  * The encoding is done using base64 encoded images in XML, and encoding it as OPAQUE data in the WBXML.
3490  * The icon is embedded using an PARM element with name ICON.
3491  *
3492  * E.g. the following bookmark (XML) is valid:
3493  *
3494  * <?xml version="1.0"?>
3495  * <!DOCTYPE CHARACTERISTIC-LIST PUBLIC "-//WAPFORUM//DTD NOKIA-OTA 1.0//EN" "http://localhost:8080/OMABootSendWEB/DTD/characteristic_list.dtd">
3496  *
3497  * <CHARACTERISTIC-LIST>
3498  *    <CHARACTERISTIC TYPE="BOOKMARK">
3499  *       <PARM NAME="NAME" VALUE="TV2"/>
3500  *       <PARM NAME="URL" VALUE="http://wap.tv2.dk"/>
3501  *       <PARM NAME="ICON" VALUE="R0lGODlhIAAgAPMAAP//AP8zAMwAAJkAAGYAAN0AAKoAAIgAAHcAAFUAAEQAACIAABEAALu7u8jIyP8AMyH5BAEAAA4ALAAAAAAgACAAQATh0MlJq704Z8bkucyiJARyHEM6HAjCNJw2hWNpnmdLJMrSyUBMICApAAqbhUiheDVgicQg8dPQSKaBQVAQGFaIXa8KDC2ZaCU5yL4QPe3yoXAIfDacfJVBZV9JNi16fWUiWChbAl5gBAxjMlclKFoGX4w8PkF/BJydO5hrbXp5caUYd6YycwVvqRY4R64goa4dMRKtGBxKaqNShIVMUSUcTwxTtCCGnC04LMWkkMtZlJbPMLdJNVlbXV8sYplW04iKi+Cg0tvUKixh6eqALfM64cnKwlH6PI+mu7y8sskaCMFFADs="/>
3502  *    </CHARACTERISTIC>
3503  * </CHARACTERISTIC-LIST>
3504  *
3505  * If not found, this is not encoded... and it will be encoded latter as an Inline String in wbxml_encode_value_element_buffer().
3506  */
wbxml_encode_ota_nokia_icon(WBXMLEncoder * encoder,WB_UTINY * buffer)3507 static WBXMLError wbxml_encode_ota_nokia_icon(WBXMLEncoder *encoder, WB_UTINY *buffer)
3508 {
3509     WBXMLError ret = WBXML_NOT_ENCODED;
3510 
3511     /* Is a VALUE attribute ? */
3512     if ((encoder->current_tag != NULL) &&
3513         (encoder->current_attr->wbxmlCodePage == 0x00) &&
3514         (encoder->current_attr->wbxmlToken == 0x11) &&
3515         (encoder->current_node && encoder->current_node->attrs))
3516     {
3517         WBXMLList *attrs = encoder->current_node->attrs;
3518         WB_ULONG index = 0;
3519         WB_ULONG nb_attrs = wbxml_list_len(attrs);
3520         WB_BOOL found = FALSE;
3521 
3522         /* Search for a NAME="ICON" attribute */
3523         while (!found && (index < nb_attrs)) {
3524             WBXMLAttribute *attr = (WBXMLAttribute*)wbxml_list_get(attrs, index);
3525 
3526             if ((WBXML_STRCMP("NAME", wbxml_attribute_get_xml_name(attr)) == 0) &&
3527                 (WBXML_STRCMP("ICON", wbxml_attribute_get_xml_value(attr)) == 0))
3528             {
3529                 WB_UTINY *data = NULL;
3530                 WB_LONG data_len = 0;
3531 
3532                 /* Decode Base64 */
3533                 if ((data_len = wbxml_base64_decode(buffer, -1, &data)) < 0)
3534                     return WBXML_NOT_ENCODED;
3535 
3536                 /* Encode opaque */
3537                 if ((ret = wbxml_encode_opaque_data(encoder, data, data_len)) != WBXML_OK)
3538                     return ret;
3539 
3540                 /* Free Data */
3541                 wbxml_free(data);
3542 
3543                 found = TRUE;
3544             }
3545 
3546             index++;
3547         }
3548     }
3549 
3550     return ret;
3551 }
3552 
3553 #endif /* WBXML_SUPPORT_OTA_SETTINGS */
3554 
3555 
3556 #if defined( WBXML_ENCODER_USE_STRTBL )
3557 
3558 /****************************
3559  * String Table Functions
3560  */
3561 
3562 /**
3563  * @brief Create a String Table element
3564  * @param string The WBXMLBuffer containing the String
3565  * @param is_stat If set to TRUE, this Buffer won't be destroyed in wbxml_strtbl_element_destroy() function
3566  * @return The newly created String Table Element, or NULL if not enought memory
3567  */
wbxml_strtbl_element_create(WBXMLBuffer * string,WB_BOOL is_stat)3568 static WBXMLStringTableElement *wbxml_strtbl_element_create(WBXMLBuffer *string, WB_BOOL is_stat)
3569 {
3570     WBXMLStringTableElement *elt = NULL;
3571 
3572     if ((elt = wbxml_malloc(sizeof(WBXMLStringTableElement))) == NULL)
3573         return NULL;
3574 
3575     elt->string = string;
3576     elt->offset = 0;
3577     elt->count = 0;
3578     elt->stat = is_stat;
3579 
3580     return elt;
3581 }
3582 
3583 
3584 /**
3585  * @brief Destroy a String Table element
3586  * @param element The element to destroy
3587  */
wbxml_strtbl_element_destroy(WBXMLStringTableElement * element)3588 static void wbxml_strtbl_element_destroy(WBXMLStringTableElement *element)
3589 {
3590     if (element == NULL)
3591         return;
3592 
3593     if (!element->stat)
3594         wbxml_buffer_destroy(element->string);
3595 
3596     wbxml_free(element);
3597 }
3598 
3599 
3600 /**
3601  * @brief Destroy a String Table element (for wbxml_list_destroy())
3602  * @param element The element to destroy
3603  */
wbxml_strtbl_element_destroy_item(void * element)3604 static void wbxml_strtbl_element_destroy_item(void *element)
3605 {
3606     wbxml_strtbl_element_destroy((WBXMLStringTableElement *) element);
3607 }
3608 
3609 
3610 /**
3611  * @brief Initialize the String Table
3612  * @param encoder The WBXML Encoder
3613  * @param root The root element of LibXML Tree
3614  */
wbxml_strtbl_initialize(WBXMLEncoder * encoder,WBXMLTreeNode * root)3615 static WBXMLError wbxml_strtbl_initialize(WBXMLEncoder *encoder, WBXMLTreeNode *root)
3616 {
3617     WBXMLList *strings = NULL, *one_ref = NULL;
3618     WBXMLError ret;
3619 
3620     if ((strings = wbxml_list_create()) == NULL)
3621         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3622 
3623     /* Collect all Strings:
3624      * [out] 'strings' is the list of pointers to WBXMLBuffer. This Buffers must not be freed.
3625      */
3626     wbxml_strtbl_collect_strings(encoder, root, strings);
3627 
3628     /* Insert, in String Table, Strings that are referenced more than one time
3629      * [out] 'strings' is NULL
3630      *       'one_ref' is the list of strings referenced only ONE time (list of WBXMLStringTableElement*)
3631      *       Strings referenced more than one time are added to String Table
3632      */
3633     if ((ret = wbxml_strtbl_check_references(encoder, &strings, &one_ref, TRUE)) != WBXML_OK) {
3634         wbxml_list_destroy(strings, NULL);
3635         return ret;
3636     }
3637 
3638     /* 'strings' is destroyed after call of wbxml_strtbl_check_references() */
3639 
3640     /* Split Strings refered only one time in Words
3641      * [out] 'strings' is the list of words. This words (WBXMLBuffer) must be freed
3642      */
3643     if ((ret = wbxml_strtbl_collect_words(one_ref, &strings)) != WBXML_OK) {
3644         wbxml_list_destroy(one_ref, wbxml_strtbl_element_destroy_item);
3645         return ret;
3646     }
3647 
3648     /* Destroy References List */
3649     wbxml_list_destroy(one_ref, wbxml_strtbl_element_destroy_item);
3650     one_ref = NULL;
3651 
3652     /* Keep Strings referenced more than one time */
3653     if (strings != NULL)
3654         wbxml_strtbl_check_references(encoder, &strings, &one_ref, FALSE);
3655 
3656     /* 'strings' is destroyed after call of wbxml_strtbl_check_references() */
3657 
3658     /* Cleanup */
3659     wbxml_list_destroy(one_ref, wbxml_strtbl_element_destroy_item);
3660 
3661     return WBXML_OK;
3662 }
3663 
3664 
3665 /**
3666  * @brief Collect Strings in XML Document (in Text Content and Attribute Values)
3667  * @param encoder [in] The WBXML Encoder
3668  * @param node [in] The current element node of LibXML Tree
3669  * @param strings [out] List of WBXMLBuffer buffers corresponding to Collected Strings
3670  */
wbxml_strtbl_collect_strings(WBXMLEncoder * encoder,WBXMLTreeNode * node,WBXMLList * strings)3671 static void wbxml_strtbl_collect_strings(WBXMLEncoder *encoder, WBXMLTreeNode *node, WBXMLList *strings)
3672 {
3673     const WBXMLAttrEntry *attr_entry = NULL;
3674     WBXMLAttribute *attr = NULL;
3675     WB_ULONG i = 0;
3676     WB_UTINY *value_left = NULL;
3677 
3678     switch (node->type)
3679     {
3680         case WBXML_TREE_TEXT_NODE:
3681             /* Ignore blank nodes */
3682             if (wbxml_buffer_contains_only_whitespaces(node->content))
3683                 break;
3684 
3685             /** @todo Shrink / Strip Blanks */
3686 
3687             /* Only add this string if it is big enought */
3688             if (wbxml_buffer_len(node->content) > WBXML_ENCODER_STRING_TABLE_MIN) {
3689                 wbxml_list_append(strings, node->content);
3690                 WBXML_DEBUG((WBXML_ENCODER, "Strtbl - Collecting String: %s", wbxml_buffer_get_cstr(node->content)));
3691             }
3692             break;
3693 
3694         case WBXML_TREE_ELEMENT_NODE:
3695             /* Collect strings in Attributes Values too */
3696             if (node->attrs != NULL) {
3697                 for (i = 0; i < wbxml_list_len(node->attrs); i++) {
3698                     /* Get attribute */
3699                     attr = wbxml_list_get(node->attrs, i);
3700 
3701                     /* Only add this string if it is big enought */
3702                     if (attr && wbxml_buffer_len(attr->value) > WBXML_ENCODER_STRING_TABLE_MIN) {
3703                         /* This mustn't be a tokenisable Attribute Start */
3704                         attr_entry = wbxml_tables_get_attr_from_xml(encoder->lang,
3705                                                                    (WB_UTINY *) wbxml_attribute_get_xml_name(attr),
3706                                                                    (WB_UTINY *) wbxml_attribute_get_xml_value(attr),
3707                                                                    &value_left);
3708 
3709                         /* - If attr_entry is NULL: no Attribute Start found
3710                          * - If attr_entry is not NULL: and Attribute Start is found, but it can be the one with
3711                          *   no Attribute Value associated. So just check that the 'value_left' is the same than
3712                          *   the attribute value we where searching for
3713                          */
3714                         if ((attr_entry == NULL) || ((attr_entry != NULL) && (value_left == (WB_UTINY *) wbxml_attribute_get_xml_value(attr))))
3715                         {
3716                             /* It mustn't contain a tokenisable Attribute Value */
3717                             if (!wbxml_tables_contains_attr_value_from_xml(encoder->lang,
3718                                                                            (WB_UTINY *) wbxml_attribute_get_xml_value(attr)))
3719                             {
3720                                 wbxml_list_append(strings, attr->value);
3721                                 WBXML_DEBUG((WBXML_ENCODER, "Strtbl - Collecting String: %s", wbxml_buffer_get_cstr(attr->value)));
3722                             }
3723                         }
3724                     }
3725                 }
3726             }
3727             break;
3728 
3729         default:
3730             /* NOOP */
3731             break;
3732     }
3733 
3734     if (node->children != NULL)
3735         wbxml_strtbl_collect_strings(encoder, node->children, strings);
3736 
3737     if (node->next != NULL)
3738         wbxml_strtbl_collect_strings(encoder, node->next, strings);
3739 }
3740 
3741 
3742 /**
3743  * @brief Split Strings into Words
3744  * @param elements [in] List of String Table Elements to split
3745  * @param result [out] Resulting list of Words
3746  * @return WBXML_OK is no error, another error code otherwise
3747  */
wbxml_strtbl_collect_words(WBXMLList * elements,WBXMLList ** result)3748 static WBXMLError wbxml_strtbl_collect_words(WBXMLList *elements, WBXMLList **result)
3749 {
3750     WBXMLStringTableElement *elt = NULL;
3751     WBXMLList *list = NULL, *temp_list = NULL;
3752     WBXMLBuffer *word = NULL;
3753     WB_ULONG i = 0;
3754 
3755     *result = NULL;
3756 
3757     for (i = 0; i < wbxml_list_len(elements); i++)
3758     {
3759         elt = (WBXMLStringTableElement *) wbxml_list_get(elements, i);
3760         if (elt == NULL) {
3761             /* There is a bug inside the wbxml strtbl implementation.
3762                wbxml_list must be used in a wrong way.
3763              */
3764             wbxml_list_destroy(list, wbxml_buffer_destroy_item);
3765             return WBXML_ERROR_INTERNAL;
3766         }
3767 
3768         if (list == NULL) {
3769             if ((list = wbxml_buffer_split_words(elt->string)) == NULL) {
3770                 wbxml_list_destroy(list, wbxml_buffer_destroy_item);
3771                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3772             }
3773         } else {
3774             if ((temp_list = wbxml_buffer_split_words(elt->string)) == NULL) {
3775                 wbxml_list_destroy(list, wbxml_buffer_destroy_item);
3776                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3777             }
3778 
3779             while ((word = wbxml_list_extract_first(temp_list)) != NULL) {
3780                 if (!wbxml_list_append(list, word)) {
3781                     wbxml_buffer_destroy(word);
3782                     wbxml_list_destroy(temp_list, wbxml_buffer_destroy_item);
3783                     wbxml_list_destroy(list, wbxml_buffer_destroy_item);
3784                     return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3785                 }
3786             }
3787 
3788             wbxml_list_destroy(temp_list, NULL);
3789         }
3790     }
3791 
3792     *result = list;
3793 
3794     return WBXML_OK;
3795 }
3796 
3797 
3798 /**
3799  * @brief Append the String Table to result Buffer
3800  * @param buff The Buffer to append the String Table to
3801  * @param strstbl The String Table to append
3802  */
wbxml_strtbl_construct(WBXMLBuffer * buff,WBXMLList * strstbl)3803 static WBXMLError wbxml_strtbl_construct(WBXMLBuffer *buff, WBXMLList *strstbl)
3804 {
3805     WBXMLStringTableElement *elt = NULL;
3806     WB_ULONG i = 0;
3807 
3808     if ((buff == NULL) || (strstbl == NULL))
3809         return WBXML_ERROR_BAD_PARAMETER;
3810 
3811     for (i = 0; i < wbxml_list_len(strstbl); i++)
3812     {
3813         if ((elt = wbxml_list_get(strstbl, i)) == NULL)
3814             continue;
3815 
3816         if (!wbxml_buffer_append(buff, elt->string))
3817             return WBXML_ERROR_ENCODER_APPEND_DATA;
3818 
3819         if (!wbxml_buffer_append_char(buff, WBXML_STR_END))
3820             return WBXML_ERROR_ENCODER_APPEND_DATA;
3821     }
3822 
3823     return WBXML_OK;
3824 }
3825 
3826 
3827 /**
3828  * @brief Check strings that have multiple references, add them to string table
3829  *        and return strings that have only one reference
3830  * @param encoder The WBXML Encoder
3831  * @param strings The List of Strings to check (List of WBXMLBuffer) : This list is freed by this function
3832  * @param one_ref List of strings that have only one reference (List of WBXMLStringTableElement)
3833  * @param stat_buff If set to TRUE, Buffers referenced by 'strings' must NOT be destroyed.
3834  * @return WBXML_OK if no error, another error code otherwise
3835  * @warning All elements of 'strings' list are removed from this list
3836  */
wbxml_strtbl_check_references(WBXMLEncoder * encoder,WBXMLList ** strings,WBXMLList ** one_ref,WB_BOOL stat_buff)3837 static WBXMLError wbxml_strtbl_check_references(WBXMLEncoder *encoder, WBXMLList **strings, WBXMLList **one_ref, WB_BOOL stat_buff)
3838 {
3839     WBXMLList *referenced = NULL, *result = NULL;
3840     WBXMLBuffer *string = NULL;
3841     WBXMLStringTableElement *ref = NULL;
3842     WB_ULONG j = 0;
3843     WB_BOOL added = FALSE;
3844 
3845     if ((strings == NULL) || (one_ref == NULL))
3846         return WBXML_ERROR_INTERNAL;
3847 
3848     *one_ref = NULL;
3849 
3850     /* Create list of String References */
3851     if ((referenced = wbxml_list_create()) == NULL)
3852         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3853 
3854 
3855     /*********************
3856      * Count References
3857      */
3858 
3859     while (wbxml_list_len(*strings) > 0)
3860     {
3861         string = (WBXMLBuffer *) wbxml_list_extract_first(*strings);
3862 
3863         /* Check if we have already found this String */
3864         for (j = 0; j < wbxml_list_len(referenced); j++)
3865         {
3866             ref = (WBXMLStringTableElement *) wbxml_list_get(referenced, j);
3867             if (ref == NULL)
3868             {
3869                 /* There is a bug inside wbxml_strtbl_check_references.
3870                    wbxml_list must be used in a wrong way.
3871                  */
3872             	if (!stat_buff)
3873                     wbxml_buffer_destroy(string);
3874                 string = NULL;
3875                 wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3876                 return WBXML_ERROR_INTERNAL;
3877             }
3878 
3879             if (wbxml_buffer_compare(ref->string, string) == 0)
3880             {
3881                 if (!stat_buff)
3882                     wbxml_buffer_destroy(string);
3883 
3884                 string = NULL;
3885                 ref->count++;
3886                 break;
3887             }
3888         }
3889 
3890         if (string != NULL)
3891         {
3892             /* New Reference Element */
3893             if ((ref = wbxml_strtbl_element_create(string, stat_buff)) == NULL)
3894             {
3895                 wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3896 
3897                 if (!stat_buff)
3898                     wbxml_list_destroy(*strings, wbxml_buffer_destroy_item);
3899                 else
3900                     wbxml_list_destroy(*strings, NULL);
3901 
3902                 *strings = NULL;
3903                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3904             }
3905 
3906             ref->count++;
3907 
3908             if (!wbxml_list_append(referenced, (void *) ref))
3909             {
3910                 wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3911 
3912                 if (!stat_buff)
3913                     wbxml_list_destroy(*strings, wbxml_buffer_destroy_item);
3914                 else
3915                     wbxml_list_destroy(*strings, NULL);
3916 
3917                 *strings = NULL;
3918                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3919             }
3920         }
3921     }
3922 
3923 
3924     wbxml_list_destroy(*strings, NULL);
3925     *strings = NULL;
3926 
3927 
3928     /***********************************************
3929      * Remove Strings that have only One reference
3930      */
3931 
3932     if ((result = wbxml_list_create()) == NULL) {
3933         wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3934         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3935     }
3936 
3937     while (wbxml_list_len(referenced) > 0)
3938     {
3939         ref = (WBXMLStringTableElement *) wbxml_list_extract_first(referenced);
3940         if ((ref->count > 1) && (wbxml_buffer_len(ref->string) > WBXML_ENCODER_STRING_TABLE_MIN)) {
3941             /* Add Element to String Table */
3942             if (!wbxml_strtbl_add_element(encoder, ref, NULL, &added)) {
3943                 wbxml_strtbl_element_destroy(ref);
3944                 wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3945                 wbxml_list_destroy(result, wbxml_strtbl_element_destroy_item);
3946                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3947             }
3948 
3949             if (!added) {
3950                 wbxml_strtbl_element_destroy(ref);
3951             }
3952         }
3953         else {
3954             /* Add Element in resulting 'not added in String Table' list */
3955             if (!wbxml_list_append(result, (void *) ref)) {
3956                 wbxml_strtbl_element_destroy(ref);
3957                 wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3958                 wbxml_list_destroy(result, wbxml_strtbl_element_destroy_item);
3959                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
3960             }
3961         }
3962     }
3963 
3964     wbxml_list_destroy(referenced, wbxml_strtbl_element_destroy_item);
3965 
3966     *one_ref = result;
3967 
3968     return WBXML_OK;
3969 }
3970 
3971 
3972 /**
3973  * @brief Add a String in String table
3974  * @param encoder [in] The WBXML Encoder
3975  * @param elt [in] The Element to add
3976  * @param index [out] The index in String Table
3977  * @param added [out] TRUE if really added, or FALSe if already in String Table
3978  * @return TRUE if no error, FALSE is Memory Error
3979  */
wbxml_strtbl_add_element(WBXMLEncoder * encoder,WBXMLStringTableElement * elt,WB_ULONG * index,WB_BOOL * added)3980 static WB_BOOL wbxml_strtbl_add_element(WBXMLEncoder *encoder, WBXMLStringTableElement *elt, WB_ULONG *index, WB_BOOL *added)
3981 {
3982     WBXMLStringTableElement *elt_tmp = NULL;
3983     WB_ULONG i = 0;
3984 
3985     if ((encoder == NULL) || (encoder->strstbl == NULL) || (elt == NULL) || (elt->string == NULL))
3986         return FALSE;
3987 
3988     *added = FALSE;
3989 
3990     /* Check if this element already exists in String Table */
3991     for (i = 0; i < wbxml_list_len(encoder->strstbl); i++)
3992     {
3993         if ((elt_tmp = wbxml_list_get(encoder->strstbl, i)) == NULL)
3994             continue;
3995 
3996         if ((wbxml_buffer_len(elt_tmp->string) == wbxml_buffer_len(elt->string)) &&
3997             (wbxml_buffer_compare(elt_tmp->string, elt->string) == 0))
3998         {
3999             /* The String already exists in the String Table */
4000             if (index != NULL)
4001                 *index = elt_tmp->offset;
4002             return TRUE;
4003         }
4004     }
4005 
4006     /* Add this string to String Table */
4007     elt->offset = encoder->strstbl_len;
4008 
4009     if (!wbxml_list_append(encoder->strstbl, (void *) elt))
4010         return FALSE;
4011 
4012     /* Index in String Table */
4013     if (index != NULL)
4014         *index = encoder->strstbl_len;
4015 
4016     /* New String Table length */
4017     encoder->strstbl_len += wbxml_buffer_len(elt->string) + 1;
4018 
4019     *added = TRUE;
4020 
4021     return TRUE;
4022 }
4023 
4024 #endif /* WBXML_ENCODER_USE_STRTBL */
4025 
4026 
4027 /*****************************************
4028  *  XML Output Functions
4029  */
4030 
4031 /****************************
4032  * Build XML Result
4033  */
4034 
4035 /**
4036  * @brief Build XML Result
4037  * @param encoder [in] The WBXML Encoder
4038  * @param xml     [out] Resulting XML document
4039  * @param xml_len [out] XML document length
4040  * @return WBXML_OK if built is OK, an error code otherwise
4041  */
xml_build_result(WBXMLEncoder * encoder,WB_UTINY ** xml,WB_ULONG * xml_len)4042 static WBXMLError xml_build_result(WBXMLEncoder *encoder, WB_UTINY **xml, WB_ULONG *xml_len)
4043 {
4044     WBXMLBuffer *header = NULL;
4045     WB_ULONG     len    = 0;
4046     WBXMLError   ret    = WBXML_OK;
4047 
4048     if (xml == NULL)
4049         return WBXML_ERROR_BAD_PARAMETER;
4050 
4051     /* Init */
4052     if (xml_len != NULL)
4053         *xml_len = 0;
4054 
4055     if (encoder->flow_mode == TRUE) {
4056         /* Header already built */
4057         header = encoder->output_header;
4058     }
4059     else {
4060         /* Create Header Buffer */
4061         if ((header = wbxml_buffer_create("", 0, WBXML_ENCODER_XML_HEADER_MALLOC_BLOCK)) == NULL)
4062             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4063 
4064         /* Fill Header Buffer */
4065         if (encoder->xml_encode_header) {
4066             if ((ret = xml_fill_header(encoder, header)) != WBXML_OK) {
4067                 wbxml_buffer_destroy(header);
4068                 return ret;
4069             }
4070         }
4071     }
4072 
4073     /* Result Buffer Length */
4074     len = wbxml_buffer_len(header) + wbxml_buffer_len(encoder->output);
4075 
4076     /* Create Result Buffer */
4077     *xml = wbxml_malloc((len + 1) * sizeof(WB_UTINY));
4078     if (*xml == NULL) {
4079         if (encoder->flow_mode == FALSE)
4080             wbxml_buffer_destroy(header);
4081         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4082     }
4083 
4084     /** @todo Use the 'output_charset' field */
4085 
4086     /* Copy Header to Result */
4087     memcpy(*xml, wbxml_buffer_get_cstr(header), wbxml_buffer_len(header));
4088 
4089     /* Copy XML Document to Result */
4090     memcpy(*xml + wbxml_buffer_len(header), wbxml_buffer_get_cstr(encoder->output), wbxml_buffer_len(encoder->output));
4091 
4092     /** @todo Remove this NULL char if not needed by charset */
4093 
4094     /* NULL Terminated Buffer */
4095     (*xml)[len] = '\0';
4096 
4097     /* Set length */
4098     if (xml_len != NULL)
4099         *xml_len = len;
4100 
4101     /* Clean-up */
4102     if (encoder->flow_mode == FALSE)
4103         wbxml_buffer_destroy(header);
4104 
4105     return WBXML_OK;
4106 }
4107 
4108 
4109 /**
4110  * @brief Fill the XML Header
4111  * @param encoder The WBXML Encoder
4112  * @param header The Buffer to Fill
4113  * @return WBXML_OK if built is OK, an error code otherwise
4114  */
xml_fill_header(WBXMLEncoder * encoder,WBXMLBuffer * header)4115 static WBXMLError xml_fill_header(WBXMLEncoder *encoder, WBXMLBuffer *header)
4116 {
4117     if ((encoder == NULL) || (header == NULL))
4118         return WBXML_ERROR_BAD_PARAMETER;
4119 
4120     /** @todo Add 'encoding' info */
4121 
4122     /* <?xml version=\"1.0\"?> */
4123     if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_HEADER))
4124         return WBXML_ERROR_ENCODER_APPEND_DATA;
4125 
4126     /* New Line */
4127     if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4128         if (!xml_encode_new_line(header))
4129             return WBXML_ERROR_ENCODER_APPEND_DATA;
4130     }
4131 
4132     /* <!DOCTYPE */
4133     if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_DOCTYPE))
4134         return WBXML_ERROR_ENCODER_APPEND_DATA;
4135 
4136     /* Check that the language is set */
4137     if (encoder->lang == NULL)
4138         return WBXML_ERROR_LANG_TABLE_UNDEFINED;
4139 
4140     /* Root Element */
4141     if (!wbxml_buffer_append_cstr(header, encoder->lang->publicID->xmlRootElt))
4142         return WBXML_ERROR_ENCODER_APPEND_DATA;
4143 
4144     if (encoder->lang->publicID->xmlPublicID &&
4145         WBXML_STRLEN(encoder->lang->publicID->xmlPublicID)) {
4146 
4147         /*  PUBLIC " */
4148         if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_PUBLIC_START))
4149             return WBXML_ERROR_ENCODER_APPEND_DATA;
4150 
4151         /* Public ID */
4152         if (!wbxml_buffer_append_cstr(header, encoder->lang->publicID->xmlPublicID))
4153             return WBXML_ERROR_ENCODER_APPEND_DATA;
4154 
4155         /* " */
4156         if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_PUBLIC_END))
4157             return WBXML_ERROR_ENCODER_APPEND_DATA;
4158     } else {
4159 	/*  SYSTEM */
4160         if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_SYSTEM))
4161             return WBXML_ERROR_ENCODER_APPEND_DATA;
4162     }
4163 
4164     /* DTD */
4165     if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_DTD))
4166         return WBXML_ERROR_ENCODER_APPEND_DATA;
4167 
4168     /* DTD */
4169     if (!wbxml_buffer_append_cstr(header, encoder->lang->publicID->xmlDTD))
4170         return WBXML_ERROR_ENCODER_APPEND_DATA;
4171 
4172     /* "> */
4173     if (!wbxml_buffer_append_cstr(header, WBXML_ENCODER_XML_END_DTD))
4174         return WBXML_ERROR_ENCODER_APPEND_DATA;
4175 
4176     /* New Line */
4177     if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4178         if (!xml_encode_new_line(header))
4179             return WBXML_ERROR_ENCODER_APPEND_DATA;
4180     }
4181 
4182     return WBXML_OK;
4183 }
4184 
4185 
4186 /****************************
4187  * XML Encoding Functions
4188  */
4189 
4190 /**
4191  * @brief Encode an XML Tag
4192  * @param encoder The WBXML Encoder
4193  * @param node The element to encode
4194  * @return WBXML_OK if encoding is OK, an error code otherwise
4195  */
xml_encode_tag(WBXMLEncoder * encoder,WBXMLTreeNode * node)4196 static WBXMLError xml_encode_tag(WBXMLEncoder *encoder, WBXMLTreeNode *node)
4197 {
4198     const WB_TINY *ns = NULL;
4199     WB_UTINY i;
4200 
4201     /* Set as current Tag */
4202     if (node->name->type == WBXML_VALUE_TOKEN)
4203         encoder->current_tag = node->name->u.token;
4204     else
4205         encoder->current_tag = NULL;
4206 
4207     /* Indent */
4208     if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4209         for (i=0; i<(encoder->indent * encoder->indent_delta); i++) {
4210             if (!wbxml_buffer_append_char(encoder->output, ' '))
4211                 return WBXML_ERROR_ENCODER_APPEND_DATA;
4212         }
4213     }
4214 
4215     /* Append < */
4216     if (!wbxml_buffer_append_char(encoder->output, '<'))
4217         return WBXML_ERROR_ENCODER_APPEND_DATA;
4218 
4219     /* Append Element Name */
4220     if (!wbxml_buffer_append_cstr(encoder->output, wbxml_tag_get_xml_name(node->name)))
4221         return WBXML_ERROR_ENCODER_APPEND_DATA;
4222 
4223     /* NameSpace handling: Check if Current Node Code Page is different than Parent Node Code Page */
4224     if ((encoder->lang->nsTable != NULL) &&
4225         ((node->parent == NULL) ||
4226          ((node->parent->type == WBXML_TREE_ELEMENT_NODE) &&
4227           (node->parent->name->type == WBXML_VALUE_TOKEN) &&
4228           (node->type == WBXML_TREE_ELEMENT_NODE) &&
4229           (node->name->type == WBXML_VALUE_TOKEN) &&
4230           (node->parent->name->u.token->wbxmlCodePage != node->name->u.token->wbxmlCodePage))))
4231     {
4232         if ((ns = wbxml_tables_get_xmlns(encoder->lang->nsTable, node->name->u.token->wbxmlCodePage)) != NULL)
4233         {
4234             /* Append xmlns=" */
4235             if (!wbxml_buffer_append_cstr(encoder->output, " xmlns=\""))
4236                 return WBXML_ERROR_ENCODER_APPEND_DATA;
4237 
4238             /* Append NameSpace */
4239             if (!wbxml_buffer_append_cstr(encoder->output, ns))
4240                 return WBXML_ERROR_ENCODER_APPEND_DATA;
4241 
4242             /* Append " */
4243             if (!wbxml_buffer_append_char(encoder->output, '"'))
4244                 return WBXML_ERROR_ENCODER_APPEND_DATA;
4245         }
4246     }
4247 
4248     return WBXML_OK;
4249 }
4250 
4251 
4252 /**
4253  * @brief Encode an XML End Tag
4254  * @param encoder The WBXML Encoder
4255  * @param node Tag
4256  * @return WBXML_OK if encoding is OK, an error code otherwise
4257  */
xml_encode_end_tag(WBXMLEncoder * encoder,WBXMLTreeNode * node)4258 static WBXMLError xml_encode_end_tag(WBXMLEncoder *encoder, WBXMLTreeNode *node)
4259 {
4260     WB_UTINY i;
4261 
4262     if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4263 
4264 #if defined( WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT )
4265         if (wbxml_tree_node_have_child_elt(node)) {
4266 #endif /* WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT */
4267 
4268             /* Add a New Line if there were content in this element */
4269             if (encoder->in_content) {
4270                 if (!xml_encode_new_line(encoder->output))
4271                     return WBXML_ERROR_ENCODER_APPEND_DATA;
4272             }
4273 
4274             encoder->indent--;
4275 
4276             /* Indent End Element */
4277             for (i=0; i<(encoder->indent * encoder->indent_delta); i++) {
4278                 if (!wbxml_buffer_append_char(encoder->output, ' '))
4279                     return WBXML_ERROR_ENCODER_APPEND_DATA;
4280             }
4281 
4282 #if defined( WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT )
4283         }
4284 #endif /* WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT */
4285 
4286     }
4287 
4288     /* Append </ */
4289     if (!wbxml_buffer_append_cstr(encoder->output, "</"))
4290         return WBXML_ERROR_ENCODER_APPEND_DATA;
4291 
4292     /* Append Element Name */
4293     if (!wbxml_buffer_append_cstr(encoder->output, wbxml_tag_get_xml_name(node->name)))
4294         return WBXML_ERROR_ENCODER_APPEND_DATA;
4295 
4296     /* Append > */
4297     if (!wbxml_buffer_append_char(encoder->output, '>'))
4298         return WBXML_ERROR_ENCODER_APPEND_DATA;
4299 
4300     /* New Line */
4301     if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4302         if (!xml_encode_new_line(encoder->output))
4303             return WBXML_ERROR_ENCODER_APPEND_DATA;
4304     }
4305 
4306     /* No more in content */
4307     encoder->in_content = FALSE;
4308 
4309     return WBXML_OK;
4310 }
4311 
4312 
4313 /**
4314  * @brief Encode a XML Attribute
4315  * @param encoder [in] The WBXML Encoder
4316  * @param attribute [in] The Attribute to encode
4317  * @return WBXML_OK if encoding is OK, an error code otherwise
4318  */
xml_encode_attr(WBXMLEncoder * encoder,WBXMLAttribute * attribute)4319 static WBXMLError xml_encode_attr(WBXMLEncoder *encoder, WBXMLAttribute *attribute)
4320 {
4321     /* Append a space */
4322     if (!wbxml_buffer_append_char(encoder->output, ' '))
4323         return WBXML_ERROR_ENCODER_APPEND_DATA;
4324 
4325     /* Append Attribute Name */
4326     if (!wbxml_buffer_append_cstr(encoder->output, wbxml_attribute_get_xml_name(attribute)))
4327         return WBXML_ERROR_ENCODER_APPEND_DATA;
4328 
4329     /* Append =" */
4330     if (!wbxml_buffer_append_cstr(encoder->output, "=\""))
4331         return WBXML_ERROR_ENCODER_APPEND_DATA;
4332 
4333     if (wbxml_attribute_get_xml_value(attribute) != NULL) {
4334         /* Fix Attribute Value text */
4335         WBXMLBuffer *tmp = NULL;
4336 
4337         /* Work with a temporary copy */
4338         if ((tmp = wbxml_buffer_create_from_cstr(wbxml_attribute_get_xml_value(attribute))) == NULL)
4339             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4340 
4341         /* Fix text */
4342         if (xml_encode_text_entities(encoder, tmp)) {
4343             wbxml_buffer_destroy(tmp);
4344             return WBXML_ERROR_ENCODER_APPEND_DATA;
4345         }
4346 
4347         wbxml_buffer_destroy(tmp);
4348     }
4349 
4350     /* Append " */
4351     if (!wbxml_buffer_append_char(encoder->output, '"'))
4352         return WBXML_ERROR_ENCODER_APPEND_DATA;
4353 
4354     return WBXML_OK;
4355 }
4356 
4357 
4358 /**
4359  * @brief Encode a End of XML Attributes List
4360  * @param encoder [in] The WBXML Encoder
4361  * @param node    [in] Current node
4362  * @return WBXML_OK if encoding is OK, an error code otherwise
4363  */
xml_encode_end_attrs(WBXMLEncoder * encoder,WBXMLTreeNode * node)4364 static WBXMLError xml_encode_end_attrs(WBXMLEncoder *encoder, WBXMLTreeNode *node)
4365 {
4366 #if defined( WBXML_ENCODER_XML_GEN_EMPTY_ELT )
4367 
4368     if (node->children == NULL) {
4369         /* Append " />" */
4370         if (!wbxml_buffer_append_cstr(encoder->output, "/>"))
4371             return WBXML_ERROR_ENCODER_APPEND_DATA;
4372 
4373         /* New Line */
4374         if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4375             if (!xml_encode_new_line(encoder->output))
4376                 return WBXML_ERROR_ENCODER_APPEND_DATA;
4377         }
4378     }
4379     else {
4380 
4381 #endif /* WBXML_ENCODER_XML_GEN_EMPTY_ELT */
4382 
4383         /* Append > */
4384         if (!wbxml_buffer_append_char(encoder->output, '>'))
4385             return WBXML_ERROR_ENCODER_APPEND_DATA;
4386 
4387         /* New Line */
4388         if (encoder->xml_gen_type == WBXML_GEN_XML_INDENT) {
4389 
4390 #if defined( WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT )
4391             if (wbxml_tree_node_have_child_elt(node)) {
4392 #endif /* WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT */
4393 
4394                 if (!xml_encode_new_line(encoder->output))
4395                     return WBXML_ERROR_ENCODER_APPEND_DATA;
4396 
4397                 /* Increment indentation */
4398                 encoder->indent++;
4399 
4400 #if defined( WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT )
4401             }
4402 #endif /* WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT */
4403 
4404         }
4405 
4406 #if defined( WBXML_ENCODER_XML_GEN_EMPTY_ELT )
4407 
4408     }
4409 
4410 #endif /* WBXML_ENCODER_XML_GEN_EMPTY_ELT */
4411 
4412     return WBXML_OK;
4413 }
4414 
4415 /**
4416  * @brief Encode an XML Text
4417  * @param encoder The WBXML Encoder
4418  * @param node    The node containing XML Text to encode
4419  * @return WBXML_OK if encoding is OK, an error code otherwise
4420  */
xml_encode_text(WBXMLEncoder * encoder,WBXMLTreeNode * node)4421 static WBXMLError xml_encode_text(WBXMLEncoder *encoder, WBXMLTreeNode *node)
4422 {
4423     WBXMLBuffer *str = node->content;
4424     WBXMLBuffer *tmp = NULL;
4425     WB_UTINY i = 0;
4426 
4427     if (encoder->in_cdata) {
4428         /* If we are in a CDATA section, do not modify the text to encode */
4429         if (!wbxml_buffer_append(encoder->output, str))
4430             return WBXML_ERROR_ENCODER_APPEND_DATA;
4431     }
4432     else {
4433         /* Work with a temporary copy */
4434         if ((tmp = wbxml_buffer_duplicate(str)) == NULL)
4435             return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4436 
4437         /* Indent */
4438         if ((encoder->xml_gen_type == WBXML_GEN_XML_INDENT) &&
4439             (!encoder->in_content))
4440         {
4441 #if defined( WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT )
4442             if (wbxml_tree_node_have_child_elt(node)) {
4443 #endif /* WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT */
4444 
4445                 /* Indent Content (only indent in first call to xml_encode_text()) */
4446                 for (i=0; i<(encoder->indent * encoder->indent_delta); i++) {
4447                     if (!wbxml_buffer_append_char(encoder->output, ' ')) {
4448                         wbxml_buffer_destroy(tmp);
4449                         return WBXML_ERROR_ENCODER_APPEND_DATA;
4450                     }
4451                 }
4452 
4453 #if defined( WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT )
4454             }
4455 #endif /* WBXML_ENCODER_XML_NO_EMPTY_ELT_INDENT */
4456         }
4457 
4458 #if defined( WBXML_SUPPORT_SYNCML )
4459         /* Change text in <Type> from "application/vnd.syncml-devinf+wbxml" to "application/vnd.syncml-devinf+xml" */
4460         if (((encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML10) ||
4461              (encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML11) ||
4462              (encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML12)) &&
4463             (encoder->current_tag != NULL) &&
4464             (encoder->current_tag->wbxmlCodePage == 0x01 ) &&
4465             (encoder->current_tag->wbxmlToken == 0x13 ) &&
4466             (wbxml_buffer_compare_cstr(tmp, "application/vnd.syncml-devinf+wbxml") == 0))
4467         {
4468             wbxml_buffer_destroy(tmp);
4469 
4470             /* Change Content */
4471             if ((tmp = wbxml_buffer_create_from_cstr("application/vnd.syncml-devinf+xml")) == NULL)
4472                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4473         }
4474         /* Change text in <Type> from "application/vnd.syncml.dmtnds+wbxml" to "application/vnd.syncml.dmtnds+xml" */
4475         if ((encoder->lang->langID == WBXML_LANG_SYNCML_SYNCML12) &&
4476             (encoder->current_tag != NULL) &&
4477             (encoder->current_tag->wbxmlCodePage == 0x01 ) &&
4478             (encoder->current_tag->wbxmlToken == 0x13 ) &&
4479             (wbxml_buffer_compare_cstr(tmp, "application/vnd.syncml.dmtnds+wbxml") == 0))
4480         {
4481             wbxml_buffer_destroy(tmp);
4482 
4483             /* Change Content */
4484             if ((tmp = wbxml_buffer_create_from_cstr("application/vnd.syncml.dmtnds+xml")) == NULL)
4485                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4486         }
4487 #endif /* WBXML_SUPPORT_SYNCML */
4488 
4489         /* Some elements are transferred as WBXML opaque data. They contain
4490          * binary data that isn't necessary valid in XML, so return them in Base
4491          * 64.
4492          */
4493         if (encoder->current_tag != NULL &&
4494             encoder->current_tag->options & WBXML_TAG_OPTION_BINARY)
4495         {
4496             WBXMLError ret;
4497             if ((ret = wbxml_buffer_encode_base64(tmp)) != WBXML_OK) {
4498                 wbxml_buffer_destroy(tmp);
4499                 return ret;
4500             }
4501         }
4502 
4503         /* Fix text */
4504         if (xml_encode_text_entities(encoder, tmp)) {
4505             wbxml_buffer_destroy(tmp);
4506             return WBXML_ERROR_ENCODER_APPEND_DATA;
4507         }
4508 
4509         /* Clean-up */
4510         wbxml_buffer_destroy(tmp);
4511     }
4512 
4513     encoder->in_content = TRUE;
4514 
4515     return WBXML_OK;
4516 }
4517 
4518 
4519 /**
4520  * @brief Append a New Line to a Buffer
4521  * @param buff The Buffer
4522  * @return TRUE if added, FALSE otherwise
4523  */
xml_encode_new_line(WBXMLBuffer * buff)4524 static WB_BOOL xml_encode_new_line(WBXMLBuffer *buff)
4525 {
4526     if (buff == NULL)
4527         return FALSE;
4528 
4529     return wbxml_buffer_append_data(buff, WBXML_ENCODER_XML_NEW_LINE, WBXML_STRLEN(WBXML_ENCODER_XML_NEW_LINE));
4530 }
4531 
4532 
4533 /**
4534  * @brief Fix an XML text buffer (content text or attribute value)
4535  * @param buff The Buffer to fix
4536  * @param normalize Normalize text ?
4537  * @return WBXML_OK if ok, an Error Code otherwise
4538  * @note Reference: http://www.w3.org/TR/2004/REC-xml-20040204/#syntax
4539  */
xml_encode_text_entities(WBXMLEncoder * encoder,WBXMLBuffer * buff)4540 static WBXMLError xml_encode_text_entities(WBXMLEncoder *encoder, WBXMLBuffer *buff)
4541 {
4542     WB_ULONG i = 0;
4543     WB_UTINY ch;
4544     WB_BOOL normalize = (WB_BOOL) (encoder->xml_gen_type == WBXML_GEN_XML_CANONICAL);
4545 
4546     for (i = 0; i < wbxml_buffer_len(buff); i++) {
4547         if (!wbxml_buffer_get_char(buff, i, &ch))
4548             continue;
4549 
4550         switch (ch) {
4551         case '<':
4552             /* Write "&lt;" */
4553             if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_lt))
4554                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4555 
4556             break;
4557 
4558         case '>':
4559             /* Write "&gt;" */
4560             if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_gt))
4561                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4562 
4563             break;
4564 
4565         case '&':
4566             /* Write "&amp;" */
4567             if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_amp))
4568                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4569 
4570             break;
4571 
4572         case '"':
4573             /* Write "&quot;" */
4574             if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_quot))
4575                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4576 
4577             break;
4578 
4579         case '\'':
4580             /* Write "&apos;" */
4581             if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_apos))
4582                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4583 
4584             break;
4585 
4586         case '\r':
4587             if (normalize) {
4588                 /* Write "&#13;" */
4589                 if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_slashr))
4590                     return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4591 
4592                 break;
4593             }
4594 
4595         case '\n':
4596             if (normalize) {
4597                 /* Write "&#10;" */
4598                 if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_slashn))
4599                     return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4600                 break;
4601             }
4602 
4603         case '\t':
4604             if (normalize) {
4605                 /* Write "&#9;" */
4606                 if (!wbxml_buffer_append_cstr(encoder->output, (WB_UTINY *) xml_tab))
4607                     return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4608                 break;
4609             }
4610 
4611         default:
4612             if (!wbxml_buffer_append_char(encoder->output, ch))
4613                 return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4614 
4615             break;
4616         }
4617     }
4618 
4619     return WBXML_OK;
4620 }
4621 
4622 
4623 /**
4624  * @brief Encode a begin of CDATA section
4625  * @param encoder The WBXML Encoder
4626  * @return WBXML_OK if encoding is OK, an error code otherwise
4627  */
xml_encode_cdata(WBXMLEncoder * encoder)4628 static WBXMLError xml_encode_cdata(WBXMLEncoder *encoder)
4629 {
4630     /* Append <![CDATA[ */
4631     if (!wbxml_buffer_append_cstr(encoder->output, "<![CDATA["))
4632         return WBXML_ERROR_ENCODER_APPEND_DATA;
4633 
4634     return WBXML_OK;
4635 }
4636 
4637 
4638 /**
4639  * @brief Encode an end of CDATA section
4640  * @param encoder The WBXML Encoder
4641  * @return WBXML_OK if encoding is OK, an error code otherwise
4642  */
xml_encode_end_cdata(WBXMLEncoder * encoder)4643 static WBXMLError xml_encode_end_cdata(WBXMLEncoder *encoder)
4644 {
4645     /* Append ]]> */
4646     if (!wbxml_buffer_append_cstr(encoder->output, "]]>"))
4647         return WBXML_ERROR_ENCODER_APPEND_DATA;
4648 
4649     return WBXML_OK;
4650 }
4651 
4652 
4653 /**
4654  * @brief Encode an encapsulated WBXML Tree to XML
4655  * @param encoder [in] The WBXML Encoder
4656  * @param tree    [in] The WBXML Tree to encode
4657  * @return WBXML_OK if encoding is OK, an error code otherwise
4658  */
xml_encode_tree(WBXMLEncoder * encoder,WBXMLTree * tree)4659 static WBXMLError xml_encode_tree(WBXMLEncoder *encoder, WBXMLTree *tree)
4660 {
4661     WBXMLEncoder *new_encoder = NULL;
4662     WB_UTINY     *xml         = NULL;
4663     WB_ULONG      xml_len     = 0;
4664     WBXMLError    ret         = WBXML_OK;
4665 
4666     if ((new_encoder = encoder_duplicate(encoder)) == NULL)
4667         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4668 
4669     /* Set Tree */
4670     new_encoder->tree = tree;
4671 
4672     /* Encode to XML */
4673     if ((ret = wbxml_encoder_encode_tree_to_xml(new_encoder, &xml, &xml_len)) != WBXML_OK) {
4674         wbxml_encoder_destroy(new_encoder);
4675         return ret;
4676     }
4677 
4678     /* Clean-up */
4679     wbxml_encoder_destroy(new_encoder);
4680 
4681     /** @bug Handle output_charset ! */
4682 
4683     /* Append xml to output */
4684     if (!wbxml_buffer_append_cstr(encoder->output, xml)) {
4685         wbxml_free(xml);
4686         return WBXML_ERROR_NOT_ENOUGH_MEMORY;
4687     }
4688 
4689     /* Clean-up */
4690     wbxml_free(xml);
4691 
4692     return WBXML_OK;
4693 }
4694