This is a megapatch with the following changes:
[platform/upstream/gstreamer.git] / gst / gstxml.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstxml.c: XML save/restore of pipelines
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include "gst_private.h"
24
25 #include "gstxml.h"
26 #include "gstbin.h"
27
28 enum {
29   OBJECT_LOADED,
30   OBJECT_SAVED,
31   LAST_SIGNAL
32 };
33
34
35 static void     gst_xml_class_init              (GstXMLClass *klass);
36 static void     gst_xml_init                    (GstXML *xml);
37
38 static GstObjectClass *parent_class = NULL;
39 static guint gst_xml_signals[LAST_SIGNAL] = { 0 };
40
41 GtkType
42 gst_xml_get_type(void)
43 {
44   static GtkType xml_type = 0;
45
46   if (!xml_type) {
47     static const GtkTypeInfo xml_info = {
48       "GstXML",
49       sizeof(GstXML),
50       sizeof(GstXMLClass),
51       (GtkClassInitFunc)gst_xml_class_init,
52       (GtkObjectInitFunc)gst_xml_init,
53       (GtkArgSetFunc)NULL,
54       (GtkArgGetFunc)NULL,
55       (GtkClassInitFunc)NULL,
56     };
57     xml_type = gtk_type_unique (GST_TYPE_OBJECT, &xml_info);
58   }
59   return xml_type;
60 }
61
62 static void
63 gst_xml_class_init (GstXMLClass *klass)
64 {
65   GtkObjectClass *gtkobject_class;
66
67   gtkobject_class = (GtkObjectClass *)klass;
68
69   parent_class = gtk_type_class (GST_TYPE_OBJECT);
70
71   gst_xml_signals[OBJECT_LOADED] =
72     gtk_signal_new ("object_loaded", GTK_RUN_LAST, gtkobject_class->type,
73                     GTK_SIGNAL_OFFSET (GstXMLClass, object_loaded),
74                     gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2,
75                     GST_TYPE_OBJECT, GTK_TYPE_POINTER);
76
77   gst_xml_signals[OBJECT_SAVED] =
78     gtk_signal_new ("object_saved", GTK_RUN_LAST, gtkobject_class->type,
79                     GTK_SIGNAL_OFFSET (GstXMLClass, object_saved),
80                     gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2,
81                     GST_TYPE_OBJECT, GTK_TYPE_POINTER);
82
83   gtk_object_class_add_signals (gtkobject_class, gst_xml_signals, LAST_SIGNAL);
84 }
85
86 static void
87 gst_xml_init(GstXML *xml)
88 {
89   xml->topelements = NULL;
90 }
91
92 /**
93  * gst_xml_new:
94  *
95  * Create a new GstXML parser object.
96  *
97  * Returns: a pointer to a new GstXML object.
98  */
99 GstXML*
100 gst_xml_new (void)
101 {
102   return GST_XML (gtk_type_new (GST_TYPE_XML));
103 }
104
105 /**
106  * gst_xml_write:
107  * @element: The element to write out
108  *
109  * Converts the given element into an XML presentation.
110  *
111  * Returns: a pointer to an XML document
112  */
113 xmlDocPtr
114 gst_xml_write (GstElement *element)
115 {
116   xmlDocPtr doc;
117   xmlNodePtr elementnode;
118   xmlNsPtr ns;
119
120   doc = xmlNewDoc ("1.0");
121   xmlNewGlobalNs (doc, "http://gstreamer.net/gst-core/1.0/", "gst");
122   ns = xmlNewNs (doc->xmlRootNode, "http://gstreamer.net/gst-core/1.0/", "gst");
123
124   doc->xmlRootNode = xmlNewDocNode (doc, ns, "GST-Pipeline", NULL);
125
126   elementnode = xmlNewChild (doc->xmlRootNode, NULL, "element", NULL);
127
128   gst_object_save_thyself (GST_OBJECT (element), elementnode);
129
130   return doc;
131 }
132
133 static gboolean
134 gst_xml_real_parse (GstXML *xml, xmlDocPtr doc, const guchar *root)
135 {
136   xmlNodePtr field, cur;
137   xmlNsPtr ns;
138
139   cur = xmlDocGetRootElement(doc);
140   if (cur == NULL) {
141     g_warning("gstxml: empty document\n");
142     return FALSE ;
143   }
144   ns = xmlSearchNsByHref(doc, cur, "http://gstreamer.net/gst-core/1.0/");
145   if (ns == NULL) {
146     g_warning("gstxml: document of wrong type, core namespace not found\n");
147     return FALSE;
148   }
149   if (strcmp(cur->name, "GST-Pipeline")) {
150     g_warning("gstxml: XML file is in wrong format\n");
151     return FALSE;
152   }
153
154   xml->ns = ns;
155
156   field = cur->xmlChildrenNode;
157
158   while (field) {
159     if (!strcmp(field->name, "element") && (field->ns == xml->ns)) {
160       GstElement *element;
161
162       element = gst_element_load_thyself(field, NULL);
163
164       xml->topelements = g_list_prepend (xml->topelements, element);
165     }
166     field = field->next;
167   }
168
169   xml->topelements = g_list_reverse (xml->topelements);
170
171   return TRUE;
172 }
173
174 /**
175  * gst_xml_parse_file:
176  * @fname: The filename with the xml description
177  * @root: The name of the root object to build
178  *
179  * Creates a new GstXML object (and the corresponding elements) from
180  * the XML file fname. Optionally it will only build the element from
181  * the element node root (if it is not NULL). This feature is useful
182  * if you only want to build a specific element from an XML file
183  * but not the pipeline it is embedded in. Note also that the XML parse
184  * tree is cached to speed up creating another GstXML object for
185  * the same file
186  *
187  * Returns: TRUE on success, FALSE otherwise
188  */
189 gboolean
190 gst_xml_parse_file (GstXML *xml, const guchar *fname, const guchar *root)
191 {
192   xmlDocPtr doc;
193
194   g_return_val_if_fail(fname != NULL, FALSE);
195
196   doc = xmlParseFile(fname);
197
198   if (!doc) {
199     g_warning("gstxml: XML file \"%s\" could not be read\n", fname);
200     return FALSE;
201   }
202
203   return gst_xml_real_parse (xml, doc, root);
204 }
205
206 /**
207  * gst_xml_parse_memory:
208  * @buffer: a pointer to the in memory XML buffer
209  * @size: the size of the buffer
210  * @root: the name of the root objects to build
211  *
212  * Creates a new GstXML object (and the corresponding elements) from
213  * an in memory XML buffer.
214  *
215  * Returns: a pointer to a new GstXML object
216  */
217 gboolean
218 gst_xml_parse_memory (GstXML *xml, guchar *buffer, guint size, const gchar *root)
219 {
220   xmlDocPtr doc;
221
222   g_return_val_if_fail(buffer != NULL, FALSE);
223
224   doc = xmlParseMemory (buffer, size);
225
226   return gst_xml_real_parse (xml, doc, root);
227 }
228
229 void
230 gst_xml_object_loaded (GstXML *xml, GstObject *object, xmlNodePtr self)
231 {
232   gtk_signal_emit (GTK_OBJECT (xml), gst_xml_signals[OBJECT_LOADED], object, self);
233 }
234
235 void
236 gst_xml_object_saved (GstXML *xml, GstObject *object, xmlNodePtr self)
237 {
238   gtk_signal_emit (GTK_OBJECT (xml), gst_xml_signals[OBJECT_SAVED], object, self);
239 }
240 /**
241  * gst_xml_get_topelements:
242  * @xml: The GstXML to get the elements from
243  *
244  * Retrive a list of toplevel elements.
245  *
246  * Returns: a GList of elements
247  */
248 GList*
249 gst_xml_get_topelements (GstXML *xml)
250 {
251   g_return_val_if_fail (xml != NULL, NULL);
252
253   return xml->topelements;
254 }
255
256 /**
257  * gst_xml_get_element:
258  * @xml: The GstXML to get the element from
259  * @name: The name of element to retreive
260  *
261  * This function is used to get a pointer to the GstElement corresponding
262  * to name in the pipeline description. You would use this if you have
263  * to do anything to the element after loading.
264  *
265  * Returns: a pointer to a new GstElement
266  */
267 GstElement*
268 gst_xml_get_element (GstXML *xml, const guchar *name)
269 {
270   GstElement *element;
271   GList *topelements;
272
273   g_return_val_if_fail(xml != NULL, NULL);
274   g_return_val_if_fail(name != NULL, NULL);
275
276   GST_DEBUG (0,"gstxml: getting element \"%s\"\n", name);
277
278   topelements = gst_xml_get_topelements (xml);
279
280   while (topelements) {
281     GstElement *top = GST_ELEMENT (topelements->data);
282
283     GST_DEBUG (0,"gstxml: getting element \"%s\"\n", name);
284     if (!strcmp (GST_ELEMENT_NAME (top), name)) {
285       return top;
286     }
287     else {
288       if (GST_IS_BIN (top)) {
289         element = gst_bin_get_by_name (GST_BIN (top), name);
290
291         if (element)
292           return element;
293       }
294     }
295     topelements = g_list_next (topelements);
296   }
297   return NULL;
298 }