libsyncml  0.5.4
sml_xml_parse.c
1 /*
2  * libsyncml - A syncml protocol implementation
3  * Copyright (C) 2005 Armin Bauer <armin.bauer@opensync.org>
4  * Copyright (C) 2007-2009 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #include <libsyncml/syncml.h>
23 
24 #include <libsyncml/syncml_internals.h>
25 #include <libsyncml/sml_elements_internals.h>
26 #include <libsyncml/sml_command_internals.h>
27 #include <libsyncml/sml_devinf_internals.h>
28 #include <libsyncml/sml_session_internals.h>
29 #include "libsyncml/sml_error_internals.h"
30 
31 #include "sml_xml_parse.h"
32 #include "sml_xml_parse_internals.h"
33 
34 #define BUFFER_SIZE 500
35 
36 static SmlBool _smlXmlParserStep(SmlXmlParser *parser)
37 {
38  SmlBool ret = FALSE;
39  do {
40  ret = (xmlTextReaderRead(parser->reader) == 1) ? TRUE : FALSE;
41  } while (ret && (xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_DOCUMENT_TYPE || \
42  xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_WHITESPACE || \
43  xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE));
44 
45  return ret;
46 }
47 
48 static SmlBool _smlXmlParserStepData(SmlXmlParser *parser)
49 {
50  SmlBool ret = FALSE;
51  do {
52  ret = (xmlTextReaderRead(parser->reader) == 1) ? TRUE : FALSE;
53  } while (ret && (xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_DOCUMENT_TYPE || \
54  xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_WHITESPACE));
55 
56  return ret;
57 }
58 
59 static SmlBool _smlXmlSkipNode(SmlXmlParser *parser)
60 {
61  int node_type;
62 
63  if (xmlTextReaderNext(parser->reader) != 1)
64  return FALSE;
65 
66  node_type = xmlTextReaderNodeType(parser->reader);
67  while (xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_DOCUMENT_TYPE ||
68  xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_WHITESPACE ||
69  xmlTextReaderNodeType(parser->reader) == XML_READER_TYPE_SIGNIFICANT_WHITESPACE)
70  {
71  if (!_smlXmlParserStep (parser))
72  return FALSE;
73  }
74 
75  return TRUE;
76 }
77 
78 static SmlBool _smlXmlParserExpectNode(SmlXmlParser *parser, int type, SmlBool empty, const char *name, SmlError **error)
79 {
80  CHECK_ERROR_REF
81  if (!_smlXmlParserStep(parser)) {
82  smlErrorSet(error, SML_ERROR_GENERIC, "No node at all");
83  return FALSE;
84  }
85 
86  if (xmlTextReaderNodeType(parser->reader) != type) {
87  smlErrorSet(error, SML_ERROR_GENERIC, "wrong node type");
88  return FALSE;
89  }
90 
91 
92  switch (type) {
93  case XML_NODE_START:
94  case XML_NODE_CLOSE:
95  if (name) {
96  if (!xmlTextReaderConstName(parser->reader)) {
97  smlErrorSet(error, SML_ERROR_GENERIC, "no name");
98  return FALSE;
99  }
100 
101  if (strcmp((char *)xmlTextReaderConstName(parser->reader), name)) {
102  smlErrorSet(error, SML_ERROR_GENERIC, "Wrong name");
103  return FALSE;
104  }
105  }
106  break;
107  case XML_NODE_TEXT:
108  if (!empty && !xmlTextReaderConstName(parser->reader)) {
109  smlErrorSet(error, SML_ERROR_GENERIC, "Empty.");
110  return FALSE;
111  }
112  break;
113  default:
114  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown node type");
115  return FALSE;
116  }
117 
118  return TRUE;
119 }
120 
121 static SmlBool _smlXmlParserGetID(SmlXmlParser *parser, unsigned int *id, const char *name, SmlError **error)
122 {
123  CHECK_ERROR_REF
124  smlAssert(parser);
125  smlAssert(id);
126 
127  if (*id) {
128  smlErrorSet(error, SML_ERROR_GENERIC, "Id already set");
129  goto error;
130  }
131 
132  if (!_smlXmlParserExpectNode(parser, XML_NODE_TEXT, FALSE, NULL, error))
133  goto error;
134 
135  *id = atoi(g_strstrip((char *)xmlTextReaderConstValue(parser->reader)));
136 
137  if (!_smlXmlParserExpectNode(parser, XML_NODE_CLOSE, FALSE, name, error))
138  goto error;
139 
140  return TRUE;
141 
142 error:
143  return FALSE;
144 }
145 
146 static SmlBool _smlXmlParserGetString(SmlXmlParser *parser, char **string, const char *name, SmlError **error)
147 {
148  CHECK_ERROR_REF
149  smlAssert(parser);
150  smlAssert(string);
151 
152  if (*string) {
153  smlErrorSet(error, SML_ERROR_GENERIC, "string already set");
154  goto error;
155  }
156 
157  /* required for empty elements like <FwV/> */
158  if (xmlTextReaderIsEmptyElement(parser->reader)) {
159  *string = g_strdup("");
160  return TRUE;
161  }
162 
163  if (!_smlXmlParserStep(parser)) {
164  smlErrorSet(error, SML_ERROR_GENERIC, "No node at all");
165  goto error_clear;
166  }
167 
168  if (xmlTextReaderNodeType(parser->reader) == XML_NODE_TEXT) {
169  *string = g_strstrip(g_strdup((char *)xmlTextReaderConstValue(parser->reader)));
170 
171  if (!_smlXmlParserExpectNode(parser, XML_NODE_CLOSE, FALSE, name, error))
172  goto error_clear;
173  } else if (xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
174  *string = g_strdup("");
175  } else {
176  smlErrorSet(error, SML_ERROR_GENERIC, "wrong node type");
177  goto error_clear;
178  }
179 
180  return TRUE;
181 
182 error_clear:
183  *string = NULL;
184 error:
185  return FALSE;
186 }
187 
188 static SmlBool _smlXmlParserGetData(SmlXmlParser *parser, char **string, unsigned int *size, const char *name, SmlError **error)
189 {
190  CHECK_ERROR_REF
191  smlAssert(parser);
192  smlAssert(string);
193  int rc = 0;
194 
195  if (*string) {
196  smlErrorSet(error, SML_ERROR_GENERIC, "string already set");
197  return FALSE;
198  }
199 
200 
201  xmlBuffer *buffer = xmlBufferCreateSize(BUFFER_SIZE);
202  if (!buffer) {
203  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new buffer");
204  goto error;
205  }
206 
207  xmlTextWriter *writer = xmlNewTextWriterMemory(buffer, 0);
208  if (!writer) {
209  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
210  goto error_free_buffer;
211  }
212 
213  /* SyncML 1.2 allows empty data elements <Data /> */
214  if (xmlTextReaderIsEmptyElement(parser->reader))
215  goto out;
216 
217  while (1) {
218  if (!_smlXmlParserStepData(parser)) {
219  smlErrorSet(error, SML_ERROR_GENERIC, "There is a missing node during the data parsing of %s.", name);
220  goto error_free_writer;
221  }
222 
223  switch (xmlTextReaderNodeType(parser->reader)) {
224  case XML_NODE_CLOSE:
225  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), name))
226  goto out;
227 
228  if (!xmlTextReaderIsEmptyElement(parser->reader))
229  rc = xmlTextWriterEndElement(writer);
230 
231  if (rc < 0) {
232  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end node");
233  goto error_free_writer;
234  }
235  break;
236  case XML_NODE_START:
237  if (!xmlTextReaderIsEmptyElement(parser->reader))
238  rc = xmlTextWriterStartElementNS(writer, NULL, xmlTextReaderConstName(parser->reader), NULL);
239  else
240  rc = xmlTextWriterWriteElementNS(writer, NULL, xmlTextReaderConstName(parser->reader), NULL, (const xmlChar*)"");
241 
242  if (rc < 0) {
243  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to start node");
244  goto error_free_writer;
245  }
246  break;
247  case XML_NODE_CDATA:
248  case XML_NODE_TEXT:
249  rc = xmlTextWriterWriteRaw(writer, xmlTextReaderConstValue(parser->reader));
250  if (rc < 0) {
251  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add string");
252  goto error_free_writer;
253  }
254  break;
255  case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
256  rc = xmlTextWriterWriteRaw(writer, xmlTextReaderConstValue(parser->reader));
257  if (rc < 0) {
258  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add string");
259  goto error_free_writer;
260  }
261  break;
262  default:
263  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown node type");
264  goto error_free_writer;
265  }
266  }
267 
268 out:
269  // do not call xmlTextWriterEndDocument here
270  // the writer was not started with xmlTextWriterStartDocument
271  // the function adds always a newline
272  // if you load only a CDATA field then a newline is additional data
273  // additional data invalidates size information of the remote peer
274  // additional data crashs by this way all length checks if smlItemCheck !!!
275 
276  xmlFreeTextWriter(writer);
277  *string = g_strndup((const char *) xmlBufferContent(buffer), xmlBufferLength(buffer));
278  if (size)
279  *size = xmlBufferLength(buffer);
280 
281  xmlBufferFree(buffer);
282 
283  return TRUE;
284 
285 error_free_writer:
286  xmlFreeTextWriter(writer);
287 error_free_buffer:
288  xmlBufferFree(buffer);
289 error:
290  *string = NULL;
291  if (size) *size = 0;
292  return FALSE;
293 }
294 
295 static SmlBool _smlSyncHeaderParseDTD(SmlProtocolVersion *version, SmlXmlParser *parser, SmlError **error)
296 {
297  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, version, parser, error);
298  CHECK_ERROR_REF
299  smlAssert(parser);
300  smlAssert(version);
301 
302  if (*version) {
303  smlErrorSet(error, SML_ERROR_GENERIC, "dtd already set");
304  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
305  return FALSE;
306  }
307 
308  char *dtd = NULL;
309  if (!_smlXmlParserGetString(parser, &dtd, SML_ELEMENT_VERDTD, error))
310  goto error;
311 
312  if (!strcmp(dtd, "1.0"))
313  *version = SML_VERSION_10;
314  else if (!strcmp(dtd, "1.1"))
315  *version = SML_VERSION_11;
316  else if (!strcmp(dtd, "1.2"))
317  *version = SML_VERSION_12;
318  else {
319  smlSafeCFree(&dtd);
320  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown VerDTD");
321  goto error;
322  }
323  smlSafeCFree(&dtd);
324 
325  smlTrace(TRACE_EXIT, "%s", __func__);
326  return TRUE;
327 
328 error:
329  *version = SML_VERSION_UNKNOWN;
330  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
331  return FALSE;
332 }
333 
334 static SmlBool _smlSyncHeaderParseProto(SmlProtocolType *type, SmlXmlParser *parser, SmlError **error)
335 {
336  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, type, parser, error);
337  CHECK_ERROR_REF
338  smlAssert(parser);
339  smlAssert(type);
340 
341  if (*type) {
342  smlErrorSet(error, SML_ERROR_GENERIC, "protocol already set");
343  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
344  return FALSE;
345  }
346 
347  char *proto = NULL;
348  if (!_smlXmlParserGetString(parser, &proto, SML_ELEMENT_VERPROTO, error))
349  goto error;
350 
351  if (!strcmp(proto, SML_VERSION_STRING_10) || !strcmp(proto, SML_VERSION_STRING_11) || !strcmp(proto, SML_VERSION_STRING_12))
352  *type = SML_PROTOCOL_SYNCML;
353  else {
354  smlSafeCFree(&proto);
355  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown VerProto");
356  goto error;
357  }
358  smlSafeCFree(&proto);
359 
360  smlTrace(TRACE_EXIT, "%s", __func__);
361  return TRUE;
362 
363 error:
364  *type = SML_PROTOCOL_UNKNOWN;
365  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
366  return FALSE;
367 }
368 
369 
370 static SmlBool _smlLocationParse(SmlLocation **location, SmlXmlParser *parser, SmlError **error)
371 {
372  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, location, parser, error);
373  CHECK_ERROR_REF
374  smlAssert(parser);
375  smlAssert(location);
376 
377  if (*location) {
378  smlErrorSet(error, SML_ERROR_GENERIC, "Location already set");
379  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
380  return FALSE;
381  }
382 
383  *location = smlTryMalloc0(sizeof(SmlLocation), error);
384  if (!location)
385  goto error;
386  (*location)->refCount = 1;
387 
388  while (1) {
389  if (!_smlXmlParserStep(parser)) {
390  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
391  goto error_free_location;
392  }
393 
394  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET) && \
395  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
396  break;
397  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE) && \
398  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
399  break;
400  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE_PARENT) && \
401  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
402  break;
403  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET_PARENT) && \
404  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
405  break;
406  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
407  smlErrorSet(error, SML_ERROR_GENERIC,
408  "The element %s is not a start node in locations (Target, Source, SourceParent or TargetParent).",
409  xmlTextReaderConstName(parser->reader));
410  goto error_free_location;
411  }
412 
413  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_LOCURI)) {
414  if (!_smlXmlParserGetString(parser, &((*location)->locURI), SML_ELEMENT_LOCURI, error))
415  goto error_free_location;
416  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_LOCNAME)) {
417  if (!_smlXmlParserGetString(parser, &((*location)->locName), SML_ELEMENT_LOCNAME, error))
418  goto error_free_location;
419  } else {
420  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node. expected SyncHdr");
421  goto error_free_location;
422  }
423  }
424 
425  if (!(*location)->locURI) {
426  smlErrorSet(error, SML_ERROR_GENERIC, "No locURI set");
427  goto error_free_location;
428  }
429 
430  smlTrace(TRACE_EXIT, "%s", __func__);
431  return TRUE;
432 
433 error_free_location:
434  smlLocationUnref(*location);
435 error:
436  *location = NULL;
437  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
438  return FALSE;
439 }
440 
441 static SmlBool _smlAnchorParse(SmlAnchor **anchor, SmlXmlParser *parser, SmlError **error)
442 {
443  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, anchor, parser, error);
444  CHECK_ERROR_REF
445  smlAssert(parser);
446  smlAssert(anchor);
447 
448  if (*anchor) {
449  smlErrorSet(error, SML_ERROR_GENERIC, "anchor already set");
450  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
451  return FALSE;
452  }
453 
454  *anchor = smlTryMalloc0(sizeof(SmlAnchor), error);
455  if (!anchor)
456  goto error;
457 
458  while (1) {
459  if (!_smlXmlParserStep(parser)) {
460  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
461  goto error_free_anchor;
462  }
463 
464  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ANCHOR) && \
465  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
466  break;
467  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
468  smlErrorSet(error, SML_ERROR_GENERIC,
469  "The element %s is not a start node in Anchor.",
470  xmlTextReaderConstName(parser->reader));
471  goto error_free_anchor;
472  }
473 
474  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_NEXT)) {
475  if (!_smlXmlParserGetString(parser, &((*anchor)->next), SML_ELEMENT_NEXT, error))
476  goto error_free_anchor;
477  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_LAST)) {
478  if (!_smlXmlParserGetString(parser, &((*anchor)->last), SML_ELEMENT_LAST, error))
479  goto error_free_anchor;
480  } else {
481  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
482  goto error_free_anchor;
483  }
484  }
485 
486  if (!(*anchor)->next) {
487  smlErrorSet(error, SML_ERROR_GENERIC, "No next set");
488  goto error_free_anchor;
489  }
490 
491  smlTrace(TRACE_EXIT, "%s", __func__);
492  return TRUE;
493 
494 error_free_anchor:
495  smlAnchorFree(*anchor);
496 error:
497  *anchor = NULL;
498  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
499  return FALSE;
500 }
501 
502 static SmlBool _smlChalMetaParse(SmlXmlParser *parser, char **format, char **type, char **nonce, SmlError **error)
503 {
504  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %p, %p, %p)", __func__, parser, format, type, nonce, error);
505  CHECK_ERROR_REF
506  smlAssert(parser);
507 
508  while (1) {
509  if (!_smlXmlParserStep(parser)) {
510  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
511  goto error;
512  }
513 
514  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META) && \
515  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
516  break;
517  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
518  smlErrorSet(error, SML_ERROR_GENERIC,
519  "The element %s is not a start node in Chal/Meta.",
520  xmlTextReaderConstName(parser->reader));
521  goto error;
522  }
523 
524  if (type && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TYPE)) {
525  if (!_smlXmlParserGetString(parser, type, SML_ELEMENT_TYPE, error))
526  goto error;
527  } else if (format && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FORMAT)) {
528  if (!_smlXmlParserGetString(parser, format, SML_ELEMENT_FORMAT, error))
529  goto error;
530  } else if (format && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_NEXTNONCE)) {
531  if (!_smlXmlParserGetString(parser, nonce, SML_ELEMENT_NEXTNONCE, error))
532  goto error;
533  } else {
534  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node: %s", xmlTextReaderConstName(parser->reader));
535  goto error;
536  }
537  }
538 
539  smlTrace(TRACE_EXIT, "%s", __func__);
540  return TRUE;
541 
542 error:
543  if (format)
544  *format = NULL;
545  if (nonce)
546  *nonce = NULL;
547  if (type)
548  *type = NULL;
549 
550  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
551  return FALSE;
552 }
553 
554 static SmlBool _smlCommandMetaParse(SmlXmlParser *parser, char **format, char **type, SmlAnchor **anchor, unsigned int *size, int *maxobjsize, SmlError **error)
555 {
556  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %p, %p, %p)", __func__, parser, format, type, anchor, size, maxobjsize, error);
557  CHECK_ERROR_REF
558  smlAssert(parser);
559 
560  if (maxobjsize)
561  *maxobjsize = -1;
562 
563  if (xmlTextReaderIsEmptyElement(parser->reader))
564  {
565  /* empty meta element <meta/> */
566  smlTrace(TRACE_EXIT, "%s - empty meta element", __func__);
567  return TRUE;
568  }
569 
570  while (1) {
571  if (!_smlXmlParserStep(parser)) {
572  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
573  goto error;
574  }
575 
576  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MEM)) {
577  /* Ignored for now */
578  smlTrace(TRACE_INTERNAL, "%s: Skipping mem node");
579  if (!_smlXmlSkipNode(parser)) {
580  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to skip mem node");
581  goto error;
582  }
583  }
584 
585  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META) && \
586  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
587  break;
588  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
589  smlErrorSet(error, SML_ERROR_GENERIC,
590  "The element %s is not a start node in Command/Meta.",
591  xmlTextReaderConstName(parser->reader));
592  goto error;
593  }
594 
595  if (type && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TYPE)) {
596  if (!_smlXmlParserGetString(parser, type, SML_ELEMENT_TYPE, error))
597  goto error;
598  } else if (anchor && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ANCHOR)) {
599  if (!_smlAnchorParse(anchor, parser, error))
600  goto error;
601  } else if (format && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FORMAT)) {
602  if (!_smlXmlParserGetString(parser, format, SML_ELEMENT_FORMAT, error))
603  goto error;
604  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MARK)) {
605  /* Ignore the mark for now */
606  char *mark = NULL;
607  if (!_smlXmlParserGetString(parser, &mark, SML_ELEMENT_MARK, error))
608  goto error;
609  smlSafeCFree(&mark);
610  } else if (size && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SIZE)) {
611  if (!_smlXmlParserGetID(parser, size, SML_ELEMENT_SIZE, error))
612  goto error;
613  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAXOBJSIZE)) {
614  /* MaxObjSize must be parsed even if there is no maxobjsize pointer */
615  unsigned int loc_maxobjsize = 0;
616  if (!_smlXmlParserGetID(parser, &loc_maxobjsize, SML_ELEMENT_MAXOBJSIZE, error))
617  goto error;
618  if (maxobjsize)
619  *maxobjsize = loc_maxobjsize;
620  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_VERSION)) {
621  /* Ignore the version for now */
622  char *version = NULL;
623  if (!_smlXmlParserGetString(parser, &version, SML_ELEMENT_VERSION, error))
624  goto error;
625  smlSafeCFree(&version);
626  } else {
627  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node for meta information: %s", xmlTextReaderConstName(parser->reader));
628  goto error;
629  }
630  }
631 
632  smlTrace(TRACE_EXIT, "%s", __func__);
633  return TRUE;
634 
635 error:
636  if (format)
637  *format = NULL;
638  if (anchor)
639  *anchor = NULL;
640  if (type)
641  *type = NULL;
642  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
643  return FALSE;
644 }
645 
646 static SmlItem *_smlItemParse(SmlXmlParser *parser, SmlCommand *cmd, SmlCommandType type, SmlError **error)
647 {
648  smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %p)", __func__, parser, cmd, type, error);
649  CHECK_ERROR_REF
650  smlAssert(parser);
651 
652  if (parser->gotMoreData) {
653  smlErrorSet(error, SML_ERROR_GENERIC, "Last item already had more data set");
654  goto error;
655  }
656 
657  SmlItem *item = smlItemNew(0, error);
658  if (!item)
659  goto error;
660 
661  /* If the item is an empty element then return immediately. */
662  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM) &&
663  xmlTextReaderIsEmptyElement(parser->reader)) {
664  smlTrace(TRACE_EXIT, "%s - empty item", __func__);
665  return item;
666  }
667 
668  if (!_smlXmlParserStep(parser)) {
669  smlErrorSet(error, SML_ERROR_GENERIC, "The first element inside of an Item structure cannot be parsed.");
670  goto error_free_item;
671  }
672 
673  while (1) {
674  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM) && \
675  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
676  break;
677  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
678  smlErrorSet(error, SML_ERROR_GENERIC,
679  "The element %s is not a start node in Item.",
680  xmlTextReaderConstName(parser->reader));
681  goto error_free_item;
682  }
683 
684  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE)) {
685  SmlLocation *source = NULL;
686  if (!_smlLocationParse(&source, parser, error))
687  goto error_free_item;
688 
689  smlItemSetSource(item, source);
690  smlLocationUnref(source);
691  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET)) {
692  SmlLocation *target = NULL;
693  if (!_smlLocationParse(&target, parser, error))
694  goto error_free_item;
695 
696  smlItemSetTarget(item, target);
697  smlLocationUnref(target);
698  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE_PARENT)) {
699  SmlLocation *source = NULL;
700  if (!_smlLocationParse(&source, parser, error))
701  goto error_free_item;
702 
703  smlItemSetSourceParent(item, source);
704  smlLocationUnref(source);
705  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET_PARENT)) {
706  SmlLocation *target = NULL;
707  if (!_smlLocationParse(&target, parser, error))
708  goto error_free_item;
709 
710  smlItemSetTargetParent(item, target);
711  smlLocationUnref(target);
712  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
713  switch (type) {
714  case SML_COMMAND_TYPE_ALERT:
715  if (!cmd) {
716  /* This is an item inside a status.
717  * We must parse the meta data
718  * but we ignore the content completely.
719  * FIXME: Can we ignore the content?
720  */
721  if (!_smlCommandMetaParse(parser, NULL, NULL, NULL, NULL, NULL, error))
722  goto error_free_item;
723  } else {
724  /* Some phones send the maxobjsize in the alert */
725  if (!_smlCommandMetaParse(parser, NULL, &(cmd->private.alert.contentType), &cmd->private.alert.anchor, NULL, &(cmd->private.alert.maxObjSize), error))
726  goto error_free_item;
727  }
728  break;
729  case SML_COMMAND_TYPE_ADD:
730  case SML_COMMAND_TYPE_DELETE:
731  case SML_COMMAND_TYPE_REPLACE:
732  if (!_smlCommandMetaParse(parser, NULL, &(item->contenttype), NULL, &cmd->size, NULL, error))
733  goto error_free_item;
734  break;
735  case SML_COMMAND_TYPE_RESULTS:
736  case SML_COMMAND_TYPE_PUT:;
737  /* Some phones send the type information for the devinf put
738  * not in the put itself but in the item */
739  if (!_smlCommandMetaParse(parser, NULL, &(item->contenttype), NULL, NULL, NULL, error))
740  goto error_free_item;
741 
742  if (!item->contenttype)
743  goto error_free_item;
744  break;
745  default:
746  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown command type");
747  goto error_free_item;
748  }
749  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATA)) {
750  /* Do nothing if the Data element is empty.
751  * The first emptyness test only covers <Data/>.
752  *
753  * Example: Funambol with WBXML on scheduleworld.com
754  */
755  if (!xmlTextReaderIsEmptyElement(parser->reader)) {
756  switch (type) {
757  case SML_COMMAND_TYPE_ALERT:
758  if (!_smlXmlParserStep(parser)) {
759  smlErrorSet(error, SML_ERROR_GENERIC, "The next element after the starting Data element in an Item is missing.");
760  goto error_free_item;
761  }
762 
763  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATA) &&
764  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
765  /* Do nothing if the Data element is empty.
766  * This only covers <Data></Data>.
767  *
768  * Example: Funambol with XML on scheduleworld.com
769  */
770  smlTrace(TRACE_INTERNAL, "%s: detected empty data element", __func__);
771  break;
772  }
773 
774  SmlAnchor *anchor = NULL;
775  if (xmlTextReaderNodeType(parser->reader) == XML_NODE_TEXT) {
776  /* Google just copies the element Next from the Anchor
777  * Please see ticket #230 for more details.
778  */
779  anchor = smlTryMalloc0(sizeof(SmlAnchor), error);
780  if (!anchor)
781  goto error_free_item;
782  anchor->next = g_strdup((char *)xmlTextReaderConstValue(parser->reader));
783  } else {
784  /* normal behaviour with anchor copy */
785  if (!_smlAnchorParse(&anchor, parser, error))
786  goto error_free_item;
787  }
788  item->anchor = anchor;
789 
790  if (!_smlXmlParserStep(parser)) {
791  smlErrorSet(error, SML_ERROR_GENERIC, "The closing Data element in an Item is missing.");
792  goto error_free_item;
793  }
794  break;
795  default:;
796  char *data = NULL;
797  unsigned int size = 0;
798  if (!_smlXmlParserGetData(parser, &data, &size, SML_ELEMENT_DATA, error))
799  goto error_free_item;
800 
801  if (!smlItemAddData(item, data, size, error)) {
802  smlSafeCFree(&data);
803  goto error_free_item;
804  }
805 
806  smlSafeCFree(&data);
807  }
808  }
809  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MOREDATA)) {
810  if (parser->version == SML_VERSION_10) {
811  smlErrorSet(error, SML_ERROR_GENERIC, "SyncML 1.0 does not allow MoreData");
812  goto error_free_item;
813  }
814 
815  item->moreData = TRUE;
816  parser->gotMoreData = TRUE;
817  if (!_smlXmlParserStep(parser)) {
818  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes2");
819  goto error_free_item;
820  }
821 
822  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MOREDATA) && \
823  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
824  if (!_smlXmlParserStep(parser)) {
825  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes3");
826  goto error_free_item;
827  }
828  }
829  continue;
830  } else {
831  smlErrorSet(error, SML_ERROR_GENERIC, "The element Item does not support the child element %s.", xmlTextReaderConstName(parser->reader));
832  goto error_free_item;
833  }
834 
835  if (!_smlXmlParserStep(parser)) {
836  smlErrorSet(error, SML_ERROR_GENERIC, "The next element in an Item structure is missing.");
837  goto error_free_item;
838  }
839  }
840 
841  smlTrace(TRACE_EXIT, "%s", __func__);
842  return item;
843 
844 error_free_item:
845  smlItemUnref(item);
846 error:
847  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
848  return NULL;
849 }
850 
851 static SmlCred *_smlCredParse(SmlXmlParser *parser, SmlError **error)
852 {
853  smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, parser, error);
854  CHECK_ERROR_REF
855  smlAssert(parser);
856  SmlCred *cred = NULL;
857  char *format = NULL;
858  char *type = NULL;
859  char *data = NULL;
860 
861  while (1) {
862  if (!_smlXmlParserStep(parser)) {
863  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
864  goto error;
865  }
866 
867  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CRED) && \
868  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
869  break;
870  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
871  smlErrorSet(error, SML_ERROR_GENERIC,
872  "The element %s is not a start node in Cred.",
873  xmlTextReaderConstName(parser->reader));
874  goto error;
875  }
876 
877  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
878  if (!_smlCommandMetaParse(parser, &format, &type, NULL, NULL, NULL, error))
879  goto error;
880  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATA)) {
881  if (!_smlXmlParserGetString(parser, &data, SML_ELEMENT_DATA, error))
882  goto error;
883  } else {
884  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node %s", xmlTextReaderConstName(parser->reader));
885  goto error;
886  }
887  }
888 
889  cred = smlCredNewFromString(type, format, data, error);
890 
891 error:
892  if (data)
893  smlSafeCFree(&data);
894 
895  if (format)
896  smlSafeCFree(&format);
897 
898  if (type)
899  smlSafeCFree(&type);
900 
901  if (!smlErrorIsSet(error))
902  {
903  smlTrace(TRACE_EXIT, "%s: %p", __func__, cred);
904  return cred;
905  } else {
906  if (cred)
907  smlCredUnref(cred);
908  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
909  return NULL;
910  }
911 }
912 
913 static SmlChal *_smlChalParse(SmlXmlParser *parser, SmlError **error)
914 {
915  smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, parser, error);
916  CHECK_ERROR_REF
917  smlAssert(parser);
918  char *format = NULL;
919  char *type = NULL;
920  char *nonce = NULL;
921 
922  while (1) {
923  if (!_smlXmlParserStep(parser)) {
924  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
925  goto error;
926  }
927 
928  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CHAL) && \
929  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
930  break;
931  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
932  smlErrorSet(error, SML_ERROR_GENERIC,
933  "The element %s is not a start node in Chal.",
934  xmlTextReaderConstName(parser->reader));
935  goto error;
936  }
937 
938  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
939  if (!_smlChalMetaParse(parser, &format, &type, &nonce, error))
940  goto error;
941  } else {
942  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node %s", xmlTextReaderConstName(parser->reader));
943  goto error;
944  }
945  }
946 
947  if (format && strcmp(format, SML_BASE64)) {
948  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown format");
949  goto error;
950  }
951 
952  SmlAuthType auth;
953  if (!type || !strcmp(type, SML_AUTH_BASIC)) {
954  auth = SML_AUTH_TYPE_BASIC;
955  } else if (!strcmp(type, SML_AUTH_MD5)) {
956  auth = SML_AUTH_TYPE_MD5;
957  } else {
958  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown type");
959  goto error;
960  }
961 
962  if (format)
963  smlSafeCFree(&format);
964  if (type)
965  smlSafeCFree(&type);
966 
967  SmlChal *chal = NULL;
968  if (nonce || auth == SML_AUTH_TYPE_MD5)
969  chal = smlChalNewFromBase64(auth, nonce, error);
970  else
971  chal = smlChalNew(auth, error);
972  if (!chal)
973  goto error;
974 
975  if (nonce)
976  smlSafeCFree(&nonce);
977 
978  smlTrace(TRACE_EXIT, "%s: %p", __func__, chal);
979  return chal;
980 
981 error:
982  if (format)
983  smlSafeCFree(&format);
984  if (type)
985  smlSafeCFree(&type);
986  if (nonce)
987  smlSafeCFree(&nonce);
988  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
989  return NULL;
990 }
991 
992 static SmlBool _smlChangeParse(SmlXmlParser *parser, SmlCommand **cmd, SmlCommandType type, const char *name, SmlError **error)
993 {
994  smlTrace(TRACE_ENTRY, "%s(%p, %i, %s, %p)", __func__, parser, type, VA_STRING(name), error);
995  CHECK_ERROR_REF
996  smlAssert(parser);
997  smlAssert(name);
998  char *contenttype = NULL;
999 
1000  *cmd = smlCommandNew(type, error);
1001  if (!*cmd)
1002  goto error;
1003  (*cmd)->refCount = 1;
1004 
1005  while (1) {
1006  if (!_smlXmlParserStep(parser)) {
1007  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1008  goto error_free_cmd;
1009  }
1010 
1011  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), name) && \
1012  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1013  break;
1014  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1015  smlErrorSet(error, SML_ERROR_GENERIC,
1016  "The element %s is not a start node in %s.",
1017  xmlTextReaderConstName(parser->reader), name);
1018  goto error_free_cmd;
1019  }
1020 
1021  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
1022  if (!_smlXmlParserGetID(parser, &((*cmd)->cmdID), SML_ELEMENT_CMDID, error))
1023  goto error_free_cmd;
1024  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM)) {
1025  SmlItem *item = _smlItemParse(parser, *cmd, type, error);
1026  if (!item)
1027  goto error_free_cmd;
1028  (*cmd)->private.change.items = g_list_append((*cmd)->private.change.items, item);
1029  if (!(*cmd)->private.change.items)
1030  {
1031  smlItemUnref(item);
1032  smlErrorSet(error, SML_ERROR_GENERIC, "g_list_append for item list of change command failed.");
1033  goto error_free_cmd;
1034  }
1035  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
1036  if (!_smlCommandMetaParse(parser, NULL, &contenttype, NULL, &(*cmd)->size, NULL, error))
1037  goto error_free_cmd;
1038  } else {
1039  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
1040  goto error_free_cmd;
1041  }
1042  }
1043 
1044  if (!(*cmd)->cmdID) {
1045  smlErrorSet(error, SML_ERROR_GENERIC, "No cmdid set");
1046  goto error_free_cmd;
1047  }
1048 
1049  if (!(*cmd)->private.change.items ||
1050  !g_list_length((*cmd)->private.change.items)) {
1051  smlErrorSet(error, SML_ERROR_GENERIC, "No items set");
1052  goto error_free_cmd;
1053  }
1054 
1055  /* some clients set the contentype in the item, don't overwrite it with NULL */
1056  guint i;
1057  for (i=0; i < g_list_length((*cmd)->private.change.items); i++)
1058  {
1059  SmlItem *item = g_list_nth_data((*cmd)->private.change.items, i);
1060  if (item->contenttype == NULL && contenttype) {
1061  item->contenttype = g_strdup(contenttype);
1062  }
1063  }
1064  if (contenttype)
1065  smlSafeCFree(&contenttype);
1066 
1067  for (i=0; i < g_list_length((*cmd)->private.change.items); i++)
1068  {
1069  SmlItem *item = g_list_nth_data((*cmd)->private.change.items, i);
1070  if ((*cmd)->size && !item->size)
1071  item->size = (*cmd)->size;
1072  }
1073 
1074  switch (type) {
1075  case SML_COMMAND_TYPE_ADD:
1076  (*cmd)->private.change.type = SML_CHANGE_ADD;
1077  break;
1078  case SML_COMMAND_TYPE_REPLACE:
1079  (*cmd)->private.change.type = SML_CHANGE_REPLACE;
1080  break;
1081  case SML_COMMAND_TYPE_DELETE:
1082  (*cmd)->private.change.type = SML_CHANGE_DELETE;
1083  break;
1084  default:
1085  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown change type set");
1086  goto error_free_cmd;
1087  }
1088 
1089  if (!(*cmd)->source)
1090  {
1091  SmlItem *item = g_list_nth_data((*cmd)->private.change.items, 0);
1092  if (item->source) {
1093  (*cmd)->source = smlLocationClone(item->source, error);
1094  if (!(*cmd)->source)
1095  goto error_free_cmd;
1096  }
1097  }
1098 
1099  if (!(*cmd)->target)
1100  {
1101  SmlItem *item = g_list_nth_data((*cmd)->private.change.items, 0);
1102  if (item->target) {
1103  (*cmd)->target = smlLocationClone(item->target, error);
1104  if (!(*cmd)->target)
1105  goto error_free_cmd;
1106  }
1107  }
1108 
1109  /* Step once more */
1110  if (!_smlXmlParserStep(parser)) {
1111  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1112  goto error_free_cmd;
1113  }
1114 
1115  smlTrace(TRACE_EXIT, "%s: %p", __func__, *cmd);
1116  return TRUE;
1117 
1118 error_free_cmd:
1119  smlCommandUnref(*cmd);
1120 error:
1121  if (contenttype)
1122  smlSafeCFree(&contenttype);
1123  *cmd = NULL;
1124  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1125  return FALSE;
1126 }
1127 
1128 static SmlBool _smlMessageParseSynchdrMeta(SmlXmlParser *parser, unsigned int *maxmsgsize, unsigned int *maxobjsize, char **emi, SmlError **error)
1129 {
1130  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, parser, maxmsgsize, maxobjsize, error);
1131  CHECK_ERROR_REF
1132  smlAssert(parser);
1133  smlAssert(maxmsgsize);
1134  smlAssert(maxobjsize);
1135  smlAssert(emi);
1136 
1137 
1138  while (1) {
1139  if (!_smlXmlParserStep(parser)) {
1140  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1141  goto error;
1142  }
1143 
1144  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META) && \
1145  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1146  break;
1147  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1148  smlErrorSet(error, SML_ERROR_GENERIC,
1149  "The element %s is not a start node in SyncHdr/Meta.",
1150  xmlTextReaderConstName(parser->reader));
1151  goto error;
1152  }
1153 
1154  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAXMSGSIZE)) {
1155  if (!_smlXmlParserGetID(parser, maxmsgsize, SML_ELEMENT_MAXMSGSIZE, error))
1156  goto error;
1157  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAXOBJSIZE)) {
1158  if (!_smlXmlParserGetID(parser, maxobjsize, SML_ELEMENT_MAXOBJSIZE, error))
1159  goto error;
1160  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_EMI)) {
1161  if (!_smlXmlParserGetString(parser, emi, SML_ELEMENT_EMI, error))
1162  goto error;
1163  } else {
1164  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node. expected MaxMsgSize, MaxObjSize or EMI. Instead of that: %s", xmlTextReaderConstName(parser->reader));
1165  goto error;
1166  }
1167  }
1168 
1169  if (!(*maxmsgsize) && !(*maxobjsize)) {
1170  smlErrorSet(error, SML_ERROR_GENERIC, "No maxmsgsize set");
1171  goto error;
1172  }
1173 
1174  smlTrace(TRACE_EXIT, "%s", __func__);
1175  return TRUE;
1176 
1177 error:
1178  *maxmsgsize = 0;
1179  *maxobjsize = 0;
1180  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1181  return FALSE;
1182 }
1183 
1184 static SmlBool _smlAlertParse(SmlXmlParser *parser, SmlCommand **cmd, SmlError **error)
1185 {
1186  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, cmd, error);
1187  CHECK_ERROR_REF
1188  smlAssert(parser);
1189  smlAssert(cmd);
1190 
1191  *cmd = smlCommandNew(SML_COMMAND_TYPE_ALERT, error);
1192  if (!*cmd)
1193  goto error;
1194  (*cmd)->refCount = 1;
1195  (*cmd)->private.alert.maxObjSize = -1;
1196 
1197  while (1) {
1198  if (!_smlXmlParserStep(parser)) {
1199  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1200  goto error_free_cmd;
1201  }
1202 
1203  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ALERT) && \
1204  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1205  break;
1206  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1207  smlErrorSet(error, SML_ERROR_GENERIC,
1208  "The element %s is not a start node in Alert.",
1209  xmlTextReaderConstName(parser->reader));
1210  goto error_free_cmd;
1211  }
1212 
1213  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
1214  if (!_smlXmlParserGetID(parser, &((*cmd)->cmdID), SML_ELEMENT_CMDID, error))
1215  goto error_free_cmd;
1216  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM)) {
1217  SmlItem *item = _smlItemParse(parser, (*cmd), SML_COMMAND_TYPE_ALERT, error);
1218  if (!item)
1219  goto error_free_cmd;
1220 
1221  (*cmd)->target = item->target;
1222  item->target = NULL;
1223  (*cmd)->source = item->source;
1224  item->source = NULL;
1225 
1226  smlItemUnref(item);
1227  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATA)) {
1228  unsigned int id = 0;
1229  if (!_smlXmlParserGetID(parser, &id, SML_ELEMENT_DATA, error))
1230  goto error_free_cmd;
1231  (*cmd)->private.alert.type = smlAlertTypeConvert(id, error);
1232  if ((*cmd)->private.alert.type == SML_ALERT_UNKNOWN &&
1233  *error != NULL)
1234  goto error_free_cmd;
1235  } else {
1236  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node %s", xmlTextReaderConstName(parser->reader));
1237  goto error_free_cmd;
1238  }
1239  }
1240 
1241  if (!(*cmd)->private.alert.type) {
1242  smlErrorSet(error, SML_ERROR_GENERIC, "No alert type set");
1243  goto error_free_cmd;
1244  }
1245 
1246  /* Step once more */
1247  if (!_smlXmlParserStep(parser)) {
1248  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1249  goto error_free_cmd;
1250  }
1251 
1252  smlTrace(TRACE_EXIT, "%s", __func__);
1253  return TRUE;
1254 
1255 error_free_cmd:
1256  smlCommandUnref(*cmd);
1257 error:
1258  *cmd = NULL;
1259  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1260  return FALSE;
1261 }
1262 
1263 static SmlParserResult _smlCommandSyncParse(SmlXmlParser *parser, SmlCommand **cmd, SmlError **error)
1264 {
1265  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, cmd, error);
1266  CHECK_ERROR_REF
1267  smlAssert(parser);
1268  smlAssert(cmd);
1269 
1270  *cmd = smlCommandNew(SML_COMMAND_TYPE_SYNC, error);
1271  if (!*cmd)
1272  goto error;
1273  (*cmd)->private.sync.maxObjSize = -1;
1274 
1275  while (1) {
1276  if (!_smlXmlParserStep(parser)) {
1277  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1278  goto error_free_cmd;
1279  }
1280 
1281  if (xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE && !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNC))
1282  break;
1283  else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1284  smlErrorSet(error, SML_ERROR_GENERIC,
1285  "The element %s is not a start node in Sync.",
1286  xmlTextReaderConstName(parser->reader));
1287  goto error_free_cmd;
1288  }
1289 
1290  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ADD) || \
1291  !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_REPLACE) || \
1292  !strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DELETE))
1293  break;
1294 
1295  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
1296  if (!_smlXmlParserGetID(parser, &((*cmd)->cmdID), SML_ELEMENT_CMDID, error))
1297  goto error_free_cmd;
1298  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM)) {
1299  SmlItem *item = _smlItemParse(parser, (*cmd), SML_COMMAND_TYPE_SYNC, error);
1300  if (!item)
1301  goto error_free_cmd;
1302  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
1303  if (!_smlCommandMetaParse(parser, NULL, NULL, NULL, NULL, &((*cmd)->private.sync.maxObjSize), error))
1304  goto error;
1305  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET)) {
1306  if (!_smlLocationParse(&(*cmd)->target, parser, error))
1307  goto error_free_cmd;
1308  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE)) {
1309  if (!_smlLocationParse(&(*cmd)->source, parser, error))
1310  goto error_free_cmd;
1311  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_NUMBEROFCHANGES)) {
1312  (*cmd)->private.sync.hasNumChanged = TRUE;
1313  if (!_smlXmlParserGetID(parser, &((*cmd)->private.sync.numChanged), SML_ELEMENT_NUMBEROFCHANGES, error))
1314  goto error_free_cmd;
1315  } else {
1316  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node: %s", xmlTextReaderConstName(parser->reader));
1317  goto error_free_cmd;
1318  }
1319  }
1320 
1321  smlTrace(TRACE_EXIT, "%s", __func__);
1322  return TRUE;
1323 
1324 error_free_cmd:
1325  smlCommandUnref(*cmd);
1326 error:
1327  *cmd = NULL;
1328  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1329  return FALSE;
1330 }
1331 
1332 static SmlMapItem *_smlMapItemParse(SmlXmlParser *parser, SmlError **error)
1333 {
1334  smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, parser, error);
1335  CHECK_ERROR_REF
1336  smlAssert(parser);
1337 
1338  SmlMapItem *item = smlTryMalloc0(sizeof(SmlMapItem), error);
1339  if (!item)
1340  goto error;
1341  item->refCount = 1;
1342 
1343  while (1) {
1344  if (!_smlXmlParserStep(parser)) {
1345  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1346  goto error_free_item;
1347  }
1348 
1349  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAPITEM) && \
1350  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1351  break;
1352  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1353  smlErrorSet(error, SML_ERROR_GENERIC,
1354  "The element %s is not a start node in MapItem.",
1355  xmlTextReaderConstName(parser->reader));
1356  goto error_free_item;
1357  }
1358 
1359  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE)) {
1360  if (!_smlLocationParse(&item->source, parser, error))
1361  goto error_free_item;
1362  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET)) {
1363  if (!_smlLocationParse(&item->target, parser, error))
1364  goto error_free_item;
1365  } else {
1366  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node %s", xmlTextReaderConstName(parser->reader));
1367  goto error_free_item;
1368  }
1369  }
1370 
1371  smlTrace(TRACE_EXIT, "%s", __func__);
1372  return item;
1373 
1374 error_free_item:
1375  smlMapItemUnref(item);
1376 error:
1377  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1378  return NULL;
1379 }
1380 
1381 static SmlBool _smlCommandMapParse(SmlXmlParser *parser, SmlCommand **cmd, SmlError **error)
1382 {
1383  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, cmd, error);
1384  CHECK_ERROR_REF
1385  smlAssert(parser);
1386  smlAssert(cmd);
1387 
1388  *cmd = smlCommandNew(SML_COMMAND_TYPE_MAP, error);
1389  if (!*cmd)
1390  goto error;
1391  (*cmd)->refCount = 1;
1392 
1393  while (1) {
1394  if (!_smlXmlParserStep(parser)) {
1395  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1396  goto error_free_cmd;
1397  }
1398 
1399  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAP) && \
1400  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1401  break;
1402  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1403  smlErrorSet(error, SML_ERROR_GENERIC,
1404  "The element %s is not a start node in Map.",
1405  xmlTextReaderConstName(parser->reader));
1406  goto error_free_cmd;
1407  }
1408 
1409  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
1410  if (!_smlXmlParserGetID(parser, &((*cmd)->cmdID), SML_ELEMENT_CMDID, error))
1411  goto error_free_cmd;
1412  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAPITEM)) {
1413  SmlMapItem *item = _smlMapItemParse(parser, error);
1414  if (!item)
1415  goto error_free_cmd;
1416  (*cmd)->private.map.items = g_list_append((*cmd)->private.map.items, item);
1417  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET)) {
1418  if (!_smlLocationParse(&(*cmd)->target, parser, error))
1419  goto error_free_cmd;
1420  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE)) {
1421  if (!_smlLocationParse(&(*cmd)->source, parser, error))
1422  goto error_free_cmd;
1423  } else {
1424  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
1425  goto error_free_cmd;
1426  }
1427  }
1428 
1429  /* Step once more */
1430  if (!_smlXmlParserStep(parser)) {
1431  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1432  goto error_free_cmd;
1433  }
1434 
1435  smlTrace(TRACE_EXIT, "%s", __func__);
1436  return TRUE;
1437 
1438 error_free_cmd:
1439  smlCommandUnref(*cmd);
1440 error:
1441  *cmd = NULL;
1442  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1443  return FALSE;
1444 }
1445 
1446 static SmlBool _smlCommandAccessParse(SmlXmlParser *parser, SmlCommand **cmd, SmlCommandType type, SmlError **error)
1447 {
1448  smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %p)", __func__, parser, cmd, type, error);
1449  CHECK_ERROR_REF
1450  smlAssert(parser);
1451  smlAssert(cmd);
1452  char *contenttype = NULL;
1453 
1454  *cmd = smlCommandNew(type, error);
1455  if (!*cmd)
1456  goto error;
1457  (*cmd)->refCount = 1;
1458 
1459  while (1) {
1460  if (!_smlXmlParserStep(parser)) {
1461  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1462  goto error_free_cmd;
1463  }
1464 
1465  if ((*cmd)->type == SML_COMMAND_TYPE_PUT &&!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_PUT) && \
1466  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1467  break;
1468  } else if ((*cmd)->type == SML_COMMAND_TYPE_GET &&!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_GET) && \
1469  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1470  break;
1471  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1472  smlErrorSet(error, SML_ERROR_GENERIC,
1473  "The element %s is not a start node in Put or Get.",
1474  xmlTextReaderConstName(parser->reader));
1475  goto error_free_cmd;
1476  }
1477 
1478  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
1479  if (!_smlXmlParserGetID(parser, &((*cmd)->cmdID), SML_ELEMENT_CMDID, error))
1480  goto error_free_cmd;
1481  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM)) {
1482  (*cmd)->private.access.item = _smlItemParse(parser, (*cmd), (*cmd)->type, error);
1483  if (!(*cmd)->private.access.item)
1484  goto error_free_cmd;
1485 
1486  (*cmd)->target = (*cmd)->private.access.item->target;
1487  (*cmd)->private.access.item->target = NULL;
1488  (*cmd)->source = (*cmd)->private.access.item->source;
1489  (*cmd)->private.access.item->source = NULL;
1490  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
1491  char *format = NULL;
1492  if (!_smlCommandMetaParse(parser, &format, &contenttype, NULL, NULL, NULL, error))
1493  goto error_free_cmd;
1494  if (format) smlSafeCFree(&format);
1495  } else {
1496  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
1497  goto error_free_cmd;
1498  }
1499  }
1500 
1501  if (!(*cmd)->private.access.item) {
1502  smlErrorSet(error, SML_ERROR_GENERIC, "Put/Get is missing item");
1503  goto error_free_cmd;
1504  }
1505 
1506  /* We only use the content type of the put command if the item itself did not have
1507  * a content type set */
1508  if (!(*cmd)->private.access.item->contenttype && contenttype)
1509  (*cmd)->private.access.item->contenttype = g_strdup(contenttype);
1510 
1511  if (contenttype)
1512  smlSafeCFree(&contenttype);
1513 
1514  /* Step once more */
1515  if (!_smlXmlParserStep(parser)) {
1516  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1517  goto error_free_cmd;
1518  }
1519 
1520  smlTrace(TRACE_EXIT, "%s", __func__);
1521  return TRUE;
1522 
1523 error_free_cmd:
1524  smlCommandUnref(*cmd);
1525 error:
1526  *cmd = NULL;
1527  if (contenttype)
1528  smlSafeCFree(&contenttype);
1529  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1530  return FALSE;
1531 }
1532 
1533 static SmlBool _smlResultsParse(SmlXmlParser *parser, SmlCommand **cmd, SmlError **error)
1534 {
1535  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, cmd, error);
1536  CHECK_ERROR_REF
1537  smlAssert(parser);
1538  smlAssert(cmd);
1539  char *contenttype = NULL;
1540  char *locURI = NULL;
1541 
1542  *cmd = smlCommandNew(SML_COMMAND_TYPE_RESULTS, error);
1543  if (!*cmd)
1544  goto error;
1545  (*cmd)->refCount = 1;
1546 
1547  (*cmd)->private.results.status = smlTryMalloc0(sizeof(SmlStatus), error);
1548  if (!(*cmd)->private.results.status)
1549  goto error;
1550  (*cmd)->private.results.status->refCount = 1;
1551  (*cmd)->private.results.status->result = (*cmd);
1552  (*cmd)->private.results.status->type = SML_COMMAND_TYPE_RESULTS;
1553 
1554  while (1) {
1555  if (!_smlXmlParserStep(parser)) {
1556  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1557  goto error_free_cmd;
1558  }
1559 
1560  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_RESULTS) && \
1561  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1562  break;
1563  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
1564  smlErrorSet(error, SML_ERROR_GENERIC,
1565  "The element %s is not a start node in Results.",
1566  xmlTextReaderConstName(parser->reader));
1567  goto error_free_cmd;
1568  }
1569 
1570 
1571  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
1572  if (!_smlXmlParserGetID(parser, &((*cmd)->cmdID), SML_ELEMENT_CMDID, error))
1573  goto error_free_cmd;
1574  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MSGREF)) {
1575  if (!_smlXmlParserGetID(parser, &((*cmd)->private.results.status->msgRef), SML_ELEMENT_MSGREF, error))
1576  goto error_free_cmd;
1577  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDREF)) {
1578  if (!_smlXmlParserGetID(parser, &((*cmd)->private.results.status->cmdRef), SML_ELEMENT_CMDREF, error))
1579  goto error_free_cmd;
1580  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCEREF)) {
1581  if (!_smlXmlParserGetString(parser, &locURI, SML_ELEMENT_SOURCEREF, error))
1582  goto error_free_cmd;
1583 
1584  (*cmd)->private.results.status->sourceRef = smlLocationNew(locURI, NULL, error);
1585  smlSafeCFree(&locURI);
1586  if (!(*cmd)->private.results.status->sourceRef)
1587  goto error_free_cmd;
1588  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGETREF)) {
1589  if (!_smlXmlParserGetString(parser, &locURI, SML_ELEMENT_TARGETREF, error))
1590  goto error_free_cmd;
1591 
1592  (*cmd)->private.results.status->targetRef = smlLocationNew(locURI, NULL, error);
1593  smlSafeCFree(&locURI);
1594  if (!(*cmd)->private.results.status->targetRef)
1595  goto error_free_cmd;
1596  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM)) {
1597  (*cmd)->private.results.status->item = _smlItemParse(parser, (*cmd), (*cmd)->type, error);
1598  if (!(*cmd)->private.results.status->item)
1599  goto error_free_cmd;
1600 
1601  (*cmd)->target = (*cmd)->private.results.status->item->target;
1602  (*cmd)->private.results.status->item->target = NULL;
1603  (*cmd)->source = (*cmd)->private.results.status->item->source;
1604  (*cmd)->private.results.status->item->source = NULL;
1605  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
1606  /* ignore format */
1607  char *format = NULL;
1608  if (!_smlCommandMetaParse(parser, &format, &contenttype, NULL, NULL, NULL, error))
1609  goto error_free_cmd;
1610  if (format) smlSafeCFree(&format);
1611  } else {
1612  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
1613  goto error_free_cmd;
1614  }
1615  }
1616 
1617  if (!(*cmd)->private.results.status->item) {
1618  smlErrorSet(error, SML_ERROR_GENERIC, "Result is missing item");
1619  goto error_free_cmd;
1620  }
1621 
1622  /* We only use the content type of the put command if the item itself did not have
1623  * a content type set */
1624  if (!(*cmd)->private.results.status->item->contenttype) {
1625  if (!contenttype) {
1626  smlErrorSet(error, SML_ERROR_GENERIC, "Result is missing content type");
1627  goto error_free_cmd;
1628  }
1629 
1630  (*cmd)->private.results.status->item->contenttype = g_strdup(contenttype);
1631  }
1632 
1633  if (contenttype)
1634  smlSafeCFree(&contenttype);
1635 
1636  /* Step once more */
1637  if (!_smlXmlParserStep(parser)) {
1638  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1639  goto error_free_cmd;
1640  }
1641 
1642  smlTrace(TRACE_EXIT, "%s", __func__);
1643  return TRUE;
1644 
1645 error_free_cmd:
1646  smlCommandUnref(*cmd);
1647 error:
1648  *cmd = NULL;
1649  if (contenttype)
1650  smlSafeCFree(&contenttype);
1651  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1652  return FALSE;
1653 }
1654 
1655 static SmlBool _smlXmlParserFixBrokenItemData(
1656  const char *data, unsigned int size,
1657  char **fixed_data, unsigned int *fixed_size,
1658  SmlError **error)
1659 {
1660  smlTrace(TRACE_ENTRY, "%s(%p, %d, %p, %p, %p)", __func__, data, size, fixed_data, fixed_size, error);
1661  CHECK_ERROR_REF
1662  smlAssert(data);
1663  smlAssert(size);
1664  smlAssert(fixed_data);
1665  smlAssert(fixed_size);
1666 
1667  /* *******************
1668  * fix wrong enconding
1669  * *******************
1670  */
1671 
1672  /* This fix was implemented for text/x-vMessage.
1673  * Some mobiles encode SMS always as UTF-16
1674  * even if the XML document is encoded in UTF-8.
1675  * Example: Nokia E71
1676  */
1677 
1678  *fixed_size = size;
1679  *fixed_data = smlTryMalloc0(size + 1, error);
1680  if (!*fixed_data)
1681  {
1682  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1683  return FALSE;
1684  }
1685  memcpy(*fixed_data, data, size);
1686  const char *position = *fixed_data;
1687 
1688  while (position + 1 < *fixed_data + *fixed_size)
1689  {
1690  /* check if the next character is a NULL byte */
1691  const char *byte = position + 1;
1692  if (*byte != 0) {
1693  /* the next byte is not NULL */
1694  position++;
1695  continue;
1696  }
1697  smlTrace(TRACE_INTERNAL, "%s: Found NULL byte in XML document at %p.", __func__, position);
1698 
1699  /* the next character is a NULL byte
1700  * so let's check how long the UTF-16 string is
1701  */
1702  const char *last_utf16 = position;
1703  while (last_utf16 + 1 < *fixed_data + *fixed_size &&
1704  *((char *)(last_utf16 + 1)) == 0)
1705  {
1706  last_utf16 += 2;
1707  }
1708 
1709  /* go to the last NULL byte */
1710  last_utf16--;
1711 
1712  /* convert the whole strong to UTF-8 */
1713  smlTrace(TRACE_INTERNAL, "%s: Converting %d bytes ...", __func__, last_utf16 - position + 1);
1714  GError *gerror = NULL;
1715  size_t read_bytes = 0;
1716  size_t written_bytes = 0;
1717  gchar *conv_string = g_convert(
1718  position, (last_utf16 - position + 1),
1719  "UTF-8", "UTF-16",
1720  &read_bytes, &written_bytes,
1721  &gerror);
1722  if (gerror != NULL)
1723  {
1724  smlErrorSet(
1725  error, SML_ERROR_GENERIC,
1726  "Character conversion from UTF-16 to UTF-8 failed. %s",
1727  gerror->message);
1728  g_error_free(gerror);
1729  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1730  return FALSE;
1731  }
1732  smlTrace(TRACE_INTERNAL, "%s: read %d --> written %d --> %d ::= %s", __func__, read_bytes, written_bytes, strlen(conv_string), conv_string);
1733 
1734  /* replace the embedded string */
1735  char *new_data = smlTryMalloc0(*fixed_size - read_bytes + written_bytes + 1, error);
1736  if (!new_data)
1737  {
1738  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1739  return FALSE;
1740  }
1741  memcpy(new_data, *fixed_data, (size_t) position - (size_t) *fixed_data);
1742  memcpy(new_data + (size_t) position - (size_t) *fixed_data, conv_string, written_bytes);
1743  memcpy(new_data + (size_t) position - (size_t) *fixed_data + written_bytes,
1744  position + read_bytes, *fixed_size - ( (size_t) position - (size_t) *fixed_data ) - read_bytes );
1745 
1746  /* fix pointers */
1747  *fixed_size = *fixed_size - read_bytes + written_bytes;
1748  position = new_data + (position - *fixed_data) + written_bytes;
1749  smlSafeCFree(fixed_data);
1750  *fixed_data = new_data;
1751  new_data = NULL;
1752  smlSafeCFree(&conv_string);
1753 
1754  smlTrace(TRACE_INTERNAL, "%s: Converted UTF-16 string to UTF-8", __func__);
1755  }
1756  smlTrace(TRACE_INTERNAL, "%s: Correctly encoded: %s", __func__, *fixed_data);
1757 
1758  /* *****************
1759  * add missing CDATA
1760  * *****************
1761  */
1762 
1763  position = *fixed_data;
1764 
1765  while (position + 1 < *fixed_data + *fixed_size)
1766  {
1767  /* find item */
1768  const char *limit_item_start = strstr(position, "<Item>");
1769  if (! limit_item_start)
1770  {
1771  smlTrace(TRACE_EXIT, "%s - no (more) Item found", __func__);
1772  return TRUE;
1773  } else {
1774  smlTrace(TRACE_INTERNAL, "%s - Item found", __func__);
1775  }
1776  const char *limit_item_end = strstr(limit_item_start, "</Item>");
1777  if (! limit_item_end)
1778  {
1779  g_warning("%s - no end of Item found.", __func__);
1780  smlTrace(TRACE_EXIT, "%s - no end of Item found", __func__);
1781  return TRUE;
1782  } else {
1783  smlTrace(TRACE_INTERNAL, "%s - end of Item found", __func__);
1784  }
1785  if (limit_item_start >= limit_item_end)
1786  {
1787  /* </Item> is before <Item> ?! */
1788  position = limit_item_end + strlen("</Item>");
1789  continue;
1790  }
1791 
1792  /* find data */
1793  const char *limit_data_start = strstr(limit_item_start, "<Data>");
1794  if (! limit_data_start)
1795  {
1796  smlTrace(TRACE_EXIT, "%s - no Data found", __func__);
1797  return TRUE;
1798  } else {
1799  smlTrace(TRACE_INTERNAL, "%s - Data found", __func__);
1800  }
1801  const char *limit_data_end = strstr(limit_data_start, "</Data>");
1802  if (! limit_data_end)
1803  {
1804  g_warning("%s - no end of Data found.", __func__);
1805  smlTrace(TRACE_EXIT, "%s - no end of Data found", __func__);
1806  return TRUE;
1807  } else {
1808  smlTrace(TRACE_INTERNAL, "%s - end of Data found", __func__);
1809  }
1810  if (limit_data_start >= limit_data_end)
1811  {
1812  /* </Data> is before <Data> ?! */
1813  position = limit_data_end + strlen("</Data>");
1814  continue;
1815  }
1816 
1817  /* check limits */
1818  if (limit_item_start >= limit_data_start ||
1819  limit_data_start >= limit_data_end ||
1820  limit_data_end >= limit_item_end)
1821  {
1822  /* There is something wrong with the encapsulation.
1823  * Expected: <Item>...<Data>...</Data>...</Item>
1824  */
1825  position = limit_item_end + strlen("</Item>");
1826  continue;
1827  }
1828 
1829  /* check for CDATA */
1830  const char *cdata_start = strstr(limit_data_start, "<![CDATA[");
1831  const char *cdata_end = NULL;
1832  if (cdata_start)
1833  cdata_end = strstr(cdata_start, "]]");
1834  if (cdata_start && cdata_end &&
1835  limit_data_start < cdata_start &&
1836  cdata_start < cdata_end &&
1837  cdata_end < limit_data_end)
1838  {
1839  /* Anything is fine. */
1840  position = limit_item_end + strlen("</Item>");
1841  continue;
1842  }
1843 
1844  /* check that there is no tag inside Data */
1845  if (g_strstr_len(
1846  limit_data_start + strlen("<Data>"),
1847  limit_data_end - limit_data_start - strlen("<Data>"),
1848  "<"))
1849  {
1850  /* There is a tag in the Data area. */
1851  position = limit_item_end + strlen("</Item>");
1852  continue;
1853  }
1854 
1855  /* There is data in an item element and it is not CDATA.
1856  * - allocate new memory
1857  * - copy before data
1858  * - add <![CDATA[
1859  * - copy data
1860  * - add ]]
1861  * - copy after data
1862  * - fix position
1863  * - cleanup
1864  */
1865 
1866  smlTrace(TRACE_INTERNAL, "%s: There is data which is not CDATA.", __func__);
1867  /* 1 is added to the real length * because of the
1868  * trailing NULL byte. This NULL byte is required
1869  * because XML documents can be represented as strings
1870  * and a string must be terminated by a NULL byte.
1871  */
1872  char *new_data = smlTryMalloc0(*fixed_size + strlen("<![CDATA[]]>") + 1, error);
1873  if (!new_data)
1874  {
1875  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1876  return FALSE;
1877  }
1878  size_t before_size = limit_data_start + strlen("<Data>") - *fixed_data;
1879  size_t data_size = limit_data_end - limit_data_start - strlen("<Data>");
1880  size_t after_size = *fixed_size - before_size - data_size;
1881 
1882  smlTrace(TRACE_INTERNAL, "%s: %i = %i + %i +%i", __func__,
1883  *fixed_size, before_size, data_size, after_size);
1884 
1885  memcpy(new_data, *fixed_data, before_size);
1886  memcpy(new_data + before_size, "<![CDATA[", strlen ("<![CDATA["));
1887  memcpy(new_data + before_size + strlen ("<![CDATA["),
1888  limit_data_start + strlen("<Data>"),
1889  data_size);
1890  memcpy(new_data + before_size + strlen ("<![CDATA[") + data_size,
1891  "]]>", strlen("]]>"));
1892  memcpy(new_data + before_size + strlen ("<![CDATA[]]>") + data_size,
1893  limit_data_end,
1894  after_size);
1895  smlSafeCFree(fixed_data);
1896  *fixed_data = new_data;
1897  new_data = NULL;
1898  *fixed_size += strlen("<![CDATA[]]>");
1899  /* The position must be calculated on base of the new string. */
1900  position = *fixed_data +
1901  before_size + strlen ("<![CDATA[]]>") +
1902  data_size + strlen("</Data></Item>");
1903  smlTrace(TRACE_INTERNAL, "%s: CDATA inserted", __func__);
1904  }
1905 
1906  smlTrace(TRACE_EXIT, "%s", __func__);
1907  return TRUE;
1908 }
1909 
1915 SmlBool smlXmlParserStart(SmlXmlParser *parser, const char *data, unsigned int size, SmlError **error)
1916 {
1917  smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %p)", __func__, parser, data, size, error);
1918  CHECK_ERROR_REF
1919  smlAssert(parser);
1920  smlAssert(data);
1921  smlAssert(size);
1922 
1923  /* Repair item data if necessary.
1924  * Some devices does not encapsulate the data correctly
1925  * (e.g. SE M600i send the second part of a chunked item
1926  * without CDATA and so the CR LF is normalied to a LF
1927  * which creates a wrong length and so the item is detected
1928  * as damaged).
1929  */
1930  parser->data = NULL;
1931  parser->size = 0;
1932  if (! _smlXmlParserFixBrokenItemData(
1933  data, size, &(parser->data), &(parser->size), error))
1934  {
1935  smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1936  return FALSE;
1937  }
1938 
1939  char *debugstr = smlPrintBinary(parser->data, parser->size);
1940  smlTrace(TRACE_INTERNAL, "Xml input: %s", debugstr);
1941  smlLog("received-%i.xml", parser->data, parser->size);
1942  smlSafeCFree(&debugstr);
1943 
1944  parser->got_command = FALSE;
1945 
1946  /* Create the new parser */
1947  parser->reader = xmlReaderForMemory(parser->data, parser->size, "/", NULL, XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA);
1948  if (!parser->reader) {
1949  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new reader");
1950  goto error;
1951  }
1952  xmlSubstituteEntitiesDefault(1);
1953 
1954  /* Check the First Node (SyncML)*/
1955  if (!_smlXmlParserExpectNode(parser, XML_NODE_START, FALSE, SML_ELEMENT_SYNCML, error))
1956  goto error_free_reader;
1957 
1958  /* Check the Second Node (SyncHdr)*/
1959  if (!_smlXmlParserExpectNode(parser, XML_NODE_START, FALSE, SML_ELEMENT_SYNCHDR, error))
1960  goto error_free_reader;
1961 
1962  smlTrace(TRACE_EXIT, "%s", __func__);
1963  return TRUE;
1964 
1965 error_free_reader:
1966  xmlFreeTextReader(parser->reader);
1967 error:
1968  parser->reader = NULL;
1969  if (parser->data)
1970  smlSafeCFree(&(parser->data));
1971  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1972  return FALSE;
1973 }
1974 
1975 SmlBool smlXmlParserEnd(SmlXmlParser *parser, SmlBool *final, SmlBool *end, SmlError **error)
1976 {
1977  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, parser, final, end, error);
1978  CHECK_ERROR_REF
1979  smlAssert(parser);
1980  SmlBool got_final = FALSE;
1981 
1982  /* Check for final */
1983  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FINAL)) {
1984  got_final = TRUE;
1985  if (!_smlXmlParserStep(parser)) {
1986  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1987  goto error;
1988  }
1989 
1990  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FINAL) && \
1991  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
1992  if (!_smlXmlParserStep(parser)) {
1993  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
1994  goto error;
1995  }
1996  }
1997  }
1998 
1999  if (final)
2000  *final = got_final;
2001 
2002  /* Check for the end. We can only decide if this was the last message if this
2003  * was the final message */
2004  if (end) {
2005  if (got_final)
2006  *end = parser->got_command ? FALSE : TRUE;
2007  else
2008  *end = FALSE;
2009  }
2010 
2011  /* Check the closing SyncBody - which is perhaps only an empty element. */
2012  if (strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCBODY) ||
2013  (!xmlTextReaderIsEmptyElement(parser->reader) &&
2014  xmlTextReaderNodeType(parser->reader) != XML_NODE_CLOSE
2015  )
2016  ) {
2017  smlErrorSet(error, SML_ERROR_GENERIC, "Wrong closing syncbody node");
2018  goto error;
2019  }
2020 
2021  /* Check the next node (SyncML)*/
2022  if (!_smlXmlParserExpectNode(parser, XML_NODE_CLOSE, FALSE, SML_ELEMENT_SYNCML, error))
2023  goto error;
2024 
2025  xmlFreeTextReader(parser->reader);
2026  parser->reader = NULL;
2027  parser->size = 0;
2028  smlSafeCFree(&(parser->data));
2029 
2030  smlTrace(TRACE_EXIT, "%s", __func__);
2031  return TRUE;
2032 
2033 error:
2034  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2035  return FALSE;
2036 }
2037 
2038 void smlXmlParserFree(SmlXmlParser *parser)
2039 {
2040  smlTrace(TRACE_ENTRY, "%s(%p)", __func__, parser);
2041  smlAssert(parser);
2042 
2043  if (parser->reader) {
2044  xmlFreeTextReader(parser->reader);
2045  }
2046  if (parser->data)
2047  smlSafeCFree(&(parser->data));
2048 
2049  smlSafeFree((gpointer *)&parser);
2050 
2051  smlTrace(TRACE_EXIT, "%s", __func__);
2052 }
2053 
2054 SmlBool smlXmlParserGetHeader(SmlXmlParser *parser, SmlHeader **header, SmlCred **cred, SmlError **error)
2055 {
2056  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, header, cred, error);
2057  CHECK_ERROR_REF
2058  smlAssert(parser);
2059  smlAssert(header);
2060  smlAssert(cred);
2061 
2062  if (!xmlTextReaderConstName(parser->reader) || strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCHDR) || \
2063  xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
2064  /* It is important to notice that empty headers are not allowed. */
2065  smlErrorSet(error, SML_ERROR_GENERIC, "Wrong starting node for a header");
2066  goto error;
2067  }
2068 
2069  parser->version = SML_VERSION_UNKNOWN;
2070 
2071  *header = smlTryMalloc0(sizeof(SmlHeader), error);
2072  if (!*header)
2073  goto error;
2074 
2075  while (1) {
2076  if (!_smlXmlParserStep(parser)) {
2077  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2078  goto error_free_header;
2079  }
2080 
2081  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCHDR) && \
2082  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2083  break;
2084  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
2085  smlErrorSet(error, SML_ERROR_GENERIC,
2086  "The element %s is not a start node in SyncHdr.",
2087  xmlTextReaderConstName(parser->reader));
2088  goto error_free_header;
2089  }
2090 
2091  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_VERDTD)) {
2092  if (!_smlSyncHeaderParseDTD(&((*header)->version), parser, error))
2093  goto error_free_header;
2094  parser->version = (*header)->version;
2095  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_VERPROTO)) {
2096  if (!_smlSyncHeaderParseProto(&((*header)->protocol), parser, error))
2097  goto error_free_header;
2098  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SESSIONID)) {
2099  if (!_smlXmlParserGetString(parser, &((*header)->sessionID), SML_ELEMENT_SESSIONID, error))
2100  goto error_free_header;
2101  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MSGID)) {
2102  if (!_smlXmlParserGetID(parser, &((*header)->messageID), SML_ELEMENT_MSGID, error))
2103  goto error_free_header;
2104  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGET)) {
2105  if (!_smlLocationParse(&((*header)->target), parser, error))
2106  goto error_free_header;
2107  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCE)) {
2108  if (!_smlLocationParse(&((*header)->source), parser, error))
2109  goto error_free_header;
2110  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_RESPURI)) {
2111  /* Only one RespURI is allowed.
2112  * If the header is not correct (more than one RespURI)
2113  * then the last RespURI is taken.
2114  */
2115  if ((*header)->responseURI) {
2116  smlTrace(TRACE_ERROR, "%s: There is more than on RespURI.", __func__);
2117  smlSafeCFree(&((*header)->responseURI));
2118  }
2119  if (!_smlXmlParserGetString(parser, &((*header)->responseURI), SML_ELEMENT_RESPURI, error))
2120  goto error_free_header;
2121  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_NORESP)) {
2122  /* This is an empty element. So the parser must not move one step forward. */
2123  (*header)->noResponse = TRUE;
2124  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_META)) {
2125  if (!_smlMessageParseSynchdrMeta(parser, &((*header)->maxmsgsize), &((*header)->maxobjsize), &((*header)->emi), error))
2126  goto error_free_header;
2127  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CRED)) {
2128  *cred = _smlCredParse(parser, error);
2129  if (!(*cred))
2130  goto error_free_header;
2131  }
2132 
2133  else {
2134  smlErrorSet(error, SML_ERROR_GENERIC, "Element %s not supported for SyncHdr.",
2135  (char *)xmlTextReaderConstName(parser->reader));
2136  goto error_free_header;
2137  }
2138  }
2139 
2140  if (!(*header)->protocol) {
2141  smlErrorSet(error, SML_ERROR_GENERIC, "No protocol set");
2142  goto error_free_header;
2143  }
2144 
2145  if (!(*header)->version) {
2146  smlErrorSet(error, SML_ERROR_GENERIC, "No dtd version set");
2147  goto error_free_header;
2148  }
2149 
2150  if (!(*header)->sessionID) {
2151  smlErrorSet(error, SML_ERROR_GENERIC, "No sessionID set");
2152  goto error_free_header;
2153  }
2154 
2155  if (!(*header)->target) {
2156  smlErrorSet(error, SML_ERROR_GENERIC, "No target set");
2157  goto error_free_header;
2158  }
2159 
2160  if (!(*header)->source) {
2161  smlErrorSet(error, SML_ERROR_GENERIC, "No source set");
2162  goto error_free_header;
2163  }
2164 
2165  if (!(*header)->messageID) {
2166  smlErrorSet(error, SML_ERROR_GENERIC, "No msgid set");
2167  goto error_free_header;
2168  }
2169 
2170  /* Check the Next Node (SyncBody)*/
2171  if (!_smlXmlParserExpectNode(parser, XML_NODE_START, FALSE, SML_ELEMENT_SYNCBODY, error))
2172  goto error_free_header;
2173 
2174  /* Step once more if it is not an empty element. */
2175  if (!xmlTextReaderIsEmptyElement(parser->reader) && !_smlXmlParserStep(parser)) {
2176  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2177  goto error_free_header;
2178  }
2179 
2180  smlTrace(TRACE_EXIT, "%s", __func__);
2181  return TRUE;
2182 
2183 error_free_header:
2184  smlHeaderFree(*header);
2185  *header = NULL;
2186 
2187  if (*cred)
2188  smlCredUnref(*cred);
2189 error:
2190  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2191  return FALSE;
2192 }
2193 
2194 SmlBool smlXmlParserGetStatus(SmlXmlParser *parser, SmlStatus **status, SmlError **error)
2195 {
2196  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, status, error);
2197  CHECK_ERROR_REF
2198  smlAssert(parser);
2199  smlAssert(status);
2200 
2201  char *locURI = NULL;
2202  SmlItem *item = NULL;
2203 
2204  /* Lets check if the next node is a command node */
2205  if (smlCommandTypeFromString((char *)xmlTextReaderConstName(parser->reader), error) != SML_COMMAND_TYPE_UNKNOWN && xmlTextReaderNodeType(parser->reader) == XML_NODE_START) {
2206  *status = NULL;
2207  smlTrace(TRACE_EXIT, "%s: Next is command", __func__);
2208  return TRUE;
2209  } else {
2210  smlErrorDeref(error);
2211  }
2212 
2213  /* Lets check if the next node is a final node */
2214  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FINAL) && (xmlTextReaderNodeType(parser->reader) == XML_NODE_START || xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE)) {
2215  *status = NULL;
2216  smlTrace(TRACE_EXIT, "%s: Next is final", __func__);
2217  return TRUE;
2218  }
2219 
2220  /* Let's check if the next node is a closing or empty syncbody node. */
2221  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCBODY) &&
2222  (xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE ||
2223  xmlTextReaderIsEmptyElement(parser->reader)
2224  )
2225  ) {
2226  *status = NULL;
2227  smlTrace(TRACE_EXIT, "%s: Next is closing syncbody", __func__);
2228  return TRUE;
2229  }
2230 
2231  if (strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_STATUS)) {
2232  smlErrorSet(error, SML_ERROR_GENERIC, "Unexpected element <%s>.",
2233  (char *)xmlTextReaderConstName(parser->reader));
2234  goto error;
2235  }
2236 
2237  if (xmlTextReaderIsEmptyElement(parser->reader))
2238  {
2239  /* An empty status element is not allowed.
2240  * Try to finish in a way that the parser can still be used.
2241  * The parser can ignore this mistake and finish correctly.
2242  * Nevertheless a second mistake which crashs the NextStep
2243  * function cannot be handled.
2244  */
2245  _smlXmlParserStep(parser);
2246  smlErrorSet(error, SML_ERROR_GENERIC, "Empty status element");
2247  goto error;
2248  }
2249 
2250  if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
2251  smlErrorSet(error, SML_ERROR_GENERIC,
2252  "The element %s is not the start node of Status.",
2253  xmlTextReaderConstName(parser->reader));
2254  goto error;
2255  }
2256 
2257  *status = smlStatusNew(SML_ERROR_UNKNOWN, 0, 0, NULL, NULL, SML_COMMAND_TYPE_UNKNOWN, error);
2258  if (!*status)
2259  goto error;
2260 
2261  while (1) {
2262  if (!_smlXmlParserStep(parser)) {
2263  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2264  goto error_free_status;
2265  }
2266 
2267  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_STATUS) && \
2268  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2269  break;
2270  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
2271  smlErrorSet(error, SML_ERROR_GENERIC,
2272  "The element %s is not a start node in Status.",
2273  xmlTextReaderConstName(parser->reader));
2274  goto error_free_status;
2275  }
2276 
2277  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDID)) {
2278  //Errr... who cares?
2279  if (!_smlXmlParserExpectNode(parser, XML_NODE_TEXT, FALSE, NULL, error))
2280  goto error_free_status;
2281  if (!_smlXmlParserExpectNode(parser, XML_NODE_CLOSE, FALSE, SML_ELEMENT_CMDID, error))
2282  goto error_free_status;
2283  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MSGREF)) {
2284  /* MsgRef is defined as parsed character data:
2285  OMA-SUP-DTD_SyncML_RepPro-V1_2-20070221-A.txt:<!ELEMENT MsgRef (#PCDATA)>
2286 
2287  SyncML Reprent Version 1.1 20020215 - Chapter 5.1.13 MsgRef:
2288  "[...] reference to a SyncML session-uniquie identifier referenced by SyncML result or response status."
2289 
2290  So it could be something else then an unsigned integer.
2291  */
2292  if (!_smlXmlParserGetID(parser, &((*status)->msgRef), SML_ELEMENT_MSGREF, error))
2293  goto error_free_status;
2294  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMDREF)) {
2295  if (!_smlXmlParserGetID(parser, &((*status)->cmdRef), SML_ELEMENT_CMDREF, error))
2296  goto error_free_status;
2297  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CMD)) {
2298  char *cmdname = NULL;
2299  if (!_smlXmlParserGetString(parser, &cmdname, SML_ELEMENT_CMD, error))
2300  goto error_free_status;
2301  (*status)->type = smlCommandTypeFromString(cmdname, error);
2302  smlSafeCFree(&cmdname);
2303  if ((*status)->type == SML_COMMAND_TYPE_UNKNOWN)
2304  goto error_free_status;
2305  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATA)) {
2306  if (!_smlXmlParserGetString(parser, &((*status)->data), SML_ELEMENT_DATA, error))
2307  goto error_free_status;
2308  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCEREF)) {
2309  if (!_smlXmlParserGetString(parser, &locURI, SML_ELEMENT_SOURCEREF, error))
2310  goto error_free_status;
2311 
2312  (*status)->sourceRef = smlLocationNew(locURI, NULL, error);
2313  smlSafeCFree(&locURI);
2314  if (!(*status)->sourceRef)
2315  goto error_free_status;
2316  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TARGETREF)) {
2317  if (!_smlXmlParserGetString(parser, &locURI, SML_ELEMENT_TARGETREF, error))
2318  goto error_free_status;
2319 
2320  (*status)->targetRef = smlLocationNew(locURI, NULL, error);
2321  smlSafeCFree(&locURI);
2322  if (!(*status)->targetRef)
2323  goto error_free_status;
2324  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_ITEM)) {
2325  /* Do not send SML_COMMAND_TYPE_ALERT
2326  * because this can give trouble.
2327  * Example: Error message for a failed ADD
2328  */
2329  item = _smlItemParse(parser, NULL, (*status)->type, error);
2330  if (!item)
2331  goto error_free_status;
2332  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CHAL)) {
2333  (*status)->chal = _smlChalParse(parser, error);
2334  if (!(*status)->chal)
2335  goto error_free_status;
2336  } else {
2337  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
2338  goto error;
2339  }
2340  }
2341 
2342  /* Step once more */
2343  if (!_smlXmlParserStep(parser)) {
2344  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2345  goto error_free_status;
2346  }
2347 
2348  if (item)
2349  {
2350  if ((*status)->type == SML_COMMAND_TYPE_ALERT) {
2351  (*status)->anchor = item->anchor;
2352  item->anchor = NULL;
2353  } else if ((*status)->type == SML_COMMAND_TYPE_ADD ||
2354  (*status)->type == SML_COMMAND_TYPE_REPLACE ||
2355  (*status)->type == SML_COMMAND_TYPE_DELETE) {
2356  /* Usually Sync is commited at once or together with an anchor.
2357  * If a single ADD, REPLACE or DELETE gets an item
2358  * then there is something going wrong.
2359  */
2360  g_warning("Received explicit status for add, delete or replace (%s).", xmlBufferContent(item->buffer));
2361  } else {
2362  smlErrorSet(error, SML_ERROR_GENERIC, "Got wrong item");
2363  smlItemUnref(item);
2364  goto error_free_status;
2365  }
2366  smlItemUnref(item);
2367  }
2368 
2369  /* MsgRef is defined as #PCDATA - so it doesn't have to be a
2370  unsigned integer AND it could be set to 0/zero as well.
2371 
2372  This sanity check breaks if MsgRef is set to 0/zero.
2373 
2374  if (!(*status)->msgRef) {
2375  smlErrorSet(error, SML_ERROR_GENERIC, "No msgref set");
2376  goto error_free_status;
2377  }
2378  */
2379 
2380  if ((*status)->type == SML_COMMAND_TYPE_UNKNOWN) {
2381  smlErrorSet(error, SML_ERROR_GENERIC, "No cmd set");
2382  goto error_free_status;
2383  }
2384 
2385  smlTrace(TRACE_INTERNAL, "Got status %p with: cmdRef %i, msgRef %i, type %i, data %s", *status, (*status)->cmdRef, (*status)->msgRef, (*status)->type, VA_STRING((*status)->data));
2386 
2387  smlTrace(TRACE_EXIT, "%s", __func__);
2388  return TRUE;
2389 
2390 error_free_status:
2391  smlStatusUnref(*status);
2392 error:
2393  *status = NULL;
2394  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2395  return FALSE;
2396 }
2397 
2398 SmlParserResult smlXmlParserGetCommand(SmlXmlParser *parser, SmlCommand **cmd, SmlError **error)
2399 {
2400  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, cmd, error);
2401  CHECK_ERROR_REF
2402  smlAssert(parser);
2403  smlAssert(cmd);
2404  *cmd = NULL;
2405 
2406  /* Lets check if the next node is a final node */
2407  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FINAL) && (xmlTextReaderNodeType(parser->reader) == XML_NODE_START || xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE)) {
2408  *cmd = NULL;
2409  smlTrace(TRACE_EXIT, "%s: Next is final", __func__);
2410  return SML_PARSER_RESULT_OTHER;
2411  }
2412 
2413  /* Let's check if the next node is a closing or empty syncbody node. */
2414  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCBODY) &&
2415  (xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE ||
2416  xmlTextReaderIsEmptyElement(parser->reader)
2417  )
2418  ) {
2419  *cmd = NULL;
2420  smlTrace(TRACE_EXIT, "%s: Next is closing syncbody", __func__);
2421  return SML_PARSER_RESULT_OTHER;
2422  }
2423 
2424  /* Lets check if the next node status node */
2425  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_STATUS) && xmlTextReaderNodeType(parser->reader) == XML_NODE_START) {
2426  *cmd = NULL;
2427  smlTrace(TRACE_EXIT, "%s: Next is status", __func__);
2428  return SML_PARSER_RESULT_STATUS;
2429  }
2430 
2431  SmlCommandType type = smlCommandTypeFromString((char *)xmlTextReaderConstName(parser->reader), error);
2432  if (!type)
2433  goto error;
2434 
2435  SmlParserResult result = SML_PARSER_RESULT_NORMAL;
2436 
2437  switch (type) {
2438  case SML_COMMAND_TYPE_ALERT:
2439  if (!_smlAlertParse(parser, cmd, error))
2440  goto error;
2441  break;
2442  case SML_COMMAND_TYPE_PUT:
2443  case SML_COMMAND_TYPE_GET:
2444  if (!_smlCommandAccessParse(parser, cmd, type, error))
2445  goto error;
2446  break;
2447  case SML_COMMAND_TYPE_SYNC:
2448  if (xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2449  if (!_smlXmlParserStep(parser)) {
2450  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2451  goto error_free_cmd;
2452  }
2453 
2454  smlTrace(TRACE_EXIT, "%s: SML_PARSER_RESULT_CLOSE", __func__);
2455  return SML_PARSER_RESULT_CLOSE;
2456  } else {
2457  if (!_smlCommandSyncParse(parser, cmd, error))
2458  goto error;
2459 
2460  result = SML_PARSER_RESULT_OPEN;
2461  }
2462  break;
2463  case SML_COMMAND_TYPE_MAP:
2464  if (!_smlCommandMapParse(parser, cmd, error))
2465  goto error;
2466  break;
2467  case SML_COMMAND_TYPE_ADD:
2468  if (!_smlChangeParse(parser, cmd, SML_COMMAND_TYPE_ADD, SML_ELEMENT_ADD, error))
2469  goto error;
2470  break;
2471  case SML_COMMAND_TYPE_REPLACE:
2472  if (!_smlChangeParse(parser, cmd, SML_COMMAND_TYPE_REPLACE, SML_ELEMENT_REPLACE, error))
2473  goto error;
2474  break;
2475  case SML_COMMAND_TYPE_DELETE:
2476  if (!_smlChangeParse(parser, cmd, SML_COMMAND_TYPE_DELETE, SML_ELEMENT_DELETE, error))
2477  goto error;
2478  break;
2479  case SML_COMMAND_TYPE_RESULTS:
2480  if (!_smlResultsParse(parser, cmd, error))
2481  goto error;
2482  break;
2483  default:
2484  smlErrorSet(error, SML_ERROR_GENERIC, "Unsupported command type");
2485  goto error;
2486  }
2487 
2488  if (!(*cmd)->cmdID) {
2489  smlErrorSet(error, SML_ERROR_GENERIC, "No cmdid set");
2490  goto error_free_cmd;
2491  }
2492 
2493  parser->got_command = TRUE;
2494 
2495  smlTrace(TRACE_EXIT, "%s: %i", __func__, result);
2496  return result;
2497 
2498 error_free_cmd:
2499  if (*cmd)
2500  smlCommandUnref(*cmd);
2501 error:
2502  *cmd = NULL;
2503  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2504  return SML_PARSER_RESULT_ERROR;
2505 }
2506 
2507 SmlXmlParser *smlXmlParserNew(SmlParserFunctions *functions, SmlError **error)
2508 {
2509  smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, functions,error);
2510  CHECK_ERROR_REF
2511  smlAssert(functions);
2512 
2513  SmlXmlParser *parser = smlTryMalloc0(sizeof(SmlXmlParser), error);
2514  if (!parser)
2515  goto error;
2516 
2517  functions->start = (SmlParserStartFunction)smlXmlParserStart;
2518  functions->free = (SmlParserFreeFunction)smlXmlParserFree;
2519  functions->end = (SmlParserEndFunction)smlXmlParserEnd;
2520  functions->get_header = (SmlParserHeaderFunction)smlXmlParserGetHeader;
2521  functions->get_cmd = (SmlParserCommandFunction)smlXmlParserGetCommand;
2522  functions->get_status = (SmlParserStatusFunction)smlXmlParserGetStatus;
2523 
2524  smlTrace(TRACE_EXIT, "%s: %p", __func__, parser);
2525  return parser;
2526 
2527 error:
2528  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2529  return NULL;
2530 }
2531 
2532 static SmlBool _smlXmlDevInfDataStoreParseDSMem(SmlXmlParser *parser, SmlDevInfDataStore *datastore, SmlError **error)
2533 {
2534  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, datastore, error);
2535  CHECK_ERROR_REF
2536  smlAssert(parser);
2537  smlAssert(datastore);
2538 
2539  if (xmlTextReaderIsEmptyElement(parser->reader)) {
2540  /* An empty DSMem element is allowed according to SyncML DevInf 1.1.2. */
2541  smlTrace(TRACE_EXIT, "%s - empty DSMem", __func__);
2542  return TRUE;
2543  }
2544 
2545  while (1) {
2546  if (!_smlXmlParserStep(parser)) {
2547  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2548  goto error;
2549  }
2550 
2551  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DSMEM) && \
2552  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2553  break;
2554  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
2555  smlErrorSet(error, SML_ERROR_GENERIC,
2556  "The element %s is not a start node in DSMem.",
2557  xmlTextReaderConstName(parser->reader));
2558  goto error;
2559  }
2560 
2561  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAXID)) {
2562  if (!_smlXmlParserGetID(parser, &(datastore->maxid), SML_ELEMENT_MAXID, error))
2563  goto error;
2564  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SHAREDMEM)) {
2565  datastore->sharedMem = TRUE;
2566  if (!_smlXmlParserStep(parser)) {
2567  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2568  goto error;
2569  }
2570 
2571  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SHAREDMEM) && \
2572  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2573  if (!_smlXmlParserStep(parser)) {
2574  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes2");
2575  goto error;
2576  }
2577  }
2578  continue;
2579  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAXMEM)) {
2580  if (!_smlXmlParserGetID(parser, &(datastore->maxmem), SML_ELEMENT_MAXMEM, error))
2581  goto error;
2582  } else {
2583  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
2584  goto error;
2585  }
2586  }
2587 
2588  smlTrace(TRACE_EXIT, "%s", __func__);
2589  return TRUE;
2590 
2591 error:
2592  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2593  return FALSE;
2594 }
2595 
2596 static SmlBool _smlXmlDevInfDataStoreParseSyncCap(SmlXmlParser *parser, SmlDevInfDataStore *datastore, SmlError **error)
2597 {
2598  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, datastore, error);
2599  CHECK_ERROR_REF
2600  smlAssert(parser);
2601  smlAssert(datastore);
2602 
2603  while (1) {
2604  if (!_smlXmlParserStep(parser)) {
2605  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2606  goto error;
2607  }
2608 
2609  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCCAP) && \
2610  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2611  break;
2612  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
2613  smlErrorSet(error, SML_ERROR_GENERIC,
2614  "The element %s is not a start node in SyncCap.",
2615  xmlTextReaderConstName(parser->reader));
2616  goto error;
2617  }
2618 
2619  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCTYPE)) {
2620  unsigned int id = 0;
2621  if (!_smlXmlParserGetID(parser, &id, SML_ELEMENT_SYNCTYPE, error))
2622  goto error;
2623  id = 1 << (id - 1);
2624  SmlDevInfSyncCap synccap = smlDevInfSyncCapConvert(id, error);
2625  if (synccap == SML_DEVINF_SYNCTYPE_UNKNOWN &&
2626  error != NULL)
2627  goto error;
2628 
2629  if (synccap != SML_DEVINF_SYNCTYPE_UNKNOWN)
2630  smlDevInfDataStoreSetSyncCap(datastore, synccap, TRUE);
2631  } else {
2632  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
2633  goto error;
2634  }
2635  }
2636 
2637  smlTrace(TRACE_EXIT, "%s", __func__);
2638  return TRUE;
2639 
2640 error:
2641  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2642  return FALSE;
2643 }
2644 
2645 static SmlBool _smlXmlDevInfDataStoreParseCTCap11(SmlXmlParser *parser, SmlDevInf *devinf, SmlError **error)
2646 {
2647  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, devinf, error);
2648  CHECK_ERROR_REF
2649  smlAssert(parser);
2650  smlAssert(devinf);
2651 
2652  /* This function was designed to parse one CTCap section */
2653  /* which can include several CTCap definitions */
2654 
2655  if (!_smlXmlParserStep(parser)) {
2656  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2657  goto error;
2658  }
2659 
2660  SmlDevInfCTCap *ctcap = NULL;
2661  SmlDevInfProperty *property = NULL;
2662  SmlDevInfPropParam *param = NULL;
2663  char *value = NULL;
2664  while (1) {
2665 
2666  const char *elem_name;
2667  elem_name = (const char*)xmlTextReaderConstName(parser->reader);
2668 
2669  smlTrace(TRACE_INTERNAL, "read: %s\n", elem_name);
2670  if (!strcmp(elem_name, SML_ELEMENT_CTCAP) &&
2671  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2672  // this is the end of the CTCap section
2673  break;
2674  }
2675 
2676  if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START)
2677  {
2678  smlErrorSet(error, SML_ERROR_GENERIC,
2679  "The element %s is not a start node in CTCap.",
2680  xmlTextReaderConstName(parser->reader));
2681  goto error;
2682  }
2683 
2684  /* determine list item type */
2685  SmlDevInfCTCapType type;
2686  type = smlDevInfCTCapTypeFromString(elem_name, error);
2687  value = NULL;
2688  if (type != SML_DEVINF_CTCAP_UNKNOWN)
2689  {
2690  _smlXmlParserGetString(parser, &value, elem_name, error);
2691  }
2692 
2693  /* now react on the different items */
2694  switch(type)
2695  {
2696  case SML_DEVINF_CTCAP_CTTYPE:
2697  // CTType => new ctcap definition
2698  if (ctcap != NULL)
2699  {
2700  if (property != NULL)
2701  {
2702  if (param != NULL)
2703  {
2704  smlDevInfPropertyAddPropParam(property, param);
2705  param = NULL;
2706  }
2707  smlDevInfCTCapAddProperty(ctcap, property);
2708  property = NULL;
2709  }
2710  smlDevInfAppendCTCap(devinf, ctcap);
2711  ctcap = NULL;
2712  }
2713  ctcap = smlDevInfNewCTCap(error);
2714  if (!ctcap)
2715  goto error;
2716  smlDevInfCTCapSetCTType(ctcap, value);
2717  break;
2718  case SML_DEVINF_CTCAP_VERCT:
2719  if (ctcap == NULL)
2720  goto error;
2721  smlDevInfCTCapSetVerCT(ctcap, value);
2722  break;
2723  case SML_DEVINF_CTCAP_PROPNAME:
2724  // PropName => new property
2725  if (ctcap == NULL)
2726  goto error;
2727  if (property != NULL)
2728  {
2729  if (param != NULL)
2730  {
2731  smlDevInfPropertyAddPropParam(property, param);
2732  param = NULL;
2733  }
2734  smlDevInfCTCapAddProperty(ctcap, property);
2735  property = NULL;
2736  }
2737  property = smlDevInfNewProperty(error);
2738  if (!property)
2739  goto error;
2740  smlDevInfPropertySetPropName(property, value);
2741  break;
2742  case SML_DEVINF_CTCAP_DATATYPE:
2743  if (property == NULL)
2744  goto error;
2745  if (param != NULL)
2746  smlDevInfPropParamSetDataType(param, value);
2747  else
2748  smlDevInfPropertySetDataType(property, value);
2749  break;
2750  case SML_DEVINF_CTCAP_MAXOCCUR:
2751  if (property == NULL)
2752  goto error;
2753  smlDevInfPropertySetMaxOccur(property, atoi(value));
2754  break;
2755  case SML_DEVINF_CTCAP_MAXSIZE:
2756  if (property == NULL)
2757  goto error;
2758  smlDevInfPropertySetMaxSize(property, atoi(value));
2759  break;
2760  case SML_DEVINF_CTCAP_NOTRUNCATE:
2761  if (property == NULL)
2762  goto error;
2763  smlDevInfPropertySetNoTruncate(property);
2764  break;
2765  case SML_DEVINF_CTCAP_DISPLAYNAME:
2766  if (property == NULL)
2767  goto error;
2768  if (param != NULL)
2769  smlDevInfPropParamSetDisplayName(param, value);
2770  else
2771  smlDevInfPropertySetDisplayName(property, value);
2772  break;
2773  case SML_DEVINF_CTCAP_VALENUM:
2774  if (property == NULL)
2775  goto error;
2776  if (param != NULL)
2777  smlDevInfPropParamAddValEnum(param, value);
2778  else
2779  smlDevInfPropertyAddValEnum(property, value);
2780  break;
2781  case SML_DEVINF_CTCAP_PARAMNAME:
2782  if (property == NULL)
2783  goto error;
2784  if (param != NULL)
2785  {
2786  smlDevInfPropertyAddPropParam(property, param);
2787  param = NULL;
2788  }
2789  param = smlDevInfNewPropParam(error);
2790  if (!param)
2791  goto error;
2792  smlDevInfPropParamSetParamName(param, value);
2793  break;
2794  case SML_DEVINF_CTCAP_SIZE:
2795  smlDevInfPropertySetPropSize(property, atoi(value));
2796  break;
2797  default:
2798  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown CTCapType: %s", elem_name);
2799  goto error;
2800  }
2801  smlSafeCFree(&value);
2802 
2803  if (!_smlXmlParserStep(parser)) {
2804  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2805  goto error;
2806  }
2807  }
2808  if (param != NULL)
2809  smlDevInfPropertyAddPropParam(property, param);
2810  if (property != NULL)
2811  smlDevInfCTCapAddProperty(ctcap, property);
2812  if (ctcap != NULL)
2813  smlDevInfAppendCTCap(devinf, ctcap);
2814 
2815  smlTrace(TRACE_EXIT, "%s", __func__);
2816  return TRUE;
2817 
2818 error:
2819  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2820  if (value != NULL)
2821  smlSafeCFree(&value);
2822  return FALSE;
2823 }
2824 
2825 static SmlDevInfPropParam *_smlXmlDevInfDataStoreParseCTCap12PropParam(SmlXmlParser *parser, SmlError **error)
2826 {
2827  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, error);
2828  CHECK_ERROR_REF
2829  smlAssert(parser);
2830 
2831  if (!_smlXmlParserStep(parser)) {
2832  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2833  goto error;
2834  }
2835 
2836  SmlDevInfPropParam *param = smlDevInfNewPropParam(error);
2837  if (!param)
2838  goto error;
2839 
2840  char *value = NULL;
2841  while (1) {
2842 
2843  const char *elem_name;
2844  elem_name = (const char*)xmlTextReaderConstName(parser->reader);
2845 
2846  smlTrace(TRACE_INTERNAL, "read: %s\n", elem_name);
2847  if (!strcmp(elem_name, SML_ELEMENT_PROPPARAM) &&
2848  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2849  // this is the end of the PropParam section
2850  break;
2851  }
2852 
2853  if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START)
2854  {
2855  smlErrorSet(error, SML_ERROR_GENERIC,
2856  "The element %s is not a start node in PropParam.",
2857  xmlTextReaderConstName(parser->reader));
2858  goto error;
2859  }
2860 
2861  /* determine item type */
2862  SmlDevInfCTCapType type;
2863  type = smlDevInfCTCapTypeFromString(elem_name, error);
2864  value = NULL;
2865  if (type != SML_DEVINF_CTCAP_UNKNOWN)
2866  {
2867  _smlXmlParserGetString(parser, &value, elem_name, error);
2868  }
2869 
2870  /* now react on the different items */
2871  switch(type)
2872  {
2873  case SML_DEVINF_CTCAP_PARAMNAME:
2874  smlDevInfPropParamSetParamName(param, value);
2875  break;
2876  case SML_DEVINF_CTCAP_DATATYPE:
2877  smlDevInfPropParamSetDataType(param, value);
2878  break;
2879  case SML_DEVINF_CTCAP_DISPLAYNAME:
2880  smlDevInfPropParamSetDisplayName(param, value);
2881  break;
2882  case SML_DEVINF_CTCAP_VALENUM:
2883  smlDevInfPropParamAddValEnum(param, value);
2884  break;
2885  default:
2886  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown CTCapType for PropParam: %s", elem_name);
2887  goto error;
2888  }
2889  smlSafeCFree(&value);
2890 
2891  if (!_smlXmlParserStep(parser)) {
2892  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2893  goto error;
2894  }
2895  }
2896 
2897  smlTrace(TRACE_EXIT, "%s", __func__);
2898  return param;
2899 
2900 error:
2901  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2902  if (value != NULL)
2903  smlSafeCFree(&value);
2904  return NULL;
2905 }
2906 
2907 static SmlDevInfProperty *_smlXmlDevInfDataStoreParseCTCap12Property(SmlXmlParser *parser, SmlError **error)
2908 {
2909  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, error);
2910  CHECK_ERROR_REF
2911  smlAssert(parser);
2912 
2913  if (!_smlXmlParserStep(parser)) {
2914  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2915  goto error;
2916  }
2917 
2918  SmlDevInfProperty *property = smlDevInfNewProperty(error);
2919  if (!property)
2920  goto error;
2921 
2922  SmlDevInfPropParam *param;
2923  char *value = NULL;
2924  while (1) {
2925 
2926  const char *elem_name;
2927  elem_name = (const char*)xmlTextReaderConstName(parser->reader);
2928 
2929  smlTrace(TRACE_INTERNAL, "read: %s\n", elem_name);
2930  if (!strcmp(elem_name, SML_ELEMENT_PROPERTY) &&
2931  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
2932  // this is the end of the Property section
2933  break;
2934  }
2935 
2936  if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START)
2937  {
2938  smlErrorSet(error, SML_ERROR_GENERIC,
2939  "The element %s is not a start node in Property.",
2940  xmlTextReaderConstName(parser->reader));
2941  goto error;
2942  }
2943 
2944  /* determine item type */
2945  SmlDevInfCTCapType type;
2946  type = smlDevInfCTCapTypeFromString(elem_name, error);
2947  value = NULL;
2948  if (type != SML_DEVINF_CTCAP_UNKNOWN &&
2949  type != SML_DEVINF_CTCAP_PROPPARAM)
2950  {
2951  _smlXmlParserGetString(parser, &value, elem_name, error);
2952  }
2953 
2954  /* now react on the different items */
2955  switch(type)
2956  {
2957  case SML_DEVINF_CTCAP_PROPNAME:
2958  smlDevInfPropertySetPropName(property, value);
2959  break;
2960  case SML_DEVINF_CTCAP_DATATYPE:
2961  smlDevInfPropertySetDataType(property, value);
2962  break;
2963  case SML_DEVINF_CTCAP_MAXOCCUR:
2964  smlDevInfPropertySetMaxOccur(property, atoi(value));
2965  break;
2966  case SML_DEVINF_CTCAP_MAXSIZE:
2967  smlDevInfPropertySetMaxSize(property, atoi(value));
2968  break;
2969  case SML_DEVINF_CTCAP_NOTRUNCATE:
2970  smlDevInfPropertySetNoTruncate(property);
2971  break;
2972  case SML_DEVINF_CTCAP_DISPLAYNAME:
2973  smlDevInfPropertySetDisplayName(property, value);
2974  break;
2975  case SML_DEVINF_CTCAP_VALENUM:
2976  smlDevInfPropertyAddValEnum(property, value);
2977  break;
2978  case SML_DEVINF_CTCAP_PROPPARAM:
2979  param = _smlXmlDevInfDataStoreParseCTCap12PropParam(parser, error);
2980  if (!param)
2981  goto error;
2982  smlDevInfPropertyAddPropParam(property, param);
2983  break;
2984  case SML_DEVINF_CTCAP_SIZE:
2985  smlDevInfPropertySetPropSize(property, atoi(value));
2986  break;
2987  default:
2988  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown CTCapType for Property: %s", elem_name);
2989  goto error;
2990  }
2991  if (value) smlSafeCFree(&value);
2992 
2993  if (!_smlXmlParserStep(parser)) {
2994  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
2995  goto error;
2996  }
2997  }
2998 
2999  smlTrace(TRACE_EXIT, "%s", __func__);
3000  return property;
3001 
3002 error:
3003  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
3004  if (value != NULL)
3005  smlSafeCFree(&value);
3006  return NULL;
3007 }
3008 
3009 static SmlBool _smlXmlDevInfDataStoreParseCTCap12(SmlXmlParser *parser, SmlDevInf *devinf, SmlError **error)
3010 {
3011  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, devinf, error);
3012  CHECK_ERROR_REF
3013  smlAssert(parser);
3014  smlAssert(devinf);
3015 
3016  /* This function was designed to parse one CTCap section */
3017  /* which can include only one CTCap definition */
3018 
3019  if (!_smlXmlParserStep(parser)) {
3020  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3021  goto error;
3022  }
3023 
3024  SmlDevInfCTCap *ctcap = smlDevInfNewCTCap(error);
3025  if (!ctcap)
3026  goto error;
3027 
3028  SmlDevInfProperty *property;
3029  char *value = NULL;
3030  while (1) {
3031 
3032  const char *elem_name;
3033  elem_name = (const char*)xmlTextReaderConstName(parser->reader);
3034 
3035  smlTrace(TRACE_INTERNAL, "read: %s\n", elem_name);
3036  if (!strcmp(elem_name, SML_ELEMENT_CTCAP) &&
3037  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3038  // this is the end of the CTCap section
3039  break;
3040  }
3041 
3042  if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START)
3043  {
3044  smlErrorSet(error, SML_ERROR_GENERIC,
3045  "The element %s is not a start node in CtCap.",
3046  xmlTextReaderConstName(parser->reader));
3047  goto error;
3048  }
3049 
3050  /* determine item type */
3051  SmlDevInfCTCapType type;
3052  type = smlDevInfCTCapTypeFromString(elem_name, error);
3053  value = NULL;
3054  if (type != SML_DEVINF_CTCAP_UNKNOWN &&
3055  type != SML_DEVINF_CTCAP_PROPERTY)
3056  {
3057  _smlXmlParserGetString(parser, &value, elem_name, error);
3058  }
3059 
3060  /* now react on the different items */
3061  switch(type)
3062  {
3063  case SML_DEVINF_CTCAP_CTTYPE:
3064  smlDevInfCTCapSetCTType(ctcap, value);
3065  break;
3066  case SML_DEVINF_CTCAP_VERCT:
3067  smlDevInfCTCapSetVerCT(ctcap, value);
3068  break;
3069  case SML_DEVINF_CTCAP_PROPERTY:
3070  property = _smlXmlDevInfDataStoreParseCTCap12Property(parser, error);
3071  if (!property)
3072  goto error;
3073  smlDevInfCTCapAddProperty(ctcap, property);
3074  break;
3075  default:
3076  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown CTCapType for CTCap: %s", elem_name);
3077  goto error;
3078  }
3079  if (value) smlSafeCFree(&value);
3080 
3081  if (!_smlXmlParserStep(parser)) {
3082  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3083  goto error;
3084  }
3085  }
3086  smlDevInfAppendCTCap(devinf, ctcap);
3087 
3088  smlTrace(TRACE_EXIT, "%s", __func__);
3089  return TRUE;
3090 
3091 error:
3092  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
3093  if (value != NULL)
3094  smlSafeCFree(&value);
3095  return FALSE;
3096 }
3097 
3098 static SmlBool _smlXmlDevInfDataStoreParseCTCap(SmlXmlParser *parser, SmlDevInf *devinf, SmlError **error)
3099 {
3100  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, devinf, error);
3101  CHECK_ERROR_REF
3102  smlAssert(parser);
3103  smlAssert(devinf);
3104 
3105  /* SyncML 1.0 and 1.1 start a new CTCap with a new CTType definition */
3106  /* SyncML 1.2 starts a new CTCap with a new CTCap definition */
3107  /* SyncML 1.2 attaches the CTCaps to the appropriate datastore */
3108  /* SyncML 1.0 and 1.1 attach the CTCaps to DevInf */
3109  /* The SyncML version is in devinf->version */
3110 
3111  SmlBool ret;
3112  if (devinf->version == SML_DEVINF_VERSION_12)
3113  ret = _smlXmlDevInfDataStoreParseCTCap12(parser, devinf, error);
3114  else
3115  ret = _smlXmlDevInfDataStoreParseCTCap11(parser, devinf, error);
3116 
3117  smlTrace(TRACE_EXIT, "%s (%d)", __func__, ret);
3118  return ret;
3119 }
3120 
3121 static SmlBool _smlXmlDevInfDataStoreParseRxTx(SmlXmlParser *parser, const char *element, char **cttype, char **version, SmlError **error)
3122 {
3123  smlTrace(TRACE_ENTRY, "%s(%p, %s, %p, %p, %p)", __func__, parser, VA_STRING(element), cttype, version, error);
3124  CHECK_ERROR_REF
3125  smlAssert(parser);
3126  smlAssert(element);
3127  smlAssert(cttype);
3128 
3129  if (!_smlXmlParserStep(parser)) {
3130  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3131  goto error;
3132  }
3133 
3134  while (1) {
3135  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), element) && \
3136  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3137  break;
3138  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
3139  smlErrorSet(error, SML_ERROR_GENERIC,
3140  "The element %s is not a start node in %s.",
3141  xmlTextReaderConstName(parser->reader), element);
3142  goto error;
3143  }
3144 
3145  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CTTYPE)) {
3146  if (!_smlXmlParserGetString(parser, cttype, SML_ELEMENT_CTTYPE, error))
3147  goto error;
3148  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_VERCT)) {
3149  /* Some phones send an empty VerCT for formats that dont have a version
3150  * (like notes). */
3151  if (!_smlXmlParserStep(parser)) {
3152  smlErrorSet(error, SML_ERROR_GENERIC, "No node at all");
3153  goto error;
3154  }
3155 
3156  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_VERCT) && \
3157  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3158  *version = g_strdup("");
3159  } else if (xmlTextReaderNodeType(parser->reader) == XML_NODE_TEXT) {
3160  *version = g_strstrip(g_strdup((char *)xmlTextReaderConstValue(parser->reader)));
3161 
3162  if (!_smlXmlParserExpectNode(parser, XML_NODE_CLOSE, FALSE, SML_ELEMENT_VERCT, error))
3163  goto error;
3164  } else {
3165  *version = g_strdup("");
3166  continue;
3167  }
3168  } else {
3169  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node");
3170  goto error;
3171  }
3172 
3173  if (!_smlXmlParserStep(parser)) {
3174  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3175  goto error;
3176  }
3177  }
3178 
3179  smlTrace(TRACE_EXIT, "%s", __func__);
3180  return TRUE;
3181 
3182 error:
3183  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
3184  return FALSE;
3185 }
3186 
3187 static SmlBool _smlXmlDevInfDataStoreParse(SmlXmlParser *parser, SmlDevInf *devinf, SmlError **error)
3188 {
3189  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, parser, devinf, error);
3190  CHECK_ERROR_REF
3191  smlAssert(devinf);
3192  smlAssert(parser);
3193 
3194  SmlDevInfDataStore *datastore = smlTryMalloc0(sizeof(SmlDevInfDataStore), error);
3195  if (!datastore)
3196  goto error;
3197  datastore->refCount = 1;
3198  datastore->rxPrefContentType = NULL;
3199  datastore->txPrefContentType = NULL;
3200 
3201  if (!_smlXmlParserStep(parser)) {
3202  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3203  goto error_free_datastore;
3204  }
3205 
3206  while (1) {
3207 
3208  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATASTORE) && \
3209  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3210  break;
3211  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
3212  smlErrorSet(error, SML_ERROR_GENERIC,
3213  "The element %s is not a start node in Datastore.",
3214  xmlTextReaderConstName(parser->reader));
3215  goto error_free_datastore;
3216  }
3217 
3218  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SOURCEREF)) {
3219  if (!_smlXmlParserGetString(parser, &(datastore->sourceref), SML_ELEMENT_SOURCEREF, error))
3220  goto error_free_datastore;
3221  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DISPLAYNAME)) {
3222  if (!_smlXmlParserGetString(parser, &(datastore->displayname), SML_ELEMENT_DISPLAYNAME, error))
3223  goto error_free_datastore;
3224  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAXGUIDSIZE)) {
3225  if (!_smlXmlParserGetID(parser, &(datastore->maxGUIDSize), SML_ELEMENT_MAXGUIDSIZE, error))
3226  goto error_free_datastore;
3227  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_RXPREF)) {
3228  if (!_smlXmlDevInfDataStoreParseRxTx(parser, SML_ELEMENT_RXPREF, &(datastore->rxPrefContentType), &(datastore->rxPrefVersion), error))
3229  goto error_free_datastore;
3230  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_RX)) {
3231  char *cttype = NULL;
3232  char *verct = NULL;
3233  if (!_smlXmlDevInfDataStoreParseRxTx(parser, SML_ELEMENT_RX, &cttype, &verct, error))
3234  goto error_free_datastore;
3235  SmlDevInfContentType *ct = smlDevInfNewContentType(cttype, verct, error);
3236  smlSafeCFree(&cttype);
3237  if (verct)
3238  smlSafeCFree(&verct);
3239  if (!ct)
3240  goto error_free_datastore;
3241  smlDevInfDataStoreAddRx(datastore, ct);
3242  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TXPREF)) {
3243  if (!_smlXmlDevInfDataStoreParseRxTx(parser, SML_ELEMENT_TXPREF, &(datastore->txPrefContentType), &(datastore->txPrefVersion), error))
3244  goto error_free_datastore;
3245  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_TX)) {
3246  char *cttype = NULL;
3247  char *verct = NULL;
3248  if (!_smlXmlDevInfDataStoreParseRxTx(parser, SML_ELEMENT_TX, &cttype, &verct, error))
3249  goto error_free_datastore;
3250  SmlDevInfContentType *ct = smlDevInfNewContentType(cttype, verct, error);
3251  smlSafeCFree(&cttype);
3252  if (verct)
3253  smlSafeCFree(&verct);
3254  if (!ct)
3255  goto error_free_datastore;
3256  smlDevInfDataStoreAddTx(datastore, ct);
3257  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CTCAP)) {
3258  if (!_smlXmlDevInfDataStoreParseCTCap(parser, devinf, error))
3259  goto error_free_datastore;
3260  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SYNCCAP)) {
3261  if (!_smlXmlDevInfDataStoreParseSyncCap(parser, datastore, error))
3262  goto error_free_datastore;
3263  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DSMEM)) {
3264  if (!_smlXmlDevInfDataStoreParseDSMem(parser, datastore, error))
3265  goto error_free_datastore;
3266  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SUPPORT_HIERARCHICAL_SYNC)) {
3267  if (devinf->version < SML_DEVINF_VERSION_12) {
3268  smlErrorSet(error, SML_ERROR_GENERIC, "SupportHierarchicalSync is only supported in OMA DS 1.2 DevInf and later.");
3269  goto error;
3270  }
3271  datastore->supportsHierarchicalSync = TRUE;
3272  if (!xmlTextReaderIsEmptyElement(parser->reader)) {
3273  if (!_smlXmlParserStep(parser)) {
3274  smlErrorSet(error, SML_ERROR_GENERIC, "The closing element of %s is missing.", SML_ELEMENT_SUPPORT_HIERARCHICAL_SYNC);
3275  goto error;
3276  }
3277  }
3278  } else {
3279  smlErrorSet(error, SML_ERROR_GENERIC, "A DataStore within DevInf includes the unsupported element %s.", (char *)xmlTextReaderConstName(parser->reader));
3280  goto error_free_datastore;
3281  }
3282 
3283  if (!_smlXmlParserStep(parser)) {
3284  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3285  goto error_free_datastore;
3286  }
3287  }
3288 
3289  smlDevInfAddDataStore(devinf, datastore);
3290 
3291  smlTrace(TRACE_EXIT, "%s", __func__);
3292  return TRUE;
3293 
3294 error_free_datastore:
3295  smlDevInfDataStoreUnref(datastore);
3296 error:
3297  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
3298  return FALSE;
3299 }
3300 
3301 SmlDevInf *smlXmlDevInfParse(const char *data, unsigned int size, SmlError **error)
3302 {
3303  smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data, size, error);
3304  CHECK_ERROR_REF
3305  smlAssert(data);
3306  smlAssert(size);
3307  SmlDevInf *devinf = NULL;
3308 
3309  //Fixme debug if
3310  char *debugstr = smlPrintBinary(data, size);
3311  smlTrace(TRACE_INTERNAL, "Xml devinf input: %s", debugstr);
3312  smlSafeCFree(&debugstr);
3313 
3314  SmlXmlParser *parser = smlTryMalloc0(sizeof(SmlXmlParser), error);
3315  if (!parser)
3316  goto error;
3317 
3318  /* Create the new parser */
3319  parser->reader = xmlReaderForMemory(data, size, "/", NULL, XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA | XML_PARSER_SUBST_ENTITIES);
3320  if (!parser->reader) {
3321  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new reader");
3322  goto error;
3323  }
3324  xmlSubstituteEntitiesDefault(1);
3325 
3326  /* Check the First Node (DevInf)*/
3327  if (!_smlXmlParserExpectNode(parser, XML_NODE_START, FALSE, SML_ELEMENT_DEVINF, error))
3328  goto error;
3329 
3330  devinf = smlTryMalloc0(sizeof(SmlDevInf), error);
3331  if (!devinf)
3332  goto error;
3333 
3334  smlDevInfRef(devinf);
3335 
3336  if (!_smlXmlParserStep(parser)) {
3337  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3338  goto error;
3339  }
3340 
3341  while (1) {
3342  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DEVINF) && \
3343  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3344  break;
3345  } else if (xmlTextReaderNodeType(parser->reader) != XML_NODE_START) {
3346  smlErrorSet(error, SML_ERROR_GENERIC,
3347  "The element %s is not a start node in DevInf.",
3348  xmlTextReaderConstName(parser->reader));
3349  goto error;
3350  }
3351 
3352 
3353  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_VERDTD)) {
3354  char *verdtd = NULL;
3355  if (!_smlXmlParserGetString(parser, &verdtd, SML_ELEMENT_VERDTD, error))
3356  goto error;
3357 
3358  if (verdtd && !strcmp(verdtd, "1.1"))
3359  devinf->version = SML_DEVINF_VERSION_11;
3360  else if (verdtd && !strcmp(verdtd, "1.0"))
3361  devinf->version = SML_DEVINF_VERSION_10;
3362  else if (verdtd && !strcmp(verdtd, "1.2"))
3363  devinf->version = SML_DEVINF_VERSION_12;
3364  else {
3365  smlSafeCFree(&verdtd);
3366  smlErrorSet(error, SML_ERROR_GENERIC, "Unknown devinf version");
3367  goto error;
3368  }
3369  smlSafeCFree(&verdtd);
3370  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MAN)) {
3371  if (!_smlXmlParserGetString(parser, &(devinf->manufacturer), SML_ELEMENT_MAN, error))
3372  goto error;
3373  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_MOD)) {
3374  if (!_smlXmlParserGetString(parser, &(devinf->model), SML_ELEMENT_MOD, error))
3375  goto error;
3376  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_OEM)) {
3377  if (!_smlXmlParserGetString(parser, &(devinf->oem), SML_ELEMENT_OEM, error))
3378  goto error;
3379  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_FWV)) {
3380  if (!_smlXmlParserGetString(parser, &(devinf->firmwareVersion), SML_ELEMENT_FWV, error))
3381  goto error;
3382  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SWV)) {
3383  if (!_smlXmlParserGetString(parser, &(devinf->softwareVersion), SML_ELEMENT_SWV, error))
3384  goto error;
3385  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_HWV)) {
3386  if (!_smlXmlParserGetString(parser, &(devinf->hardwareVersion), SML_ELEMENT_HWV, error))
3387  goto error;
3388  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DEVID)) {
3389  if (!_smlXmlParserGetString(parser, &(devinf->devid), SML_ELEMENT_DEVID, error))
3390  goto error;
3391  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DEVTYPE)) {
3392  char *devtype = NULL;
3393  if (!_smlXmlParserGetString(parser, &devtype, SML_ELEMENT_DEVTYPE, error))
3394  goto error;
3395 
3396  devinf->devtyp = smlDevInfDevTypeFromString(devtype, error);
3397  smlSafeCFree(&devtype);
3398 
3399  if (devinf->devtyp == SML_DEVINF_DEVTYPE_UNKNOWN)
3400  goto error;
3401  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_UTC)) {
3402  if (devinf->version == SML_DEVINF_VERSION_10) {
3403  smlErrorSet(error, SML_ERROR_GENERIC, "Devinf 1.0 does not allow UTC");
3404  goto error;
3405  }
3406 
3407  devinf->supportsUTC = TRUE;
3408  if (!_smlXmlParserStep(parser)) {
3409  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3410  goto error;
3411  }
3412 
3413  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_UTC) && \
3414  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3415  if (!_smlXmlParserStep(parser)) {
3416  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes2");
3417  goto error;
3418  }
3419  }
3420  continue;
3421  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SUPPORTLARGEOBJS)) {
3422  if (devinf->version == SML_DEVINF_VERSION_10) {
3423  smlErrorSet(error, SML_ERROR_GENERIC, "Devinf 1.0 does not allow large objects");
3424  goto error;
3425  }
3426 
3427  devinf->supportsLargeObjs = TRUE;
3428  if (!_smlXmlParserStep(parser)) {
3429  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3430  goto error;
3431  }
3432 
3433  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SUPPORTLARGEOBJS) && \
3434  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3435  if (!_smlXmlParserStep(parser)) {
3436  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes2");
3437  goto error;
3438  }
3439  }
3440  continue;
3441  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SUPPORTNUMBEROFCHANGES)) {
3442  if (devinf->version == SML_DEVINF_VERSION_10) {
3443  smlErrorSet(error, SML_ERROR_GENERIC, "Devinf 1.0 does not allow number of changes");
3444  goto error;
3445  }
3446 
3447  devinf->supportsNumberOfChanges = TRUE;
3448  if (!_smlXmlParserStep(parser)) {
3449  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3450  goto error;
3451  }
3452 
3453  if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_SUPPORTNUMBEROFCHANGES) && \
3454  xmlTextReaderNodeType(parser->reader) == XML_NODE_CLOSE) {
3455  if (!_smlXmlParserStep(parser)) {
3456  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes2");
3457  goto error;
3458  }
3459  }
3460  continue;
3461  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_DATASTORE)) {
3462  if (!_smlXmlDevInfDataStoreParse(parser, devinf, error))
3463  goto error;
3464  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_CTCAP)) {
3465  /* This must be SyncML 1.0 or 1.1.
3466  * OMA DM 1.2 puts CTCap into the datastores.
3467  */
3468  if (!_smlXmlDevInfDataStoreParseCTCap(parser, devinf, error))
3469  goto error;
3470  } else if (!strcmp((char *)xmlTextReaderConstName(parser->reader), SML_ELEMENT_EXT)) {
3471  /* Ignored for now */
3472  smlTrace(TRACE_INTERNAL, "%s: Skipping ext node");
3473  if (!_smlXmlSkipNode(parser)) {
3474  smlErrorSet(error, SML_ERROR_GENERIC, "Unable to skip ext node");
3475  goto error;
3476  }
3477  continue;
3478  } else {
3479  smlErrorSet(error, SML_ERROR_GENERIC, "wrong initial node: %s", (char *)xmlTextReaderConstName(parser->reader));
3480  goto error;
3481  }
3482 
3483  if (!_smlXmlParserStep(parser)) {
3484  smlErrorSet(error, SML_ERROR_GENERIC, "Missing nodes");
3485  goto error;
3486  }
3487  }
3488 
3489  xmlFreeTextReader(parser->reader);
3490  parser->reader = NULL;
3491  smlSafeFree((gpointer *)&parser);
3492 
3493  smlTrace(TRACE_EXIT, "%s", __func__);
3494  return devinf;
3495 
3496 error:
3497  if (parser && parser->reader) {
3498  xmlFreeTextReader(parser->reader);
3499  parser->reader = NULL;
3500  }
3501  if (parser)
3502  smlSafeFree((gpointer *)&parser);
3503  if (devinf)
3504  smlDevInfUnref(devinf);
3505  smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
3506  return NULL;
3507 }
3508