2 * Copyright (C) 2007 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
4 * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * SECTION:gupnp-didl-lite-parser
24 * @short_description: A/V DIDL-Lite XML parser
26 * #GUPnPDIDLLiteParser parses DIDL-Lite XML strings.
33 #include "gupnp-didl-lite-object-private.h"
35 #include "gupnp-didl-lite-parser-private.h"
37 G_DEFINE_TYPE (GUPnPDIDLLiteParser,
38 gupnp_didl_lite_parser,
48 static guint signals[SIGNAL_LAST];
51 verify_didl_attributes (xmlNode *node)
55 content = xml_util_get_child_element_content (node, "date");
57 /* try to roughly verify the passed date with ^\d{4}-\d{2}-\d{2} */
58 char *ptr = (char *) content;
61 if (state == 4 || state == 7) {
76 return xml_util_verify_attribute_is_boolean (node, "restricted");
80 parse_elements (GUPnPDIDLLiteParser *parser,
91 gupnp_didl_lite_parser_init (G_GNUC_UNUSED GUPnPDIDLLiteParser *parser)
96 gupnp_didl_lite_parser_dispose (GObject *object)
98 GObjectClass *gobject_class;
100 gobject_class = G_OBJECT_CLASS (gupnp_didl_lite_parser_parent_class);
101 gobject_class->dispose (object);
105 gupnp_didl_lite_parser_class_init (GUPnPDIDLLiteParserClass *klass)
107 GObjectClass *object_class;
109 object_class = G_OBJECT_CLASS (klass);
111 object_class->dispose = gupnp_didl_lite_parser_dispose;
114 * GUPnPDIDLLiteParser::object-available:
115 * @parser: The #GUPnPDIDLLiteParser that received the signal
116 * @object: The now available #GUPnPDIDLLiteObject
118 * The ::object-available signal is emitted each time an object is
119 * found in the DIDL-Lite XML being parsed.
121 signals[OBJECT_AVAILABLE] =
122 g_signal_new ("object-available",
123 GUPNP_TYPE_DIDL_LITE_PARSER,
125 G_STRUCT_OFFSET (GUPnPDIDLLiteParserClass,
129 g_cclosure_marshal_VOID__OBJECT,
132 GUPNP_TYPE_DIDL_LITE_OBJECT);
135 * GUPnPDIDLLiteParser::item-available:
136 * @parser: The #GUPnPDIDLLiteParser that received the signal
137 * @item: The now available #GUPnPDIDLLiteItem
139 * The ::item-available signal is emitted each time an item is found in
140 * the DIDL-Lite XML being parsed.
142 signals[ITEM_AVAILABLE] =
143 g_signal_new ("item-available",
144 GUPNP_TYPE_DIDL_LITE_PARSER,
146 G_STRUCT_OFFSET (GUPnPDIDLLiteParserClass,
150 g_cclosure_marshal_VOID__OBJECT,
153 GUPNP_TYPE_DIDL_LITE_ITEM);
156 * GUPnPDIDLLiteParser::container-available:
157 * @parser: The #GUPnPDIDLLiteParser that received the signal
158 * @container: The now available #GUPnPDIDLLiteContainer
160 * The ::container-available signal is emitted each time a container is
161 * found in the DIDL-Lite XML being parsed.
163 signals[CONTAINER_AVAILABLE] =
164 g_signal_new ("container-available",
165 GUPNP_TYPE_DIDL_LITE_PARSER,
167 G_STRUCT_OFFSET (GUPnPDIDLLiteParserClass,
168 container_available),
171 g_cclosure_marshal_VOID__OBJECT,
174 GUPNP_TYPE_DIDL_LITE_CONTAINER);
178 * gupnp_didl_lite_parser_new:
180 * Return value: A new #GUPnPDIDLLiteParser object.
182 GUPnPDIDLLiteParser *
183 gupnp_didl_lite_parser_new (void)
185 return g_object_new (GUPNP_TYPE_DIDL_LITE_PARSER, NULL);
189 * gupnp_didl_lite_parser_parse_didl:
190 * @parser: A #GUPnPDIDLLiteParser
191 * @didl: The DIDL-Lite XML string to be parsed
192 * @error: The location where to store any error, or NULL
194 * Parses DIDL-Lite XML string @didl, emitting the ::object-available,
195 * ::item-available and ::container-available signals appropriately during the
198 * Return value: TRUE on success.
201 gupnp_didl_lite_parser_parse_didl (GUPnPDIDLLiteParser *parser,
205 return gupnp_didl_lite_parser_parse_didl_recursive (parser,
212 * gupnp_didl_lite_parser_parse_didl_recursive:
213 * @parser: A #GUPnPDIDLLiteParser
214 * @didl: The DIDL-Lite XML string to be parsed
215 * @error: The location where to store any error, or NULL
217 * Parses DIDL-Lite XML string @didl, emitting the ::object-available,
218 * ::item-available and ::container-available signals appropriately during the
221 * Return value: TRUE on success.
224 gupnp_didl_lite_parser_parse_didl_recursive (GUPnPDIDLLiteParser *parser,
232 xmlNs *upnp_ns = NULL;
234 xmlNs *dlna_ns = NULL;
236 GUPnPXMLDoc *xml_doc;
239 doc = xmlRecoverMemory (didl, strlen (didl));
243 GUPNP_XML_ERROR_PARSE,
244 "Could not parse DIDL-Lite XML:\n%s", didl);
249 /* Get a pointer to root element */
250 element = xml_util_get_element ((xmlNode *) doc,
253 if (element == NULL) {
256 GUPNP_XML_ERROR_NO_NODE,
257 "No 'DIDL-Lite' node in the DIDL-Lite XML:\n%s",
264 if (element->children == NULL) {
267 GUPNP_XML_ERROR_EMPTY_NODE,
268 "Empty 'DIDL-Lite' node in the DIDL-Lite XML:\n%s",
275 /* Lookup UPnP and DC namespaces */
276 ns_list = xmlGetNsList (doc,
277 xmlDocGetRootElement (doc));
282 for (i = 0; ns_list[i] != NULL; i++) {
283 const char *prefix = (const char *) ns_list[i]->prefix;
289 g_ascii_strcasecmp (prefix, "upnp") == 0)
290 upnp_ns = ns_list[i];
292 g_ascii_strcasecmp (prefix, "dc") == 0)
294 else if (! dlna_ns &&
295 g_ascii_strcasecmp (prefix, "dlna") == 0)
296 dlna_ns = ns_list[i];
298 g_ascii_strcasecmp (prefix, "pv") == 0)
305 /* Create UPnP and DC namespaces if they don't exist */
307 upnp_ns = xmlNewNs (xmlDocGetRootElement (doc),
309 "urn:schemas-upnp-org:metadata-1-0/upnp/",
311 GUPNP_DIDL_LITE_WRITER_NAMESPACE_UPNP);
313 dc_ns = xmlNewNs (xmlDocGetRootElement (doc),
315 "http://purl.org/dc/elements/1.1/",
317 GUPNP_DIDL_LITE_WRITER_NAMESPACE_DC);
319 dlna_ns = xmlNewNs (xmlDocGetRootElement (doc),
321 "urn:schemas-dlna-org:metadata-2-0/",
323 GUPNP_DIDL_LITE_WRITER_NAMESPACE_DLNA);
325 dlna_ns = xmlNewNs (xmlDocGetRootElement (doc),
327 "http://www.pv.com/pvns/",
329 GUPNP_DIDL_LITE_WRITER_NAMESPACE_PV);
331 xml_doc = gupnp_xml_doc_new (doc);
333 result = parse_elements (parser,
342 g_object_unref (xml_doc);
348 parse_elements (GUPnPDIDLLiteParser *parser,
350 GUPnPXMLDoc *xml_doc,
360 for (element = node->children; element; element = element->next) {
361 GUPnPDIDLLiteObject *object;
363 object = gupnp_didl_lite_object_new_from_xml (element, xml_doc,
370 if (GUPNP_IS_DIDL_LITE_CONTAINER (object)) {
371 g_signal_emit (parser,
372 signals[CONTAINER_AVAILABLE],
376 !parse_elements (parser,
385 g_object_unref (object);
389 } else if (GUPNP_IS_DIDL_LITE_ITEM (object)) {
390 node = gupnp_didl_lite_object_get_xml_node (object);
391 if (!verify_didl_attributes (node)) {
392 g_object_unref (object);
395 GUPNP_XML_ERROR_INVALID_ATTRIBUTE,
396 "Could not parse DIDL-Lite XML");
401 g_signal_emit (parser,
402 signals[ITEM_AVAILABLE],
407 g_signal_emit (parser,
408 signals[OBJECT_AVAILABLE],
412 g_object_unref (object);