Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wap_push_si_compiler.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * wap_push_si_compiler.c: Tokenizes a SI document. SI DTD is defined in
59  * Wapforum specification WAP-167-ServiceInd-20010731-a (hereafter called si),
60  * chapter 8.2.
61  *
62  * By Aarno Syvšnen for Wiral Ltd
63  */
64 
65 #include <ctype.h>
66 #include <inttypes.h>
67 #include <libxml/xmlmemory.h>
68 #include <libxml/tree.h>
69 #include <libxml/debugXML.h>
70 #include <libxml/encoding.h>
71 
72 #include "shared.h"
73 #include "xml_shared.h"
74 #include "wap_push_si_compiler.h"
75 
76 /****************************************************************************
77  *
78  * Global variables
79  *
80  * Two token table types, one and two token fields
81  */
82 
83 struct si_2table_t {
84  char *name;
85  unsigned char token;
86 };
87 
88 typedef struct si_2table_t si_2table_t;
89 
90 /*
91  * Value part can mean part or whole of the value. It can be NULL, too, which
92  * means that no part of the value will be tokenised. See si, chapter 9.3.2.
93  */
94 struct si_3table_t {
95  char *name;
96  char *value_part;
97  unsigned char token;
98 };
99 
100 typedef struct si_3table_t si_3table_t;
101 
102 /*
103  * Elements from tag code page zero. These are defined in si, chapter 9.3.1.
104  */
105 
107  { "si", 0x05 },
108  { "indication", 0x06 },
109  { "info", 0x07 },
110  { "item", 0x08 }
111 };
112 
113 #define NUMBER_OF_ELEMENTS sizeof(si_elements)/sizeof(si_elements[0])
114 
115 /*
116  * Attributes (and start or whole value of ) from attribute code page zero.
117  * These are defined in si, chapter 9.3.2.
118  */
119 
121  { "action", "signal-none", 0x05 },
122  { "action", "signal-low", 0x06 },
123  { "action", "signal-medium", 0x07 },
124  { "action", "signal-high", 0x08 },
125  { "action", "delete", 0x09 },
126  { "created", NULL, 0x0a },
127  { "href", "https://www.", 0x0f },
128  { "href", "http://www.", 0x0d },
129  { "href", "https://", 0x0e },
130  { "href", "http://", 0x0c },
131  { "href", NULL, 0x0b },
132  { "si-expires", NULL, 0x10 },
133  { "si-id", NULL, 0x11 },
134  { "class", NULL, 0x12 }
135 };
136 
137 #define NUMBER_OF_ATTRIBUTES sizeof(si_attributes)/sizeof(si_attributes[0])
138 
139 /*
140  * Attribute value tokes (URL value codes), from si, chapter 9.3.3.
141  */
142 
144  { ".com/", 0x85 },
145  { ".edu/", 0x86 },
146  { ".net/", 0x87 },
147  { ".org/", 0x88 }
148 };
149 
150 #define NUMBER_OF_URL_VALUES sizeof(si_URL_values)/sizeof(si_URL_values[0])
151 
152 #include "xml_definitions.h"
153 
154 /****************************************************************************
155  *
156  * Prototypes of internal functions. Note that 'Ptr' means here '*'.
157  */
158 
159 static int parse_document(xmlDocPtr document, Octstr *charset,
160  simple_binary_t **si_binary);
161 static int parse_node(xmlNodePtr node, simple_binary_t **sibxml);
162 static int parse_element(xmlNodePtr node, simple_binary_t **sibxml);
163 static int parse_text(xmlNodePtr node, simple_binary_t **sibxml);
164 static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml); static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml);
165 static int url(int hex);
166 static int action(int hex);
167 static int date(int hex);
168 static Octstr *tokenize_date(Octstr *date);
169 static void octstr_drop_trailing_zeros(Octstr **date_token);
170 static void flag_date_length(Octstr **token);
171 static void parse_url_value(Octstr *value, simple_binary_t **sibxml);
172 
173 /****************************************************************************
174  *
175  * Implementation of the external function
176  */
177 
178 int si_compile(Octstr *si_doc, Octstr *charset, Octstr **si_binary)
179 {
180  simple_binary_t *sibxml;
181  int ret;
182  xmlDocPtr pDoc;
183  size_t size;
184  char *si_c_text;
185 
186  *si_binary = octstr_create("");
187  sibxml = simple_binary_create();
188 
189  octstr_strip_blanks(si_doc);
190  set_charset(si_doc, charset);
191  size = octstr_len(si_doc);
192  si_c_text = octstr_get_cstr(si_doc);
193  pDoc = xmlParseMemory(si_c_text, size);
194 
195  ret = 0;
196  if (pDoc) {
197  ret = parse_document(pDoc, charset, &sibxml);
198  simple_binary_output(*si_binary, sibxml);
199  xmlFreeDoc(pDoc);
200  } else {
201  xmlFreeDoc(pDoc);
202  octstr_destroy(*si_binary);
203  simple_binary_destroy(sibxml);
204  error(0, "SI: No document to parse. Probably an error in SI source");
205  return -1;
206  }
207 
208  simple_binary_destroy(sibxml);
209 
210  return ret;
211 }
212 
213 /****************************************************************************
214  *
215  * Implementation of internal functions
216  *
217  * Parse document node. Store si version number, public identifier and char-
218  * acter set into the start of the document. FIXME: Add parse_prologue!
219  */
220 
221 static int parse_document(xmlDocPtr document, Octstr *charset,
222  simple_binary_t **sibxml)
223 {
224  xmlNodePtr node;
225 
226  (*sibxml)->wbxml_version = 0x02; /* WBXML Version number 1.2 */
227  (*sibxml)->public_id = 0x05; /* SI 1.0 Public ID */
228 
229  charset = octstr_create("UTF-8");
230  (*sibxml)->charset = parse_charset(charset);
231  octstr_destroy(charset);
232 
233  node = xmlDocGetRootElement(document);
234  return parse_node(node, sibxml);
235 }
236 
237 /*
238  * Parse an element node. Check if there is a token for an element tag; if not
239  * output the element as a string, else ouput the token. After that, call
240  * attribute parsing functions
241  * Returns: 1, add an end tag (element node has no children)
242  * 0, do not add an end tag (it has children)
243  * -1, an error occurred
244  */
245 static int parse_element(xmlNodePtr node, simple_binary_t **sibxml)
246 {
247  Octstr *name,
248  *outos;
249  size_t i;
250  unsigned char status_bits,
251  si_hex;
252  int add_end_tag;
253  xmlAttrPtr attribute;
254 
255  name = octstr_create((char *)node->name);
256  outos = NULL;
257  if (octstr_len(name) == 0) {
258  octstr_destroy(name);
259  return -1;
260  }
261 
262  i = 0;
263  while (i < NUMBER_OF_ELEMENTS) {
264  if (octstr_compare(name, octstr_imm(si_elements[i].name)) == 0)
265  break;
266  ++i;
267  }
268 
269  status_bits = 0x00;
270  si_hex = 0x00;
271  add_end_tag = 0;
272 
273  if (i != NUMBER_OF_ELEMENTS) {
274  si_hex = si_elements[i].token;
275  if ((status_bits = element_check_content(node)) > 0) {
276  si_hex = si_hex | status_bits;
277 
278  if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
279  add_end_tag = 1;
280  }
281  output_char(si_hex, sibxml);
282  } else {
283  warning(0, "unknown tag %s in SI source", octstr_get_cstr(name));
284  si_hex = WBXML_LITERAL;
285  if ((status_bits = element_check_content(node)) > 0) {
286  si_hex = si_hex | status_bits;
287  /* If this node has children, the end tag must be added after
288  them. */
289  if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
290  add_end_tag = 1;
291  }
292  output_char(si_hex, sibxml);
293  output_octet_string(outos = octstr_duplicate(name), sibxml);
294  }
295 
296  if (node->properties != NULL) {
297  attribute = node->properties;
298  while (attribute != NULL) {
299  parse_attribute(attribute, sibxml);
300  attribute = attribute->next;
301  }
302  parse_end(sibxml);
303  }
304 
305  octstr_destroy(outos);
306  octstr_destroy(name);
307  return add_end_tag;
308 }
309 
310 /*
311  * Parse a text node of a si document. Ignore empty text nodes (space addi-
312  * tions to certain points will produce these). Si codes text nodes as an
313  * inline string.
314  */
315 
316 static int parse_text(xmlNodePtr node, simple_binary_t **sibxml)
317 {
318  Octstr *temp;
319 
320  temp = create_octstr_from_node((char *)node);
321 
322  octstr_shrink_blanks(temp);
323  octstr_strip_blanks(temp);
324 
325  if (octstr_len(temp) == 0) {
326  octstr_destroy(temp);
327  return 0;
328  }
329 
330  parse_inline_string(temp, sibxml);
331  octstr_destroy(temp);
332 
333  return 0;
334 }
335 
336 /*
337  * Tokenises an attribute, and in most cases, the start of its value (some-
338  * times whole of it). Tokenisation is based on tables in si, chapters 9.3.2
339  * and 9.3.3.
340  * Returns 0 when success, -1 when error.
341  */
342 static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml)
343 {
344  Octstr *name,
345  *value,
346  *valueos,
347  *tokenized_date;
348  unsigned char si_hex;
349  size_t i,
350  value_len;
351 
352  name = octstr_create((char *)attr->name);
353 
354  if (attr->children != NULL)
355  value = create_octstr_from_node((char *)attr->children);
356  else
357  value = NULL;
358 
359  if (value == NULL)
360  goto error;
361 
362  i = 0;
363  valueos = NULL;
364  while (i < NUMBER_OF_ATTRIBUTES) {
365  if (octstr_compare(name, octstr_imm(si_attributes[i].name)) == 0) {
366  if (si_attributes[i].value_part == NULL) {
367  break;
368  } else {
369  value_len = octstr_len(valueos =
370  octstr_imm(si_attributes[i].value_part));
371  if (octstr_ncompare(value, valueos, value_len) == 0) {
372  break;
373  }
374  }
375  }
376  ++i;
377  }
378 
379  if (i == NUMBER_OF_ATTRIBUTES)
380  goto error;
381 
382  tokenized_date = NULL;
383  si_hex = si_attributes[i].token;
384  if (action(si_hex)) {
385  output_char(si_hex, sibxml);
386  } else if (url(si_hex)) {
387  output_char(si_hex, sibxml);
388  octstr_delete(value, 0, octstr_len(valueos));
389  parse_url_value(value, sibxml);
390  } else if (date(si_hex)) {
391  if ((tokenized_date = tokenize_date(value)) == NULL)
392  goto error;
393  output_char(si_hex, sibxml);
394  output_octet_string(tokenized_date, sibxml);
395  } else {
396  output_char(si_hex, sibxml);
397  parse_inline_string(value, sibxml);
398  }
399 
400  octstr_destroy(tokenized_date);
401  octstr_destroy(name);
402  octstr_destroy(value);
403  return 0;
404 
405 error:
406  octstr_destroy(name);
407  octstr_destroy(value);
408  return -1;
409 }
410 
411 
412 /*
413  * checks whether a si attribute value is an URL or some other kind of value.
414  * Returns 1 for an URL and 0 otherwise.
415  */
416 
417 static int url(int hex)
418 {
419  switch ((unsigned char) hex) {
420  case 0x0b: /* href */
421  case 0x0c: case 0x0e: /* href http://, href https:// */
422  case 0x0d: case 0x0f: /* href http://www., href https://www. */
423  return 1;
424  }
425  return 0;
426 }
427 
428 /*
429  * checks whether a si attribute value is an action attribute or some other
430  * kind of value.
431  * Returns 1 for an action attribute and 0 otherwise.
432  */
433 
434 static int action(int hex)
435 {
436  switch ((unsigned char) hex) {
437  case 0x05: case 0x06: /* action signal-none, action signal-low */
438  case 0x07: case 0x08: /* action signal-medium, action signal-high */
439  case 0x09: /* action delete */
440  return 1;
441  }
442  return 0;
443 }
444 
445 /*
446  * checks whether a si attribute value is an OSI date or some other kind of
447  * value.
448  * Returns 1 for an action attribute and 0 otherwise.
449  */
450 
451 static int date(int hex)
452 {
453  switch ((unsigned char) hex) {
454  case 0x0a: case 0x10: /* created, si-expires */
455  return 1;
456  }
457  return 0;
458 }
459 
460 /*
461  * Tokenises an OSI date. Procedure is defined in si, chapter 9.2.2. Validate
462  * OSI date as specified in 9.2.1.1. Returns NULL when error, a tokenised date
463  * string otherwise.
464  */
466 {
467  Octstr *date_token;
468  long j;
469  size_t i,
470  date_len;
471  unsigned char c;
472 
473  if (!parse_date(date)) {
474  return NULL;
475  }
476 
477  date_token = octstr_create("");
478  octstr_append_char(date_token, WBXML_OPAQUE);
479 
480  i = 0;
481  j = 0;
482  date_len = octstr_len(date);
483  while (i < date_len) {
484  c = octstr_get_char(date, i);
485  if (c != 'T' && c != 'Z' && c != '-' && c != ':') {
486  if (isdigit(c)) {
487  octstr_set_bits(date_token, 4*j + 8, 4, c & 0x0f);
488  ++j;
489  } else {
490  octstr_destroy(date_token);
491  return NULL;
492  }
493  }
494  ++i;
495  }
496 
497  octstr_drop_trailing_zeros(&date_token);
498  flag_date_length(&date_token);
499 
500  return date_token;
501 }
502 
503 static void octstr_drop_trailing_zeros(Octstr **date_token)
504 {
505  while (1) {
506  if (octstr_get_char(*date_token, octstr_len(*date_token) - 1) == '\0')
507  octstr_delete(*date_token, octstr_len(*date_token) - 1, 1);
508  else
509  return;
510  }
511 }
512 
514 {
515  Octstr *lenos;
516 
517  lenos = octstr_format("%c", octstr_len(*token) - 1);
518  octstr_insert(*token, lenos, 1);
519 
520  octstr_destroy(lenos);
521 }
522 
523 /*
524  * The recursive parsing function for the parsing tree. Function checks the
525  * type of the node, calls for the right parse function for the type, then
526  * calls itself for the first child of the current node if there's one and
527  * after that calls itself for the next child on the list.
528  */
529 
530 static int parse_node(xmlNodePtr node, simple_binary_t **sibxml)
531 {
532  int status = 0;
533 
534  /* Call for the parser function of the node type. */
535  switch (node->type) {
536  case XML_ELEMENT_NODE:
537  status = parse_element(node, sibxml);
538  break;
539  case XML_TEXT_NODE:
540  status = parse_text(node, sibxml);
541  break;
542  case XML_CDATA_SECTION_NODE:
543  status = parse_cdata(node, sibxml);
544  break;
545  case XML_COMMENT_NODE:
546  case XML_PI_NODE:
547  /* Comments and PIs are ignored. */
548  break;
549  /*
550  * XML has also many other node types, these are not needed with
551  * SI. Therefore they are assumed to be an error.
552  */
553  default:
554  error(0, "SI compiler: Unknown XML node in the SI source.");
555  return -1;
556  break;
557  }
558 
559  /*
560  * If node is an element with content, it will need an end tag after it's
561  * children. The status for it is returned by parse_element.
562  */
563  switch (status) {
564  case 0:
565 
566  if (node->children != NULL)
567  if (parse_node(node->children, sibxml) == -1)
568  return -1;
569  break;
570  case 1:
571  if (node->children != NULL)
572  if (parse_node(node->children, sibxml) == -1)
573  return -1;
574  parse_end(sibxml);
575  break;
576 
577  case -1: /* Something went wrong in the parsing. */
578  return -1;
579  default:
580  warning(0,"SI compiler: undefined return value in a parse function.");
581  return -1;
582  break;
583  }
584 
585  if (node->next != NULL)
586  if (parse_node(node->next, sibxml) == -1)
587  return -1;
588 
589  return 0;
590 }
591 
592 /*
593  * Cdata section parsing function. Output this "as it is"
594  */
595 
596 static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml)
597 {
598  int ret = 0;
599  Octstr *temp;
600 
601  temp = create_octstr_from_node((char *)node);
602  parse_octet_string(temp, sibxml);
603  octstr_destroy(temp);
604 
605  return ret;
606 }
607 
608 /*
609  * In the case of SI documents, only attribute values to be tokenized are
610  * parts of urls (see si, chapter 9.3.3). The caller romoves the start of an
611  * url. Check whether we can find parts in the value. If not, parse value a an
612  * inline string, otherwise parse parts before and after tokenizable parts as
613  * inline strings.
614  */
615 void parse_url_value(Octstr *value, simple_binary_t **sibxml)
616 {
617  size_t i;
618  long pos;
619  Octstr *urlos,
620  *first_part,
621  *last_part;
622  size_t first_part_len;
623 
624  i = 0;
625  first_part_len = 0;
626  first_part = NULL;
627  last_part = NULL;
628  while (i < NUMBER_OF_URL_VALUES) {
629  pos = octstr_search(value,
630  urlos = octstr_imm(si_URL_values[i].name), 0);
631  if (pos >= 0) {
632  first_part = octstr_duplicate(value);
633  octstr_delete(first_part, pos, octstr_len(first_part) - pos);
634  first_part_len = octstr_len(first_part);
635  parse_inline_string(first_part, sibxml);
636  output_char(si_URL_values[i].token, sibxml);
637  last_part = octstr_duplicate(value);
638  octstr_delete(last_part, 0, first_part_len + octstr_len(urlos));
639  parse_inline_string(last_part, sibxml);
640  octstr_destroy(first_part);
641  octstr_destroy(last_part);
642  break;
643  }
644  octstr_destroy(urlos);
645  ++i;
646  }
647 
648  if (pos < 0)
649  parse_inline_string(value, sibxml);
650 
651 }
652 
void error(int err, const char *fmt,...)
Definition: log.c:612
static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml)
int size
Definition: wsasm.c:84
void output_octet_string(Octstr *os, simple_binary_t **sibxml)
Definition: xml_shared.c:349
static si_2table_t si_elements[]
unsigned char element_check_content(xmlNodePtr node)
Definition: xml_shared.c:242
#define NUMBER_OF_ELEMENTS
static int parse_node(xmlNodePtr node, simple_binary_t **sibxml)
Octstr * parse_date(Octstr *date)
Definition: shared.c:232
void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value)
Definition: octstr.c:1847
static void parse_url_value(Octstr *value, simple_binary_t **sibxml)
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1068
static void flag_date_length(Octstr **token)
void parse_octet_string(Octstr *os, simple_binary_t **binary)
Definition: xml_shared.c:331
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1344
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
int si_compile(Octstr *si_doc, Octstr *charset, Octstr **si_binary)
static si_3table_t si_attributes[]
Octstr * charset
Definition: test_ota.c:68
static int parse_text(xmlNodePtr node, simple_binary_t **sibxml)
void simple_binary_destroy(simple_binary_t *binary)
Definition: xml_shared.c:298
static si_2table_t si_URL_values[]
void parse_inline_string(Octstr *temp, simple_binary_t **binary)
Definition: xml_shared.c:339
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1301
int parse_charset(Octstr *os)
Definition: xml_shared.c:189
int token
Definition: wslexer.c:157
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
#define WBXML_LITERAL
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:950
static int action(int hex)
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml)
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:624
#define WBXML_OPAQUE
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
unsigned char token
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
void simple_binary_output(Octstr *os, simple_binary_t *binary)
Definition: xml_shared.c:311
Definition: octstr.c:118
void set_charset(Octstr *document, Octstr *charset)
Definition: xml_shared.c:111
static void octstr_drop_trailing_zeros(Octstr **date_token)
void parse_end(simple_binary_t **binary)
Definition: xml_shared.c:321
static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **si_binary)
void output_char(int byte, simple_binary_t **binary)
Definition: xml_shared.c:326
#define WBXML_CONTENT_BIT
static int date(int hex)
#define create_octstr_from_node(node)
simple_binary_t * simple_binary_create(void)
Definition: xml_shared.c:284
#define NUMBER_OF_ATTRIBUTES
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
void octstr_shrink_blanks(Octstr *text)
Definition: octstr.c:1431
static Octstr * tokenize_date(Octstr *date)
#define NUMBER_OF_URL_VALUES
static int url(int hex)
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
unsigned char token
static int parse_element(xmlNodePtr node, simple_binary_t **sibxml)
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.