source: trunk/third/gstreamer/gst/gstxml.c @ 21448

Revision 21448, 10.3 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21447, which included commits to RCS files with non-trunk default branches.
Line 
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 "gstmarshal.h"
27#include "gstinfo.h"
28#include "gstbin.h"
29
30enum
31{
32  OBJECT_LOADED,
33  LAST_SIGNAL
34};
35
36static void gst_xml_class_init (GstXMLClass * klass);
37static void gst_xml_init (GstXML * xml);
38
39static void gst_xml_object_loaded (GstObject * private, GstObject * object,
40    xmlNodePtr self, gpointer data);
41
42static GstObjectClass *parent_class = NULL;
43static guint gst_xml_signals[LAST_SIGNAL] = { 0 };
44
45GType
46gst_xml_get_type (void)
47{
48  static GType xml_type = 0;
49
50  if (!xml_type) {
51    static const GTypeInfo xml_info = {
52      sizeof (GstXMLClass),
53      NULL,
54      NULL,
55      (GClassInitFunc) gst_xml_class_init,
56      NULL,
57      NULL,
58      sizeof (GstXML),
59      0,
60      (GInstanceInitFunc) gst_xml_init,
61      NULL
62    };
63    xml_type = g_type_register_static (GST_TYPE_OBJECT, "GstXML", &xml_info, 0);
64  }
65  return xml_type;
66}
67
68static void
69gst_xml_class_init (GstXMLClass * klass)
70{
71  GObjectClass *gobject_class;
72
73  gobject_class = (GObjectClass *) klass;
74
75  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
76
77  /* FIXME G_TYPE_POINTER should be GType of xmlNodePtr */
78  gst_xml_signals[OBJECT_LOADED] =
79      g_signal_new ("object-loaded", G_TYPE_FROM_CLASS (klass),
80      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstXMLClass, object_loaded), NULL,
81      NULL, gst_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2, GST_TYPE_OBJECT,
82      G_TYPE_POINTER);
83
84}
85
86static void
87gst_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 */
99GstXML *
100gst_xml_new (void)
101{
102  return GST_XML (g_object_new (GST_TYPE_XML, NULL));
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 */
113xmlDocPtr
114gst_xml_write (GstElement * element)
115{
116  xmlDocPtr doc;
117  xmlNodePtr elementnode;
118  xmlNsPtr gst_ns;
119
120  doc = xmlNewDoc ("1.0");
121
122  doc->xmlRootNode = xmlNewDocNode (doc, NULL, "gstreamer", NULL);
123
124  gst_ns =
125      xmlNewNs (doc->xmlRootNode, "http://gstreamer.net/gst-core/1.0/", "gst");
126
127  elementnode = xmlNewChild (doc->xmlRootNode, gst_ns, "element", NULL);
128
129  gst_object_save_thyself (GST_OBJECT (element), elementnode);
130
131  return doc;
132}
133
134/**
135 * gst_xml_write_file:
136 * @element: The element to write out
137 * @out: an open file, like stdout
138 *
139 * Converts the given element into XML and writes the formatted XML to an open
140 * file.
141 *
142 * Returns: number of bytes written on success, -1 otherwise.
143 */
144gint
145gst_xml_write_file (GstElement * element, FILE * out)
146{
147  xmlDocPtr cur;
148
149#ifdef HAVE_LIBXML2
150  xmlOutputBufferPtr buf;
151#endif
152  const char *encoding;
153  xmlCharEncodingHandlerPtr handler = NULL;
154  int indent;
155  gboolean ret;
156
157  cur = gst_xml_write (element);
158  if (!cur)
159    return -1;
160
161#ifdef HAVE_LIBXML2
162  encoding = (const char *) cur->encoding;
163
164  if (encoding != NULL) {
165    xmlCharEncoding enc;
166
167    enc = xmlParseCharEncoding (encoding);
168
169    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
170      xmlGenericError (xmlGenericErrorContext,
171          "xmlDocDump: document not in UTF8\n");
172      return -1;
173    }
174    if (enc != XML_CHAR_ENCODING_UTF8) {
175      handler = xmlFindCharEncodingHandler (encoding);
176      if (handler == NULL) {
177        xmlFree ((char *) cur->encoding);
178        cur->encoding = NULL;
179      }
180    }
181  }
182
183  buf = xmlOutputBufferCreateFile (out, handler);
184
185  indent = xmlIndentTreeOutput;
186  xmlIndentTreeOutput = 1;
187  ret = xmlSaveFormatFileTo (buf, cur, NULL, 1);
188  xmlIndentTreeOutput = indent;
189#else
190  /* apparently this doesn't return anything in libxml1 */
191  xmlDocDump (out, cur);
192  ret = 1;
193#endif
194
195  return ret;
196}
197
198/**
199 * gst_xml_parse_doc:
200 * @xml: a pointer to a GstXML object
201 * @doc: a pointer to an xml document to parse
202 * @root: The name of the root object to build
203 *
204 * Fills the GstXML object with the elements from the
205 * xmlDocPtr.
206 *
207 * Returns: TRUE on success, FALSE otherwise
208 */
209gboolean
210gst_xml_parse_doc (GstXML * xml, xmlDocPtr doc, const guchar * root)
211{
212  xmlNodePtr field, cur;
213  xmlNsPtr ns;
214
215  cur = xmlDocGetRootElement (doc);
216  if (cur == NULL) {
217    g_warning ("gstxml: empty document\n");
218    return FALSE;
219  }
220  ns = xmlSearchNsByHref (doc, cur, "http://gstreamer.net/gst-core/1.0/");
221  if (ns == NULL) {
222    g_warning ("gstxml: document of wrong type, core namespace not found\n");
223    return FALSE;
224  }
225  if (strcmp (cur->name, "gstreamer")) {
226    g_warning ("gstxml: XML file is in wrong format\n");
227    return FALSE;
228  }
229
230  gst_class_signal_connect (GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (xml)),
231      "object_loaded", gst_xml_object_loaded, xml);
232
233  xml->ns = ns;
234
235  field = cur->xmlChildrenNode;
236
237  while (field) {
238    if (!strcmp (field->name, "element") && (field->ns == xml->ns)) {
239      GstElement *element;
240
241      element = gst_xml_make_element (field, NULL);
242
243      xml->topelements = g_list_prepend (xml->topelements, element);
244    }
245    field = field->next;
246  }
247
248  xml->topelements = g_list_reverse (xml->topelements);
249
250  return TRUE;
251}
252
253/**
254 * gst_xml_parse_file:
255 * @xml: a pointer to a GstXML object
256 * @fname: The filename with the xml description
257 * @root: The name of the root object to build
258 *
259 * Fills the GstXML object with the corresponding elements from
260 * the XML file fname. Optionally it will only build the element from
261 * the element node root (if it is not NULL). This feature is useful
262 * if you only want to build a specific element from an XML file
263 * but not the pipeline it is embedded in.
264 *
265 * Pass "-" as fname to read from stdin. You can also pass a URI
266 * of any format that libxml supports, including http.
267 *
268 * Returns: TRUE on success, FALSE otherwise
269 */
270gboolean
271gst_xml_parse_file (GstXML * xml, const guchar * fname, const guchar * root)
272{
273  xmlDocPtr doc;
274
275  g_return_val_if_fail (fname != NULL, FALSE);
276
277  doc = xmlParseFile (fname);
278
279  if (!doc) {
280    g_warning ("gstxml: XML file \"%s\" could not be read\n", fname);
281    return FALSE;
282  }
283
284  return gst_xml_parse_doc (xml, doc, root);
285}
286
287/**
288 * gst_xml_parse_memory:
289 * @xml: a pointer to a GstXML object
290 * @buffer: a pointer to the in memory XML buffer
291 * @size: the size of the buffer
292 * @root: the name of the root objects to build
293 *
294 * Fills the GstXML object with the corresponding elements from
295 * an in memory XML buffer.
296 *
297 * Returns: TRUE on success
298 */
299gboolean
300gst_xml_parse_memory (GstXML * xml, guchar * buffer, guint size,
301    const gchar * root)
302{
303  xmlDocPtr doc;
304
305  g_return_val_if_fail (buffer != NULL, FALSE);
306
307  doc = xmlParseMemory (buffer, size);
308
309  return gst_xml_parse_doc (xml, doc, root);
310}
311
312static void
313gst_xml_object_loaded (GstObject * private, GstObject * object, xmlNodePtr self,
314    gpointer data)
315{
316  GstXML *xml = GST_XML (data);
317
318  /* FIXME check that this element was created from the same xmlDocPtr... */
319  g_signal_emit (G_OBJECT (xml), gst_xml_signals[OBJECT_LOADED], 0, object,
320      self);
321}
322
323/**
324 * gst_xml_get_topelements:
325 * @xml: The GstXML to get the elements from
326 *
327 * Retrive a list of toplevel elements.
328 *
329 * Returns: a GList of elements
330 */
331GList *
332gst_xml_get_topelements (GstXML * xml)
333{
334  g_return_val_if_fail (xml != NULL, NULL);
335
336  return xml->topelements;
337}
338
339/**
340 * gst_xml_get_element:
341 * @xml: The GstXML to get the element from
342 * @name: The name of element to retreive
343 *
344 * This function is used to get a pointer to the GstElement corresponding
345 * to name in the pipeline description. You would use this if you have
346 * to do anything to the element after loading.
347 *
348 * Returns: a pointer to a new GstElement
349 */
350GstElement *
351gst_xml_get_element (GstXML * xml, const guchar * name)
352{
353  GstElement *element;
354  GList *topelements;
355
356  g_return_val_if_fail (xml != NULL, NULL);
357  g_return_val_if_fail (name != NULL, NULL);
358
359  GST_DEBUG ("gstxml: getting element \"%s\"", name);
360
361  topelements = gst_xml_get_topelements (xml);
362
363  while (topelements) {
364    GstElement *top = GST_ELEMENT (topelements->data);
365
366    GST_DEBUG ("gstxml: getting element \"%s\"", name);
367    if (!strcmp (GST_ELEMENT_NAME (top), name)) {
368      return top;
369    } else {
370      if (GST_IS_BIN (top)) {
371        element = gst_bin_get_by_name (GST_BIN (top), name);
372
373        if (element)
374          return element;
375      }
376    }
377    topelements = g_list_next (topelements);
378  }
379  return NULL;
380}
381
382/**
383 * gst_xml_make_element:
384 * @cur: the xml node
385 * @parent: the parent of this object when it's loaded
386 *
387 * Load the element from the XML description
388 *
389 * Returns: the new element
390 */
391GstElement *
392gst_xml_make_element (xmlNodePtr cur, GstObject * parent)
393{
394  xmlNodePtr children = cur->xmlChildrenNode;
395  GstElement *element;
396  guchar *name = NULL;
397  guchar *type = NULL;
398
399  /* first get the needed tags to construct the element */
400  while (children) {
401    if (!strcmp (children->name, "name")) {
402      name = xmlNodeGetContent (children);
403    } else if (!strcmp (children->name, "type")) {
404      type = xmlNodeGetContent (children);
405    }
406    children = children->next;
407  }
408  g_return_val_if_fail (name != NULL, NULL);
409  g_return_val_if_fail (type != NULL, NULL);
410
411  GST_CAT_INFO (GST_CAT_XML, "loading \"%s\" of type \"%s\"", name, type);
412
413  element = gst_element_factory_make (type, name);
414
415  g_return_val_if_fail (element != NULL, NULL);
416
417  g_free (type);
418  g_free (name);
419
420  /* ne need to set the parent on this object bacause the pads */
421  /* will go through the hierarchy to link to their peers */
422  if (parent)
423    gst_object_set_parent (GST_OBJECT (element), parent);
424
425  gst_object_restore_thyself (GST_OBJECT (element), cur);
426
427  return element;
428}
Note: See TracBrowser for help on using the repository browser.