2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstxml.c: XML save/restore of pipelines
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include "gst_private.h"
34 static void gst_xml_class_init (GstXMLClass *klass);
35 static void gst_xml_init (GstXML *xml);
37 static void gst_xml_object_loaded (GstObject *private, GstObject *object, xmlNodePtr self, gpointer data);
39 static GstObjectClass *parent_class = NULL;
40 static guint gst_xml_signals[LAST_SIGNAL] = { 0 };
43 gst_xml_get_type(void)
45 static GType xml_type = 0;
48 static const GTypeInfo xml_info = {
52 (GClassInitFunc)gst_xml_class_init,
57 (GInstanceInitFunc)gst_xml_init,
60 xml_type = g_type_register_static (GST_TYPE_OBJECT, "GstXML", &xml_info, 0);
66 gst_xml_class_init (GstXMLClass *klass)
68 GObjectClass *gobject_class;
70 gobject_class = (GObjectClass *)klass;
72 parent_class = g_type_class_ref (GST_TYPE_OBJECT);
74 gst_xml_signals[OBJECT_LOADED] =
75 g_signal_new ("object_loaded", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
76 G_STRUCT_OFFSET (GstXMLClass, object_loaded), NULL, NULL,
77 gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
78 GST_TYPE_OBJECT, G_TYPE_POINTER);
83 gst_xml_init(GstXML *xml)
85 xml->topelements = NULL;
91 * Create a new GstXML parser object.
93 * Returns: a pointer to a new GstXML object.
98 return GST_XML (g_object_new(GST_TYPE_XML,NULL));
103 * @element: The element to write out
105 * Converts the given element into an XML presentation.
107 * Returns: a pointer to an XML document
110 gst_xml_write (GstElement *element)
113 xmlNodePtr elementnode;
116 doc = xmlNewDoc ("1.0");
118 doc->xmlRootNode = xmlNewDocNode (doc, NULL, "gstreamer", NULL);
120 ns = xmlNewNs (doc->xmlRootNode, "http://gstreamer.net/gst-core/1.0/", "gst");
122 elementnode = xmlNewChild (doc->xmlRootNode, ns, "element", NULL);
124 gst_object_save_thyself (GST_OBJECT (element), elementnode);
130 * gst_xml_write_file:
131 * @element: The element to write out
132 * @out: an open file, like stdout
134 * Converts the given element into XML and writes the formatted XML to an open
137 * Returns: number of bytes written on success, -1 otherwise.
140 gst_xml_write_file (GstElement *element, FILE *out)
144 xmlOutputBufferPtr buf;
146 const char * encoding;
147 xmlCharEncodingHandlerPtr handler = NULL;
151 cur = gst_xml_write (element);
155 encoding = (const char *) cur->encoding;
157 if (encoding != NULL) {
160 enc = xmlParseCharEncoding (encoding);
162 if (cur->charset != XML_CHAR_ENCODING_UTF8) {
163 xmlGenericError (xmlGenericErrorContext,
164 "xmlDocDump: document not in UTF8\n");
167 if (enc != XML_CHAR_ENCODING_UTF8) {
168 handler = xmlFindCharEncodingHandler (encoding);
169 if (handler == NULL) {
170 xmlFree ((char *) cur->encoding);
171 cur->encoding = NULL;
176 buf = xmlOutputBufferCreateFile (out, handler);
178 indent = xmlIndentTreeOutput;
179 xmlIndentTreeOutput = 1;
180 ret = xmlSaveFormatFileTo(buf, cur, NULL, 1);
181 xmlIndentTreeOutput = indent;
183 /* apparently this doesn't return anything in libxml1 */
184 xmlDocDump (out, cur);
193 * @xml: a pointer to a GstXML object
194 * @doc: a pointer to an xml document to parse
195 * @root: The name of the root object to build
197 * Fills the GstXML object with the elements from the
200 * Returns: TRUE on success, FALSE otherwise
203 gst_xml_parse_doc (GstXML *xml, xmlDocPtr doc, const guchar *root)
205 xmlNodePtr field, cur;
208 cur = xmlDocGetRootElement(doc);
210 g_warning("gstxml: empty document\n");
213 ns = xmlSearchNsByHref(doc, cur, "http://gstreamer.net/gst-core/1.0/");
215 g_warning("gstxml: document of wrong type, core namespace not found\n");
218 if (strcmp(cur->name, "gstreamer")) {
219 g_warning("gstxml: XML file is in wrong format\n");
223 gst_class_signal_connect (GST_OBJECT_CLASS (G_OBJECT_GET_CLASS(xml)),
224 "object_loaded", gst_xml_object_loaded, xml);
228 field = cur->xmlChildrenNode;
231 if (!strcmp(field->name, "element") && (field->ns == xml->ns)) {
234 element = gst_xml_make_element (field, NULL);
236 xml->topelements = g_list_prepend (xml->topelements, element);
241 xml->topelements = g_list_reverse (xml->topelements);
247 * gst_xml_parse_file:
248 * @xml: a pointer to a GstXML object
249 * @fname: The filename with the xml description
250 * @root: The name of the root object to build
252 * Fills the GstXML object with the corresponding elements from
253 * the XML file fname. Optionally it will only build the element from
254 * the element node root (if it is not NULL). This feature is useful
255 * if you only want to build a specific element from an XML file
256 * but not the pipeline it is embedded in.
258 * Pass "-" as fname to read from stdin. You can also pass a URI
259 * of any format that libxml supports, including http.
261 * Returns: TRUE on success, FALSE otherwise
264 gst_xml_parse_file (GstXML *xml, const guchar *fname, const guchar *root)
268 g_return_val_if_fail(fname != NULL, FALSE);
270 doc = xmlParseFile(fname);
273 g_warning("gstxml: XML file \"%s\" could not be read\n", fname);
277 return gst_xml_parse_doc (xml, doc, root);
281 * gst_xml_parse_memory:
282 * @xml: a pointer to a GstXML object
283 * @buffer: a pointer to the in memory XML buffer
284 * @size: the size of the buffer
285 * @root: the name of the root objects to build
287 * Fills the GstXML object with the corresponding elements from
288 * an in memory XML buffer.
290 * Returns: TRUE on success
293 gst_xml_parse_memory (GstXML *xml, guchar *buffer, guint size, const gchar *root)
297 g_return_val_if_fail(buffer != NULL, FALSE);
299 doc = xmlParseMemory (buffer, size);
301 return gst_xml_parse_doc (xml, doc, root);
305 gst_xml_object_loaded (GstObject *private, GstObject *object, xmlNodePtr self, gpointer data)
307 GstXML *xml = GST_XML (data);
309 /* FIXME check that this element was created from the same xmlDocPtr...*/
310 g_signal_emit (G_OBJECT (xml), gst_xml_signals[OBJECT_LOADED], 0, object, self);
314 * gst_xml_get_topelements:
315 * @xml: The GstXML to get the elements from
317 * Retrive a list of toplevel elements.
319 * Returns: a GList of elements
322 gst_xml_get_topelements (GstXML *xml)
324 g_return_val_if_fail (xml != NULL, NULL);
326 return xml->topelements;
330 * gst_xml_get_element:
331 * @xml: The GstXML to get the element from
332 * @name: The name of element to retreive
334 * This function is used to get a pointer to the GstElement corresponding
335 * to name in the pipeline description. You would use this if you have
336 * to do anything to the element after loading.
338 * Returns: a pointer to a new GstElement
341 gst_xml_get_element (GstXML *xml, const guchar *name)
346 g_return_val_if_fail(xml != NULL, NULL);
347 g_return_val_if_fail(name != NULL, NULL);
349 GST_DEBUG (0,"gstxml: getting element \"%s\"", name);
351 topelements = gst_xml_get_topelements (xml);
353 while (topelements) {
354 GstElement *top = GST_ELEMENT (topelements->data);
356 GST_DEBUG (0,"gstxml: getting element \"%s\"", name);
357 if (!strcmp (GST_ELEMENT_NAME (top), name)) {
361 if (GST_IS_BIN (top)) {
362 element = gst_bin_get_by_name (GST_BIN (top), name);
368 topelements = g_list_next (topelements);
374 * gst_xml_make_element:
376 * @parent: the parent of this object when it's loaded
378 * Load the element from the XML description
380 * Returns: the new element
383 gst_xml_make_element (xmlNodePtr cur, GstObject *parent)
385 xmlNodePtr children = cur->xmlChildrenNode;
390 /* first get the needed tags to construct the element */
392 if (!strcmp (children->name, "name")) {
393 name = xmlNodeGetContent (children);
394 } else if (!strcmp (children->name, "type")) {
395 type = xmlNodeGetContent (children);
397 children = children->next;
399 g_return_val_if_fail (name != NULL, NULL);
400 g_return_val_if_fail (type != NULL, NULL);
402 GST_INFO (GST_CAT_XML,"loading \"%s\" of type \"%s\"", name, type);
404 element = gst_element_factory_make (type, name);
406 g_return_val_if_fail (element != NULL, NULL);
408 /* ne need to set the parent on this object bacause the pads */
409 /* will go through the hierarchy to connect to thier peers */
411 gst_object_set_parent (GST_OBJECT (element), parent);
413 gst_object_restore_thyself (GST_OBJECT (element), cur);