Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

xtag.c

00001 /*****************************************************************************
00002  * xtag.c : a trivial parser for XML-like tags
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research
00005  *                         Organisation (CSIRO) Australia
00006  * Copyright (C) 2000-2004 the VideoLAN team
00007  *
00008  * $Id: xtag.c 11664 2005-07-09 06:17:09Z courmisch $
00009  *
00010  * Authors: Conrad Parker <[email protected]>
00011  *          Andre Pang <[email protected]>
00012  *          Gildas Bazin <[email protected]>
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU General Public License as published by
00016  * the Free Software Foundation; either version 2 of the License, or
00017  * (at your option) any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00027  *****************************************************************************/
00028 
00029 #include <stdlib.h>
00030 #include <vlc/vlc.h>
00031 
00032 #include "vlc_xml.h"
00033 #include "vlc_block.h"
00034 #include "vlc_stream.h"
00035 
00036 #include <ctype.h>
00037 #include <string.h>
00038 #include <stdarg.h>
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 
00042 #undef XTAG_DEBUG
00043 
00044 typedef struct _XList
00045 {
00046     struct _XList *prev;
00047     struct _XList *next;
00048     void *data;
00049 } XList;
00050 
00051 /*
00052  * struct XTag is kind of a union ... it normally represents a whole
00053  * tag (and its children), but it could alternatively represent some
00054  * PCDATA. Basically, if tag->pcdata is non-NULL, interpret only it and
00055  * ignore the name, attributes and inner_tags.
00056  */
00057 typedef struct _XTag
00058 {
00059     char *name;
00060     char *pcdata;
00061     struct _XTag *parent;
00062     XList *attributes;
00063     XList *children;
00064     XList *current_child;
00065 } XTag;
00066 
00067 typedef struct _XAttribute
00068 {
00069     char *name;
00070     char *value;
00071 } XAttribute;
00072 
00073 typedef struct _XTagParser
00074 {
00075     int valid; /* boolean */
00076     XTag *current_tag;
00077     char *start;
00078     char *end;
00079 } XTagParser;
00080 
00081 /*****************************************************************************
00082  * Module descriptor
00083  *****************************************************************************/
00084 static int  Open ( vlc_object_t * );
00085 static void Close( vlc_object_t * );
00086 
00087 vlc_module_begin();
00088     set_category( CAT_ADVANCED );
00089     set_subcategory( SUBCAT_ADVANCED_XML );
00090     set_description( _("Simple XML Parser") );
00091     set_capability( "xml", 5 );
00092     set_callbacks( Open, Close );
00093 vlc_module_end();
00094 
00095 struct xml_reader_sys_t
00096 {
00097     XTag *p_root; /* Root tag */
00098     XTag *p_curtag; /* Current tag */
00099     XList *p_curattr; /* Current attribute */
00100     vlc_bool_t b_endtag;
00101 };
00102 
00103 static xml_reader_t *ReaderCreate( xml_t *, stream_t * );
00104 static void ReaderDelete( xml_reader_t * );
00105 static int ReaderRead( xml_reader_t * );
00106 static int ReaderNodeType( xml_reader_t * );
00107 static char *ReaderName( xml_reader_t * );
00108 static char *ReaderValue( xml_reader_t * );
00109 static int ReaderNextAttr( xml_reader_t * );
00110 
00111 static int ReaderUseDTD ( xml_reader_t *, vlc_bool_t );
00112 
00113 static void CatalogLoad( xml_t *, const char * );
00114 static void CatalogAdd( xml_t *, const char *, const char *, const char * );
00115 
00116 static XTag *xtag_new_parse( const char *, int );
00117 static char *xtag_get_name( XTag * );
00118 static char *xtag_get_pcdata( XTag * );
00119 static char *xtag_get_attribute( XTag *, char * );
00120 static XTag *xtag_first_child( XTag *, char * );
00121 static XTag *xtag_next_child( XTag *, char * );
00122 static XTag *xtag_free( XTag * );
00123 static int xtag_snprint( char *, int, XTag * );
00124 
00125 /*****************************************************************************
00126  * Module initialization
00127  *****************************************************************************/
00128 static int Open( vlc_object_t *p_this )
00129 {
00130     xml_t *p_xml = (xml_t *)p_this;
00131 
00132     p_xml->pf_reader_create = ReaderCreate;
00133     p_xml->pf_reader_delete = ReaderDelete;
00134 
00135     p_xml->pf_catalog_load = CatalogLoad;
00136     p_xml->pf_catalog_add  = CatalogAdd;
00137 
00138     return VLC_SUCCESS;
00139 }
00140 
00141 /*****************************************************************************
00142  * Module deinitialization
00143  *****************************************************************************/
00144 static void Close( vlc_object_t *p_this )
00145 {
00146     return;
00147 }
00148 
00149 /*****************************************************************************
00150  * Catalogue functions
00151  *****************************************************************************/
00152 static void CatalogLoad( xml_t *p_xml, const char *psz_filename )
00153 {
00154     msg_Dbg( p_xml, "catalog support not implemented" );
00155 }
00156 
00157 static void CatalogAdd( xml_t *p_xml, const char *psz_arg1,
00158                           const char *psz_arg2, const char *psz_filename )
00159 {
00160 }
00161 
00162 /*****************************************************************************
00163  * Reader functions
00164  *****************************************************************************/
00165 static xml_reader_t *ReaderCreate( xml_t *p_xml, stream_t *s )
00166 {
00167     xml_reader_t *p_reader;
00168     char *p_buffer;
00169     int i_size, i_pos = 0, i_buffer = 2048;
00170     XTag *p_root;
00171 
00172     /* Open and read file */
00173     p_buffer = malloc( i_buffer );
00174     if( p_buffer == NULL ) return NULL;
00175 
00176     while( ( i_size = stream_Read( s, &p_buffer[i_pos], 2048 ) ) == 2048 )
00177     {
00178         i_pos += i_size;
00179         i_buffer += i_size;
00180         p_buffer = realloc( p_buffer, i_buffer );
00181     }
00182     p_buffer[ i_pos + i_size ] = 0; /* 0 terminated string */
00183 
00184     if( i_pos + i_size == 0 )
00185     {
00186         msg_Dbg( p_xml, "empty xml" );
00187         free( p_buffer );
00188         return 0;
00189     }
00190 
00191     p_root = xtag_new_parse( p_buffer, i_buffer );
00192     if( !p_root )
00193     {
00194         msg_Warn( p_xml, "couldn't parse xml" );
00195         free( p_buffer );
00196         return 0;
00197     }
00198 
00199     p_reader = malloc( sizeof(xml_reader_t) );
00200     p_reader->p_sys = malloc( sizeof(xml_reader_sys_t) );
00201     p_reader->p_sys->p_root = p_root;
00202     p_reader->p_sys->p_curtag = NULL;
00203     p_reader->p_sys->p_curattr = NULL;
00204     p_reader->p_sys->b_endtag = VLC_FALSE;
00205     p_reader->p_xml = p_xml;
00206 
00207     p_reader->pf_read = ReaderRead;
00208     p_reader->pf_node_type = ReaderNodeType;
00209     p_reader->pf_name = ReaderName;
00210     p_reader->pf_value = ReaderValue;
00211     p_reader->pf_next_attr = ReaderNextAttr;
00212     p_reader->pf_use_dtd = ReaderUseDTD;
00213 
00214     return p_reader;
00215 }
00216 
00217 static void ReaderDelete( xml_reader_t *p_reader )
00218 {
00219     xtag_free( p_reader->p_sys->p_root );
00220     free( p_reader->p_sys );
00221     free( p_reader );
00222 }
00223 
00224 static int ReaderUseDTD ( xml_reader_t *p_reader, vlc_bool_t b_use )
00225 {
00226     return VLC_EGENERIC;
00227 }
00228 
00229 static int ReaderRead( xml_reader_t *p_reader )
00230 {
00231     XTag *p_child;
00232 
00233     if( !p_reader->p_sys->p_curtag )
00234     {
00235         p_reader->p_sys->p_curtag = p_reader->p_sys->p_root;
00236         return 1;
00237     }
00238 
00239     while( 1 )
00240     {
00241         if( (p_child = xtag_next_child( p_reader->p_sys->p_curtag, 0 )) )
00242         {
00243             p_reader->p_sys->p_curtag = p_child;
00244             p_reader->p_sys->p_curattr = 0;
00245             p_reader->p_sys->b_endtag = VLC_FALSE;
00246             return 1;
00247         }
00248 
00249         if( p_reader->p_sys->p_curtag->name && /* no end tag for pcdata */
00250             !p_reader->p_sys->b_endtag )
00251         {
00252             p_reader->p_sys->b_endtag = VLC_TRUE;
00253             return 1;
00254         }
00255 
00256         p_reader->p_sys->b_endtag = VLC_FALSE;
00257         if( !p_reader->p_sys->p_curtag->parent ) return 0;
00258         p_reader->p_sys->p_curtag = p_reader->p_sys->p_curtag->parent;
00259     }
00260 
00261     return 0;
00262 }
00263 
00264 static int ReaderNodeType( xml_reader_t *p_reader )
00265 {
00266     if( p_reader->p_sys->p_curtag->name &&
00267         p_reader->p_sys->b_endtag ) return XML_READER_ENDELEM;
00268     if( p_reader->p_sys->p_curtag->name ) return XML_READER_STARTELEM;
00269     if( p_reader->p_sys->p_curtag->pcdata ) return XML_READER_TEXT;
00270     return XML_READER_NONE;
00271 }
00272 
00273 static char *ReaderName( xml_reader_t *p_reader )
00274 {
00275     const char *psz_name;
00276 
00277     if( !p_reader->p_sys->p_curattr )
00278     {
00279         psz_name = xtag_get_name( p_reader->p_sys->p_curtag );
00280 #ifdef XTAG_DEBUG
00281         printf( "TAG: %s\n", psz_name );
00282 #endif
00283     }
00284     else
00285         psz_name = ((XAttribute *)p_reader->p_sys->p_curattr->data)->name;
00286 
00287     if( psz_name ) return strdup( psz_name );
00288     else return 0;
00289 }
00290 
00291 static char *ReaderValue( xml_reader_t *p_reader )
00292 {
00293     const char *psz_name;
00294     if( p_reader->p_sys->p_curtag->pcdata )
00295     {
00296 #ifdef XTAG_DEBUG
00297         printf( "%s\n", p_reader->p_sys->p_curtag->pcdata );
00298 #endif
00299         return strdup( p_reader->p_sys->p_curtag->pcdata );
00300     }
00301 
00302     if( !p_reader->p_sys->p_curattr ) return 0;
00303 
00304 #ifdef XTAG_DEBUG
00305     printf( "%s=%s\n", ((XAttribute *)p_reader->p_sys->p_curattr->data)->name,
00306             ((XAttribute *)p_reader->p_sys->p_curattr->data)->value );
00307 #endif
00308 
00309     psz_name = ((XAttribute *)p_reader->p_sys->p_curattr->data)->value;
00310 
00311     if( psz_name ) return strdup( psz_name );
00312     else return 0;
00313 }
00314 
00315 static int ReaderNextAttr( xml_reader_t *p_reader )
00316 {
00317     if( !p_reader->p_sys->p_curattr )
00318         p_reader->p_sys->p_curattr = p_reader->p_sys->p_curtag->attributes;
00319     else if( p_reader->p_sys->p_curattr )
00320         p_reader->p_sys->p_curattr = p_reader->p_sys->p_curattr->next;
00321  
00322     if( p_reader->p_sys->p_curattr ) return VLC_SUCCESS;
00323     else return VLC_EGENERIC;
00324 }
00325 
00326 /*****************************************************************************
00327  * XTAG parser functions
00328  *****************************************************************************/
00329 
00330 static XList *xlist_append( XList *list, void *data )
00331 {
00332     XList *l, *last;
00333 
00334     l = (XList *)malloc( sizeof(XList) );
00335     l->prev = l->next = NULL;
00336     l->data = data;
00337 
00338     if( list == NULL ) return l;
00339 
00340     for( last = list; last; last = last->next )
00341         if( last->next == NULL ) break;
00342 
00343     if( last ) last->next = l;
00344     l->prev = last; 
00345     return list;
00346 }
00347 
00348 static void xlist_free( XList *list )
00349 {
00350     XList *l, *ln;
00351 
00352     for( l = list; l; l = ln )
00353     {
00354         ln = l->next;
00355         free( l );
00356     }
00357 }
00358 
00359 /* Character classes */
00360 #define X_NONE           0
00361 #define X_WHITESPACE  1<<0
00362 #define X_OPENTAG     1<<1
00363 #define X_CLOSETAG    1<<2
00364 #define X_DQUOTE      1<<3
00365 #define X_SQUOTE      1<<4
00366 #define X_EQUAL       1<<5
00367 #define X_SLASH       1<<6
00368 #define X_QMARK       1<<7
00369 #define X_DASH        1<<8
00370 
00371 static int xtag_cin( char c, int char_class )
00372 {
00373     if( char_class & X_WHITESPACE ) if( isspace(c) ) return VLC_TRUE;
00374     if( char_class & X_OPENTAG )    if( c == '<' ) return VLC_TRUE;
00375     if( char_class & X_CLOSETAG )   if( c == '>' ) return VLC_TRUE;
00376     if( char_class & X_DQUOTE )     if( c == '"' ) return VLC_TRUE;
00377     if( char_class & X_SQUOTE )     if( c == '\'' ) return VLC_TRUE;
00378     if( char_class & X_EQUAL )      if( c == '=' ) return VLC_TRUE;
00379     if( char_class & X_SLASH )      if( c == '/' ) return VLC_TRUE;
00380     if( char_class & X_QMARK )      if( c == '!' ) return VLC_TRUE;
00381     if( char_class & X_DASH  )      if( c == '-' ) return VLC_TRUE;
00382 
00383     return VLC_FALSE;
00384 }
00385 
00386 static int xtag_index( XTagParser *parser, int char_class )
00387 {
00388     char *s = parser->start;
00389     int i;
00390 
00391     for( i = 0; s[i] && s != parser->end; i++ )
00392     {
00393         if( xtag_cin( s[i], char_class ) ) return i;
00394     }
00395 
00396     return -1;
00397 }
00398 
00399 static void xtag_skip_over( XTagParser *parser, int char_class )
00400 {
00401     char *s = parser->start;
00402     int i;
00403 
00404     if( !parser->valid ) return;
00405 
00406     for( i = 0; s[i] && s != parser->end; i++ )
00407     {
00408         if( !xtag_cin( s[i], char_class ) )
00409         {
00410             parser->start = &s[i];
00411             return;
00412         }
00413     }
00414 
00415     return;
00416 }
00417 
00418 static void xtag_skip_whitespace( XTagParser * parser )
00419 {
00420     xtag_skip_over( parser, X_WHITESPACE );
00421 }
00422 
00423 static char *xtag_slurp_to( XTagParser *parser, int good_end, int bad_end )
00424 {
00425     char *ret, *s = parser->start;
00426     int xi;
00427 
00428     if( !parser->valid ) return NULL;
00429 
00430     xi = xtag_index( parser, good_end | bad_end );
00431 
00432     if( xi > 0 && xtag_cin (s[xi], good_end) )
00433     {
00434         ret = malloc( (xi+1) * sizeof(char) );
00435         strncpy( ret, s, xi );
00436         ret[xi] = '\0';
00437         parser->start = &s[xi];
00438         return ret;
00439     }
00440 
00441     return NULL;
00442 }
00443 
00444 static int xtag_assert_and_pass( XTagParser *parser, int char_class )
00445 {
00446     char *s = parser->start;
00447 
00448     if( !parser->valid ) return VLC_FALSE;
00449 
00450     if( !xtag_cin( s[0], char_class ) )
00451     {
00452         parser->valid = VLC_FALSE;
00453         return VLC_FALSE;
00454     }
00455 
00456     parser->start = &s[1];
00457 
00458     return VLC_TRUE;
00459 }
00460 
00461 static char *xtag_slurp_quoted( XTagParser *parser )
00462 {
00463     char * ret, *s;
00464     int quote = X_DQUOTE; /* quote char to match on */
00465     int xi;
00466 
00467     if( !parser->valid ) return NULL;
00468 
00469     xtag_skip_whitespace( parser );
00470 
00471     s = parser->start;
00472 
00473     if( xtag_cin( s[0], X_SQUOTE ) ) quote = X_SQUOTE;
00474 
00475     if( !xtag_assert_and_pass( parser, quote ) ) return NULL;
00476 
00477     s = parser->start;
00478 
00479     for( xi = 0; s[xi]; xi++ )
00480     {
00481         if( xtag_cin( s[xi], quote ) )
00482         {
00483             if( !(xi > 1 && s[xi-1] == '\\') ) break;
00484         }
00485     }
00486 
00487     ret = malloc( (xi+1) * sizeof(char) );
00488     strncpy( ret, s, xi );
00489     ret[xi] = '\0';
00490     parser->start = &s[xi];
00491 
00492     if( !xtag_assert_and_pass( parser, quote ) ) return NULL;
00493 
00494     return ret;
00495 }
00496 
00497 static XAttribute *xtag_parse_attribute( XTagParser *parser )
00498 {
00499     XAttribute *attr;
00500     char *name, *value;
00501     char *s;
00502 
00503     if( !parser->valid ) return NULL;
00504 
00505     xtag_skip_whitespace( parser );
00506  
00507     name = xtag_slurp_to( parser, X_WHITESPACE|X_EQUAL, X_SLASH|X_CLOSETAG );
00508     if( name == NULL ) return NULL;
00509 
00510     xtag_skip_whitespace( parser );
00511     s = parser->start;
00512 
00513     if( !xtag_assert_and_pass( parser, X_EQUAL ) )
00514     {
00515 #ifdef XTAG_DEBUG
00516         printf( "xtag: attr failed EQUAL on <%s>\n", name );
00517 #endif
00518         goto err_free_name;
00519     }
00520 
00521     xtag_skip_whitespace( parser );
00522 
00523     value = xtag_slurp_quoted( parser );
00524 
00525     if( value == NULL )
00526     {
00527 #ifdef XTAG_DEBUG
00528         printf ("Got NULL quoted attribute value\n");
00529 #endif
00530         goto err_free_name;
00531     }
00532 
00533     attr = malloc( sizeof (*attr) );
00534     attr->name = name;
00535     attr->value = value;
00536     return attr;
00537 
00538  err_free_name:
00539     free (name);
00540     parser->valid = VLC_FALSE;
00541     return NULL;
00542 }
00543 
00544 static XTag *xtag_parse_tag( XTagParser *parser )
00545 {
00546     XTag *tag, *inner;
00547     XAttribute *attr;
00548     char *name;
00549     char *pcdata;
00550     char *s;
00551 
00552     if( !parser->valid ) return NULL;
00553 
00554 #if 0 /* Do we really want all the whitespace pcdata ? */
00555     xtag_skip_whitespace( parser );
00556 #endif
00557 
00558     if( (pcdata = xtag_slurp_to( parser, X_OPENTAG, X_NONE )) != NULL )
00559     {
00560         tag = malloc( sizeof(*tag) );
00561         tag->name = NULL;
00562         tag->pcdata = pcdata;
00563         tag->parent = parser->current_tag;
00564         tag->attributes = NULL;
00565         tag->children = NULL;
00566         tag->current_child = NULL;
00567 
00568         return tag;
00569     }
00570 
00571     s = parser->start;
00572 
00573     /* if this starts a close tag, return NULL and let the parent take it */
00574     if( xtag_cin( s[0], X_OPENTAG ) && xtag_cin( s[1], X_SLASH ) )
00575         return NULL;
00576 
00577     /* if this starts a comment tag, skip until end */
00578     if( xtag_cin( s[0], X_OPENTAG ) && xtag_cin( s[1], X_QMARK ) &&
00579         xtag_cin( s[2], X_DASH ) && xtag_cin( s[3], X_DASH ) )
00580     {
00581         int xi;
00582 
00583         parser->start = s = &s[4];
00584 
00585         while( (xi = xtag_index( parser, X_DASH )) >= 0 )
00586         {
00587             parser->start = s = &s[xi+1];
00588 
00589             if( xtag_cin( s[0], X_DASH ) && xtag_cin( s[1], X_CLOSETAG ) )
00590             {
00591                 parser->start = &s[2];
00592                 xtag_skip_whitespace( parser );
00593                 return xtag_parse_tag( parser );
00594             }
00595         }
00596 
00597         return NULL;
00598     }
00599 
00600     /* FIXME: if this starts a DOCTYPE tag, skip until end */
00601     if( xtag_cin( s[0], X_OPENTAG ) && xtag_cin( s[1], X_QMARK ) )
00602     {
00603         int xi = xtag_index( parser, X_CLOSETAG );
00604         if( xi <= 0 ) return NULL;
00605 
00606         parser->start = &s[xi+1];
00607         xtag_skip_whitespace( parser );
00608         return xtag_parse_tag( parser );
00609     }
00610 
00611     if( !xtag_assert_and_pass( parser, X_OPENTAG ) ) return NULL;
00612 
00613     name = xtag_slurp_to( parser, X_WHITESPACE|X_SLASH|X_CLOSETAG, X_NONE );
00614     if( name == NULL ) return NULL;
00615 
00616 #ifdef XTAG_DEBUG
00617     printf ("<%s ...\n", name);
00618 #endif
00619 
00620     tag = malloc( sizeof(*tag) );
00621     tag->name = name;
00622     tag->pcdata = NULL;
00623     tag->parent = parser->current_tag;
00624     tag->attributes = NULL;
00625     tag->children = NULL;
00626     tag->current_child = NULL;
00627 
00628     s = parser->start;
00629 
00630     if( xtag_cin( s[0], X_WHITESPACE ) )
00631     {
00632         while( (attr = xtag_parse_attribute( parser )) != NULL )
00633         {
00634             tag->attributes = xlist_append( tag->attributes, attr );
00635         }
00636     }
00637 
00638     xtag_skip_whitespace( parser );
00639 
00640     s = parser->start;
00641 
00642     if( xtag_cin( s[0], X_CLOSETAG ) )
00643     {
00644         parser->current_tag = tag;
00645 
00646         xtag_assert_and_pass( parser, X_CLOSETAG );
00647 
00648         while( (inner = xtag_parse_tag( parser ) ) != NULL )
00649         {
00650             tag->children = xlist_append( tag->children, inner );
00651         }
00652 
00653         parser->current_tag = tag->parent;
00654         xtag_skip_whitespace( parser );
00655 
00656         xtag_assert_and_pass( parser, X_OPENTAG );
00657         xtag_assert_and_pass( parser, X_SLASH );
00658         name = xtag_slurp_to( parser, X_WHITESPACE | X_CLOSETAG, X_NONE );
00659         if( name )
00660         {
00661             if( strcmp( name, tag->name ) )
00662             {
00663 #ifdef XTAG_DEBUG
00664                 printf ("got %s expected %s\n", name, tag->name);
00665 #endif
00666                 parser->valid = VLC_FALSE;
00667             }
00668             free( name );
00669         }
00670 
00671         xtag_skip_whitespace( parser );
00672         xtag_assert_and_pass( parser, X_CLOSETAG );
00673 
00674     }
00675     else
00676     {
00677         xtag_assert_and_pass( parser, X_SLASH );
00678         xtag_assert_and_pass( parser, X_CLOSETAG );
00679     }
00680 
00681     return tag;
00682 }
00683 
00684 static XTag *xtag_free( XTag *xtag )
00685 {
00686     XList *l;
00687     XAttribute *attr;
00688     XTag *child;
00689 
00690     if( xtag == NULL ) return NULL;
00691 
00692     if( xtag->name ) free( xtag->name );
00693     if( xtag->pcdata ) free( xtag->pcdata );
00694 
00695     for( l = xtag->attributes; l; l = l->next )
00696     {
00697         if( (attr = (XAttribute *)l->data) != NULL )
00698         {
00699             if( attr->name ) free( attr->name );
00700             if( attr->value ) free( attr->value );
00701             free( attr );
00702         }
00703     }
00704     xlist_free( xtag->attributes );
00705 
00706     for( l = xtag->children; l; l = l->next )
00707     {
00708         child = (XTag *)l->data;
00709         xtag_free( child );
00710     }
00711     xlist_free( xtag->children );
00712 
00713     free( xtag );
00714 
00715     return NULL;
00716 }
00717 
00718 static XTag *xtag_new_parse( const char *s, int n )
00719 {
00720     XTagParser parser;
00721     XTag *tag, *ttag, *wrapper;
00722 
00723     parser.valid = VLC_TRUE;
00724     parser.current_tag = NULL;
00725     parser.start = (char *)s;
00726 
00727     if( n == -1 ) parser.end = NULL;
00728     else if( n == 0 )
00729     {
00730 #ifdef XTAG_DEBUG
00731         printf ("empty buffer");
00732 #endif        
00733         return NULL;
00734     }
00735     else parser.end = (char *)&s[n];
00736 
00737     /* can't have whitespace pcdata outside rootnode */
00738     xtag_skip_whitespace( &parser );
00739 
00740     tag = xtag_parse_tag( &parser );
00741 
00742     if( !parser.valid )
00743     {
00744 #ifdef XTAG_DEBUG
00745         printf ("invalid file");
00746 #endif
00747         xtag_free( tag );
00748         return NULL;
00749     }
00750 
00751     if( (ttag = xtag_parse_tag( &parser )) != NULL )
00752     {
00753         if( !parser.valid )
00754         {
00755             xtag_free( ttag );
00756             return tag;
00757         }
00758 
00759         wrapper = malloc( sizeof(XTag) );
00760         wrapper->name = NULL;
00761         wrapper->pcdata = NULL;
00762         wrapper->parent = NULL;
00763         wrapper->attributes = NULL;
00764         wrapper->children = NULL;
00765         wrapper->current_child = NULL;
00766 
00767         wrapper->children = xlist_append( wrapper->children, tag );
00768         wrapper->children = xlist_append( wrapper->children, ttag );
00769 
00770         while( (ttag = xtag_parse_tag( &parser )) != NULL )
00771         {
00772             if( !parser.valid )
00773             {
00774                 xtag_free( ttag );
00775                 return wrapper;
00776             }
00777 
00778             wrapper->children = xlist_append( wrapper->children, ttag );
00779         }
00780         return wrapper;
00781     }
00782 
00783     return tag;
00784 }
00785 
00786 static char *xtag_get_name( XTag *xtag )
00787 {
00788     return xtag ? xtag->name : NULL;
00789 }
00790 
00791 static char *xtag_get_pcdata( XTag *xtag )
00792 {
00793     XList *l;
00794     XTag *child;
00795 
00796     if( xtag == NULL ) return NULL;
00797 
00798     for( l = xtag->children; l; l = l->next )
00799     {
00800         child = (XTag *)l->data;
00801         if( child->pcdata != NULL )
00802         {
00803             return child->pcdata;
00804         }
00805     }
00806 
00807     return NULL;
00808 }
00809 
00810 static char *xtag_get_attribute( XTag *xtag, char *attribute )
00811 {
00812     XList *l;
00813     XAttribute *attr;
00814 
00815     if( xtag == NULL ) return NULL;
00816 
00817     for( l = xtag->attributes; l; l = l->next )
00818     {
00819         if( (attr = (XAttribute *)l->data) != NULL )
00820         {
00821             if( !strcmp( attr->name, attribute ) ) return attr->value;
00822         }
00823     }
00824 
00825     return NULL;
00826 }
00827 
00828 static XTag *xtag_first_child( XTag *xtag, char *name )
00829 {
00830     XList *l;
00831     XTag *child;
00832 
00833     if( xtag == NULL ) return NULL;
00834     if( (l = xtag->children) == NULL ) return NULL;
00835 
00836     if( name == NULL )
00837     {
00838         xtag->current_child = l;
00839         return (XTag *)l->data;
00840     }
00841 
00842     for( ; l; l = l->next )
00843     {
00844         child = (XTag *)l->data;
00845 
00846         if( !strcmp( child->name, name ) )
00847         {
00848             xtag->current_child = l;
00849             return child;
00850         }
00851     }
00852 
00853     xtag->current_child = NULL;
00854 
00855     return NULL;
00856 }
00857 
00858 static XTag *xtag_next_child( XTag *xtag, char *name )
00859 {
00860     XList *l;
00861     XTag *child;
00862 
00863     if( xtag == NULL ) return NULL;
00864 
00865     if( (l = xtag->current_child) == NULL )
00866         return xtag_first_child( xtag, name );
00867 
00868     if( (l = l->next) == NULL ) return NULL;
00869 
00870     if( name == NULL )
00871     {
00872         xtag->current_child = l;
00873         return (XTag *)l->data;
00874     }
00875 
00876     for( ; l; l = l->next )
00877     {
00878         child = (XTag *)l->data;
00879 
00880         if( !strcmp( child->name, name ) )
00881         {
00882             xtag->current_child = l;
00883             return child;
00884         }
00885     }
00886 
00887     xtag->current_child = NULL;
00888 
00889     return NULL;
00890 }
00891 
00892 /*
00893  * This snprints function takes a variable list of char *, the last of
00894  * which must be NULL, and prints each in turn to buf.
00895  * Returns C99-style total length that would have been written, even if
00896  * this is larger than n.
00897  */
00898 static int xtag_snprints( char *buf, int n, ... )
00899 {
00900     va_list ap;
00901     char *s;
00902     int len, to_copy, total = 0;
00903 
00904     va_start( ap, n );
00905   
00906     for( s = va_arg( ap, char * ); s; s = va_arg( ap, char *) )
00907     {
00908         len = strlen (s);
00909 
00910         if( (to_copy = __MIN(n, len) ) > 0 )
00911         {
00912             memcpy( buf, s, to_copy );
00913             buf += to_copy;
00914             n -= to_copy;
00915         }
00916 
00917         total += len;
00918     }
00919 
00920     va_end( ap );
00921 
00922     return total;
00923 }
00924 
00925 static int xtag_snprint( char *buf, int n, XTag *xtag )
00926 {
00927     int nn, written = 0;
00928     XList *l;
00929     XAttribute *attr;
00930     XTag *child;
00931 
00932 #define FORWARD(N) \
00933     buf += __MIN(n, N); \
00934     n = __MAX(n-N, 0);  \
00935     written += N;
00936 
00937     if( xtag == NULL )
00938     {
00939         if( n > 0 ) buf[0] = '\0';
00940         return 0;
00941     }
00942 
00943     if( xtag->pcdata )
00944     {
00945         nn = xtag_snprints( buf, n, xtag->pcdata, NULL );
00946         FORWARD( nn );
00947 
00948         return written;
00949     }
00950 
00951     if( xtag->name )
00952     {
00953         nn = xtag_snprints( buf, n, "<", xtag->name, NULL );
00954         FORWARD( nn );
00955 
00956         for( l = xtag->attributes; l; l = l->next )
00957         {
00958             attr = (XAttribute *)l->data;
00959       
00960             nn = xtag_snprints( buf, n, " ", attr->name, "=\"", attr->value,
00961                                 "\"", NULL);
00962             FORWARD( nn );
00963         }
00964 
00965         if( xtag->children == NULL )
00966         {
00967             nn = xtag_snprints ( buf, n, "/>", NULL );
00968             FORWARD( nn );
00969 
00970             return written;
00971         }
00972 
00973         nn = xtag_snprints( buf, n, ">", NULL );
00974         FORWARD( nn );
00975     }
00976 
00977     for( l = xtag->children; l; l = l->next )
00978     {
00979         child = (XTag *)l->data;
00980 
00981         nn = xtag_snprint( buf, n, child );
00982         FORWARD( nn );
00983     }
00984 
00985     if( xtag->name )
00986     {
00987         nn = xtag_snprints( buf, n, "</", xtag->name, ">", NULL );
00988         FORWARD( nn );
00989     }
00990 
00991     return written;
00992 }

Generated on Tue Dec 20 10:14:28 2005 for vlc-0.8.4a by  doxygen 1.4.2