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

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wap_push_si_compiler.c: Tokenizes a SI document. SI DTD is defined in 
  3.  * Wapforum specification WAP-167-ServiceInd-20010731-a (hereafter called si),
  4.  * chapter 8.2.
  5.  *
  6.  * By Aarno Syv鋘en for Wiral Ltd
  7.  */
  8. #include <ctype.h>
  9. #include <libxml/xmlmemory.h>
  10. #include <libxml/tree.h>
  11. #include <libxml/debugXML.h>
  12. #include <libxml/encoding.h>
  13. #include "shared.h"
  14. #include "xml_shared.h"
  15. #include "wap_push_si_compiler.h"
  16. /****************************************************************************
  17.  *
  18.  * Global variables
  19.  *
  20.  * Two token table types, one and two token fields
  21.  */
  22. struct si_2table_t {
  23.     char *name;
  24.     unsigned char token;
  25. };
  26. typedef struct si_2table_t si_2table_t;
  27. /*
  28.  * Value part can mean part or whole of the value. It can be NULL, too, which
  29.  * means that no part of the value will be tokenised. See si, chapter 9.3.2.
  30.  */
  31. struct si_3table_t {
  32.     char *name;
  33.     char *value_part;
  34.     unsigned char token;
  35. };
  36. typedef struct si_3table_t si_3table_t;
  37. /*
  38.  * Elements from tag code page zero. These are defined in si, chapter 9.3.1.
  39.  */
  40. static si_2table_t si_elements[] = {
  41.     { "si", 0x05 },
  42.     { "indication", 0x06 },
  43.     { "info", 0x07 },
  44.     { "item", 0x08 }
  45. };
  46. #define NUMBER_OF_ELEMENTS sizeof(si_elements)/sizeof(si_elements[0])
  47. /*
  48.  * Attributes (and start or whole value of ) from attribute code page zero. 
  49.  * These are defined in si, chapter 9.3.2.
  50.  */
  51. static si_3table_t si_attributes[] = {
  52.     { "action", "signal-none", 0x05 },
  53.     { "action", "signal-low", 0x06 },
  54.     { "action", "signal-medium", 0x07 },
  55.     { "action", "signal-high", 0x08 },
  56.     { "action", "delete", 0x09 },
  57.     { "created", NULL, 0x0a },
  58.     { "href", "https://www.", 0x0f },
  59.     { "href", "http://www.", 0x0d },
  60.     { "href", "https://", 0x0e },
  61.     { "href", "http://", 0x0c },
  62.     { "href", NULL, 0x0b },
  63.     { "si-expires", NULL, 0x10 },
  64.     { "si-id", NULL, 0x11 },
  65.     { "class", NULL, 0x12 }
  66. };
  67. #define NUMBER_OF_ATTRIBUTES sizeof(si_attributes)/sizeof(si_attributes[0])
  68. /*
  69.  * Attribute value tokes (URL value codes), from si, chapter 9.3.3.
  70.  */
  71. static si_2table_t si_URL_values[] = {
  72.   { ".com/", 0x85 },
  73.   { ".edu/", 0x86 },
  74.   { ".net/", 0x87 },
  75.   { ".org/", 0x88 }
  76. };
  77. #define NUMBER_OF_URL_VALUES sizeof(si_URL_values)/sizeof(si_URL_values[0])
  78. #include "xml_definitions.h"
  79. /****************************************************************************
  80.  *
  81.  * Prototypes of internal functions. Note that 'Ptr' means here '*'.
  82.  */
  83. static int parse_document(xmlDocPtr document, Octstr *charset, 
  84.   simple_binary_t **si_binary);
  85. static int parse_node(xmlNodePtr node, simple_binary_t **sibxml);    
  86. static int parse_element(xmlNodePtr node, simple_binary_t **sibxml);
  87. static int parse_text(xmlNodePtr node, simple_binary_t **sibxml);   
  88. static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml);             static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml);       
  89. static int url(int hex);   
  90. static int action(int hex);
  91. static int date(int hex);
  92. static Octstr *tokenize_date(Octstr *date);
  93. static void octstr_drop_trailing_zeros(Octstr **date_token);
  94. static void flag_date_length(Octstr **token);
  95. static void parse_url_value(Octstr *value, simple_binary_t **sibxml);
  96.                           
  97. /****************************************************************************
  98.  *
  99.  * Implementation of the external function
  100.  */
  101. int si_compile(Octstr *si_doc, Octstr *charset, Octstr **si_binary)
  102. {
  103.     simple_binary_t *sibxml;
  104.     int ret;
  105.     xmlDocPtr pDoc;
  106.     size_t size;
  107.     char *si_c_text;
  108.     *si_binary = octstr_create(""); 
  109.     sibxml = simple_binary_create();
  110.     octstr_strip_blanks(si_doc);
  111.     set_charset(si_doc, charset);
  112.     size = octstr_len(si_doc);
  113.     si_c_text = octstr_get_cstr(si_doc);
  114.     pDoc = xmlParseMemory(si_c_text, size);
  115.     ret = 0;
  116.     if (pDoc) {
  117.         ret = parse_document(pDoc, charset, &sibxml);
  118.         simple_binary_output(*si_binary, sibxml);
  119.         xmlFreeDoc(pDoc);
  120.     } else {
  121.         xmlFreeDoc(pDoc);
  122.         octstr_destroy(*si_binary);
  123.         simple_binary_destroy(sibxml);
  124.         error(0, "SI: No document to parse. Probably an error in SI source");
  125.         return -1;
  126.     }
  127.     simple_binary_destroy(sibxml);
  128.     return ret;
  129. }
  130. /****************************************************************************
  131.  *
  132.  * Implementation of internal functions
  133.  *
  134.  * Parse document node. Store si version number, public identifier and char-
  135.  * acter set into the start of the document. FIXME: Add parse_prologue!
  136.  */
  137. static int parse_document(xmlDocPtr document, Octstr *charset, 
  138.                           simple_binary_t **sibxml)
  139. {
  140.     xmlNodePtr node;
  141.     (*sibxml)->wbxml_version = 0x02; /* WBXML Version number 1.2  */
  142.     (*sibxml)->public_id = 0x05; /* SI 1.0 Public ID */
  143.     
  144.     charset = octstr_create("UTF-8");
  145.     (*sibxml)->charset = parse_charset(charset);
  146.     octstr_destroy(charset);
  147.     node = xmlDocGetRootElement(document);
  148.     return parse_node(node, sibxml);
  149. }
  150. /*
  151.  * Parse an element node. Check if there is a token for an element tag; if not
  152.  * output the element as a string, else ouput the token. After that, call 
  153.  * attribute parsing functions
  154.  * Returns:      1, add an end tag (element node has no children)
  155.  *               0, do not add an end tag (it has children)
  156.  *              -1, an error occurred
  157.  */
  158. static int parse_element(xmlNodePtr node, simple_binary_t **sibxml)
  159. {
  160.     Octstr *name,
  161.            *outos;
  162.     size_t i;
  163.     unsigned char status_bits,
  164.              si_hex;
  165.     int add_end_tag;
  166.     xmlAttrPtr attribute;
  167.     name = octstr_create(node->name);
  168.     outos = NULL;
  169.     if (octstr_len(name) == 0) {
  170.         octstr_destroy(name);
  171.         return -1;
  172.     }
  173.     i = 0;
  174.     while (i < NUMBER_OF_ELEMENTS) {
  175.         if (octstr_compare(name, octstr_imm(si_elements[i].name)) == 0)
  176.             break;
  177.         ++i;
  178.     }
  179.     status_bits = 0x00;
  180.     si_hex = 0x00;
  181.     add_end_tag = 0;
  182.     if (i != NUMBER_OF_ELEMENTS) {
  183.         si_hex = si_elements[i].token;
  184.         if ((status_bits = element_check_content(node)) > 0) {
  185.     si_hex = si_hex | status_bits;
  186.     
  187.     if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
  188.         add_end_tag = 1;
  189.         }
  190.         output_char(si_hex, sibxml);
  191.     } else {
  192.         warning(0, "unknown tag %s in SI source", octstr_get_cstr(name));
  193.         si_hex = WBXML_LITERAL;
  194.         if ((status_bits = element_check_content(node)) > 0) {
  195.     si_hex = si_hex | status_bits;
  196.     /* If this node has children, the end tag must be added after 
  197.        them. */
  198.     if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
  199. add_end_tag = 1;
  200. }
  201. output_char(si_hex, sibxml);
  202.         output_octet_string(outos = octstr_duplicate(name), sibxml);
  203.     }
  204.     if (node->properties != NULL) {
  205. attribute = node->properties;
  206. while (attribute != NULL) {
  207.     parse_attribute(attribute, sibxml);
  208.     attribute = attribute->next;
  209. }
  210. parse_end(sibxml);
  211.     }
  212.     octstr_destroy(outos);
  213.     octstr_destroy(name);
  214.     return add_end_tag;
  215. }
  216. /*
  217.  * Parse a text node of a si document. Ignore empty text nodes (space addi-
  218.  * tions to certain points will produce these). Si codes text nodes as an
  219.  * inline string.
  220.  */
  221. static int parse_text(xmlNodePtr node, simple_binary_t **sibxml)
  222. {
  223.     Octstr *temp;
  224.     temp = create_octstr_from_node(node);
  225.     octstr_shrink_blanks(temp);
  226.     octstr_strip_blanks(temp);
  227.     if (octstr_len(temp) == 0) {
  228.         octstr_destroy(temp);
  229.         return 0;
  230.     }
  231.     parse_inline_string(temp, sibxml);    
  232.     octstr_destroy(temp);
  233.     return 0;
  234. }
  235. /*
  236.  * Tokenises an attribute, and in most cases, the start of its value (some-
  237.  * times whole of it). Tokenisation is based on tables in si, chapters 9.3.2
  238.  * and 9.3.3. 
  239.  * Returns 0 when success, -1 when error.
  240.  */
  241. static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml)
  242. {
  243.     Octstr *name,
  244.            *value,
  245.            *valueos,
  246.            *tokenized_date;
  247.     unsigned char si_hex;
  248.     size_t i,
  249.            value_len;
  250.     name = octstr_create(attr->name);
  251.     if (attr->children != NULL)
  252. value = create_octstr_from_node(attr->children);
  253.     else 
  254. value = NULL;
  255.     if (value == NULL)
  256.         goto error;
  257.     i = 0;
  258.     valueos = NULL;
  259.     while (i < NUMBER_OF_ATTRIBUTES) {
  260.         if (octstr_compare(name, octstr_imm(si_attributes[i].name)) == 0) {
  261.     if (si_attributes[i].value_part == NULL) {
  262.         break; 
  263.             } else {
  264.                 value_len = octstr_len(valueos = 
  265.                     octstr_imm(si_attributes[i].value_part));
  266.         if (octstr_ncompare(value, valueos, value_len) == 0) {
  267.     break;
  268.                 }
  269.             }
  270.         }
  271.        ++i;
  272.     }
  273.     if (i == NUMBER_OF_ATTRIBUTES)
  274.         goto error;
  275.     tokenized_date = NULL;
  276.     si_hex = si_attributes[i].token;
  277.     if (action(si_hex)) {
  278.         output_char(si_hex, sibxml);
  279.     } else if (url(si_hex)) {
  280.         output_char(si_hex, sibxml);
  281.         octstr_delete(value, 0, octstr_len(valueos));
  282.         parse_url_value(value, sibxml);
  283.     } else if (date(si_hex)) {
  284.         if ((tokenized_date = tokenize_date(value)) == NULL)
  285.             goto error;
  286.         output_char(si_hex, sibxml);
  287.         output_octet_string(tokenized_date, sibxml);
  288.     } else {
  289.         output_char(si_hex, sibxml);
  290.         parse_inline_string(value, sibxml);
  291.     }  
  292.     octstr_destroy(tokenized_date);
  293.     octstr_destroy(name);
  294.     octstr_destroy(value);
  295.     return 0;
  296. error:
  297.     octstr_destroy(name);
  298.     octstr_destroy(value);
  299.     return -1;
  300. }
  301. /*
  302.  * checks whether a si attribute value is an URL or some other kind of value. 
  303.  * Returns 1 for an URL and 0 otherwise.
  304.  */
  305. static int url(int hex)
  306. {
  307.     switch ((unsigned char) hex) {
  308.     case 0x0b:            /* href */
  309.     case 0x0c: case 0x0e: /* href http://, href https:// */
  310.     case 0x0d: case 0x0f: /* href http://www., href https://www. */
  311. return 1;
  312.     }
  313.     return 0;
  314. }
  315. /*
  316.  * checks whether a si attribute value is an action attribute or some other 
  317.  * kind of value. 
  318.  * Returns 1 for an action attribute and 0 otherwise.
  319.  */
  320. static int action(int hex)
  321. {
  322.     switch ((unsigned char) hex) {
  323.     case 0x05: case 0x06: /* action signal-none, action signal-low */
  324.     case 0x07: case 0x08: /* action signal-medium, action signal-high */
  325.     case 0x09:            /* action delete */
  326. return 1;
  327.     }
  328.     return 0;
  329. }
  330. /*
  331.  * checks whether a si attribute value is an OSI date or some other kind of 
  332.  * value. 
  333.  * Returns 1 for an action attribute and 0 otherwise.
  334.  */
  335. static int date(int hex)
  336. {
  337.     switch ((unsigned char) hex) {
  338.     case 0x0a: case 0x10: /* created, si-expires */
  339. return 1;
  340.     }
  341.     return 0;
  342. }
  343. /*
  344.  * Tokenises an OSI date. Procedure is defined in si, chapter 9.2.2. Validate
  345.  * OSI date as specified in 9.2.1.1. Returns NULL when error, a tokenised date 
  346.  * string otherwise.
  347.  */
  348. static Octstr *tokenize_date(Octstr *date)
  349. {
  350.     Octstr *date_token;
  351.     long j;
  352.     size_t i,
  353.            date_len;
  354.     unsigned char c;
  355.     if (!parse_date(date)) {
  356.         return NULL;
  357.     }
  358.     date_token = octstr_create("");
  359.     octstr_append_char(date_token, WBXML_OPAQUE);
  360.     i = 0;
  361.     j = 0;
  362.     date_len = octstr_len(date);
  363.     while (i < date_len) {
  364.         c = octstr_get_char(date, i);
  365.         if (c != 'T' && c != 'Z' && c != '-' && c != ':') {
  366.             if (isdigit(c)) {
  367.                 octstr_set_bits(date_token, 4*j + 8, 4, c & 0x0f);
  368.                 ++j;
  369.             } else {
  370.                 octstr_destroy(date_token);
  371.                 return NULL;
  372.             }
  373.         }  
  374.         ++i; 
  375.     }
  376.     octstr_drop_trailing_zeros(&date_token);
  377.     flag_date_length(&date_token);
  378.     return date_token;
  379. }
  380. static void octstr_drop_trailing_zeros(Octstr **date_token)
  381. {
  382.     while (1) {
  383.         if (octstr_get_char(*date_token, octstr_len(*date_token) - 1) == '')
  384.             octstr_delete(*date_token, octstr_len(*date_token) - 1, 1);
  385.         else
  386.             return;
  387.     }
  388. }
  389. static void flag_date_length(Octstr **token)
  390. {
  391.     Octstr *lenos;
  392.     lenos = octstr_format("%c", octstr_len(*token) - 1);
  393.     octstr_insert(*token, lenos, 1);
  394.     octstr_destroy(lenos);
  395. }
  396. /*
  397.  * The recursive parsing function for the parsing tree. Function checks the 
  398.  * type of the node, calls for the right parse function for the type, then 
  399.  * calls itself for the first child of the current node if there's one and 
  400.  * after that calls itself for the next child on the list.
  401.  */
  402. static int parse_node(xmlNodePtr node, simple_binary_t **sibxml)
  403. {
  404.     int status = 0;
  405.     
  406.     /* Call for the parser function of the node type. */
  407.     switch (node->type) {
  408.     case XML_ELEMENT_NODE:
  409. status = parse_element(node, sibxml);
  410. break;
  411.     case XML_TEXT_NODE:
  412. status = parse_text(node, sibxml);
  413. break;
  414.     case XML_CDATA_SECTION_NODE:
  415. status = parse_cdata(node, sibxml);
  416. break;
  417.     case XML_COMMENT_NODE:
  418.     case XML_PI_NODE:
  419. /* Comments and PIs are ignored. */
  420. break;
  421. /*
  422.  * XML has also many other node types, these are not needed with 
  423.  * SI. Therefore they are assumed to be an error.
  424.  */
  425.     default:
  426. error(0, "SI compiler: Unknown XML node in the SI source.");
  427. return -1;
  428. break;
  429.     }
  430.     /* 
  431.      * If node is an element with content, it will need an end tag after it's
  432.      * children. The status for it is returned by parse_element.
  433.      */
  434.     switch (status) {
  435.     case 0:
  436. if (node->children != NULL)
  437.     if (parse_node(node->children, sibxml) == -1)
  438. return -1;
  439. break;
  440.     case 1:
  441. if (node->children != NULL)
  442.     if (parse_node(node->children, sibxml) == -1)
  443. return -1;
  444. parse_end(sibxml);
  445. break;
  446.     case -1: /* Something went wrong in the parsing. */
  447. return -1;
  448.     default:
  449. warning(0,"SI compiler: undefined return value in a parse function.");
  450. return -1;
  451. break;
  452.     }
  453.     if (node->next != NULL)
  454. if (parse_node(node->next, sibxml) == -1)
  455.     return -1;
  456.     return 0;
  457. }
  458. /*
  459.  * Cdata section parsing function. Output this "as it is"
  460.  */
  461. static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml)
  462. {
  463.     int ret = 0;
  464.     Octstr *temp;
  465.     temp = create_octstr_from_node(node);
  466.     parse_octet_string(temp, sibxml);
  467.     octstr_destroy(temp);
  468.     return ret;
  469. }
  470. /*
  471.  * In the case of SI documents, only attribute values to be tokenized are
  472.  * parts of urls (see si, chapter 9.3.3). The caller romoves the start of an
  473.  * url. Check whether we can find parts in the value. If not, parse value a an
  474.  * inline string, otherwise parse parts before and after tokenizable parts as
  475.  * inline strings.
  476.  */
  477. void parse_url_value(Octstr *value, simple_binary_t **sibxml)
  478. {
  479.     size_t i;
  480.     long pos;
  481.     Octstr *urlos,
  482.            *first_part,
  483.    *last_part;
  484.     size_t first_part_len;
  485.     i = 0;
  486.     first_part_len = 0;
  487.     first_part = NULL;
  488.     last_part = NULL;
  489.     while (i < NUMBER_OF_URL_VALUES) {
  490.         pos = octstr_search(value, 
  491.             urlos = octstr_imm(si_URL_values[i].name), 0);
  492.         if (pos >= 0) {
  493.     first_part = octstr_duplicate(value);
  494.             octstr_delete(first_part, pos, octstr_len(first_part) - pos);
  495.             first_part_len = octstr_len(first_part);
  496.             parse_inline_string(first_part, sibxml);
  497.             output_char(si_URL_values[i].token, sibxml);
  498.             last_part = octstr_duplicate(value);
  499.             octstr_delete(last_part, 0, first_part_len + octstr_len(urlos));
  500.             parse_inline_string(last_part, sibxml);
  501.     octstr_destroy(first_part);
  502.             octstr_destroy(last_part);
  503.             break;
  504.         }
  505.         octstr_destroy(urlos);
  506.         ++i;
  507.     }
  508.     if (pos < 0) 
  509. parse_inline_string(value, sibxml);
  510.         
  511. }