xtag.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:13k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * xlist.c : a trivial parser for XML-like tags
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research
  5.  *                         Organisation (CSIRO) Australia
  6.  * Copyright (C) 2000-2004 VideoLAN
  7.  *
  8.  * $Id: xtag.c 7397 2004-04-20 17:27:30Z sam $
  9.  *
  10.  * Authors: Conrad Parker <Conrad.Parker@csiro.au>
  11.  *          Andre Pang <Andre.Pang@csiro.au>
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  26.  *****************************************************************************/
  27. #include "config.h"
  28. #include <ctype.h>
  29. #include <string.h>
  30. #include <stdarg.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <xlist.h>
  34. #undef XTAG_DEBUG
  35. #undef FALSE
  36. #undef TRUE
  37. #define FALSE (0)
  38. #define TRUE (!FALSE)
  39. #undef MIN
  40. #define MIN(a,b) ((a)<(b)?(a):(b))
  41. #undef MAX
  42. #define MAX(a,b) ((a)>(b)?(a):(b))
  43. typedef struct _XTag XTag;
  44. typedef struct _XAttribute XAttribute;
  45. typedef struct _XTagParser XTagParser;
  46. /*
  47.  * struct _XTag is kind of a union ... it normally represents a whole
  48.  * tag (and its children), but it could alternatively represent some
  49.  * PCDATA. Basically, if tag->pcdata is non-NULL, interpret only it and
  50.  * ignore the name, attributes and inner_tags.
  51.  */
  52. struct _XTag {
  53.   char * name;
  54.   char * pcdata;
  55.   XTag * parent;
  56.   XList * attributes;
  57.   XList * children;
  58.   XList * current_child;
  59. };
  60. struct _XAttribute {
  61.   char * name;
  62.   char * value;
  63. };
  64. struct _XTagParser {
  65.   int valid; /* boolean */
  66.   XTag * current_tag;
  67.   char * start;
  68.   char * end;
  69. };
  70. /* Character classes */
  71. #define X_NONE           0
  72. #define X_WHITESPACE  1<<0
  73. #define X_OPENTAG     1<<1
  74. #define X_CLOSETAG    1<<2
  75. #define X_DQUOTE      1<<3
  76. #define X_SQUOTE      1<<4
  77. #define X_EQUAL       1<<5
  78. #define X_SLASH       1<<6
  79. static int
  80. xtag_cin (char c, int char_class)
  81. {
  82.   if (char_class & X_WHITESPACE)
  83.     if (isspace(c)) return TRUE;
  84.   if (char_class & X_OPENTAG)
  85.     if (c == '<') return TRUE;
  86.   if (char_class & X_CLOSETAG)
  87.     if (c == '>') return TRUE;
  88.   if (char_class & X_DQUOTE)
  89.     if (c == '"') return TRUE;
  90.   if (char_class & X_SQUOTE)
  91.     if (c == ''') return TRUE;
  92.   if (char_class & X_EQUAL)
  93.     if (c == '=') return TRUE;
  94.   if (char_class & X_SLASH)
  95.     if (c == '/') return TRUE;
  96.   return FALSE;
  97. }
  98. static int
  99. xtag_index (XTagParser * parser, int char_class)
  100. {
  101.   char * s;
  102.   int i;
  103.   s = parser->start;
  104.   for (i = 0; s[i] && s != parser->end; i++) {
  105.     if (xtag_cin(s[i], char_class)) return i;
  106.   }
  107.   return -1;
  108. }
  109. static void
  110. xtag_skip_over (XTagParser * parser, int char_class)
  111. {
  112.   char * s;
  113.   int i;
  114.   if (!parser->valid) return;
  115.   s = (char *)parser->start;
  116.   for (i = 0; s[i] && s != parser->end; i++) {
  117.     if (!xtag_cin(s[i], char_class)) {
  118.       parser->start = &s[i];
  119.       return;
  120.     }
  121.   }
  122.   return;
  123. }
  124. static void
  125. xtag_skip_whitespace (XTagParser * parser)
  126. {
  127.   xtag_skip_over (parser, X_WHITESPACE);
  128. }
  129. #if 0
  130. static void
  131. xtag_skip_to (XTagParser * parser, int char_class)
  132. {
  133.   char * s;
  134.   int i;
  135.   if (!parser->valid) return;
  136.   s = (char *)parser->start;
  137.   for (i = 0; s[i] && s != parser->end; i++) {
  138.     if (xtag_cin(s[i], char_class)) {
  139.       parser->start = &s[i];
  140.       return;
  141.     }
  142.   }
  143.   return;  
  144. }
  145. #endif
  146. static char *
  147. xtag_slurp_to (XTagParser * parser, int good_end, int bad_end)
  148. {
  149.   char * s, * ret;
  150.   int xi;
  151.   if (!parser->valid) return NULL;
  152.   s = parser->start;
  153.   xi = xtag_index (parser, good_end | bad_end);
  154.   if (xi > 0 && xtag_cin (s[xi], good_end)) {
  155.     ret = malloc ((xi+1) * sizeof(char));
  156.     strncpy (ret, s, xi);
  157.     ret[xi] = '';
  158.     parser->start = &s[xi];
  159.     return ret;
  160.   }
  161.   return NULL;
  162. }
  163. static int
  164. xtag_assert_and_pass (XTagParser * parser, int char_class)
  165. {
  166.   char * s;
  167.   if (!parser->valid) return FALSE;
  168.   s = parser->start;
  169.   if (!xtag_cin (s[0], char_class)) {
  170.     parser->valid = FALSE;
  171.     return FALSE;
  172.   }
  173.   parser->start = &s[1];
  174.   return TRUE;
  175. }
  176. static char *
  177. xtag_slurp_quoted (XTagParser * parser)
  178. {
  179.   char * s, * ret;
  180.   int quote = X_DQUOTE; /* quote char to match on */
  181.   int xi;
  182.   if (!parser->valid) return NULL;
  183.   xtag_skip_whitespace (parser);
  184.   s = parser->start;
  185.   if (xtag_cin (s[0], X_SQUOTE)) quote = X_SQUOTE;
  186.   if (!xtag_assert_and_pass (parser, quote)) return NULL;
  187.   s = parser->start;
  188.   for (xi = 0; s[xi]; xi++) {
  189.     if (xtag_cin (s[xi], quote)) {
  190.       if (!(xi > 1 && s[xi-1] == '\')) break;
  191.     }
  192.   }
  193.   ret = malloc ((xi+1) * sizeof(char));
  194.   strncpy (ret, s, xi);
  195.   ret[xi] = '';
  196.   parser->start = &s[xi];
  197.   if (!xtag_assert_and_pass (parser, quote)) return NULL;
  198.   return ret;
  199. }
  200. static XAttribute *
  201. xtag_parse_attribute (XTagParser * parser)
  202. {
  203.   XAttribute * attr;
  204.   char * name, * value;
  205.   char * s;
  206.   if (!parser->valid) return NULL;
  207.   xtag_skip_whitespace (parser);
  208.  
  209.   name = xtag_slurp_to (parser, X_WHITESPACE | X_EQUAL, X_SLASH | X_CLOSETAG);
  210.   if (name == NULL) return NULL;
  211.   xtag_skip_whitespace (parser);
  212.   s = parser->start;
  213.   if (!xtag_assert_and_pass (parser, X_EQUAL)) {
  214. #ifdef XTAG_DEBUG
  215.     printf ("xtag: attr failed EQUAL on <%s>n", name);
  216. #endif
  217.     goto err_free_name;
  218.   }
  219.   xtag_skip_whitespace (parser);
  220.   value = xtag_slurp_quoted (parser);
  221.   if (value == NULL) {
  222. #ifdef XTAG_DEBUG
  223.     printf ("Got NULL quoted attribute valuen");
  224. #endif
  225.     goto err_free_name;
  226.   }
  227.   attr = malloc (sizeof (*attr));
  228.   attr->name = name;
  229.   attr->value = value;
  230.   return attr;
  231.  err_free_name:
  232.   free (name);
  233.   parser->valid = FALSE;
  234.   return NULL;
  235. }
  236. static XTag *
  237. xtag_parse_tag (XTagParser * parser)
  238. {
  239.   XTag * tag, * inner;
  240.   XAttribute * attr;
  241.   char * name;
  242.   char * pcdata;
  243.   char * s;
  244.   if (!parser->valid) return NULL;
  245.   if ((pcdata = xtag_slurp_to (parser, X_OPENTAG, X_NONE)) != NULL) {
  246.     tag = malloc (sizeof (*tag));
  247.     tag->name = NULL;
  248.     tag->pcdata = pcdata;
  249.     tag->parent = parser->current_tag;
  250.     tag->attributes = NULL;
  251.     tag->children = NULL;
  252.     tag->current_child = NULL;
  253.     return tag;
  254.   }
  255.   s = parser->start;
  256.   /* if this starts a close tag, return NULL and let the parent take it */
  257.   if (xtag_cin (s[0], X_OPENTAG) && xtag_cin (s[1], X_SLASH))
  258.     return NULL;
  259.   if (!xtag_assert_and_pass (parser, X_OPENTAG)) return NULL;
  260.   name = xtag_slurp_to (parser, X_WHITESPACE | X_SLASH | X_CLOSETAG, X_NONE);
  261.   if (name == NULL) return NULL;
  262. #ifdef XTAG_DEBUG
  263.   printf ("<%s ...n", name);
  264. #endif
  265.   tag = malloc (sizeof (*tag));
  266.   tag->name = name;
  267.   tag->pcdata = NULL;
  268.   tag->parent = parser->current_tag;
  269.   tag->attributes = NULL;
  270.   tag->children = NULL;
  271.   tag->current_child = NULL;
  272.   s = parser->start;
  273.   if (xtag_cin (s[0], X_WHITESPACE)) {
  274.     while ((attr = xtag_parse_attribute (parser)) != NULL) {
  275.       tag->attributes = xlist_append (tag->attributes, attr);
  276.     }
  277.   }
  278.   xtag_skip_whitespace (parser);
  279.   s = parser->start;
  280.   if (xtag_cin (s[0], X_CLOSETAG)) {
  281.     parser->current_tag = tag;
  282.     xtag_assert_and_pass (parser, X_CLOSETAG);
  283.     while ((inner = xtag_parse_tag (parser)) != NULL) {
  284.       tag->children = xlist_append (tag->children, inner);
  285.     }
  286.     xtag_skip_whitespace (parser);
  287.     xtag_assert_and_pass (parser, X_OPENTAG);
  288.     xtag_assert_and_pass (parser, X_SLASH);
  289.     name = xtag_slurp_to (parser, X_WHITESPACE | X_CLOSETAG, X_NONE);
  290.     if (name) {
  291.       if (strcmp (name, tag->name)) {
  292. #ifdef XTAG_DEBUG
  293.         printf ("got %s expected %sn", name, tag->name);
  294. #endif
  295.         parser->valid = FALSE;
  296.       }
  297.       free (name);
  298.     }
  299.     xtag_skip_whitespace (parser);
  300.     xtag_assert_and_pass (parser, X_CLOSETAG);
  301.   } else {
  302.     xtag_assert_and_pass (parser, X_SLASH);
  303.     xtag_assert_and_pass (parser, X_CLOSETAG);
  304.   }
  305.   return tag;
  306. }
  307. XTag *
  308. xtag_free (XTag * xtag)
  309. {
  310.   XList * l;
  311.   XAttribute * attr;
  312.   XTag * child;
  313.   if (xtag == NULL) return NULL;
  314.   if (xtag->name) free (xtag->name);
  315.   if (xtag->pcdata) free (xtag->pcdata);
  316.   for (l = xtag->attributes; l; l = l->next) {
  317.     if ((attr = (XAttribute *)l->data) != NULL) {
  318.       if (attr->name) free (attr->name);
  319.       if (attr->value) free (attr->value);
  320.       free (attr);
  321.     }
  322.   }
  323.   xlist_free (xtag->attributes);
  324.   for (l = xtag->children; l; l = l->next) {
  325.     child = (XTag *)l->data;
  326.     xtag_free (child);
  327.   }
  328.   xlist_free (xtag->children);
  329.   free (xtag);
  330.   return NULL;
  331. }
  332. XTag *
  333. xtag_new_parse (const char * s, int n)
  334. {
  335.   XTagParser parser;
  336.   XTag * tag, * ttag, * wrapper;
  337.   parser.valid = TRUE;
  338.   parser.current_tag = NULL;
  339.   parser.start = (char *)s;
  340.   if (n == -1)
  341.     parser.end = NULL;
  342.   else if (n == 0)
  343.     return NULL;
  344.   else
  345.     parser.end = (char *)&s[n];
  346.   tag = xtag_parse_tag (&parser);
  347.   if (!parser.valid) {
  348.     xtag_free (tag);
  349.     return NULL;
  350.   }
  351.   if ((ttag = xtag_parse_tag (&parser)) != NULL) {
  352.     if (!parser.valid) {
  353.       xtag_free (ttag);
  354.       return tag;
  355.     }
  356.     wrapper = malloc (sizeof (XTag));
  357.     wrapper->name = NULL;
  358.     wrapper->pcdata = NULL;
  359.     wrapper->parent = NULL;
  360.     wrapper->attributes = NULL;
  361.     wrapper->children = NULL;
  362.     wrapper->current_child = NULL;
  363.     wrapper->children = xlist_append (wrapper->children, tag);
  364.     wrapper->children = xlist_append (wrapper->children, ttag);
  365.     while ((ttag = xtag_parse_tag (&parser)) != NULL) {
  366.       if (!parser.valid) {
  367.         xtag_free (ttag);
  368.         return wrapper;
  369.       }
  370.       wrapper->children = xlist_append (wrapper->children, ttag);
  371.     }
  372.     return wrapper;
  373.   }
  374.   return tag;
  375. }
  376. char *
  377. xtag_get_name (XTag * xtag)
  378. {
  379.   return xtag ? xtag->name : NULL;
  380. }
  381. char *
  382. xtag_get_pcdata (XTag * xtag)
  383. {
  384.   XList * l;
  385.   XTag * child;
  386.   if (xtag == NULL) return NULL;
  387.   for (l = xtag->children; l; l = l->next) {
  388.     child = (XTag *)l->data;
  389.     if (child->pcdata != NULL) {
  390.       return child->pcdata;
  391.     }
  392.   }
  393.   return NULL;
  394. }
  395. char *
  396. xtag_get_attribute (XTag * xtag, char * attribute)
  397. {
  398.   XList * l;
  399.   XAttribute * attr;
  400.   if (xtag == NULL) return NULL;
  401.   for (l = xtag->attributes; l; l = l->next) {
  402.     if ((attr = (XAttribute *)l->data) != NULL) {
  403.       if (!strcmp (attr->name, attribute))
  404.         return attr->value;
  405.     }
  406.   }
  407.   return NULL;
  408. }
  409. XTag *
  410. xtag_first_child (XTag * xtag, char * name)
  411. {
  412.   XList * l;
  413.   XTag * child;
  414.   if (xtag == NULL) return NULL;
  415.   if ((l = xtag->children) == NULL) return NULL;
  416.   if (name == NULL) {
  417.     xtag->current_child = l;
  418.     return (XTag *)l->data;
  419.   }
  420.   for (; l; l = l->next) {
  421.     child = (XTag *)l->data;
  422.     if (!strcmp(child->name, name)) {
  423.       xtag->current_child = l;
  424.       return child;
  425.     }
  426.   }
  427.   xtag->current_child = NULL;
  428.   return NULL;
  429. }
  430. XTag *
  431. xtag_next_child (XTag * xtag, char * name)
  432. {
  433.   XList * l;
  434.   XTag * child;
  435.   if (xtag == NULL) return NULL;
  436.   if ((l = xtag->current_child) == NULL)
  437.     return xtag_first_child (xtag, name);
  438.   if ((l = l->next) == NULL)
  439.     return NULL;
  440.   if (name == NULL) {
  441.     xtag->current_child = l;
  442.     return (XTag *)l->data;
  443.   }
  444.   for (; l; l = l->next) {
  445.     child = (XTag *)l->data;
  446.     if (!strcmp(child->name, name)) {
  447.       xtag->current_child = l;
  448.       return child;
  449.     }
  450.   }
  451.   xtag->current_child = NULL;
  452.   return NULL;
  453. }
  454. /*
  455.  * This snprints function takes a variable list of char *, the last of
  456.  * which must be NULL, and prints each in turn to buf.
  457.  * Returns C99-style total length that would have been written, even if
  458.  * this is larger than n.
  459.  */
  460. static int
  461. xtag_snprints (char * buf, int n, ...)
  462. {
  463.   va_list ap;
  464.   char * s;
  465.   int len, to_copy, total = 0;
  466.   va_start (ap, n);
  467.   
  468.   for (s = va_arg (ap, char *); s; s = va_arg (ap, char *)) {
  469.     len = strlen (s);
  470.     if ((to_copy = MIN (n, len)) > 0) {
  471.       memcpy (buf, s, to_copy);
  472.       buf += to_copy;
  473.       n -= to_copy;
  474.     }
  475.     total += len;
  476.   }
  477.   va_end (ap);
  478.   return total;
  479. }
  480. int
  481. xtag_snprint (char * buf, int n, XTag * xtag)
  482. {
  483.   int nn, written = 0;
  484.   XList * l;
  485.   XAttribute * attr;
  486.   XTag * child;
  487. #define FORWARD(N) 
  488.   buf += MIN (n, N); 
  489.   n = MAX (n-N, 0);  
  490.   written += N;
  491.   if (xtag == NULL) {
  492.     if (n > 0) buf[0] = '';
  493.     return 0;
  494.   }
  495.   if (xtag->pcdata) {
  496.     nn = xtag_snprints (buf, n, xtag->pcdata, NULL);
  497.     FORWARD(nn);
  498.     return written;
  499.   }
  500.   if (xtag->name) {
  501.     nn = xtag_snprints (buf, n, "<", xtag->name, NULL);
  502.     FORWARD(nn);
  503.     for (l = xtag->attributes; l; l = l->next) {
  504.       attr = (XAttribute *)l->data;
  505.       
  506.       nn = xtag_snprints (buf, n, " ", attr->name, "="", attr->value, """,
  507.                           NULL);
  508.       FORWARD(nn);
  509.     }
  510.     
  511.     if (xtag->children == NULL) {
  512.       nn = xtag_snprints (buf, n, "/>", NULL);
  513.       FORWARD(nn);
  514.       return written;
  515.     }
  516.     
  517.     nn = xtag_snprints (buf, n, ">", NULL);
  518.     FORWARD(nn);
  519.   }
  520.   for (l = xtag->children; l; l = l->next) {
  521.     child = (XTag *)l->data;
  522.     nn = xtag_snprint (buf, n, child);
  523.     FORWARD(nn);
  524.   }
  525.   if (xtag->name) {
  526.     nn = xtag_snprints (buf, n, "</", xtag->name, ">", NULL);
  527.     FORWARD(nn);
  528.   }
  529.   return written;
  530. }