From: Gildas Bazin Date: Fri, 26 Nov 2004 10:04:08 +0000 (+0000) Subject: * ALL: New XML module type. X-Git-Tag: 0.8.2~1602 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=6d51bbdccb9b0ff857ddb9684479cd9fee393fb7;p=vlc * ALL: New XML module type. * include/vlc_xml.h, src/misc/xml.c: core wrapper for XML modules. * modules/misc/xml/xtag.c: trivial XML parser module. * modules/misc/xml/libxml.c: XML parser module using libxml2. * modules/gui/skins2/parser/*: removed dependancy on libxml2 and use an XML module. --- diff --git a/Makefile.am b/Makefile.am index 08788b731e..f7fd34eb78 100644 --- a/Makefile.am +++ b/Makefile.am @@ -116,6 +116,7 @@ HEADERS_include = \ include/vlc_video.h \ include/vlc_vlm.h \ include/vlc_vod.h \ + include/vlc_xml.h \ include/vout_synchro.h \ include/win32_specific.h \ $(NULL) @@ -376,6 +377,7 @@ SOURCES_libvlc_common = \ src/misc/error.c \ src/misc/net.c \ src/misc/vlm.c \ + src/misc/xml.c \ src/extras/libc.c \ $(NULL) diff --git a/configure.ac b/configure.ac index bf44b8b1f1..a75d469e64 100644 --- a/configure.ac +++ b/configure.ac @@ -444,7 +444,7 @@ AM_CONDITIONAL(BUILD_GETOPT, ${need_getopt}) if test "${SYS}" != "mingw32"; then AC_TYPE_SIGNAL AC_CHECK_LIB(m,cos,[ - VLC_ADD_LDFLAGS([adjust distort a52tofloat32 dtstofloat32 x264],[-lm]) + VLC_ADD_LDFLAGS([adjust distort a52tofloat32 dtstofloat32 x264 goom],[-lm]) ]) AC_CHECK_LIB(m,pow,[ VLC_ADD_LDFLAGS([ffmpeg ffmpegaltivec stream_out_transrate i420_rgb faad toolame equalizer vlc],[-lm]) @@ -954,7 +954,7 @@ VLC_ADD_PLUGINS([trivial_channel_mixer simple_channel_mixer headphone_channel_mi VLC_ADD_PLUGINS([trivial_mixer spdif_mixer float32_mixer]) VLC_ADD_PLUGINS([aout_file equalizer]) VLC_ADD_PLUGINS([i420_rgb i420_yuy2 i422_yuy2 i420_ymga]) -VLC_ADD_PLUGINS([id3 playlist export sgimb m3u]) +VLC_ADD_PLUGINS([id3 playlist export sgimb m3u xtag]) VLC_ADD_PLUGINS([rawvideo blend scale time marq]) VLC_ADD_PLUGINS([wav araw subtitle vobsub adpcm a52sys dtssys au]) VLC_ADD_PLUGINS([access_file access_udp access_tcp access_http ipv4 access_mms]) @@ -2857,6 +2857,39 @@ from http://www.freetype.org/, or configure with --disable-freetype. Have a nice fi fi +dnl +dnl libxml2 module +dnl +AC_ARG_ENABLE(libxml2, + [ --enable-libxml2 libxml2 support (default enabled)]) +if test "${enable_libxml2}" != "no" +then + XML2_PATH="${PATH}" + AC_ARG_WITH(xml2-config-path, + [ --with-xml2-config-path=PATH xml2-config path (default search in \$PATH)], + [ if test "${with_xml2_config_path}" != "no"; then + XML2_PATH="${with_xml2_config_path}:${PATH}" + fi ]) + AC_PATH_PROG(XML2_CONFIG, xml2-config, no, ${XML2_PATH}) + if test "${XML2_CONFIG}" != "no"; then + VLC_ADD_CPPFLAGS([xml],[`${XML2_CONFIG} --cflags`]) + VLC_ADD_LDFLAGS([xml],[`${XML2_CONFIG} --libs`]) + dnl depends on the xmlTextReader extension + LDFLAGS="${LDFLAGS_save} ${LDFLAGS_xml}" + AC_CHECK_LIB(xml2,xmlTextReaderConstName,[ + VLC_ADD_PLUGINS([xml]) ],[ + AC_MSG_WARN([libxml2 missing the xmlTextReader extension, you should update your version]) + if test "${enable_xml2}" = "yes"; then + AC_MSG_ERROR([libxml2 missing the xmlTextReader extension]) + fi]) + LDFLAGS="${LDFLAGS_save}" + else + if test "${enable_xml2}" = "yes"; then + AC_MSG_ERROR([Could not find libxml2]) + fi + fi +fi + dnl dnl SVG module dnl @@ -3278,33 +3311,6 @@ if test "${enable_skins2}" = "yes" || (test "${SYS}" != "darwin" && test "${SYS} fi fi - dnl libxml2 - XML2_PATH="${PATH}" - AC_ARG_WITH(xml2-config-path, - [ --with-xml2-config-path=PATH xml2-config path (default search in \$PATH)], - [ if test "${with_xml2_config_path}" != "no"; then - XML2_PATH="${with_xml2_config_path}:${PATH}" - fi ]) - AC_PATH_PROG(XML2_CONFIG, xml2-config, no, ${XML2_PATH}) - if test "${XML2_CONFIG}" != "no"; then - VLC_ADD_CPPFLAGS([skins2],[`${XML2_CONFIG} --cflags`]) - VLC_ADD_LDFLAGS([skins2],[`${XML2_CONFIG} --libs`]) - dnl skins2 depends on the xmlTextReader extension - LDFLAGS="${LDFLAGS_save} ${LDFLAGS_skins2}" - AC_CHECK_LIB(xml2,xmlTextReaderConstName,[],[ - skins2_missing_lib="yes" - AC_MSG_WARN([libxml2 missing the xmlTextReader extension, you should update your version; maybe you are missing libpng.]) - if test "${enable_skins2}" = "yes"; then - AC_MSG_ERROR([libxml2 missing the xmlTextReader extension (required for skins2)]) - fi]) - LDFLAGS="${LDFLAGS_save}" - else - skins2_missing_lib="yes" - if test "${enable_skins2}" = "yes"; then - AC_MSG_ERROR([Could not find libxml2 (required for skins2)]) - fi - fi - if test "${skins2_missing_lib}" = "no" && (test "${SYS}" = "mingw32" -o "${SYS}" = "cygwin"); then VLC_ADD_PLUGINS([skins2]) ALIASES="${ALIASES} svlc" @@ -3736,12 +3742,14 @@ then fi else AC_CHECK_HEADERS(goom/goom.h, [ + LDFLAGS="${LDFLAGS_save} ${LDFLAGS_goom}" AC_CHECK_LIB(goom2, goom_init, [ VLC_ADD_PLUGINS([goom]) VLC_ADD_LDFLAGS([goom],[-lgoom2]) ],[ AC_MSG_ERROR([Could not find goom on your system: you may get it from http://www.ios-software.com/.]) ]) + LDFLAGS="${LDFLAGS_save}" ]) fi fi @@ -4225,6 +4233,7 @@ AC_CONFIG_FILES([ modules/misc/network/Makefile modules/misc/testsuite/Makefile modules/misc/playlist/Makefile + modules/misc/xml/Makefile modules/mux/Makefile modules/mux/mpeg/Makefile modules/packetizer/Makefile diff --git a/include/vlc_common.h b/include/vlc_common.h index a37a6db281..1b03a8531c 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -370,6 +370,12 @@ typedef struct tls_t tls_t; typedef struct tls_server_t tls_server_t; typedef struct tls_session_t tls_session_t; +/* XML */ +typedef struct xml_t xml_t; +typedef struct xml_sys_t xml_sys_t; +typedef struct xml_reader_t xml_reader_t; +typedef struct xml_reader_sys_t xml_reader_sys_t; + /* vod server */ typedef struct vod_t vod_t; typedef struct vod_sys_t vod_sys_t; diff --git a/include/vlc_objects.h b/include/vlc_objects.h index b3965902ff..52265d88a4 100644 --- a/include/vlc_objects.h +++ b/include/vlc_objects.h @@ -58,6 +58,7 @@ #define VLC_OBJECT_SPU (-24) #define VLC_OBJECT_TLS (-25) #define VLC_OBJECT_SD (-26) +#define VLC_OBJECT_XML (-27) #define VLC_OBJECT_GENERIC (-666) diff --git a/include/vlc_xml.h b/include/vlc_xml.h new file mode 100644 index 0000000000..0788f33f47 --- /dev/null +++ b/include/vlc_xml.h @@ -0,0 +1,75 @@ +/***************************************************************************** + * xml.h + ***************************************************************************** + * Copyright (C) 2004 VideoLAN + * $Id$ + * + * Author: Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#ifndef _VLC_XML_H +#define _VLC_XML_H + +struct xml_t +{ + VLC_COMMON_MEMBERS + + /* Module properties */ + module_t *p_module; + xml_sys_t *p_sys; + + xml_reader_t * (*pf_reader_create) ( xml_t *, const char * ); + void (*pf_reader_delete) ( xml_reader_t * ); + + void (*pf_catalog_load) ( xml_t *, const char * ); + void (*pf_catalog_add) ( xml_t *, const char *, const char *, + const char * ); +}; + +#define xml_Create( a ) __xml_Create( VLC_OBJECT(a) ) +VLC_EXPORT( xml_t *, __xml_Create, ( vlc_object_t * ) ); +VLC_EXPORT( void, xml_Delete, ( xml_t * ) ); + +#define xml_ReaderCreate( a, b ) a->pf_reader_create( a, b ) +#define xml_ReaderDelete( a, b ) a->pf_reader_delete( b ) +#define xml_CatalogLoad( a, b ) a->pf_catalog_load( a, b ) +#define xml_CatalogAdd( a, b, c, d ) a->pf_catalog_add( a, b, c, d ) + +struct xml_reader_t +{ + xml_t *p_xml; + xml_reader_sys_t *p_sys; + + int (*pf_read) ( xml_reader_t * ); + int (*pf_node_type) ( xml_reader_t * ); + char * (*pf_name) ( xml_reader_t * ); + char * (*pf_value) ( xml_reader_t * ); + int (*pf_next_attr) ( xml_reader_t * ); +}; + +#define xml_ReaderRead( a ) a->pf_read( a ) +#define xml_ReaderNodeType( a ) a->pf_node_type( a ) +#define xml_ReaderName( a ) a->pf_name( a ) +#define xml_ReaderValue( a ) a->pf_value( a ) +#define xml_ReaderNextAttr( a ) a->pf_next_attr( a ) + +#define XML_READER_NONE 0 +#define XML_READER_STARTELEM 1 +#define XML_READER_ENDELEM 2 +#define XML_READER_TEXT 3 + +#endif diff --git a/modules/gui/skins2/parser/skin_parser.cpp b/modules/gui/skins2/parser/skin_parser.cpp index dbf2e76282..c7b85f964f 100644 --- a/modules/gui/skins2/parser/skin_parser.cpp +++ b/modules/gui/skins2/parser/skin_parser.cpp @@ -22,80 +22,36 @@ *****************************************************************************/ #include "skin_parser.hpp" -#include "../src/os_factory.hpp" #include -#include -#include - -// Current DTD version -#define SKINS_DTD_VERSION "2.0" - -// Static variable to avoid initializing catalogs twice -bool SkinParser::m_initialized = false; - SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName, const string &rPath ): XMLParser( pIntf, rFileName ), m_xOffset( 0 ), m_yOffset( 0 ), m_path( rPath ) { - // Avoid duplicate initialization (mutex needed ?) - if( !m_initialized ) - { - // Get the resource path and look for the DTD - OSFactory *pOSFactory = OSFactory::instance( getIntf() ); - const list &resPath = pOSFactory->getResourcePath(); - const string &sep = pOSFactory->getDirSeparator(); - list::const_iterator it; - struct stat statBuf; - - // Try to load the catalog first (needed at least on win32 where - // we don't have a default catalog) - for( it = resPath.begin(); it != resPath.end(); it++ ) - { - string catalog_path = (*it) + sep + "skin.catalog"; - if( !stat( catalog_path.c_str(), &statBuf ) ) - { - msg_Dbg( getIntf(), "Using catalog %s", catalog_path.c_str() ); - xmlLoadCatalog( catalog_path.c_str() ); - break; - } - } - if( it == resPath.end() ) - { - // Ok, try the default one - xmlInitializeCatalog(); - } - - for( it = resPath.begin(); it != resPath.end(); it++ ) - { - string path = (*it) + sep + "skin.dtd"; - if( !stat( path.c_str(), &statBuf ) ) - { - // DTD found - msg_Dbg( getIntf(), "Using DTD %s", path.c_str() ); - - // Add an entry in the default catalog - xmlCatalogAdd( (xmlChar*)"public", - (xmlChar*)("-//VideoLAN//DTD VLC Skins V" - SKINS_DTD_VERSION "//EN"), - (xmlChar*)path.c_str() ); - break; - } - } - if( it == resPath.end() ) - { - msg_Err( getIntf(), "Cannot find the skins DTD !"); - } - m_initialized = true; - } } void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) { +#define CheckDefault( a, b ) \ + if( attr.find(a) == attr.end() ) attr[a] = strdup(b); +#define RequireDefault( a ) \ + if( attr.find(a) == attr.end() ) \ + { \ + msg_Err( getIntf(), "Bad theme (element: %s, missing attribute: %s)", \ + rName.c_str(), a ); \ + m_errors = true; return; \ + } + if( rName == "Anchor" ) { + RequireDefault( "priority" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "points", "(0,0)" ); + CheckDefault( "range", "10" ); + const BuilderData::Anchor anchor( atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, atoi( attr["range"] ), atoi( attr["priority"] ), attr["points"], m_curLayoutId ); @@ -104,6 +60,10 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Bitmap" ) { + RequireDefault( "id" ); + RequireDefault( "file" ); + RequireDefault( "alphacolor" ); + const BuilderData::Bitmap bitmap( uniqueId( attr["id"] ), convertFileName( attr["file"] ), convertColor( attr["alphacolor"] ) ); @@ -112,6 +72,10 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "BitmapFont" ) { + RequireDefault( "id" ); + RequireDefault( "file" ); + CheckDefault( "type", "digits" ); + const BuilderData::BitmapFont font( uniqueId( attr["id"] ), convertFileName( attr["file"] ), attr["type"] ); @@ -120,10 +84,24 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Button" ) { - const BuilderData::Button button( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], - attr["rightbottom"], attr["visible"], attr["up"], attr["down"], - attr["over"], attr["action"], attr["tooltiptext"], attr["help"], + RequireDefault( "up" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "down", "none" ); + CheckDefault( "over", "none" ); + CheckDefault( "action", "none" ); + CheckDefault( "tooltiptext", "" ); + CheckDefault( "help", "" ); + + const BuilderData::Button button( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["lefttop"], attr["rightbottom"], attr["visible"], + attr["up"], attr["down"], attr["over"], attr["action"], + attr["tooltiptext"], attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; m_data.m_listButton.push_back( button ); @@ -131,9 +109,29 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Checkbox" ) { - const BuilderData::Checkbox checkbox( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], - attr["rightbottom"], attr["visible"], attr["up1"], attr["down1"], attr["over1"], + RequireDefault( "up1" ); + RequireDefault( "up2" ); + RequireDefault( "state" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "down1", "none" ); + CheckDefault( "over1", "none" ); + CheckDefault( "down2", "none" ); + CheckDefault( "over2", "none" ); + CheckDefault( "action1", "none" ); + CheckDefault( "action2", "none" ); + CheckDefault( "tooltiptext1", "" ); + CheckDefault( "tooltiptext2", "" ); + CheckDefault( "help", "" ); + + const BuilderData::Checkbox checkbox( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["lefttop"], attr["rightbottom"], attr["visible"], + attr["up1"], attr["down1"], attr["over1"], attr["up2"], attr["down2"], attr["over2"], attr["state"], attr["action1"], attr["action2"], attr["tooltiptext1"], attr["tooltiptext2"], attr["help"], m_curLayer, m_curWindowId, @@ -144,6 +142,10 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Font" ) { + RequireDefault( "id" ); + RequireDefault( "file" ); + CheckDefault( "size", "12" ); + const BuilderData::Font fontData( uniqueId( attr["id"] ), convertFileName( attr["file"] ), atoi( attr["size"] ) ); @@ -152,6 +154,9 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Group" ) { + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + m_xOffset += atoi( attr["x"] ); m_yOffset += atoi( attr["y"] ); m_xOffsetList.push_back( atoi( attr["x"] ) ); @@ -160,9 +165,19 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Image" ) { - const BuilderData::Image imageData( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], - attr["rightbottom"], attr["visible"], + RequireDefault( "image" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "action", "none" ); + CheckDefault( "help", "" ); + + const BuilderData::Image imageData( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["lefttop"], attr["rightbottom"], attr["visible"], attr["image"], attr["action"], attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; @@ -171,6 +186,14 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Layout" ) { + RequireDefault( "width" ); + RequireDefault( "height" ); + CheckDefault( "id", "none" ); + CheckDefault( "minwidth", "-1" ); + CheckDefault( "maxwidth", "-1" ); + CheckDefault( "minheight", "-1" ); + CheckDefault( "maxheight", "-1" ); + m_curLayoutId = uniqueId( attr["id"] ); const BuilderData::Layout layout( m_curLayoutId, atoi( attr["width"] ), atoi( attr["height"] ), atoi( attr["minwidth"] ), @@ -182,6 +205,22 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Playlist" ) { + RequireDefault( "id" ); + RequireDefault( "font" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "fgcolor", "#000000" ); + CheckDefault( "playcolor", "#FF0000" ); + CheckDefault( "bgcolor1", "#FFFFFF" ); + CheckDefault( "bgcolor2", "#FFFFFF" ); + CheckDefault( "selcolor", "#0000FF" ); + CheckDefault( "help", "" ); + m_curListId = uniqueId( attr["id"] ); const BuilderData::List listData( m_curListId, atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["visible"], @@ -199,11 +238,25 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "RadialSlider" ) { + RequireDefault( "sequence" ); + RequireDefault( "nbimages" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "minangle", "0" ); + CheckDefault( "maxangle", "360" ); + CheckDefault( "value", "none" ); + CheckDefault( "tooltiptext", "" ); + CheckDefault( "help", "" ); + const BuilderData::RadialSlider radial( uniqueId( attr["id"] ), attr["visible"], atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], attr["rightbottom"], attr["sequence"], - atoi( attr["nbImages"] ), atof( attr["minAngle"] ) * M_PI / 180, + atoi( attr["nbImages"] ), atof( attr["minAngle"] ) * M_PI /180, atof( attr["maxAngle"] ) * M_PI / 180, attr["value"], attr["tooltiptext"], attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); @@ -213,6 +266,23 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Slider" ) { + RequireDefault( "up" ); + RequireDefault( "points" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "down", "none" ); + CheckDefault( "over", "none" ); + CheckDefault( "thickness", "10" ); + CheckDefault( "value", "none" ); + CheckDefault( "tooltiptext", "" ); + CheckDefault( "help", "" ); + string newValue = attr["value"]; if( m_curListId != "" ) { @@ -232,6 +302,16 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Text" ) { + RequireDefault( "font" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "text", "" ); + CheckDefault( "color", "#000000" ); + CheckDefault( "width", "0" ); + CheckDefault( "help", "" ); + const BuilderData::Text textData( uniqueId( attr["id"] ), atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["visible"], attr["font"], @@ -244,6 +324,12 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Theme" ) { + RequireDefault( "version" ); + CheckDefault( "tooltipfont", "defaultfont" ); + CheckDefault( "magnet", "15" ); + CheckDefault( "alpha", "255" ); + CheckDefault( "movealpha", "255" ); + // Check the version if( strcmp( attr["version"], SKINS_DTD_VERSION ) ) { @@ -267,6 +353,16 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Video" ) { + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "help", "" ); + const BuilderData::Video videoData( uniqueId( attr["id"] ), atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, atoi( attr["width"] ), atoi( attr["height" ]), @@ -279,6 +375,13 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Window" ) { + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "dragdrop", "true" ); + CheckDefault( "playondrop", "true" ); + m_curWindowId = uniqueId( attr["id"] ); const BuilderData::Window window( m_curWindowId, atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, @@ -391,4 +494,3 @@ const string SkinParser::uniqueId( const string &id ) return newId; } - diff --git a/modules/gui/skins2/parser/skin_parser.hpp b/modules/gui/skins2/parser/skin_parser.hpp index 812bc258b4..aa18d38087 100644 --- a/modules/gui/skins2/parser/skin_parser.hpp +++ b/modules/gui/skins2/parser/skin_parser.hpp @@ -40,8 +40,6 @@ class SkinParser: public XMLParser const BuilderData &getData() const { return m_data; } private: - // Static variable to avoid initializing catalogs twice - static bool m_initialized; /// Container for mapping data from the XML BuilderData m_data; /// Current IDs diff --git a/modules/gui/skins2/parser/xmlparser.cpp b/modules/gui/skins2/parser/xmlparser.cpp index a1dee47110..37ff58e998 100644 --- a/modules/gui/skins2/parser/xmlparser.cpp +++ b/modules/gui/skins2/parser/xmlparser.cpp @@ -22,110 +22,157 @@ *****************************************************************************/ #include "xmlparser.hpp" +#include "../src/os_factory.hpp" + +#include + +// Static variable to avoid initializing catalogs twice +static bool m_initialized = false; XMLParser::XMLParser( intf_thread_t *pIntf, const string &rFileName ): SkinObject( pIntf ) { - m_pReader = xmlNewTextReaderFilename( rFileName.c_str() ); + m_pXML = xml_Create( pIntf ); + if( !m_pXML ) + { + msg_Err( getIntf(), "Failed to open XML parser" ); + m_pReader = NULL; + return; + } + + // Avoid duplicate initialization (mutex needed ?) + if( !m_initialized ) + { + LoadCatalog(); + m_initialized = true; + } + + m_pReader = xml_ReaderCreate( m_pXML, rFileName.c_str() ); if( !m_pReader ) { msg_Err( getIntf(), "Failed to open %s for parsing", rFileName.c_str() ); return; } +} - // Activate DTD validation - xmlTextReaderSetParserProp( m_pReader, XML_PARSER_DEFAULTATTRS, 1 ); - xmlTextReaderSetParserProp( m_pReader, XML_PARSER_VALIDATE, 1 ); - // Set the error handler - xmlTextReaderSetErrorHandler( m_pReader, handleError, this ); +XMLParser::~XMLParser() +{ + if( m_pReader && m_pXML ) xml_ReaderDelete( m_pXML, m_pReader ); + if( m_pXML ) xml_Delete( m_pXML ); } -XMLParser::~XMLParser() +void XMLParser::LoadCatalog() { - if( m_pReader ) + // Get the resource path and look for the DTD + OSFactory *pOSFactory = OSFactory::instance( getIntf() ); + const list &resPath = pOSFactory->getResourcePath(); + const string &sep = pOSFactory->getDirSeparator(); + list::const_iterator it; + struct stat statBuf; + + // Try to load the catalog first (needed at least on win32 where + // we don't have a default catalog) + for( it = resPath.begin(); it != resPath.end(); it++ ) + { + string catalog_path = (*it) + sep + "skin.catalog"; + if( !stat( catalog_path.c_str(), &statBuf ) ) + { + msg_Dbg( getIntf(), "Using catalog %s", catalog_path.c_str() ); + xml_CatalogLoad( m_pXML, catalog_path.c_str() ); + break; + } + } + if( it == resPath.end() ) { - xmlFreeTextReader( m_pReader ); + // Ok, try the default one + xml_CatalogLoad( m_pXML, 0 ); } -} + for( it = resPath.begin(); it != resPath.end(); it++ ) + { + string path = (*it) + sep + "skin.dtd"; + if( !stat( path.c_str(), &statBuf ) ) + { + // DTD found + msg_Dbg( getIntf(), "Using DTD %s", path.c_str() ); -bool XMLParser::parse() -{ - if( !m_pReader ) + // Add an entry in the default catalog + xml_CatalogAdd( m_pXML, "public", + "-//VideoLAN//DTD VLC Skins V" + SKINS_DTD_VERSION "//EN", path.c_str() ); + break; + } + } + if( it == resPath.end() ) { - return false; + msg_Err( getIntf(), "Cannot find the skins DTD !"); } +} + +bool XMLParser::parse() +{ + if( !m_pReader ) return false; m_errors = false; - int ret = xmlTextReaderRead( m_pReader ); - while (ret == 1) + int ret = xml_ReaderRead( m_pReader ); + while( ret == 1 ) { - if( m_errors ) - { - return false; - } + if( m_errors ) return false; + // Get the node type - int type = xmlTextReaderNodeType( m_pReader ); - switch (type ) + int type = xml_ReaderNodeType( m_pReader ); + switch( type ) { // Error case -1: return false; break; - // Begin element - case 1: + case XML_READER_STARTELEM: { // Read the element name - const xmlChar *eltName = xmlTextReaderConstName( m_pReader ); - if( !eltName ) - { - return false; - } + char *eltName = xml_ReaderName( m_pReader ); + if( !eltName ) return false; + // Read the attributes AttrList_t attributes; - while( xmlTextReaderMoveToNextAttribute( m_pReader ) == 1 ) + while( xml_ReaderNextAttr( m_pReader ) == VLC_SUCCESS ) + { + char *name = xml_ReaderName( m_pReader ); + char *value = xml_ReaderValue( m_pReader ); + if( !name || !value ) return false; + attributes[name] = value; + } + + handleBeginElement( eltName, attributes ); + + map ::iterator it = + attributes.begin(); + while( it != attributes.end() ) { - const xmlChar *name = xmlTextReaderConstName( m_pReader ); - const xmlChar *value = xmlTextReaderConstValue( m_pReader ); - if( !name || !value ) - { - return false; - } - attributes[(const char*)name] = (const char*)value; + free( (char *)it->second ); + it++; } - handleBeginElement( (const char*)eltName, attributes); break; } // End element - case 15: + case XML_READER_ENDELEM: + { // Read the element name - const xmlChar *eltName = xmlTextReaderConstName( m_pReader ); - if( !eltName ) - { - return false; - } - handleEndElement( (const char*)eltName ); + char *eltName = xml_ReaderName( m_pReader ); + if( !eltName ) return false; + + handleEndElement( eltName ); + free( eltName ); break; + } } - ret = xmlTextReaderRead( m_pReader ); + ret = xml_ReaderRead( m_pReader ); } return (ret == 0 && !m_errors ); } - - -void XMLParser::handleError( void *pArg, const char *pMsg, - xmlParserSeverities severity, - xmlTextReaderLocatorPtr locator) -{ - XMLParser *pThis = (XMLParser*)pArg; - int line = xmlTextReaderLocatorLineNumber( locator ); - msg_Err( pThis->getIntf(), "XML parser error (line %d) : %s", line, pMsg ); - pThis->m_errors = true; -} - diff --git a/modules/gui/skins2/parser/xmlparser.hpp b/modules/gui/skins2/parser/xmlparser.hpp index d57696266e..a4c3f11de0 100644 --- a/modules/gui/skins2/parser/xmlparser.hpp +++ b/modules/gui/skins2/parser/xmlparser.hpp @@ -2,7 +2,7 @@ * xmlparser.hpp ***************************************************************************** * Copyright (C) 2004 VideoLAN - * $Id: xmlparser.hpp,v 1.6 2004/03/01 19:36:43 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * @@ -25,9 +25,12 @@ #define XMLPARSER_HPP #include "../src/skin_common.hpp" -#include +#include "vlc_xml.h" #include +// Current DTD version +#define SKINS_DTD_VERSION "2.0" + /// XML parser using libxml2 text reader API class XMLParser: public SkinObject { @@ -54,17 +57,16 @@ class XMLParser: public SkinObject bool m_errors; /// Callbacks - virtual void handleBeginElement( const string &rName, AttrList_t &attr ) {} + virtual void handleBeginElement( const string &rName, + AttrList_t &attr ) {} virtual void handleEndElement( const string &rName ) {} private: - /// Reader context - xmlTextReaderPtr m_pReader; + void LoadCatalog(); - /// Callback for validation errors - static void handleError( void *pArg, const char *pMsg, - xmlParserSeverities severity, - xmlTextReaderLocatorPtr locator); + /// Reader context + xml_t *m_pXML; + xml_reader_t *m_pReader; }; #endif diff --git a/modules/gui/skins2/src/ft2_bitmap.hpp b/modules/gui/skins2/src/ft2_bitmap.hpp index b925725c3e..0201a2253a 100644 --- a/modules/gui/skins2/src/ft2_bitmap.hpp +++ b/modules/gui/skins2/src/ft2_bitmap.hpp @@ -2,7 +2,7 @@ * ft2_bitmap.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: ft2_bitmap.hpp,v 1.1 2004/01/03 23:31:33 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/logger.hpp b/modules/gui/skins2/src/logger.hpp index 837909b5d3..0b8a35c490 100644 --- a/modules/gui/skins2/src/logger.hpp +++ b/modules/gui/skins2/src/logger.hpp @@ -2,7 +2,7 @@ * logger.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: logger.hpp,v 1.1 2004/01/03 23:31:33 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/os_graphics.hpp b/modules/gui/skins2/src/os_graphics.hpp index 8866c09b3a..92bf1a518f 100644 --- a/modules/gui/skins2/src/os_graphics.hpp +++ b/modules/gui/skins2/src/os_graphics.hpp @@ -2,7 +2,7 @@ * os_graphics.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: os_graphics.hpp,v 1.1 2004/01/03 23:31:33 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/os_timer.hpp b/modules/gui/skins2/src/os_timer.hpp index d9deb213ee..ac8965590b 100644 --- a/modules/gui/skins2/src/os_timer.hpp +++ b/modules/gui/skins2/src/os_timer.hpp @@ -2,7 +2,7 @@ * os_timer.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: os_timer.hpp,v 1.1 2004/01/03 23:31:33 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/os_tooltip.hpp b/modules/gui/skins2/src/os_tooltip.hpp index 019ef5287a..8b653b15e1 100644 --- a/modules/gui/skins2/src/os_tooltip.hpp +++ b/modules/gui/skins2/src/os_tooltip.hpp @@ -2,7 +2,7 @@ * os_tooltip.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: os_tooltip.hpp,v 1.1 2004/01/03 23:31:33 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/png_bitmap.hpp b/modules/gui/skins2/src/png_bitmap.hpp index 698b1ef0a8..4b7383817f 100644 --- a/modules/gui/skins2/src/png_bitmap.hpp +++ b/modules/gui/skins2/src/png_bitmap.hpp @@ -2,7 +2,7 @@ * png_bitmap.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: png_bitmap.hpp,v 1.1 2004/01/03 23:31:33 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/scaled_bitmap.hpp b/modules/gui/skins2/src/scaled_bitmap.hpp index c10afe3c52..640512b442 100644 --- a/modules/gui/skins2/src/scaled_bitmap.hpp +++ b/modules/gui/skins2/src/scaled_bitmap.hpp @@ -2,7 +2,7 @@ * scaled_bitmap.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: scaled_bitmap.hpp,v 1.1 2004/01/03 23:31:34 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/gui/skins2/src/tooltip.hpp b/modules/gui/skins2/src/tooltip.hpp index 6084887713..040a4fc758 100644 --- a/modules/gui/skins2/src/tooltip.hpp +++ b/modules/gui/skins2/src/tooltip.hpp @@ -2,7 +2,7 @@ * tooltip.hpp ***************************************************************************** * Copyright (C) 2003 VideoLAN - * $Id: tooltip.hpp,v 1.1 2004/01/03 23:31:34 asmax Exp $ + * $Id$ * * Authors: Cyril Deguet * Olivier Teulière diff --git a/modules/misc/xml/Modules.am b/modules/misc/xml/Modules.am new file mode 100644 index 0000000000..e52dcbbd48 --- /dev/null +++ b/modules/misc/xml/Modules.am @@ -0,0 +1,2 @@ +SOURCES_xtag = xtag.c +SOURCES_xml = libxml.c diff --git a/modules/misc/xml/libxml.c b/modules/misc/xml/libxml.c new file mode 100644 index 0000000000..abdcdc21c1 --- /dev/null +++ b/modules/misc/xml/libxml.c @@ -0,0 +1,214 @@ +/***************************************************************************** + * libxml.c: XML parser using libxml2 + ***************************************************************************** + * Copyright (C) 2004 VideoLAN + * $Id$ + * + * Authors: Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include +#include + +#include "vlc_xml.h" + +#include +#include + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +vlc_module_begin(); + set_description( _("XML Parser (using libxml2)") ); + set_capability( "xml", 10 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct xml_reader_sys_t +{ + /* libxml2 reader context */ + xmlTextReaderPtr p_reader; +}; + +static xml_reader_t *ReaderCreate( xml_t *, const char * ); +static void ReaderDelete( xml_reader_t * ); +static int ReaderRead( xml_reader_t * ); +static int ReaderNodeType( xml_reader_t * ); +static char *ReaderName( xml_reader_t * ); +static char *ReaderValue( xml_reader_t * ); +static int ReaderNextAttr( xml_reader_t * ); + +static void CatalogLoad( xml_t *, const char * ); +static void CatalogAdd( xml_t *, const char *, const char *, const char * ); + +/***************************************************************************** + * Module initialization + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + xml_t *p_xml = (xml_t *)p_this; + + p_xml->pf_reader_create = ReaderCreate; + p_xml->pf_reader_delete = ReaderDelete; + + p_xml->pf_catalog_load = CatalogLoad; + p_xml->pf_catalog_add = CatalogAdd; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Module deinitialization + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + return; +} + +/***************************************************************************** + * Catalogue functions + *****************************************************************************/ +static void CatalogLoad( xml_t *p_xml, const char *psz_filename ) +{ + if( !psz_filename ) xmlInitializeCatalog(); + else xmlLoadCatalog( psz_filename ); +} + +static void CatalogAdd( xml_t *p_xml, const char *psz_arg1, + const char *psz_arg2, const char *psz_filename ) +{ + xmlCatalogAdd( psz_arg1, psz_arg2, psz_filename ); +} + +/***************************************************************************** + * Reader functions + *****************************************************************************/ +static void ReaderErrorHandler( void *p_arg, const char *p_msg, + xmlParserSeverities severity, + xmlTextReaderLocatorPtr locator) +{ + xml_reader_t *p_reader = (xml_reader_t *)p_arg; + int line = xmlTextReaderLocatorLineNumber( locator ); + msg_Err( p_reader->p_xml, "XML parser error (line %d) : %s", line, p_msg ); +} + +static xml_reader_t *ReaderCreate( xml_t *p_xml, const char *psz_filename ) +{ + xml_reader_t *p_reader; + xml_reader_sys_t *p_sys; + xmlTextReaderPtr p_libxml_reader; + + p_libxml_reader = xmlNewTextReaderFilename( psz_filename ); + if( !p_libxml_reader ) + { + msg_Err( p_xml, "failed to open file %s for parsing", psz_filename ); + return 0; + } + + p_reader = malloc( sizeof(xml_reader_t) ); + p_reader->p_sys = p_sys = malloc( sizeof(xml_reader_sys_t) ); + p_reader->p_sys->p_reader = p_libxml_reader; + p_reader->p_xml = p_xml; + + /* Activate DTD validation */ + xmlTextReaderSetParserProp( p_libxml_reader, XML_PARSER_DEFAULTATTRS, 1 ); + xmlTextReaderSetParserProp( p_libxml_reader, XML_PARSER_VALIDATE, 1 ); + + /* Set the error handler */ + xmlTextReaderSetErrorHandler( p_libxml_reader, + ReaderErrorHandler, p_reader ); + + + p_reader->pf_read = ReaderRead; + p_reader->pf_node_type = ReaderNodeType; + p_reader->pf_name = ReaderName; + p_reader->pf_value = ReaderValue; + p_reader->pf_next_attr = ReaderNextAttr; + + return p_reader; +} + +static void ReaderDelete( xml_reader_t *p_reader ) +{ + xmlFreeTextReader( p_reader->p_sys->p_reader ); + free( p_reader->p_sys ); + free( p_reader ); +} + +static int ReaderRead( xml_reader_t *p_reader ) +{ + int i_ret = xmlTextReaderRead( p_reader->p_sys->p_reader ); + +#if 0 + switch( i_ret ) + { + default: + } +#endif + + return i_ret; +} + +static int ReaderNodeType( xml_reader_t *p_reader ) +{ + int i_ret = xmlTextReaderNodeType( p_reader->p_sys->p_reader ); + + switch( i_ret ) + { + case XML_READER_TYPE_ELEMENT: + i_ret = XML_READER_STARTELEM; + break; + case XML_READER_TYPE_END_ELEMENT: + i_ret = XML_READER_ENDELEM; + break; + case -1: + i_ret = -1; + break; + default: + i_ret = XML_READER_NONE; + break; + } + + return i_ret; +} + +static char *ReaderName( xml_reader_t *p_reader ) +{ + const xmlChar *psz_name = + xmlTextReaderConstName( p_reader->p_sys->p_reader ); + + if( psz_name ) return strdup( psz_name ); + else return 0; +} + +static char *ReaderValue( xml_reader_t *p_reader ) +{ + const xmlChar *psz_value = + xmlTextReaderConstValue( p_reader->p_sys->p_reader ); + + if( psz_value ) return strdup( psz_value ); + else return 0; +} + +static int ReaderNextAttr( xml_reader_t *p_reader ) +{ + return ( xmlTextReaderMoveToNextAttribute( p_reader->p_sys->p_reader ) + == 1 ) ? VLC_SUCCESS : VLC_EGENERIC; +} diff --git a/modules/misc/xml/xtag.c b/modules/misc/xml/xtag.c new file mode 100644 index 0000000000..c8b910af5a --- /dev/null +++ b/modules/misc/xml/xtag.c @@ -0,0 +1,957 @@ +/***************************************************************************** + * xtag.c : a trivial parser for XML-like tags + ***************************************************************************** + * Copyright (C) 2003-2004 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) Australia + * Copyright (C) 2000-2004 VideoLAN + * + * $Id$ + * + * Authors: Conrad Parker + * Andre Pang + * Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include +#include + +#include "vlc_xml.h" + +#include +#include +#include +#include +#include + +#undef XTAG_DEBUG + +typedef struct _XList +{ + struct _XList *prev; + struct _XList *next; + void *data; +} XList; + +/* + * struct XTag is kind of a union ... it normally represents a whole + * tag (and its children), but it could alternatively represent some + * PCDATA. Basically, if tag->pcdata is non-NULL, interpret only it and + * ignore the name, attributes and inner_tags. + */ +typedef struct _XTag +{ + char *name; + char *pcdata; + struct _XTag *parent; + XList *attributes; + XList *children; + XList *current_child; +} XTag; + +typedef struct _XAttribute +{ + char *name; + char *value; +} XAttribute; + +typedef struct _XTagParser +{ + int valid; /* boolean */ + XTag *current_tag; + char *start; + char *end; +} XTagParser; + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +vlc_module_begin(); + set_description( _("Simple XML Parser") ); + set_capability( "xml", 5 ); + set_callbacks( Open, Close ); +vlc_module_end(); + +struct xml_reader_sys_t +{ + XTag *p_root; /* Root tag */ + XTag *p_curtag; /* Current tag */ + XList *p_curattr; /* Current attribute */ + vlc_bool_t b_endtag; +}; + +static xml_reader_t *ReaderCreate( xml_t *, const char * ); +static void ReaderDelete( xml_reader_t * ); +static int ReaderRead( xml_reader_t * ); +static int ReaderNodeType( xml_reader_t * ); +static char *ReaderName( xml_reader_t * ); +static char *ReaderValue( xml_reader_t * ); +static int ReaderNextAttr( xml_reader_t * ); + +static void CatalogLoad( xml_t *, const char * ); +static void CatalogAdd( xml_t *, const char *, const char *, const char * ); + +static XTag *xtag_new_parse( const char *, int ); +static char *xtag_get_name( XTag * ); +static char *xtag_get_pcdata( XTag * ); +static char *xtag_get_attribute( XTag *, char * ); +static XTag *xtag_first_child( XTag *, char * ); +static XTag *xtag_next_child( XTag *, char * ); +static XTag *xtag_free( XTag * ); +static int xtag_snprint( char *, int, XTag * ); + +/***************************************************************************** + * Module initialization + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + xml_t *p_xml = (xml_t *)p_this; + + p_xml->pf_reader_create = ReaderCreate; + p_xml->pf_reader_delete = ReaderDelete; + + p_xml->pf_catalog_load = CatalogLoad; + p_xml->pf_catalog_add = CatalogAdd; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Module deinitialization + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + return; +} + +/***************************************************************************** + * Catalogue functions + *****************************************************************************/ +static void CatalogLoad( xml_t *p_xml, const char *psz_filename ) +{ + msg_Dbg( p_xml, "catalog support not implemented" ); +} + +static void CatalogAdd( xml_t *p_xml, const char *psz_arg1, + const char *psz_arg2, const char *psz_filename ) +{ +} + +/***************************************************************************** + * Reader functions + *****************************************************************************/ +static xml_reader_t *ReaderCreate( xml_t *p_xml, const char *psz_filename ) +{ + xml_reader_t *p_reader; + xml_reader_sys_t *p_sys; + char *p_buffer; + int i_buffer; + FILE *file; + XTag *p_root; + + /* Open and read file */ + file = fopen( psz_filename, "rt" ); + if( !file ) + { + msg_Warn( p_xml, "could not open file '%s'", psz_filename ); + return 0; + } + + fseek( file, 0L, SEEK_END ); + i_buffer = ftell( file ); + fseek( file, 0L, SEEK_SET ); + p_buffer = malloc( i_buffer + 1 ); + i_buffer = fread( p_buffer, 1, i_buffer, file ); + p_buffer[i_buffer] = 0; + fclose( file ); + + if( !i_buffer ) + { + msg_Dbg( p_xml, "file '%s' is empty", psz_filename ); + free( p_buffer ); + return 0; + } + + p_root = xtag_new_parse( p_buffer, i_buffer ); + if( !p_root ) + { + msg_Warn( p_xml, "couldn't parse file '%s'", psz_filename ); + free( p_buffer ); + return 0; + } + + p_reader = malloc( sizeof(xml_reader_t) ); + p_reader->p_sys = p_sys = malloc( sizeof(xml_reader_sys_t) ); + p_reader->p_sys->p_root = p_root; + p_reader->p_sys->p_curtag = NULL; + p_reader->p_sys->p_curattr = NULL; + p_reader->p_sys->b_endtag = VLC_FALSE; + p_reader->p_xml = p_xml; + + p_reader->pf_read = ReaderRead; + p_reader->pf_node_type = ReaderNodeType; + p_reader->pf_name = ReaderName; + p_reader->pf_value = ReaderValue; + p_reader->pf_next_attr = ReaderNextAttr; + + return p_reader; +} + +static void ReaderDelete( xml_reader_t *p_reader ) +{ + xtag_free( p_reader->p_sys->p_root ); + free( p_reader->p_sys ); + free( p_reader ); +} + +static int ReaderRead( xml_reader_t *p_reader ) +{ + XTag *p_child; + + if( !p_reader->p_sys->p_curtag ) + { + p_reader->p_sys->p_curtag = p_reader->p_sys->p_root; + return 1; + } + + while( 1 ) + { + if( (p_child = xtag_next_child( p_reader->p_sys->p_curtag, 0 )) ) + { + p_reader->p_sys->p_curtag = p_child; + p_reader->p_sys->p_curattr = 0; + p_reader->p_sys->b_endtag = VLC_FALSE; + return 1; + } + + if( !p_reader->p_sys->b_endtag ) + { + p_reader->p_sys->b_endtag = VLC_TRUE; + return 1; + } + + p_reader->p_sys->b_endtag = VLC_FALSE; + if( !p_reader->p_sys->p_curtag->parent ) return 0; + p_reader->p_sys->p_curtag = p_reader->p_sys->p_curtag->parent; + } + + return 0; +} + +static int ReaderNodeType( xml_reader_t *p_reader ) +{ + if( p_reader->p_sys->p_curtag->name && + p_reader->p_sys->b_endtag ) return XML_READER_ENDELEM; + if( p_reader->p_sys->p_curtag->name ) return XML_READER_STARTELEM; + if( p_reader->p_sys->p_curtag->pcdata ) return XML_READER_TEXT; + return XML_READER_NONE; +} + +static char *ReaderName( xml_reader_t *p_reader ) +{ + const char *psz_name; + + if( !p_reader->p_sys->p_curattr ) + psz_name = xtag_get_name( p_reader->p_sys->p_curtag ); + else + psz_name = ((XAttribute *)p_reader->p_sys->p_curattr->data)->name; + + if( psz_name ) return strdup( psz_name ); + else return 0; +} + +static char *ReaderValue( xml_reader_t *p_reader ) +{ + const char *psz_name; + + if( !p_reader->p_sys->p_curattr ) return 0; + +#ifdef XTAG_DEBUG + printf( "%s=%s\n", ((XAttribute *)p_reader->p_sys->p_curattr->data)->name, + ((XAttribute *)p_reader->p_sys->p_curattr->data)->value ); +#endif + + psz_name = ((XAttribute *)p_reader->p_sys->p_curattr->data)->value; + + if( psz_name ) return strdup( psz_name ); + else return 0; +} + +static int ReaderNextAttr( xml_reader_t *p_reader ) +{ + if( !p_reader->p_sys->p_curattr ) + p_reader->p_sys->p_curattr = p_reader->p_sys->p_curtag->attributes; + else if( p_reader->p_sys->p_curattr ) + p_reader->p_sys->p_curattr = p_reader->p_sys->p_curattr->next; + + if( p_reader->p_sys->p_curattr ) return VLC_SUCCESS; + else return VLC_EGENERIC; +} + +/***************************************************************************** + * XTAG parser functions + *****************************************************************************/ + +static XList *xlist_append( XList *list, void *data ) +{ + XList *l, *last; + + l = (XList *)malloc( sizeof(XList) ); + l->prev = l->next = NULL; + l->data = data; + + if( list == NULL ) return l; + + for( last = list; last; last = last->next ) + if( last->next == NULL ) break; + + if( last ) last->next = l; + l->prev = last; + return list; +} + +static void xlist_free( XList *list ) +{ + XList *l, *ln; + + for( l = list; l; l = ln ) + { + ln = l->next; + free( l ); + } +} + +/* Character classes */ +#define X_NONE 0 +#define X_WHITESPACE 1<<0 +#define X_OPENTAG 1<<1 +#define X_CLOSETAG 1<<2 +#define X_DQUOTE 1<<3 +#define X_SQUOTE 1<<4 +#define X_EQUAL 1<<5 +#define X_SLASH 1<<6 +#define X_QMARK 1<<7 +#define X_DASH 1<<8 + +static int xtag_cin( char c, int char_class ) +{ + if( char_class & X_WHITESPACE ) if( isspace(c) ) return VLC_TRUE; + if( char_class & X_OPENTAG ) if( c == '<' ) return VLC_TRUE; + if( char_class & X_CLOSETAG ) if( c == '>' ) return VLC_TRUE; + if( char_class & X_DQUOTE ) if( c == '"' ) return VLC_TRUE; + if( char_class & X_SQUOTE ) if( c == '\'' ) return VLC_TRUE; + if( char_class & X_EQUAL ) if( c == '=' ) return VLC_TRUE; + if( char_class & X_SLASH ) if( c == '/' ) return VLC_TRUE; + if( char_class & X_QMARK ) if( c == '!' ) return VLC_TRUE; + if( char_class & X_DASH ) if( c == '-' ) return VLC_TRUE; + + return VLC_FALSE; +} + +static int xtag_index( XTagParser *parser, int char_class ) +{ + char *s = parser->start; + int i; + + for( i = 0; s[i] && s != parser->end; i++ ) + { + if( xtag_cin( s[i], char_class ) ) return i; + } + + return -1; +} + +static void xtag_skip_over( XTagParser *parser, int char_class ) +{ + char *s = parser->start; + int i; + + if( !parser->valid ) return; + + for( i = 0; s[i] && s != parser->end; i++ ) + { + if( !xtag_cin( s[i], char_class ) ) + { + parser->start = &s[i]; + return; + } + } + + return; +} + +static void xtag_skip_whitespace( XTagParser * parser ) +{ + xtag_skip_over( parser, X_WHITESPACE ); +} + +static char *xtag_slurp_to( XTagParser *parser, int good_end, int bad_end ) +{ + char *ret, *s = parser->start; + int xi; + + if( !parser->valid ) return NULL; + + xi = xtag_index( parser, good_end | bad_end ); + + if( xi > 0 && xtag_cin (s[xi], good_end) ) + { + ret = malloc( (xi+1) * sizeof(char) ); + strncpy( ret, s, xi ); + ret[xi] = '\0'; + parser->start = &s[xi]; + return ret; + } + + return NULL; +} + +static int xtag_assert_and_pass( XTagParser *parser, int char_class ) +{ + char *s = parser->start; + + if( !parser->valid ) return VLC_FALSE; + + if( !xtag_cin( s[0], char_class ) ) + { + parser->valid = VLC_FALSE; + return VLC_FALSE; + } + + parser->start = &s[1]; + + return VLC_TRUE; +} + +static char *xtag_slurp_quoted( XTagParser *parser ) +{ + char * ret, *s; + int quote = X_DQUOTE; /* quote char to match on */ + int xi; + + if( !parser->valid ) return NULL; + + xtag_skip_whitespace( parser ); + + s = parser->start; + + if( xtag_cin( s[0], X_SQUOTE ) ) quote = X_SQUOTE; + + if( !xtag_assert_and_pass( parser, quote ) ) return NULL; + + s = parser->start; + + for( xi = 0; s[xi]; xi++ ) + { + if( xtag_cin( s[xi], quote ) ) + { + if( !(xi > 1 && s[xi-1] == '\\') ) break; + } + } + + ret = malloc( (xi+1) * sizeof(char) ); + strncpy( ret, s, xi ); + ret[xi] = '\0'; + parser->start = &s[xi]; + + if( !xtag_assert_and_pass( parser, quote ) ) return NULL; + + return ret; +} + +static XAttribute *xtag_parse_attribute( XTagParser *parser ) +{ + XAttribute *attr; + char *name, *value; + char *s; + + if( !parser->valid ) return NULL; + + xtag_skip_whitespace( parser ); + + name = xtag_slurp_to( parser, X_WHITESPACE|X_EQUAL, X_SLASH|X_CLOSETAG ); + if( name == NULL ) return NULL; + + xtag_skip_whitespace( parser ); + s = parser->start; + + if( !xtag_assert_and_pass( parser, X_EQUAL ) ) + { +#ifdef XTAG_DEBUG + printf( "xtag: attr failed EQUAL on <%s>\n", name ); +#endif + goto err_free_name; + } + + xtag_skip_whitespace( parser ); + + value = xtag_slurp_quoted( parser ); + + if( value == NULL ) + { +#ifdef XTAG_DEBUG + printf ("Got NULL quoted attribute value\n"); +#endif + goto err_free_name; + } + + attr = malloc( sizeof (*attr) ); + attr->name = name; + attr->value = value; + return attr; + + err_free_name: + free (name); + parser->valid = VLC_FALSE; + return NULL; +} + +static XTag *xtag_parse_tag( XTagParser *parser ) +{ + XTag *tag, *inner; + XAttribute *attr; + char *name; + char *pcdata; + char *s; + + if( !parser->valid ) return NULL; + + xtag_skip_whitespace (parser); + + if( (pcdata = xtag_slurp_to( parser, X_OPENTAG, X_NONE )) != NULL ) + { + tag = malloc( sizeof(*tag) ); + tag->name = NULL; + tag->pcdata = pcdata; + tag->parent = parser->current_tag; + tag->attributes = NULL; + tag->children = NULL; + tag->current_child = NULL; + + return tag; + } + + s = parser->start; + + /* if this starts a close tag, return NULL and let the parent take it */ + if( xtag_cin( s[0], X_OPENTAG ) && xtag_cin( s[1], X_SLASH ) ) + return NULL; + + /* if this starts a comment tag, skip until end */ + if( xtag_cin( s[0], X_OPENTAG ) && xtag_cin( s[1], X_QMARK ) && + xtag_cin( s[2], X_DASH ) && xtag_cin( s[3], X_DASH ) ) + { + int xi; + + parser->start = s = &s[4]; + + while( (xi = xtag_index( parser, X_DASH )) >= 0 ) + { + parser->start = s = &s[xi]; + + if( xtag_cin( s[0], X_DASH ) && xtag_cin( s[1], X_DASH ) && + xtag_cin( s[2], X_CLOSETAG ) ) + { + parser->start = &s[3]; + return xtag_parse_tag( parser ); + } + } + + return NULL; + } + + /* FIXME: if this starts a DOCTYPE tag, skip until end */ + if( xtag_cin( s[0], X_OPENTAG ) && xtag_cin( s[1], X_QMARK ) ) + { + int xi = xtag_index( parser, X_CLOSETAG ); + if( xi <= 0 ) return NULL; + + parser->start = &s[xi+1]; + return xtag_parse_tag( parser ); + } + + if( !xtag_assert_and_pass( parser, X_OPENTAG ) ) return NULL; + + name = xtag_slurp_to( parser, X_WHITESPACE|X_SLASH|X_CLOSETAG, X_NONE ); + if( name == NULL ) return NULL; + +#ifdef XTAG_DEBUG + printf ("<%s ...\n", name); +#endif + + tag = malloc( sizeof(*tag) ); + tag->name = name; + tag->pcdata = NULL; + tag->parent = parser->current_tag; + tag->attributes = NULL; + tag->children = NULL; + tag->current_child = NULL; + + s = parser->start; + + if( xtag_cin( s[0], X_WHITESPACE ) ) + { + while( (attr = xtag_parse_attribute( parser )) != NULL ) + { + tag->attributes = xlist_append( tag->attributes, attr ); + } + } + + xtag_skip_whitespace (parser); + + s = parser->start; + + if( xtag_cin( s[0], X_CLOSETAG ) ) + { + parser->current_tag = tag; + + xtag_assert_and_pass (parser, X_CLOSETAG); + + while( (inner = xtag_parse_tag( parser ) ) != NULL ) + { + tag->children = xlist_append( tag->children, inner ); + } + + xtag_skip_whitespace (parser); + + xtag_assert_and_pass (parser, X_OPENTAG); + xtag_assert_and_pass (parser, X_SLASH); + name = xtag_slurp_to (parser, X_WHITESPACE | X_CLOSETAG, X_NONE); + if( name ) + { + if( strcmp( name, tag->name ) ) + { +#ifdef XTAG_DEBUG + printf ("got %s expected %s\n", name, tag->name); +#endif + parser->valid = VLC_FALSE; + } + free( name ); + } + + xtag_skip_whitespace( parser ); + xtag_assert_and_pass( parser, X_CLOSETAG ); + + } + else + { + xtag_assert_and_pass( parser, X_SLASH ); + xtag_assert_and_pass( parser, X_CLOSETAG ); + } + + return tag; +} + +static XTag *xtag_free( XTag *xtag ) +{ + XList *l; + XAttribute *attr; + XTag *child; + + if( xtag == NULL ) return NULL; + + if( xtag->name ) free( xtag->name ); + if( xtag->pcdata ) free( xtag->pcdata ); + + for( l = xtag->attributes; l; l = l->next ) + { + if( (attr = (XAttribute *)l->data) != NULL ) + { + if( attr->name ) free( attr->name ); + if( attr->value ) free( attr->value ); + free( attr ); + } + } + xlist_free( xtag->attributes ); + + for( l = xtag->children; l; l = l->next ) + { + child = (XTag *)l->data; + xtag_free( child ); + } + xlist_free( xtag->children ); + + free( xtag ); + + return NULL; +} + +static XTag *xtag_new_parse( const char *s, int n ) +{ + XTagParser parser; + XTag *tag, *ttag, *wrapper; + + parser.valid = VLC_TRUE; + parser.current_tag = NULL; + parser.start = (char *)s; + + if( n == -1 ) parser.end = NULL; + else if( n == 0 ) return NULL; + else parser.end = (char *)&s[n]; + + tag = xtag_parse_tag( &parser ); + + if( !parser.valid ) + { + xtag_free( tag ); + return NULL; + } + + if( (ttag = xtag_parse_tag( &parser )) != NULL ) + { + if( !parser.valid ) + { + xtag_free( ttag ); + return tag; + } + + wrapper = malloc( sizeof(XTag) ); + wrapper->name = NULL; + wrapper->pcdata = NULL; + wrapper->parent = NULL; + wrapper->attributes = NULL; + wrapper->children = NULL; + wrapper->current_child = NULL; + + wrapper->children = xlist_append( wrapper->children, tag ); + wrapper->children = xlist_append( wrapper->children, ttag ); + + while( (ttag = xtag_parse_tag( &parser )) != NULL ) + { + if( !parser.valid ) + { + xtag_free( ttag ); + return wrapper; + } + + wrapper->children = xlist_append( wrapper->children, ttag ); + } + return wrapper; + } + + return tag; +} + +static char *xtag_get_name( XTag *xtag ) +{ + return xtag ? xtag->name : NULL; +} + +static char *xtag_get_pcdata( XTag *xtag ) +{ + XList *l; + XTag *child; + + if( xtag == NULL ) return NULL; + + for( l = xtag->children; l; l = l->next ) + { + child = (XTag *)l->data; + if( child->pcdata != NULL ) + { + return child->pcdata; + } + } + + return NULL; +} + +static char *xtag_get_attribute( XTag *xtag, char *attribute ) +{ + XList *l; + XAttribute *attr; + + if( xtag == NULL ) return NULL; + + for( l = xtag->attributes; l; l = l->next ) + { + if( (attr = (XAttribute *)l->data) != NULL ) + { + if( !strcmp( attr->name, attribute ) ) return attr->value; + } + } + + return NULL; +} + +static XTag *xtag_first_child( XTag *xtag, char *name ) +{ + XList *l; + XTag *child; + + if( xtag == NULL ) return NULL; + if( (l = xtag->children) == NULL ) return NULL; + + if( name == NULL ) + { + xtag->current_child = l; + return (XTag *)l->data; + } + + for( ; l; l = l->next ) + { + child = (XTag *)l->data; + + if( !strcmp( child->name, name ) ) + { + xtag->current_child = l; + return child; + } + } + + xtag->current_child = NULL; + + return NULL; +} + +static XTag *xtag_next_child( XTag *xtag, char *name ) +{ + XList *l; + XTag *child; + + if( xtag == NULL ) return NULL; + + if( (l = xtag->current_child) == NULL ) + return xtag_first_child( xtag, name ); + + if( (l = l->next) == NULL ) return NULL; + + if( name == NULL ) + { + xtag->current_child = l; + return (XTag *)l->data; + } + + for( ; l; l = l->next ) + { + child = (XTag *)l->data; + + if( !strcmp( child->name, name ) ) + { + xtag->current_child = l; + return child; + } + } + + xtag->current_child = NULL; + + return NULL; +} + +/* + * This snprints function takes a variable list of char *, the last of + * which must be NULL, and prints each in turn to buf. + * Returns C99-style total length that would have been written, even if + * this is larger than n. + */ +static int xtag_snprints( char *buf, int n, ... ) +{ + va_list ap; + char *s; + int len, to_copy, total = 0; + + va_start( ap, n ); + + for( s = va_arg( ap, char * ); s; s = va_arg( ap, char *) ) + { + len = strlen (s); + + if( (to_copy = __MIN(n, len) ) > 0 ) + { + memcpy( buf, s, to_copy ); + buf += to_copy; + n -= to_copy; + } + + total += len; + } + + va_end( ap ); + + return total; +} + +static int xtag_snprint( char *buf, int n, XTag *xtag ) +{ + int nn, written = 0; + XList *l; + XAttribute *attr; + XTag *child; + +#define FORWARD(N) \ + buf += __MIN(n, N); \ + n = __MAX(n-N, 0); \ + written += N; + + if( xtag == NULL ) + { + if( n > 0 ) buf[0] = '\0'; + return 0; + } + + if( xtag->pcdata ) + { + nn = xtag_snprints( buf, n, xtag->pcdata, NULL ); + FORWARD( nn ); + + return written; + } + + if( xtag->name ) + { + nn = xtag_snprints( buf, n, "<", xtag->name, NULL ); + FORWARD( nn ); + + for( l = xtag->attributes; l; l = l->next ) + { + attr = (XAttribute *)l->data; + + nn = xtag_snprints( buf, n, " ", attr->name, "=\"", attr->value, + "\"", NULL); + FORWARD( nn ); + } + + if( xtag->children == NULL ) + { + nn = xtag_snprints ( buf, n, "/>", NULL ); + FORWARD( nn ); + + return written; + } + + nn = xtag_snprints( buf, n, ">", NULL ); + FORWARD( nn ); + } + + for( l = xtag->children; l; l = l->next ) + { + child = (XTag *)l->data; + + nn = xtag_snprint( buf, n, child ); + FORWARD( nn ); + } + + if( xtag->name ) + { + nn = xtag_snprints( buf, n, "name, ">", NULL ); + FORWARD( nn ); + } + + return written; +} diff --git a/src/misc/modules.c b/src/misc/modules.c index 89d7584443..8d87a890f8 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -100,6 +100,7 @@ #include "osd.h" #include "vlc_httpd.h" #include "vlc_tls.h" +#include "vlc_xml.h" #include "iso_lang.h" #include "charset.h" diff --git a/src/misc/objects.c b/src/misc/objects.c index 92edd69993..c7c1f1be32 100644 --- a/src/misc/objects.c +++ b/src/misc/objects.c @@ -54,6 +54,7 @@ #include "vlc_vlm.h" #include "vlc_vod.h" #include "vlc_tls.h" +#include "vlc_xml.h" /***************************************************************************** * Local prototypes @@ -194,6 +195,10 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type ) i_size = sizeof( tls_t ); psz_type = "tls"; break; + case VLC_OBJECT_XML: + i_size = sizeof( xml_t ); + psz_type = "xml"; + break; case VLC_OBJECT_OPENGL: i_size = sizeof( vout_thread_t ); psz_type = "opengl provider"; diff --git a/src/misc/xml.c b/src/misc/xml.c new file mode 100644 index 0000000000..ae8a81b797 --- /dev/null +++ b/src/misc/xml.c @@ -0,0 +1,62 @@ +/***************************************************************************** + * xml.c: XML parser wrapper for XML modules + ***************************************************************************** + * Copyright (C) 2004 VideoLAN + * $Id$ + * + * Authors: Gildas Bazin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include +#include + +#include "vlc_xml.h" + +/***************************************************************************** + * xml_Create: + ***************************************************************************** + * Create an instance of an XML parser. + * Returns NULL on error. + *****************************************************************************/ +xml_t *__xml_Create( vlc_object_t *p_this ) +{ + xml_t *p_xml; + + p_xml = vlc_object_create( p_this, VLC_OBJECT_XML ); + vlc_object_attach( p_xml, p_this ); + + p_xml->p_module = module_Need( p_xml, "xml", 0, 0 ); + if( !p_xml->p_module ) + { + vlc_object_detach( p_xml ); + vlc_object_destroy( p_xml ); + msg_Err( p_this, "XML provider not found" ); + return NULL; + } + + return p_xml; +} + +/***************************************************************************** + * xml_Delete: Deletes an instance of xml_t + *****************************************************************************/ +void xml_Delete( xml_t *p_xml ) +{ + module_Unneed( p_xml, p_xml->p_module ); + vlc_object_detach( p_xml ); + vlc_object_destroy( p_xml ); +}