wml_compiler.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:44k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wml_compiler.c - compiling WML to WML binary
  3.  *
  4.  * This is an implemention for WML compiler for compiling the WML text 
  5.  * format to WML binary format, which is used for transmitting the 
  6.  * decks to the mobile terminal to decrease the use of the bandwidth.
  7.  *
  8.  *
  9.  * Tuomas Luttinen for Wapit Ltd.
  10.  */
  11. #include "config.h"
  12. #include <time.h>
  13. #include <unistd.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <string.h>
  18. #include <math.h>
  19. #include <ctype.h>
  20. #include <libxml/xmlmemory.h>
  21. #include <libxml/tree.h>
  22. #include <libxml/debugXML.h>
  23. #include <libxml/encoding.h>
  24. #include "gwlib/gwlib.h"
  25. #include "wml_compiler.h"
  26. #include "xml_definitions.h"
  27. /***********************************************************************
  28.  * Declarations of data types. 
  29.  */
  30. typedef enum { NOESC, ESC, UNESC, FAILED } var_esc_t;
  31. /*
  32.  * The wml token table node with two fields.
  33.  */
  34. typedef struct {
  35.     char *text;
  36.     unsigned char token;
  37. } wml_table_t;
  38. /*
  39.  * The wml token table node with three fields.
  40.  */
  41. typedef struct {
  42.     char *text1;
  43.     char *text2;
  44.     unsigned char token;
  45. } wml_table3_t;
  46. /*
  47.  * The binary WML structure, that has been passed around between the 
  48.  * internal functions. It contains the header fields for wbxml version, 
  49.  * the WML public ID and the character set, the length of the string table, 
  50.  * the list structure implementing the string table and the octet string 
  51.  * containing the encoded WML binary.
  52.  */
  53. typedef struct {
  54.     unsigned char wbxml_version;
  55.     unsigned char wml_public_id;
  56.     unsigned long character_set;
  57.     unsigned long string_table_length;
  58.     List *string_table;
  59.     Octstr *wbxml_string;
  60. } wml_binary_t;
  61. /*
  62.  * The string table list node.
  63.  */
  64. typedef struct {
  65.     unsigned long offset;
  66.     Octstr *string;
  67. } string_table_t;
  68. /*
  69.  * The string table proposal list node.
  70.  */
  71. typedef struct {
  72.     int count;
  73.     Octstr *string;
  74. } string_table_proposal_t;
  75. /*
  76.  * The wml hash table node.
  77.  */
  78. typedef struct {
  79.     Octstr *item;
  80.     unsigned char binary;
  81. } wml_hash_t;
  82. /*
  83.  * The hash table node for attribute and values.
  84.  */
  85. typedef struct {
  86.     Octstr *attribute;
  87.     unsigned char binary;
  88.     List *value_list;
  89. } wml_attribute_t;
  90. #include "xml_shared.h"
  91. #include "wml_definitions.h"
  92. /***********************************************************************
  93.  * Declarations of global variables. 
  94.  */
  95. Dict *wml_elements_dict;
  96. Dict *wml_attributes_dict;
  97. List *wml_attr_values_list;
  98. List *wml_URL_values_list;
  99. /***********************************************************************
  100.  * Declarations of internal functions. These are defined at the end of
  101.  * the file.
  102.  */
  103. /*
  104.  * Parsing functions. These funtions operate on a single node or a 
  105.  * smaller datatype. Look for more details on the functions at the 
  106.  * definitions.
  107.  */
  108. static int parse_document(xmlDocPtr document, Octstr *charset, 
  109.   wml_binary_t **wbxml);
  110. static int parse_node(xmlNodePtr node, wml_binary_t **wbxml);
  111. static int parse_element(xmlNodePtr node, wml_binary_t **wbxml);
  112. static int parse_attribute(xmlAttrPtr attr, wml_binary_t **wbxml);
  113. static int parse_attr_value(Octstr *attr_value, List *tokens, 
  114.     wml_binary_t **wbxml);
  115. static int parse_text(xmlNodePtr node, wml_binary_t **wbxml);
  116. static int parse_cdata(xmlNodePtr node, wml_binary_t **wbxml);
  117. static int parse_st_octet_string(Octstr *ostr, int cdata, wml_binary_t **wbxml);
  118. static void parse_st_end(wml_binary_t **wbxml);
  119. static void parse_entities(Octstr *wml_source);
  120. /*
  121.  * Variable functions. These functions are used to find and parse variables.
  122.  */
  123. static int parse_variable(Octstr *text, int start, Octstr **output, 
  124.   wml_binary_t **wbxml);
  125. static Octstr *get_variable(Octstr *text, int start);
  126. static var_esc_t check_variable_syntax(Octstr *variable);
  127. /*
  128.  * wml_binary-functions. These are used to create, destroy and modify
  129.  * wml_binary_t.
  130.  */
  131. static wml_binary_t *wml_binary_create(void);
  132. static void wml_binary_destroy(wml_binary_t *wbxml);
  133. static void wml_binary_output(Octstr *ostr, wml_binary_t *wbxml);
  134. /* Output into the wml_binary. */
  135. static void output_st_char(int byte, wml_binary_t **wbxml);
  136. static void output_st_octet_string(Octstr *ostr, wml_binary_t **wbxml);
  137. static void output_variable(Octstr *variable, Octstr **output, 
  138.     var_esc_t escaped, wml_binary_t **wbxml);
  139. /*
  140.  * Memory allocation and deallocations.
  141.  */
  142. static wml_hash_t *hash_create(char *text, unsigned char token);
  143. static wml_attribute_t *attribute_create(void);
  144. static void attr_dict_construct(wml_table3_t *attributes, Dict *attr_dict);
  145. static void hash_destroy(void *p);
  146. static void attribute_destroy(void *p);
  147. /*
  148.  * Comparison functions for the hash tables.
  149.  */
  150. static int hash_cmp(void *hash1, void *hash2);
  151. /*
  152.  * Miscellaneous help functions.
  153.  */
  154. static int check_do_elements(xmlNodePtr node);
  155. static var_esc_t check_variable_name(xmlNodePtr node);
  156. static Octstr *get_do_element_name(xmlNodePtr node);
  157. static int check_if_url(int hex);
  158. static int check_if_emphasis(xmlNodePtr node);
  159. static int wml_table_len(wml_table_t *table);
  160. static int wml_table3_len(wml_table3_t *table);
  161. /* 
  162.  * String table functions, used to add and remove strings into and from the
  163.  * string table.
  164.  */
  165. static string_table_t *string_table_create(int offset, Octstr *ostr);
  166. static void string_table_destroy(string_table_t *node);
  167. static string_table_proposal_t *string_table_proposal_create(Octstr *ostr);
  168. static void string_table_proposal_destroy(string_table_proposal_t *node);
  169. static void string_table_build(xmlNodePtr node, wml_binary_t **wbxml);
  170. static void string_table_collect_strings(xmlNodePtr node, List *strings);
  171. static List *string_table_collect_words(List *strings);
  172. static List *string_table_sort_list(List *start);
  173. static List *string_table_add_many(List *sorted, wml_binary_t **wbxml);
  174. static unsigned long string_table_add(Octstr *ostr, wml_binary_t **wbxml);
  175. static void string_table_apply(Octstr *ostr, wml_binary_t **wbxml);
  176. static void string_table_output(Octstr *ostr, wml_binary_t **wbxml);
  177. /***********************************************************************
  178.  * Implementations of the functions declared in wml_compiler.h.
  179.  */
  180. /*
  181.  * The actual compiler function. This operates as interface to the compiler.
  182.  * For more information, look wml_compiler.h. 
  183.  */
  184. int wml_compile(Octstr *wml_text,
  185. Octstr *charset,
  186. Octstr **wml_binary)
  187. {
  188.     int ret = 0;
  189.     size_t size;
  190.     xmlDocPtr pDoc = NULL;
  191.     char *wml_c_text;
  192.     wml_binary_t *wbxml = NULL;
  193.     *wml_binary = octstr_create("");
  194.     wbxml = wml_binary_create();
  195.     /* Remove the extra space from start and the end of the WML Document. */
  196.     octstr_strip_blanks(wml_text);
  197.     /* Check the WML-code for -characters and for WML entities. Fast patch.
  198.        -- tuo */
  199.     parse_entities(wml_text);
  200.     set_charset(wml_text, charset);
  201.     
  202.     size = octstr_len(wml_text);
  203.     wml_c_text = octstr_get_cstr(wml_text);
  204.     if (octstr_search_char(wml_text, '', 0) != -1) {    
  205. error(0, 
  206.       "WML compiler: Compiling error: "
  207.       "\0 character found in the middle of the WML source.");
  208. ret = -1;
  209.     } else {
  210. /* 
  211.  * An empty octet string for the binary output is created, the wml 
  212.  * source is parsed into a parsing tree and the tree is then compiled 
  213.  * into binary.
  214.  */
  215. pDoc = xmlParseMemory(wml_c_text, size);
  216. if(pDoc != NULL) {
  217.     ret = parse_document(pDoc, charset, &wbxml);
  218.     wml_binary_output(*wml_binary, wbxml);
  219. } else {    
  220.     error(0, 
  221.   "WML compiler: Compiling error: "
  222.   "libxml returned a NULL pointer");
  223.     ret = -1;
  224. }
  225.     }
  226.     wml_binary_destroy(wbxml);
  227.     if (pDoc) 
  228.         xmlFreeDoc (pDoc);
  229.     return ret;
  230. }
  231. /*
  232.  * Initialization: makes up the hash tables for the compiler.
  233.  */
  234. void wml_init()
  235. {
  236.     int i = 0, len = 0;
  237.     wml_hash_t *temp = NULL;
  238.     
  239.     /* The wml elements into a hash table. */
  240.     len = wml_table_len(wml_elements);
  241.     wml_elements_dict = dict_create(len, hash_destroy);
  242.     for (i = 0; i < len; i++) {
  243. temp = hash_create(wml_elements[i].text, wml_elements[i].token);
  244. dict_put(wml_elements_dict, temp->item, temp);
  245.     }
  246.     /* Attributes. */
  247.     len = wml_table3_len(wml_attributes);
  248.     wml_attributes_dict = dict_create(len, attribute_destroy);
  249.     attr_dict_construct(wml_attributes, wml_attributes_dict);
  250.     /* Attribute values. */
  251.     len = wml_table_len(wml_attribute_values);
  252.     wml_attr_values_list = list_create();
  253.     for (i = 0; i < len; i++) {
  254. temp = hash_create(wml_attribute_values[i].text, 
  255.    wml_attribute_values[i].token);
  256. list_append(wml_attr_values_list, temp);
  257.     }
  258.     /* URL values. */
  259.     len = wml_table_len(wml_URL_values);
  260.     wml_URL_values_list = list_create();
  261.     for (i = 0; i < len; i++) {
  262. temp = hash_create(wml_URL_values[i].text, wml_URL_values[i].token);
  263. list_append(wml_URL_values_list, temp);
  264.     }
  265. }
  266. /*
  267.  * Shutdown: Frees the memory allocated by initialization.
  268.  */
  269. void wml_shutdown()
  270. {
  271.     dict_destroy(wml_elements_dict);
  272.     dict_destroy(wml_attributes_dict);
  273.     list_destroy(wml_attr_values_list, hash_destroy);
  274.     list_destroy(wml_URL_values_list, hash_destroy);
  275. }
  276. /***********************************************************************
  277.  * Internal functions.
  278.  */
  279. /*
  280.  * parse_node - the recursive parsing function for the parsing tree.
  281.  * Function checks the type of the node, calls for the right parse 
  282.  * function for the type, then calls itself for the first child of
  283.  * the current node if there's one and after that calls itself for the 
  284.  * next child on the list.
  285.  */
  286. static int parse_node(xmlNodePtr node, wml_binary_t **wbxml)
  287. {
  288.     int status = 0;
  289.     
  290.     /* Call for the parser function of the node type. */
  291.     switch (node->type) {
  292.     case XML_ELEMENT_NODE:
  293. status = parse_element(node, wbxml);
  294. break;
  295.     case XML_TEXT_NODE:
  296. status = parse_text(node, wbxml);
  297. break;
  298.     case XML_CDATA_SECTION_NODE:
  299. status = parse_cdata(node, wbxml);
  300. break;
  301.     case XML_COMMENT_NODE:
  302.     case XML_PI_NODE:
  303. /* Comments and PIs are ignored. */
  304. break;
  305. /*
  306.  * XML has also many other node types, these are not needed with 
  307.  * WML. Therefore they are assumed to be an error.
  308.  */
  309.     default:
  310. error(0, "WML compiler: Unknown XML node in the WML source.");
  311. return -1;
  312. break;
  313.     }
  314.     /* 
  315.      * If node is an element with content, it will need an end tag after it's
  316.      * children. The status for it is returned by parse_element.
  317.      */
  318.     switch (status) {
  319.     case 0:
  320. if (node->children != NULL)
  321.     if (parse_node(node->children, wbxml) == -1)
  322. return -1;
  323. break;
  324.     case 1:
  325. if (node->children != NULL)
  326.     if (parse_node(node->children, wbxml) == -1)
  327. return -1;
  328. parse_st_end(wbxml);
  329. break;
  330.     case -1: /* Something went wrong in the parsing. */
  331. return -1;
  332.     default:
  333. error(0,
  334.       "WML compiler: undefined return value in a parse function.");
  335. return -1;
  336. break;
  337.     }
  338.     if (node->next != NULL)
  339. if (parse_node(node->next, wbxml) == -1)
  340.     return -1;
  341.     return 0;
  342. }
  343. /*
  344.  * parse_document - the parsing function for the document node.
  345.  * The function outputs the WBXML version, WML public id and the
  346.  * character set values into start of the wbxml.
  347.  */
  348. static int parse_document(xmlDocPtr document, Octstr *charset, 
  349.   wml_binary_t **wbxml)
  350. {
  351.     Octstr *chars;
  352.     xmlNodePtr node;
  353.     if (document == NULL) {
  354. error(0, "WML compiler: XML parsing failed, no parsed document.");
  355. error(0, "Most probably an error in the WML source.");
  356. return -1;
  357.     }
  358.     /* XXX - A bad hack, WBXML version is assumed to be 1.1. -tuo */
  359.     (*wbxml)->wbxml_version = 0x01; /* WBXML Version number 1.1 */
  360.     (*wbxml)->wml_public_id = 0x04; /* WML 1.1 Public ID */
  361.     (*wbxml)->string_table_length = 0x00; /* String table length=0 */
  362.     chars = octstr_create("UTF-8");
  363.     (*wbxml)->character_set = parse_charset(chars);
  364.     octstr_destroy(chars);
  365.     node = xmlDocGetRootElement(document);
  366.     string_table_build(node, wbxml);
  367.     return parse_node(node, wbxml);
  368. }
  369. /*
  370.  * parse_element - the parsing function for an element node.
  371.  * The element tag is encoded into one octet hexadecimal value, 
  372.  * if possible. Otherwise it is encoded as text. If the element 
  373.  * needs an end tag, the function returns 1, for no end tag 0
  374.  * and -1 for an error.
  375.  */
  376. static int parse_element(xmlNodePtr node, wml_binary_t **wbxml)
  377. {
  378.     int add_end_tag = 0;
  379.     unsigned char wbxml_hex = 0, status_bits;
  380.     xmlAttrPtr attribute;
  381.     Octstr *name;
  382.     wml_hash_t *element;
  383.     name = octstr_create(node->name);
  384.     /* Check, if the tag can be found from the code page. */
  385.     if ((element = dict_get(wml_elements_dict, name)) != NULL) {
  386. wbxml_hex = element->binary;
  387. /* A conformance patch: no do-elements of same name in a card or
  388.    template. An extremely ugly patch. --tuo */
  389. if (wbxml_hex == 0x27 || /* Card */
  390.     wbxml_hex == 0x3B)   /* Template */
  391.     if (check_do_elements(node) == -1) {
  392. add_end_tag = -1;
  393. error(0, "WML compiler: Two or more do elements with same"
  394.       " name in a card or template element.");
  395.     }
  396. /* A conformance patch: if variable in setvar has a bad name, it's
  397.    ignored. */
  398. if (wbxml_hex == 0x3E) /* Setvar */
  399.     if (check_variable_name(node) == FAILED) {
  400. octstr_destroy(name);
  401. return add_end_tag;
  402.     }
  403. if ((status_bits = element_check_content(node)) > 0) {
  404.     wbxml_hex = wbxml_hex | status_bits;
  405.     /* If this node has children, the end tag must be added after 
  406.        them. */
  407.     if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
  408. add_end_tag = 1;
  409. }
  410. output_st_char(wbxml_hex, wbxml);
  411.     } else {    
  412. /* The tag was not on the code page, it has to be encoded as a 
  413.    string. */
  414. wbxml_hex = WBXML_LITERAL;
  415. if ((status_bits = element_check_content(node)) > 0) {
  416.     wbxml_hex = wbxml_hex | status_bits;
  417.     /* If this node has children, the end tag must be added after 
  418.        them. */
  419.     if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
  420. add_end_tag = 1;
  421. }
  422. output_st_char(wbxml_hex, wbxml);
  423. output_st_char(string_table_add(octstr_duplicate(name), wbxml), wbxml);
  424. warning(0, "WML compiler: Unknown tag in WML source: <%s>", 
  425. octstr_get_cstr(name));
  426.     }
  427.     /* Encode the attribute list for this node and add end tag after the 
  428.        list. */
  429.     if(node->properties != NULL) {
  430. attribute = node->properties;
  431. while (attribute != NULL) {
  432.     parse_attribute(attribute, wbxml);
  433.     attribute = attribute->next;
  434. }
  435. parse_st_end(wbxml);
  436.     }
  437.     octstr_destroy(name);
  438.     return add_end_tag;
  439. }
  440. /*
  441.  * parse_attribute - the parsing function for attributes. The function 
  442.  * encodes the attribute (and probably start of the value) as a one 
  443.  * hexadecimal octet. The value (or the rest of it) is coded as a string 
  444.  * maybe using predefined attribute value tokens to reduce the length
  445.  * of the output. Returns 0 for success, -1 for error.
  446.  */
  447. static int parse_attribute(xmlAttrPtr attr, wml_binary_t **wbxml)
  448. {
  449.     int status = 0;
  450.     int coded_length = 0;
  451.     unsigned char wbxml_hex = 0x00;
  452.     wml_hash_t *hit = NULL;
  453.     wml_attribute_t *attribute = NULL;
  454.     Octstr *name = NULL, *pattern = NULL, *p = NULL;
  455.     name = octstr_create(attr->name);
  456.     if (attr->children != NULL)
  457. pattern = create_octstr_from_node(attr->children);
  458.     else 
  459. pattern = NULL;
  460.     /* Check if the attribute is found on the code page. */
  461.     if ((attribute = dict_get(wml_attributes_dict, name)) != NULL) {
  462. if (attr->children == NULL || 
  463.     (hit = list_search(attribute->value_list, (void *)pattern, 
  464.        hash_cmp)) == NULL) {
  465. wbxml_hex = attribute->binary;
  466. output_st_char(wbxml_hex, wbxml);
  467. } else if (hit->binary) {
  468.     wbxml_hex = hit->binary;
  469.     coded_length = octstr_len(hit->item);
  470.     output_st_char(wbxml_hex, wbxml);
  471. } else
  472.     status = -1;
  473.     } else {
  474. /* The attribute was not on the code page, it has to be encoded as a 
  475.    string. */
  476. wbxml_hex = WBXML_LITERAL;
  477. output_st_char(wbxml_hex, wbxml);
  478. output_st_char(string_table_add(octstr_duplicate(name), wbxml), wbxml);
  479. warning(0, "WML compiler: Unknown attribute in WML source: <%s>", 
  480. octstr_get_cstr(name));
  481.     }
  482.     if (status >= 0) {
  483. /* The rest of the attribute is coded as a inline string. */
  484. if (pattern != NULL && 
  485.     coded_length < (int) octstr_len(pattern)) {
  486.     if (coded_length == 0)
  487. p = create_octstr_from_node(attr->children); 
  488.     else
  489. p = octstr_copy(pattern, coded_length, 
  490. octstr_len(pattern) - coded_length); 
  491.     if (check_if_url(wbxml_hex))
  492. status = parse_attr_value(p, wml_URL_values_list,
  493.   wbxml);
  494.     else
  495. status = parse_attr_value(p, wml_attr_values_list,
  496.   wbxml);
  497.     if (status != 0)
  498. error(0, 
  499.       "WML compiler: could not output attribute "
  500.       "value as a string.");
  501.     octstr_destroy(p);
  502. }
  503.     }
  504.     /* Memory cleanup. */
  505.     octstr_destroy(name);
  506.     if (pattern != NULL)
  507. octstr_destroy(pattern);
  508.     return status;
  509. }
  510. /*
  511.  * parse_attr_value - parses an attributes value using WML value codes.
  512.  */
  513. static int parse_attr_value(Octstr *attr_value, List *tokens,
  514.     wml_binary_t **wbxml)
  515. {
  516.     int i, pos, wbxml_hex;
  517.     wml_hash_t *temp = NULL;
  518.     Octstr *cut_text = NULL;
  519.     /*
  520.      * The attribute value is search for text strings that can be replaced 
  521.      * with one byte codes. Note that the algorith is not foolproof; seaching 
  522.      * is done in an order and the text before first hit is not checked for 
  523.      * those tokens that are after the hit in the order. Most likely it would 
  524.      * be waste of time anyway. String table is not used here, since at least 
  525.      * Nokia 7110 doesn't seem to understand string table references here.
  526.      */
  527.     /* A fast patch to allow reserved names to be variable names. May produce 
  528.        a little longer binary at some points. --tuo */
  529.     if (octstr_search_char(attr_value, '$', 0) >= 0) {
  530. if (parse_st_octet_string(attr_value, 0, wbxml) != 0)
  531.     return -1;
  532.     } else {
  533. for (i = 0; i < list_len(tokens); i++) {
  534.     temp = list_get(tokens, i);
  535.     pos = octstr_search(attr_value, temp->item, 0);
  536.     switch (pos) {
  537.     case -1:
  538. break;
  539.     case 0:
  540. wbxml_hex = temp->binary;
  541. output_st_char(wbxml_hex, wbxml);
  542. octstr_delete(attr_value, 0, octstr_len(temp->item));
  543. break;
  544.     default:
  545. /* 
  546.  *  There is some text before the first hit, that has to 
  547.  *  be handled too. 
  548.  */
  549. gw_assert(pos <= octstr_len(attr_value));
  550. cut_text = octstr_copy(attr_value, 0, pos);
  551. if (parse_st_octet_string(cut_text, 0, wbxml) != 0)
  552.     return -1;
  553. octstr_destroy(cut_text);
  554.     
  555. wbxml_hex = temp->binary;
  556. output_st_char(wbxml_hex, wbxml);
  557. octstr_delete(attr_value, 0, pos + octstr_len(temp->item));
  558. break;
  559.     }
  560. }
  561. /* 
  562.  * If no hits, then the attr_value is handled as a normal text, 
  563.  * otherwise the remaining part is searched for other hits too. 
  564.  */
  565. if ((int) octstr_len(attr_value) > 0) {
  566.     if (i < list_len(tokens))
  567. parse_attr_value(attr_value, tokens, wbxml);
  568.     else
  569. if (parse_st_octet_string(attr_value, 0, wbxml) != 0)
  570.     return -1;
  571. }
  572.     }
  573.     return 0;
  574. }
  575. /*
  576.  * parse_st_end - adds end tag to an element.
  577.  */
  578. static void parse_st_end(wml_binary_t **wbxml)
  579. {
  580.     output_st_char(WBXML_END, wbxml);
  581. }
  582. /*
  583.  * parse_text - a text string parsing function.
  584.  * This function parses a text node. 
  585.  */
  586. static int parse_text(xmlNodePtr node, wml_binary_t **wbxml)
  587. {
  588.     int ret;
  589.     Octstr *temp;
  590.     temp = create_octstr_from_node(node);
  591.     octstr_shrink_blanks(temp);
  592.     if (!check_if_emphasis(node->prev) && !check_if_emphasis(node->next))
  593. octstr_strip_blanks(temp);
  594.     if (octstr_len(temp) == 0)
  595.         ret = 0;
  596.     else 
  597.         ret = parse_st_octet_string(temp, 0, wbxml);
  598.     /* Memory cleanup. */
  599.     octstr_destroy(temp);
  600.     return ret;
  601. }
  602. /*
  603.  * parse_cdata - a cdata section parsing function.
  604.  * This function parses a cdata section that is outputted into the binary 
  605.  * "as is". 
  606.  */
  607. static int parse_cdata(xmlNodePtr node, wml_binary_t **wbxml)
  608. {
  609.     int ret = 0;
  610.     Octstr *temp;
  611.     temp = create_octstr_from_node(node);
  612.     parse_st_octet_string(temp, 1, wbxml);
  613.     
  614.     /* Memory cleanup. */
  615.     octstr_destroy(temp);
  616.     return ret;
  617. }
  618. /*
  619.  * parse_variable - a variable parsing function. 
  620.  * Arguments:
  621.  * - text: the octet string containing a variable
  622.  * - start: the starting position of the variable not including 
  623.  *   trailing &
  624.  * Returns: lenth of the variable for success, -1 for failure, 0 for 
  625.  * variable syntax error, when it will be ignored. 
  626.  * Parsed variable is returned as an octet string in Octstr **output.
  627.  */
  628. static int parse_variable(Octstr *text, int start, Octstr **output, 
  629.   wml_binary_t **wbxml)
  630. {
  631.     var_esc_t esc;
  632.     int ret;
  633.     Octstr *variable;
  634.     variable = get_variable(text, start + 1);
  635.     octstr_truncate(*output, 0);
  636.     if (variable == NULL)
  637. return 0;
  638.     if (octstr_get_char(variable, 0) == '$') {
  639. octstr_append_char(*output, '$');
  640. octstr_destroy(variable);
  641. ret = 2;
  642.     } else {
  643. if (octstr_get_char(text, start + 1) == '(')
  644.     ret = octstr_len(variable) + 3;
  645. else
  646.     ret = octstr_len(variable) + 1;
  647. if ((esc = check_variable_syntax(variable)) != FAILED)
  648.     output_variable(variable, output, esc, wbxml);
  649. else
  650.     octstr_destroy(variable);
  651.     }
  652.     return ret;
  653. }
  654. /*
  655.  * get_variable - get the variable name from text.
  656.  * Octstr *text contains the text with a variable name starting at point 
  657.  * int start.
  658.  */
  659. static Octstr *get_variable(Octstr *text, int start)
  660. {
  661.     Octstr *var = NULL;
  662.     long end;
  663.     int ch;
  664.     gw_assert(text != NULL);
  665.     gw_assert(start >= 0 && start <= (int) octstr_len(text));
  666.     ch = octstr_get_char(text, start);
  667.     if (ch == '$') {
  668. var = octstr_create("$");
  669.     } else if (ch == '(') {
  670. start ++;
  671. end = octstr_search_char(text, ')', start);
  672. if (end == -1)
  673.     error(0, "WML compiler: braces opened, but not closed for a "
  674.   "variable.");
  675. else if (end - start == 0)
  676.     error(0, "WML compiler: empty braces without variable.");
  677. else
  678.     var = octstr_copy(text, start, end - start);
  679.     } else {
  680. end = start + 1;
  681. while (isalnum(ch = octstr_get_char(text, end)) || (ch == '_'))
  682.     end ++;
  683. var = octstr_copy(text, start, end - start);
  684.     }
  685.     return var;
  686. }
  687. /*
  688.  * check_variable_syntax - checks the variable syntax and the possible 
  689.  * escape mode it has. Octstr *variable contains the variable string.
  690.  */
  691. static var_esc_t check_variable_syntax(Octstr *variable)
  692. {
  693.     Octstr *escape;
  694.     char ch;
  695.     int pos, len, i;
  696.     var_esc_t ret;
  697.     if ((pos = octstr_search_char(variable, ':', 0)) > 0) {
  698. len = octstr_len(variable) - pos;
  699. escape = octstr_copy(variable, pos + 1, len - 1);
  700. octstr_truncate(variable, pos);
  701. octstr_truncate(escape, len);
  702. octstr_convert_range(escape, 0, octstr_len(escape), tolower);
  703. if (octstr_str_compare(escape, "noesc") == 0 ||
  704.     octstr_str_compare(escape, "n") == 0 )
  705.     ret = NOESC;
  706. else if (octstr_str_compare(escape, "unesc") == 0 ||
  707.  octstr_str_compare(escape, "u") == 0 )
  708.     ret = UNESC;
  709. else if (octstr_str_compare(escape, "escape") == 0 ||
  710.  octstr_str_compare(escape, "e") == 0 )
  711.     ret = ESC;
  712. else {
  713.     error(0, "WML compiler: syntax error in variable escaping.");
  714.     octstr_destroy(escape);
  715.     return FAILED;
  716. }
  717. octstr_destroy(escape);
  718.     } else
  719. ret = NOESC;
  720.     ch = octstr_get_char(variable, 0);
  721.     if (!(isalpha((int)ch)) && ch != '_') {
  722. error(0, "WML compiler: syntax error in variable; name starting "
  723.       "with %c.", ch);
  724. return FAILED;
  725.     } else
  726. for (i = 1; i < (int) octstr_len(variable); i++)
  727.     if (!isalnum((int)(ch = octstr_get_char(variable, 0))) && 
  728. ch != '_') {
  729. warning(0, "WML compiler: syntax error in variable.");
  730. return FAILED;
  731.     }
  732.     return ret;
  733. }
  734. /*
  735.  * parse_st_octet_string - parse an octet string into wbxml_string, the string 
  736.  * is checked for variables. If string is string table applicable, it will 
  737.  * be checked for string insrtances that are in the string table, otherwise 
  738.  * not. Returns 0 for success, -1 for error.
  739.  */
  740. static int parse_st_octet_string(Octstr *ostr, int cdata, wml_binary_t **wbxml)
  741. {
  742.     Octstr *output, *var, *temp = NULL;
  743.     int var_len;
  744.     int start = 0, pos = 0, len;
  745.     /* No variables? Ok, let's take the easy way... (CDATA never contains 
  746.        variables.) */
  747.     if ((pos = octstr_search_char(ostr, '$', 0)) < 0 || cdata == 1) {
  748. string_table_apply(ostr, wbxml);
  749. return 0;
  750.     }
  751.     len = octstr_len(ostr);
  752.     output = octstr_create("");
  753.     var = octstr_create("");
  754.     while (pos < len) {
  755. if (octstr_get_char(ostr, pos) == '$') {
  756.     if (pos > start) {
  757. temp = octstr_copy(ostr, start, pos - start);
  758. octstr_insert(output, temp, octstr_len(output));
  759. octstr_destroy(temp);
  760.     }
  761.   
  762.     if ((var_len = parse_variable(ostr, pos, &var, wbxml)) > 0) {
  763. if (octstr_len(var) > 0) {
  764.     if (octstr_get_char(var, 0) == '$')
  765. /*
  766.  * No, it's not actually variable, but $-character 
  767.  * escaped as "$$". So everything should be packed 
  768.  * into one string. 
  769.  */
  770. octstr_insert(output, var, octstr_len(output));
  771.     else {
  772. /*
  773.  * The string is output as a inline string and the 
  774.  * variable as a string table variable reference. 
  775.  */
  776. if (octstr_len(output) > 0)
  777.     string_table_apply(output, wbxml);
  778. octstr_truncate(output, 0);
  779. output_st_octet_string(var, wbxml);
  780.     }
  781.     /* Variable had a syntax error, so it's skipped. */
  782. }
  783. pos = pos + var_len;
  784. start = pos;
  785.     } else
  786. return -1;
  787. } else
  788.     pos ++;
  789.     }
  790.     /* Was there still something after the last variable? */
  791.     if (start < pos) {
  792. if (octstr_len(output) == 0) {
  793.     octstr_destroy(output);
  794.     output = octstr_copy(ostr, start, pos - start);
  795. } else {
  796.     temp = octstr_copy(ostr, start, pos - start);
  797.     octstr_insert(output, temp, octstr_len(output));
  798.     octstr_destroy(temp);
  799. }
  800.     }
  801.     if (octstr_len(output) > 0)
  802. string_table_apply(output, wbxml);
  803.   
  804.     octstr_destroy(output);
  805.     octstr_destroy(var);
  806.   
  807.     return 0;
  808. }
  809. /*
  810.  * parse_entities - replaces WML entites in the WML source with equivalent
  811.  * numerical entities. A fast patch for WAP 1.1 compliance.
  812.  */
  813. static void parse_entities(Octstr *wml_source)
  814. {
  815.     static char entity_nbsp[] = "&nbsp;";
  816.     static char entity_shy[] = "&shy;";
  817.     static char nbsp[] = "&#160;";
  818.     static char shy[] = "&#173;";
  819.     int pos = 0;
  820.     Octstr *temp;
  821.     if ((pos = octstr_search(wml_source, octstr_imm(entity_nbsp),
  822.      pos)) >= 0) {
  823. temp = octstr_create(nbsp);
  824. while (pos >= 0) {
  825.     octstr_delete(wml_source, pos, strlen(entity_nbsp));
  826.     octstr_insert(wml_source, temp, pos);
  827.     pos = octstr_search(wml_source, 
  828. octstr_imm(entity_nbsp), pos);
  829. }
  830. octstr_destroy(temp);
  831.     }
  832.     pos = 0;
  833.     if ((pos = octstr_search(wml_source, octstr_imm(entity_shy),
  834.      pos)) >= 0) {
  835. temp = octstr_create(shy);
  836. while (pos >= 0) {
  837.     octstr_delete(wml_source, pos, strlen(entity_shy));
  838.     octstr_insert(wml_source, temp, pos);
  839.     pos = octstr_search(wml_source, 
  840. octstr_imm(entity_shy), pos);
  841. }
  842. octstr_destroy(temp);
  843.     }
  844. }
  845. /*
  846.  * wml_binary_create - reserves memory for the wml_binary_t and sets the 
  847.  * fields to zeroes and NULLs.
  848.  */
  849. static wml_binary_t *wml_binary_create(void)
  850. {
  851.     wml_binary_t *wbxml;
  852.     wbxml = gw_malloc(sizeof(wml_binary_t));
  853.     wbxml->wbxml_version = 0x00;
  854.     wbxml->wml_public_id = 0x00;
  855.     wbxml->character_set = 0x00;
  856.     wbxml->string_table_length = 0x00;
  857.     wbxml->string_table = list_create();
  858.     wbxml->wbxml_string = octstr_create("");
  859.     return wbxml;
  860. }
  861. /*
  862.  * wml_binary_destroy - frees the memory allocated for the wml_binary_t.
  863.  */
  864. static void wml_binary_destroy(wml_binary_t *wbxml)
  865. {
  866.     if (wbxml != NULL) {
  867. list_destroy(wbxml->string_table, NULL);
  868. octstr_destroy(wbxml->wbxml_string);
  869. gw_free(wbxml);
  870.     }
  871. }
  872. /*
  873.  * wml_binary_output - outputs all the fiels of wml_binary_t into ostr.
  874.  */
  875. static void wml_binary_output(Octstr *ostr, wml_binary_t *wbxml)
  876. {
  877.     octstr_append_char(ostr, wbxml->wbxml_version);
  878.     octstr_append_char(ostr, wbxml->wml_public_id);
  879.     octstr_append_uintvar(ostr, wbxml->character_set);
  880.     octstr_append_uintvar(ostr, wbxml->string_table_length);
  881.     if (wbxml->string_table_length > 0)
  882. string_table_output(ostr, &wbxml);
  883.     octstr_insert(ostr, wbxml->wbxml_string, octstr_len(ostr));
  884. }
  885. /*
  886.  * output_st_char - output a character into wbxml_string.
  887.  * Returns 0 for success, -1 for error.
  888.  */
  889. static void output_st_char(int byte, wml_binary_t **wbxml)
  890. {
  891.     octstr_append_char((*wbxml)->wbxml_string, byte);
  892. }
  893. /*
  894.  * output_st_octet_string - output an octet string into wbxml.
  895.  * Returns 0 for success, -1 for an error. No conversions.
  896.  */
  897. static void output_st_octet_string(Octstr *ostr, wml_binary_t **wbxml)
  898. {
  899.     octstr_insert((*wbxml)->wbxml_string, ostr, 
  900.   octstr_len((*wbxml)->wbxml_string));
  901. }
  902. /*
  903.  * output_variable - output a variable reference into the string table.
  904.  */
  905. static void output_variable(Octstr *variable, Octstr **output, 
  906.     var_esc_t escaped, wml_binary_t **wbxml)
  907. {
  908.   switch (escaped)
  909.     {
  910.     case ESC:
  911.       octstr_append_char(*output, WBXML_EXT_T_0);
  912.       break;
  913.     case UNESC:
  914.       octstr_append_char(*output, WBXML_EXT_T_1);
  915.       break;
  916.     default:
  917.       octstr_append_char(*output, WBXML_EXT_T_2);
  918.       break;
  919.     }
  920.   octstr_append_uintvar(*output, string_table_add(variable, wbxml));
  921. }
  922. /*
  923.  * hash_create - allocates memory for a 2 field hash table node.
  924.  */
  925. static wml_hash_t *hash_create(char *text, unsigned char token)
  926. {
  927.     wml_hash_t *table_node;
  928.     table_node = gw_malloc(sizeof(wml_hash_t));
  929.     table_node->item = octstr_create(text);
  930.     table_node->binary = token;
  931.     return table_node;
  932. }
  933. /*
  934.  * attribute_create - allocates memory for the attributes hash table node 
  935.  * that contains the attribute, the binary for it and a list of binary values
  936.  * tied with the attribute.
  937.  */
  938. static wml_attribute_t *attribute_create(void)
  939. {
  940.     wml_attribute_t *attr;
  941.     attr = gw_malloc(sizeof(wml_attribute_t));
  942.     attr->attribute = NULL;
  943.     attr->binary = 0;
  944.     attr->value_list = list_create();
  945.     return attr;
  946. }
  947. /*
  948.  * attr_dict_construct - takes a table of attributes and their values and 
  949.  * inputs these into a dictionary. 
  950.  */
  951. static void attr_dict_construct(wml_table3_t *attributes, Dict *attr_dict)
  952. {
  953.     int i = 0;
  954.     wml_attribute_t *node = NULL;
  955.     wml_hash_t *temp = NULL;
  956.     node = attribute_create();
  957.     do {
  958. if (node->attribute == NULL)
  959.     node->attribute = octstr_create(attributes[i].text1);
  960. else if (strcmp(attributes[i].text1, attributes[i-1].text1) != 0) {
  961.     dict_put(attr_dict, node->attribute, node);
  962.     node = attribute_create();
  963.     node->attribute = octstr_create(attributes[i].text1);
  964. }
  965. if (attributes[i].text2 == NULL)
  966.     node->binary = attributes[i].token;
  967. else {
  968.     temp = hash_create(attributes[i].text2, attributes[i].token);
  969.     list_append(node->value_list, (void *)temp);
  970. }
  971. i++;
  972.     } while (attributes[i].text1 != NULL);
  973.     dict_put(attr_dict, node->attribute, node);
  974. }
  975. /*
  976.  * hash_destroy - deallocates memory of a 2 field hash table node.
  977.  */
  978. static void hash_destroy(void *p)
  979. {
  980.     wml_hash_t *node;
  981.     if (p == NULL)
  982.         return;
  983.     node = p;
  984.     octstr_destroy(node->item);
  985.     gw_free(node);
  986. }
  987. /*
  988.  * attribute_destroy - deallocates memory of a attribute hash table node.
  989.  */
  990. static void attribute_destroy(void *p)
  991. {
  992.     wml_attribute_t *node;
  993.     if (p == NULL)
  994. return;
  995.     node = p;
  996.     octstr_destroy(node->attribute);
  997.     list_destroy(node->value_list, hash_destroy);
  998.     gw_free(node);
  999. }
  1000. /*
  1001.  * hash_cmp - compares pattern against item and if the pattern matches the 
  1002.  * item returns 1, else 0.
  1003.  */
  1004. static int hash_cmp(void *item, void *pattern)
  1005. {
  1006.     int ret = 0;
  1007.     gw_assert(item != NULL && pattern != NULL);
  1008.     gw_assert(((wml_hash_t *)item)->item != NULL);
  1009.     if (octstr_search(pattern, ((wml_hash_t *)item)->item, 0) == 0)
  1010. ret = 1;
  1011.     return ret;
  1012. }
  1013. /*
  1014.  * check_do_elements - a helper function for parse_element for checking if a
  1015.  * card or template element has two or more do elements of the same name. 
  1016.  * Returns 0 for OK and -1 for an error (== do elements with same name found).
  1017.  */
  1018. static int check_do_elements(xmlNodePtr node)
  1019. {
  1020.     xmlNodePtr child;
  1021.     int i, status = 0;
  1022.     Octstr *name = NULL;
  1023.     List *name_list = NULL;
  1024.     
  1025.     name_list = list_create();
  1026.     if ((child = node->children) != NULL) {
  1027. while (child != NULL) {
  1028.     if (strcmp(child->name, "do") == 0) {
  1029. name = get_do_element_name(child);
  1030. if (name == NULL) {
  1031.     error(0, "WML compiler: no name or type in a do element");
  1032.     return -1;
  1033. }
  1034. for (i = 0; i < list_len(name_list); i ++)
  1035.     if (octstr_compare(list_get(name_list, i), name) == 0) {
  1036. octstr_destroy(name);
  1037. status = -1;
  1038. break;
  1039.     }
  1040. if (status != -1)
  1041.     list_append(name_list, name);
  1042. else
  1043.     break;
  1044.     }
  1045.     child = child->next;
  1046. }
  1047.     }
  1048.     list_destroy(name_list, octstr_destroy_item);
  1049.     return status;
  1050. }
  1051. /*
  1052.  * check_variable_name - checks the name for variable in a setvar element.
  1053.  * If the name has syntax error, -1 is returned, else 0.
  1054.  */
  1055. static var_esc_t check_variable_name(xmlNodePtr node)
  1056. {
  1057.     Octstr *name = NULL;
  1058.     xmlAttrPtr attr; 
  1059.     var_esc_t ret = FAILED;
  1060.     if ((attr = node->properties) != NULL) {
  1061. while (attr != NULL) {
  1062.     if (strcmp(attr->name, "name") == 0) {
  1063. name = create_octstr_from_node(attr->children);
  1064. break;
  1065.     }
  1066.     attr = attr->next;
  1067. }
  1068.     }
  1069.     if (attr == NULL) {
  1070. error(0, "WML compiler: no name in a setvar element");
  1071. return FAILED;
  1072.     }
  1073.     ret = check_variable_syntax(name);
  1074.     octstr_destroy(name);
  1075.     return ret;
  1076. }
  1077. /*
  1078.  * get_do_element_name - returns the name for a do element. Name is either 
  1079.  * name when the element has the attribute or defaults to the type attribute 
  1080.  * if there is no name.
  1081.  */
  1082. static Octstr *get_do_element_name(xmlNodePtr node)
  1083. {
  1084.     Octstr *name = NULL;
  1085.     xmlAttrPtr attr; 
  1086.     if ((attr = node->properties) != NULL) {
  1087. while (attr != NULL) {
  1088.     if (strcmp(attr->name, "name") == 0) {
  1089. name = create_octstr_from_node(attr->children);
  1090. break;
  1091.     }
  1092.     attr = attr->next;
  1093. }
  1094. if (attr == NULL) {
  1095.     attr = node->properties;
  1096.     while (attr != NULL) {
  1097. if (strcmp(attr->name, "type") == 0) {
  1098.     name = create_octstr_from_node(attr->children);
  1099.     break;
  1100. }
  1101. attr = attr->next;
  1102.     }
  1103. }
  1104.     }
  1105.     return name;
  1106. }
  1107. /*
  1108.  * check_if_url - checks whether the attribute value is an URL or some other 
  1109.  * kind of value. Returns 1 for an URL and 0 otherwise.
  1110.  */
  1111. static int check_if_url(int hex)
  1112. {
  1113.     switch ((unsigned char) hex) {
  1114.     case 0x4A: case 0x4B: case 0x4C: /* href, href http://, href https:// */
  1115.     case 0x32: case 0x58: case 0x59: /* src, src http://, src https:// */
  1116. return 1;
  1117. break;
  1118.     }
  1119.     return 0;
  1120. }
  1121. /*
  1122.  * check_if_emphasis - checks if the node is an emphasis element. 
  1123.  * Returns 1 for an emphasis and 0 otherwise.
  1124.  */
  1125. static int check_if_emphasis(xmlNodePtr node)
  1126. {
  1127.     if (node == NULL || node->name == NULL)
  1128. return 0;
  1129.     if (strcmp(node->name, "b") == 0)
  1130. return 1;
  1131.     if (strcmp(node->name, "big") == 0)
  1132. return 1;
  1133.     if (strcmp(node->name, "em") == 0)
  1134. return 1;
  1135.     if (strcmp(node->name, "i") == 0)
  1136. return 1;
  1137.     if (strcmp(node->name, "small") == 0)
  1138. return 1;
  1139.     if (strcmp(node->name, "strong") == 0)
  1140. return 1;
  1141.     if (strcmp(node->name, "u") == 0)
  1142. return 1;
  1143.     return 0;
  1144. }
  1145. /*
  1146.  * wml_table_len - returns the length of a wml_table_t array.
  1147.  */
  1148. static int wml_table_len(wml_table_t *table)
  1149. {
  1150.     int i = 0;
  1151.     while (table[i].text != NULL)
  1152. i++;
  1153.     return i;
  1154. }
  1155. /*
  1156.  * wml_table3_len - returns the length of a wml_table3_t array.
  1157.  */
  1158. static int wml_table3_len(wml_table3_t *table)
  1159. {
  1160.     int i = 0;
  1161.     while (table[i].text1 != NULL)
  1162. i++;
  1163.     return i;
  1164. }
  1165. /*
  1166.  * string_table_create - reserves memory for the string_table_t and sets the 
  1167.  * fields.
  1168.  */
  1169. static string_table_t *string_table_create(int offset, Octstr *ostr)
  1170. {
  1171.     string_table_t *node;
  1172.     node = gw_malloc(sizeof(string_table_t));
  1173.     node->offset = offset;
  1174.     node->string = ostr;
  1175.     return node;
  1176. }
  1177. /*
  1178.  * string_table_destroy - frees the memory allocated for the string_table_t.
  1179.  */
  1180. static void string_table_destroy(string_table_t *node)
  1181. {
  1182.     if (node != NULL) {
  1183. octstr_destroy(node->string);
  1184. gw_free(node);
  1185.     }
  1186. }
  1187. /*
  1188.  * string_table_proposal_create - reserves memory for the 
  1189.  * string_table_proposal_t and sets the fields.
  1190.  */
  1191. static string_table_proposal_t *string_table_proposal_create(Octstr *ostr)
  1192. {
  1193.     string_table_proposal_t *node;
  1194.     node = gw_malloc(sizeof(string_table_proposal_t));
  1195.     node->count = 1;
  1196.     node->string = ostr;
  1197.     return node;
  1198. }
  1199. /*
  1200.  * string_table_proposal_destroy - frees the memory allocated for the 
  1201.  * string_table_proposal_t.
  1202.  */
  1203. static void string_table_proposal_destroy(string_table_proposal_t *node)
  1204. {
  1205.     if (node != NULL) {
  1206. octstr_destroy(node->string);
  1207. gw_free(node);
  1208.     }
  1209. }
  1210. /*
  1211.  * string_table_build - collects the strings from the WML source into a list, 
  1212.  * adds those strings that appear more than once into string table. The rest 
  1213.  * of the strings are sliced into words and the same procedure is executed to 
  1214.  * the list of these words.
  1215.  */
  1216. static void string_table_build(xmlNodePtr node, wml_binary_t **wbxml)
  1217. {
  1218.     string_table_proposal_t *item = NULL;
  1219.     List *list = NULL;
  1220.     list = list_create();
  1221.     string_table_collect_strings(node, list);
  1222.     list = string_table_add_many(string_table_sort_list(list), wbxml);
  1223.     list =  string_table_collect_words(list);
  1224.     /* Don't add strings if there aren't any. (no NULLs please) */
  1225.     if (list) {
  1226. list = string_table_add_many(string_table_sort_list(list), wbxml);
  1227.     }
  1228.     /* Memory cleanup. */
  1229.     while (list_len(list)) {
  1230. item = list_extract_first(list);
  1231. string_table_proposal_destroy(item);
  1232.     }
  1233.     list_destroy(list, NULL);
  1234. }
  1235. /*
  1236.  * string_table_collect_strings - collects the strings from the WML 
  1237.  * ocument into a list that is then further processed to build the 
  1238.  * string table for the document.
  1239.  */
  1240. static void string_table_collect_strings(xmlNodePtr node, List *strings)
  1241. {
  1242.     Octstr *string;
  1243.     xmlAttrPtr attribute;
  1244.     switch (node->type) {
  1245.     case XML_TEXT_NODE:
  1246. string = create_octstr_from_node(node);
  1247.     
  1248. octstr_shrink_blanks(string);
  1249. octstr_strip_blanks(string);
  1250. if (octstr_len(string) > WBXML_STRING_TABLE_MIN)
  1251.     octstr_strip_nonalphanums(string);
  1252. if (octstr_len(string) > WBXML_STRING_TABLE_MIN)
  1253.     list_append(strings, string);
  1254. else 
  1255.     octstr_destroy(string);
  1256. break;
  1257.     case XML_ELEMENT_NODE:
  1258. if(node->properties != NULL) {
  1259.     attribute = node->properties;
  1260.     while (attribute != NULL) {
  1261. if (attribute->children != NULL)
  1262.     string_table_collect_strings(attribute->children, strings);
  1263. attribute = attribute->next;
  1264.     }
  1265. }
  1266. break;
  1267.     default:
  1268. break;
  1269.     }
  1270.     if (node->children != NULL)
  1271. string_table_collect_strings(node->children, strings);
  1272.     if (node->next != NULL)
  1273. string_table_collect_strings(node->next, strings);
  1274. }
  1275. /*
  1276.  * string_table_sort_list - takes a list of octet strings and returns a list
  1277.  * of string_table_proposal_t:s that contains the same strings with number of 
  1278.  * instants of every string in the input list.
  1279.  */
  1280. static List *string_table_sort_list(List *start)
  1281. {
  1282.     int i;
  1283.     Octstr *string = NULL;
  1284.     string_table_proposal_t *item = NULL;
  1285.     List *sorted = NULL;
  1286.     sorted = list_create();
  1287.     while (list_len(start)) {
  1288. string = list_extract_first(start);
  1289.       
  1290. /* Check whether the string is unique. */
  1291. for (i = 0; i < list_len(sorted); i++) {
  1292.     item = list_get(sorted, i);
  1293.     if (octstr_compare(item->string, string) == 0) {
  1294. octstr_destroy(string);
  1295. string = NULL;
  1296. item->count ++;
  1297. break;
  1298.     }
  1299. }
  1300. if (string != NULL) {
  1301.     item = string_table_proposal_create(string);
  1302.     list_append(sorted, item);
  1303. }
  1304.     }
  1305.     list_destroy(start, NULL);
  1306.     return sorted;
  1307. }
  1308. /*
  1309.  * string_table_add_many - takes a list of string with number of instants and
  1310.  * adds those whose number is greater than 1 into the string table. Returns 
  1311.  * the list ofrejected strings for memory cleanup.
  1312.  */
  1313. static List *string_table_add_many(List *sorted, wml_binary_t **wbxml)
  1314. {
  1315.     string_table_proposal_t *item = NULL;
  1316.     List *list = NULL;
  1317.     list = list_create();
  1318.     while (list_len(sorted)) {
  1319. item = list_extract_first(sorted);
  1320. if (item->count > 1 && octstr_len(item->string) > 
  1321.     WBXML_STRING_TABLE_MIN) {
  1322.     string_table_add(octstr_duplicate(item->string), wbxml);
  1323.     string_table_proposal_destroy(item);
  1324. } else
  1325.     list_append(list, item);
  1326.     }
  1327.     list_destroy(sorted, NULL);
  1328.     return list;
  1329. }
  1330. /*
  1331.  * string_table_collect_words - takes a list of strings and returns a list 
  1332.  * of words contained by those strings.
  1333.  */
  1334. static List *string_table_collect_words(List *strings)
  1335. {
  1336.     Octstr *word = NULL;
  1337.     string_table_proposal_t *item = NULL;
  1338.     List *list = NULL, *temp_list = NULL;
  1339.     while (list_len(strings)) {
  1340. item = list_extract_first(strings);
  1341. if (list == NULL) {
  1342.     list = octstr_split_words(item->string);
  1343.     string_table_proposal_destroy(item);
  1344. } else {
  1345.     temp_list = octstr_split_words(item->string);
  1346.     while ((word = list_extract_first(temp_list)) != NULL)
  1347. list_append(list, word);
  1348.     list_destroy(temp_list, NULL);
  1349.     string_table_proposal_destroy(item);
  1350. }
  1351.     }
  1352.     list_destroy(strings, NULL);
  1353.     return list;
  1354. }
  1355. /*
  1356.  * string_table_add - adds a string to the string table. Duplicates are
  1357.  * discarded. The function returns the offset of the string in the 
  1358.  * string table; if the string is already in the table then the offset 
  1359.  * of the first copy.
  1360.  */
  1361. static unsigned long string_table_add(Octstr *ostr, wml_binary_t **wbxml)
  1362. {
  1363.     string_table_t *item = NULL;
  1364.     unsigned long i, offset = 0;
  1365.     /* Check whether the string is unique. */
  1366.     for (i = 0; i < (unsigned long)list_len((*wbxml)->string_table); i++) {
  1367. item = list_get((*wbxml)->string_table, i);
  1368. if (octstr_compare(item->string, ostr) == 0) {
  1369.     octstr_destroy(ostr);
  1370.     return item->offset;
  1371. }
  1372.     }
  1373.     /* Create a new list item for the string table. */
  1374.     offset = (*wbxml)->string_table_length;
  1375.     item = string_table_create(offset, ostr);
  1376.     (*wbxml)->string_table_length = 
  1377. (*wbxml)->string_table_length + octstr_len(ostr) + 1;
  1378.     list_append((*wbxml)->string_table, item);
  1379.     return offset;
  1380. }
  1381. /*
  1382.  * string_table_apply - takes a octet string of WML bnary and goes it 
  1383.  * through searching for substrings that are in the string table and 
  1384.  * replaces them with string table references.
  1385.  */
  1386. static void string_table_apply(Octstr *ostr, wml_binary_t **wbxml)
  1387. {
  1388.     Octstr *input = NULL;
  1389.     string_table_t *item = NULL;
  1390.     long i = 0, word_s = 0, str_e = 0;
  1391.     input = octstr_create("");
  1392.     for (i = 0; i < list_len((*wbxml)->string_table); i++) {
  1393. item = list_get((*wbxml)->string_table, i);
  1394. if (octstr_len(item->string) > WBXML_STRING_TABLE_MIN)
  1395.     /* No use to replace 1 to 3 character substring, the reference 
  1396.        will eat the saving up. A variable will be in the string table 
  1397.        even though it's only 1 character long. */
  1398.     if ((word_s = octstr_search(ostr, item->string, 0)) >= 0) {
  1399. /* Check whether the octet string are equal if they are equal 
  1400.    in length. */
  1401. if (octstr_len(ostr) == octstr_len(item->string)) {
  1402.     if ((word_s = octstr_compare(ostr, item->string)) == 0)
  1403.     {
  1404. octstr_truncate(ostr, 0);
  1405. octstr_append_char(ostr, WBXML_STR_T);
  1406. octstr_append_uintvar(ostr, item->offset);
  1407. str_e = 1;
  1408.     }
  1409. }
  1410. /* Check the possible substrings. */
  1411. else if (octstr_len(ostr) > octstr_len(item->string))
  1412. {
  1413.     if (word_s + octstr_len(item->string) == octstr_len(ostr))
  1414. str_e = 1;
  1415.     octstr_delete(ostr, word_s, octstr_len(item->string));
  1416.     octstr_truncate(input, 0);
  1417.     /* Substring in the start? No STR_END then. */
  1418.     if (word_s > 0)
  1419. octstr_append_char(input, WBXML_STR_END);
  1420.                   
  1421.     octstr_append_char(input, WBXML_STR_T);
  1422.     octstr_append_uintvar(input, item->offset);
  1423.     /* Subtring the end? No need to start a new one. */
  1424.     if ( word_s < octstr_len(ostr))
  1425. octstr_append_char(input, WBXML_STR_I);
  1426.     octstr_insert(ostr, input, word_s);
  1427. }
  1428. /* If te string table entry is longer than the string, it can 
  1429.    be skipped. */
  1430.     }
  1431.     }
  1432.     octstr_destroy(input);
  1433.     if (octstr_get_char(ostr, 0) != WBXML_STR_T)
  1434. output_st_char(WBXML_STR_I, wbxml);
  1435.     if (!str_e)
  1436. octstr_append_char(ostr, WBXML_STR_END);    
  1437.     output_st_octet_string(ostr, wbxml);
  1438. }
  1439. /*
  1440.  * string_table_output - writes the contents of the string table 
  1441.  * into an octet string that is sent to the phone.
  1442.  */
  1443. static void string_table_output(Octstr *ostr, wml_binary_t **wbxml)
  1444. {
  1445.     string_table_t *item;
  1446.     while ((item = list_extract_first((*wbxml)->string_table)) != NULL) {
  1447. octstr_insert(ostr, item->string, octstr_len(ostr));
  1448. octstr_append_char(ostr, WBXML_STR_END);
  1449. string_table_destroy(item);
  1450.     }
  1451. }