xtag.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:14k
源码类别:

midi

开发平台:

Unix_Linux

  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 the VideoLAN team
  7.  *
  8.  * $Id: 3a661b906297e040940adeb7b4b30095315d55ab $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <vlc_common.h>
  31. #include <ctype.h>
  32. #include <stdarg.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include "xlist.h"
  37. #include <assert.h>
  38. #undef XTAG_DEBUG
  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. void   xtag_free (XTag * xtag);
  71. XTag * xtag_new_parse (const char * s, int n);
  72. char * xtag_get_name (XTag * xtag);
  73. char * xtag_get_pcdata (XTag * xtag);
  74. char * xtag_get_attribute (XTag * xtag, const char* attribute);
  75. XTag * xtag_first_child (XTag * xtag, const char * name);
  76. XTag * xtag_next_child (XTag * xtag, char * name);
  77. int    xtag_snprint (char * buf, int n, XTag * xtag);
  78. /* Character classes */
  79. #define X_NONE           0
  80. #define X_WHITESPACE  1<<0
  81. #define X_OPENTAG     1<<1
  82. #define X_CLOSETAG    1<<2
  83. #define X_DQUOTE      1<<3
  84. #define X_SQUOTE      1<<4
  85. #define X_EQUAL       1<<5
  86. #define X_SLASH       1<<6
  87. static int
  88. xtag_cin (char c, int char_class)
  89. {
  90.   if (char_class & X_WHITESPACE)
  91.     if (isspace(c)) return true;
  92.   if (char_class & X_OPENTAG)
  93.     if (c == '<') return true;
  94.   if (char_class & X_CLOSETAG)
  95.     if (c == '>') return true;
  96.   if (char_class & X_DQUOTE)
  97.     if (c == '"') return true;
  98.   if (char_class & X_SQUOTE)
  99.     if (c == ''') return true;
  100.   if (char_class & X_EQUAL)
  101.     if (c == '=') return true;
  102.   if (char_class & X_SLASH)
  103.     if (c == '/') return true;
  104.   return false;
  105. }
  106. static int
  107. xtag_index (XTagParser * parser, int char_class)
  108. {
  109.   char * s;
  110.   int i;
  111.   s = parser->start;
  112.   for (i = 0; s[i] && s != parser->end; i++) {
  113.     if (xtag_cin(s[i], char_class)) return i;
  114.   }
  115.   return -1;
  116. }
  117. static void
  118. xtag_skip_over (XTagParser * parser, int char_class)
  119. {
  120.   char * s;
  121.   int i;
  122.   if (!parser->valid) return;
  123.   s = (char *)parser->start;
  124.   for (i = 0; s[i] && s != parser->end; i++) {
  125.     if (!xtag_cin(s[i], char_class)) {
  126.       parser->start = &s[i];
  127.       return;
  128.     }
  129.   }
  130.   return;
  131. }
  132. static void
  133. xtag_skip_whitespace (XTagParser * parser)
  134. {
  135.   xtag_skip_over (parser, X_WHITESPACE);
  136. }
  137. #if 0
  138. static void
  139. xtag_skip_to (XTagParser * parser, int char_class)
  140. {
  141.   char * s;
  142.   int i;
  143.   if (!parser->valid) return;
  144.   s = (char *)parser->start;
  145.   for (i = 0; s[i] && s != parser->end; i++) {
  146.     if (xtag_cin(s[i], char_class)) {
  147.       parser->start = &s[i];
  148.       return;
  149.     }
  150.   }
  151.   return;
  152. }
  153. #endif
  154. static char *
  155. xtag_slurp_to (XTagParser * parser, int good_end, int bad_end)
  156. {
  157.   char * s, * ret;
  158.   int xi;
  159.   if (!parser->valid) return NULL;
  160.   s = parser->start;
  161.   xi = xtag_index (parser, good_end | bad_end);
  162.   if (xi > 0 && xtag_cin (s[xi], good_end)) {
  163.     ret = malloc (xi+1);
  164.     strncpy (ret, s, xi);
  165.     ret[xi] = '';
  166.     parser->start = &s[xi];
  167.     return ret;
  168.   }
  169.   return NULL;
  170. }
  171. static int
  172. xtag_assert_and_pass (XTagParser * parser, int char_class)
  173. {
  174.   char * s;
  175.   if (!parser->valid) return false;
  176.   s = parser->start;
  177.   if (!xtag_cin (s[0], char_class)) {
  178.     parser->valid = false;
  179.     return false;
  180.   }
  181.   parser->start = &s[1];
  182.   return true;
  183. }
  184. static char *
  185. xtag_slurp_quoted (XTagParser * parser)
  186. {
  187.   char * s, * ret;
  188.   int quote = X_DQUOTE; /* quote char to match on */
  189.   int xi;
  190.   if (!parser->valid) return NULL;
  191.   xtag_skip_whitespace (parser);
  192.   s = parser->start;
  193.   if (xtag_cin (s[0], X_SQUOTE)) quote = X_SQUOTE;
  194.   if (!xtag_assert_and_pass (parser, quote)) return NULL;
  195.   s = parser->start;
  196.   for (xi = 0; s[xi]; xi++) {
  197.     if (xtag_cin (s[xi], quote)) {
  198.       if (!(xi > 1 && s[xi-1] == '\')) break;
  199.     }
  200.   }
  201.   ret = malloc (xi+1);
  202.   strncpy (ret, s, xi);
  203.   ret[xi] = '';
  204.   parser->start = &s[xi];
  205.   if (!xtag_assert_and_pass (parser, quote))
  206.   {
  207.      free( ret );
  208.      return NULL;
  209.   }
  210.   return ret;
  211. }
  212. static XAttribute *
  213. xtag_parse_attribute (XTagParser * parser)
  214. {
  215.   XAttribute * attr;
  216.   char * name, * value;
  217.   char * s;
  218.   if (!parser->valid) return NULL;
  219.   xtag_skip_whitespace (parser);
  220.  
  221.   name = xtag_slurp_to (parser, X_WHITESPACE | X_EQUAL, X_SLASH | X_CLOSETAG);
  222.   if (name == NULL) return NULL;
  223.   xtag_skip_whitespace (parser);
  224.   s = parser->start;
  225.   if (!xtag_assert_and_pass (parser, X_EQUAL)) {
  226. #ifdef XTAG_DEBUG
  227.     printf ("xtag: attr failed EQUAL on <%s>n", name);
  228. #endif
  229.     goto err_free_name;
  230.   }
  231.   xtag_skip_whitespace (parser);
  232.   value = xtag_slurp_quoted (parser);
  233.   if (value == NULL) {
  234. #ifdef XTAG_DEBUG
  235.     printf ("Got NULL quoted attribute valuen");
  236. #endif
  237.     goto err_free_name;
  238.   }
  239.   attr = malloc (sizeof (*attr));
  240.   attr->name = name;
  241.   attr->value = value;
  242.   return attr;
  243.  err_free_name:
  244.   free (name);
  245.   parser->valid = false;
  246.   return NULL;
  247. }
  248. static XTag *
  249. xtag_parse_tag (XTagParser * parser)
  250. {
  251.   XTag * tag, * inner;
  252.   XAttribute * attr;
  253.   char * name;
  254.   char * pcdata;
  255.   char * s;
  256.   if (!parser->valid) return NULL;
  257.   if ((pcdata = xtag_slurp_to (parser, X_OPENTAG, X_NONE)) != NULL) {
  258.     tag = malloc (sizeof (*tag));
  259.     tag->name = NULL;
  260.     tag->pcdata = pcdata;
  261.     tag->parent = parser->current_tag;
  262.     tag->attributes = NULL;
  263.     tag->children = NULL;
  264.     tag->current_child = NULL;
  265.     return tag;
  266.   }
  267.   s = parser->start;
  268.   /* if this starts a close tag, return NULL and let the parent take it */
  269.   if (xtag_cin (s[0], X_OPENTAG) && xtag_cin (s[1], X_SLASH))
  270.     return NULL;
  271.   if (!xtag_assert_and_pass (parser, X_OPENTAG)) return NULL;
  272.   name = xtag_slurp_to (parser, X_WHITESPACE | X_SLASH | X_CLOSETAG, X_NONE);
  273.   if (name == NULL) return NULL;
  274. #ifdef XTAG_DEBUG
  275.   printf ("<%s ...n", name);
  276. #endif
  277.   tag = malloc (sizeof (*tag));
  278.   tag->name = name;
  279.   tag->pcdata = NULL;
  280.   tag->parent = parser->current_tag;
  281.   tag->attributes = NULL;
  282.   tag->children = NULL;
  283.   tag->current_child = NULL;
  284.   s = parser->start;
  285.   if (xtag_cin (s[0], X_WHITESPACE)) {
  286.     while ((attr = xtag_parse_attribute (parser)) != NULL) {
  287.       tag->attributes = xlist_append (tag->attributes, attr);
  288.     }
  289.   }
  290.   xtag_skip_whitespace (parser);
  291.   s = parser->start;
  292.   if (xtag_cin (s[0], X_CLOSETAG)) {
  293.     parser->current_tag = tag;
  294.     xtag_assert_and_pass (parser, X_CLOSETAG);
  295.     while ((inner = xtag_parse_tag (parser)) != NULL) {
  296.       tag->children = xlist_append (tag->children, inner);
  297.     }
  298.     xtag_skip_whitespace (parser);
  299.     xtag_assert_and_pass (parser, X_OPENTAG);
  300.     xtag_assert_and_pass (parser, X_SLASH);
  301.     name = xtag_slurp_to (parser, X_WHITESPACE | X_CLOSETAG, X_NONE);
  302.     if (name) {
  303.       if (name && tag->name && strcmp (name, tag->name)) {
  304. #ifdef XTAG_DEBUG
  305.         printf ("got %s expected %sn", name, tag->name);
  306. #endif
  307.         parser->valid = false;
  308.       }
  309.       free (name);
  310.     }
  311.     xtag_skip_whitespace (parser);
  312.     xtag_assert_and_pass (parser, X_CLOSETAG);
  313.   } else {
  314.     xtag_assert_and_pass (parser, X_SLASH);
  315.     xtag_assert_and_pass (parser, X_CLOSETAG);
  316.   }
  317.   return tag;
  318. }
  319. void xtag_free (XTag * xtag)
  320. {
  321.   XList * l;
  322.   XAttribute * attr;
  323.   XTag * child;
  324.   if( !xtag )
  325.     return;
  326.   free( xtag->name );
  327.   free( xtag->pcdata );
  328.   for( l = xtag->attributes; l; l = l->next) {
  329.     if((attr = (XAttribute *)l->data) != NULL) {
  330.       free( attr->name );
  331.       free( attr->value );
  332.       free( attr );
  333.     }
  334.   }
  335.   xlist_free (xtag->attributes);
  336.   for (l = xtag->children; l; l = l->next) {
  337.     child = (XTag *)l->data;
  338.     xtag_free( child );
  339.   }
  340.   xlist_free (xtag->children);
  341.   free( xtag );
  342. }
  343. XTag *
  344. xtag_new_parse (const char * s, int n)
  345. {
  346.   XTagParser parser;
  347.   XTag * tag, * ttag, * wrapper;
  348.   parser.valid = true;
  349.   parser.current_tag = NULL;
  350.   parser.start = (char *)s;
  351.   if (n == -1)
  352.     parser.end = NULL;
  353.   else if (n == 0)
  354.     return NULL;
  355.   else
  356.     parser.end = (char *)&s[n];
  357.   tag = xtag_parse_tag (&parser);
  358.   if (!parser.valid) {
  359.     xtag_free (tag);
  360.     return NULL;
  361.   }
  362.   if ((ttag = xtag_parse_tag (&parser)) != NULL) {
  363.     if (!parser.valid) {
  364.       xtag_free (ttag);
  365.       return tag;
  366.     }
  367.     wrapper = malloc (sizeof (XTag));
  368.     wrapper->name = NULL;
  369.     wrapper->pcdata = NULL;
  370.     wrapper->parent = NULL;
  371.     wrapper->attributes = NULL;
  372.     wrapper->children = NULL;
  373.     wrapper->current_child = NULL;
  374.     wrapper->children = xlist_append (wrapper->children, tag);
  375.     wrapper->children = xlist_append (wrapper->children, ttag);
  376.     while ((ttag = xtag_parse_tag (&parser)) != NULL) {
  377.       if (!parser.valid) {
  378.         xtag_free (ttag);
  379.         return wrapper;
  380.       }
  381.       wrapper->children = xlist_append (wrapper->children, ttag);
  382.     }
  383.     return wrapper;
  384.   }
  385.   return tag;
  386. }
  387. char *
  388. xtag_get_name (XTag * xtag)
  389. {
  390.   return xtag ? xtag->name : NULL;
  391. }
  392. char *
  393. xtag_get_pcdata (XTag * xtag)
  394. {
  395.   XList * l;
  396.   XTag * child;
  397.   if (xtag == NULL) return NULL;
  398.   for (l = xtag->children; l; l = l->next) {
  399.     child = (XTag *)l->data;
  400.     if (child->pcdata != NULL) {
  401.       return child->pcdata;
  402.     }
  403.   }
  404.   return NULL;
  405. }
  406. char* xtag_get_attribute (XTag * xtag, const char * attribute)
  407. {
  408.     XList * l;
  409.     XAttribute * attr;
  410.     if( !xtag )
  411.         return NULL;
  412.     for( l = xtag->attributes; l; l = l->next )
  413.     {
  414.         if( ( attr = (XAttribute *)l->data ) != NULL )
  415.         {
  416.             if( attr->name && attribute && !strcmp( attr->name, attribute ) )
  417.                 return attr->value;
  418.         }
  419.     }
  420.     return NULL;
  421. }
  422. XTag* xtag_first_child (XTag * xtag, const char * name)
  423. {
  424.     XList * l;
  425.     XTag * child;
  426.     if( !xtag )
  427.         return NULL;
  428.     if( ( l = xtag->children ) == NULL )
  429.         return NULL;
  430.     if( !name )
  431.     {
  432.         xtag->current_child = l;
  433.         return (XTag *)l->data;
  434.     }
  435.     for( ; l; l = l->next )
  436.     {
  437.         child = (XTag *)l->data;
  438.         if( child->name && name && !strcmp( child->name, name ) )
  439.         {
  440.             xtag->current_child = l;
  441.             return child;
  442.         }
  443.     }
  444.     xtag->current_child = NULL;
  445.     return NULL;
  446. }
  447. XTag *
  448. xtag_next_child (XTag * xtag, char * name)
  449. {
  450.   XList * l;
  451.   XTag * child;
  452.   if (xtag == NULL) return NULL;
  453.   if ((l = xtag->current_child) == NULL)
  454.     return xtag_first_child (xtag, name);
  455.   if ((l = l->next) == NULL)
  456.     return NULL;
  457.   if (name == NULL) {
  458.     xtag->current_child = l;
  459.     return (XTag *)l->data;
  460.   }
  461.   for (; l; l = l->next) {
  462.     child = (XTag *)l->data;
  463.     if (child->name && name && !strcmp(child->name, name)) {
  464.       xtag->current_child = l;
  465.       return child;
  466.     }
  467.   }
  468.   xtag->current_child = NULL;
  469.   return NULL;
  470. }
  471. /*
  472.  * This snprints function takes a variable list of char *, the last of
  473.  * which must be NULL, and prints each in turn to buf.
  474.  * Returns C99-style total length that would have been written, even if
  475.  * this is larger than n.
  476.  */
  477. static int
  478. xtag_snprints (char * buf, int n, ...)
  479. {
  480.   va_list ap;
  481.   char * s;
  482.   int len, to_copy, total = 0;
  483.   va_start (ap, n);
  484.  
  485.   for (s = va_arg (ap, char *); s; s = va_arg (ap, char *)) {
  486.     len = strlen (s);
  487.     if ((to_copy = MIN (n, len)) > 0) {
  488.       memcpy (buf, s, to_copy);
  489.       buf += to_copy;
  490.       n -= to_copy;
  491.     }
  492.     total += len;
  493.   }
  494.   va_end (ap);
  495.   return total;
  496. }
  497. int
  498. xtag_snprint (char * buf, int n, XTag * xtag)
  499. {
  500.   int nn, written = 0;
  501.   XList * l;
  502.   XAttribute * attr;
  503.   XTag * child;
  504. #define FORWARD(N) 
  505.   buf += MIN (n, N); 
  506.   n = MAX (n-N, 0);  
  507.   written += N;
  508.   if (xtag == NULL) {
  509.     if (n > 0) buf[0] = '';
  510.     return 0;
  511.   }
  512.   if (xtag->pcdata) {
  513.     nn = xtag_snprints (buf, n, xtag->pcdata, NULL);
  514.     FORWARD(nn);
  515.     return written;
  516.   }
  517.   if (xtag->name) {
  518.     nn = xtag_snprints (buf, n, "<", xtag->name, NULL);
  519.     FORWARD(nn);
  520.     for (l = xtag->attributes; l; l = l->next) {
  521.       attr = (XAttribute *)l->data;
  522.  
  523.       nn = xtag_snprints (buf, n, " ", attr->name, "="", attr->value, """,
  524.                           NULL);
  525.       FORWARD(nn);
  526.     }
  527.  
  528.     if (xtag->children == NULL) {
  529.       nn = xtag_snprints (buf, n, "/>", NULL);
  530.       FORWARD(nn);
  531.       return written;
  532.     }
  533.  
  534.     nn = xtag_snprints (buf, n, ">", NULL);
  535.     FORWARD(nn);
  536.   }
  537.   for (l = xtag->children; l; l = l->next) {
  538.     child = (XTag *)l->data;
  539.     nn = xtag_snprint (buf, n, child);
  540.     FORWARD(nn);
  541.   }
  542.   if (xtag->name) {
  543.     nn = xtag_snprints (buf, n, "</", xtag->name, ">", NULL);
  544.     FORWARD(nn);
  545.   }
  546.   return written;
  547. }