/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Bastien Nocera Copyright (C) 2003, 2004 Colin Walters The Gnome Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Gnome Library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Gnome Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Author: Bastien Nocera */ #include "config.h" #include #include #ifndef TOTEM_PL_PARSER_MINI #include "xmlparser.h" #include #include "totem-pl-parser.h" #include "totemplparser-marshal.h" #include "totem-disc.h" #endif /* !TOTEM_PL_PARSER_MINI */ #include "totem-pl-parser-mini.h" #include "totem-pl-parser-wm.h" #include "totem-pl-parser-lines.h" #include "totem-pl-parser-private.h" #define ASX_NEEDLE " MIME_READ_CHUNK_SIZE) len = MIME_READ_CHUNK_SIZE; if (memmem (data, len, ASX_NEEDLE, strlen (ASX_NEEDLE)) != NULL) return ASX_MIME_TYPE; if (memmem (data, len, ASX_NEEDLE2, strlen (ASX_NEEDLE2)) != NULL) return ASX_MIME_TYPE; if (memmem (data, len, ASX_NEEDLE3, strlen (ASX_NEEDLE3)) != NULL) return ASX_MIME_TYPE; return FALSE; } const char * totem_pl_parser_is_asf (const char *data, gsize len) { if (len == 0) return NULL; if (g_str_has_prefix (data, "[Reference]") != FALSE || g_str_has_prefix (data, "ASF ") != FALSE || g_str_has_prefix (data, "[Address]") != FALSE) { return ASF_REF_MIME_TYPE; } return totem_pl_parser_is_asx (data, len); } #ifndef TOTEM_PL_PARSER_MINI static TotemPlParserResult totem_pl_parser_add_asf_reference_parser (TotemPlParser *parser, GFile *file, GFile *base_file, gpointer data) { char *contents, **lines, *ref, *split_char; gsize size; if (g_file_load_contents (file, NULL, &contents, &size, NULL, NULL) == FALSE) return TOTEM_PL_PARSER_RESULT_ERROR; if (strstr(contents,"\x0d") == NULL) { split_char = "\n"; } else { split_char = "\x0d\n"; } lines = g_strsplit (contents, split_char, 0); g_free (contents); /* Try to get Ref1 first */ ref = totem_pl_parser_read_ini_line_string (lines, "Ref1", FALSE); if (ref == NULL) { g_strfreev (lines); return totem_pl_parser_add_asx (parser, file, base_file, data); } /* change http to mmsh, thanks Microsoft */ if (g_str_has_prefix (ref, "http") != FALSE) memcpy(ref, "mmsh", 4); totem_pl_parser_add_one_url (parser, ref, NULL); g_free (ref); /* Don't try to get Ref2, as it's only ever * supposed to be a fallback */ g_strfreev (lines); return TOTEM_PL_PARSER_RESULT_SUCCESS; } static TotemPlParserResult totem_pl_parser_add_asf_parser (TotemPlParser *parser, GFile *file, GFile *base_file, gpointer data) { TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED; char *contents, *ref; gsize size; /* NSC files are handled directly by GStreamer */ if (g_str_has_prefix (data, "[Address]") != FALSE) return TOTEM_PL_PARSER_RESULT_UNHANDLED; if (g_str_has_prefix (data, "ASF ") == FALSE) { return totem_pl_parser_add_asf_reference_parser (parser, file, base_file, data); } if (g_file_load_contents (file, NULL, &contents, &size, NULL, NULL) == FALSE) return TOTEM_PL_PARSER_RESULT_ERROR; if (size <= 4) { g_free (contents); return TOTEM_PL_PARSER_RESULT_ERROR; } /* Skip 'ASF ' */ ref = contents + 4; if (g_str_has_prefix (ref, "http") != FALSE) { memcpy(ref, "mmsh", 4); totem_pl_parser_add_one_url (parser, ref, NULL); retval = TOTEM_PL_PARSER_RESULT_SUCCESS; } g_free (contents); return retval; } static gboolean parse_asx_entry (TotemPlParser *parser, GFile *base_file, xml_node_t *parent) { xml_node_t *node; TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS; GFile *resolved; const char *url; const char *title, *duration, *starttime, *author; const char *moreinfo, *abstract, *copyright; title = NULL; url = NULL; duration = NULL; starttime = NULL; moreinfo = NULL; abstract = NULL; copyright = NULL; author = NULL; for (node = parent->child; node != NULL; node = node->next) { if (node->name == NULL) continue; /* ENTRY can only have one title node but multiple REFs */ if (g_ascii_strcasecmp (node->name, "ref") == 0) { const char *tmp; tmp = xml_parser_get_property (node, "href"); if (tmp == NULL) continue; /* FIXME, should we prefer mms streams, or non-mms? * See bug #352559 */ if (url == NULL) url = tmp; continue; } if (g_ascii_strcasecmp (node->name, "title") == 0) title = node->data; if (g_ascii_strcasecmp (node->name, "author") == 0) author = node->data; if (g_ascii_strcasecmp (node->name, "moreinfo") == 0) { const char *tmp; tmp = xml_parser_get_property (node, "href"); if (tmp == NULL) continue; moreinfo = tmp; } if (g_ascii_strcasecmp (node->name, "copyright") == 0) copyright = node->data; if (g_ascii_strcasecmp (node->name, "abstract") == 0) abstract = node->data; if (g_ascii_strcasecmp (node->name, "duration") == 0) { const char *tmp; tmp = xml_parser_get_property (node, "value"); if (tmp == NULL) continue; duration = tmp; } if (g_ascii_strcasecmp (node->name, "starttime") == 0) { const char *tmp; tmp = xml_parser_get_property (node, "value"); if (tmp == NULL) continue; starttime = tmp; } if (g_ascii_strcasecmp (node->name, "param") == 0) { const char *name, *value; name = xml_parser_get_property (node, "name"); if (name == NULL || g_ascii_strcasecmp (name, "showwhilebuffering") != 0) continue; value = xml_parser_get_property (node, "value"); if (value == NULL || g_ascii_strcasecmp (value, "true") != 0) continue; /* We ignore items that are the buffering images */ retval = TOTEM_PL_PARSER_RESULT_IGNORED; goto bail; } } if (url == NULL) return TOTEM_PL_PARSER_RESULT_ERROR; resolved = g_file_resolve_relative_path (base_file, url); /* .asx files can contain references to other .asx files */ retval = totem_pl_parser_parse_internal (parser, resolved, NULL); if (retval != TOTEM_PL_PARSER_RESULT_SUCCESS) { totem_pl_parser_add_url (parser, TOTEM_PL_PARSER_FIELD_FILE, resolved, TOTEM_PL_PARSER_FIELD_TITLE, title, TOTEM_PL_PARSER_FIELD_ABSTRACT, abstract, TOTEM_PL_PARSER_FIELD_COPYRIGHT, copyright, TOTEM_PL_PARSER_FIELD_AUTHOR, author, TOTEM_PL_PARSER_FIELD_STARTTIME, starttime, TOTEM_PL_PARSER_FIELD_DURATION, duration, TOTEM_PL_PARSER_FIELD_MOREINFO, moreinfo, NULL); retval = TOTEM_PL_PARSER_RESULT_SUCCESS; } g_object_unref (resolved); bail: return retval; } static gboolean parse_asx_entryref (TotemPlParser *parser, GFile *base_file, xml_node_t *node) { TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS; const char *url; GFile *resolved; url = xml_parser_get_property (node, "href"); if (url == NULL) return TOTEM_PL_PARSER_RESULT_ERROR; resolved = g_file_resolve_relative_path (base_file, url); /* .asx files can contain references to other .asx files */ retval = totem_pl_parser_parse_internal (parser, resolved, NULL); if (retval != TOTEM_PL_PARSER_RESULT_SUCCESS) { totem_pl_parser_add_url (parser, TOTEM_PL_PARSER_FIELD_FILE, resolved, NULL); retval = TOTEM_PL_PARSER_RESULT_SUCCESS; } g_object_unref (resolved); return retval; } //FIXME the retval is completely wrong static gboolean parse_asx_entries (TotemPlParser *parser, const char *url, GFile *base_file, xml_node_t *parent) { char *title = NULL; GFile *new_base; xml_node_t *node; TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_ERROR; new_base = NULL; for (node = parent->child; node != NULL; node = node->next) { if (node->name == NULL) continue; if (g_ascii_strcasecmp (node->name, "title") == 0) { g_free (title); title = g_strdup (node->data); totem_pl_parser_add_url (parser, TOTEM_PL_PARSER_FIELD_IS_PLAYLIST, TRUE, TOTEM_PL_PARSER_FIELD_URL, url, TOTEM_PL_PARSER_FIELD_TITLE, title, NULL); } if (g_ascii_strcasecmp (node->name, "base") == 0) { const char *str; str = xml_parser_get_property (node, "href"); if (str != NULL) { if (new_base != NULL) g_object_unref (new_base); new_base = g_file_new_for_uri (str); } } if (g_ascii_strcasecmp (node->name, "entry") == 0) { /* Whee! found an entry here, find the REF and TITLE */ if (parse_asx_entry (parser, new_base ? new_base : base_file, node) != FALSE) retval = TOTEM_PL_PARSER_RESULT_SUCCESS; } if (g_ascii_strcasecmp (node->name, "entryref") == 0) { /* Found an entryref, extract the REF attribute */ if (parse_asx_entryref (parser, new_base ? new_base : base_file, node) != FALSE) retval = TOTEM_PL_PARSER_RESULT_SUCCESS; } if (g_ascii_strcasecmp (node->name, "repeat") == 0) { /* Repeat at the top-level */ if (parse_asx_entries (parser, url, new_base ? new_base : base_file, node) != FALSE) retval = TOTEM_PL_PARSER_RESULT_SUCCESS; } } if (new_base != NULL) g_object_unref (new_base); if (title != NULL) totem_pl_parser_playlist_end (parser, url); g_free (title); return retval; } TotemPlParserResult totem_pl_parser_add_asx (TotemPlParser *parser, GFile *file, GFile *base_file, gpointer data) { xml_node_t* doc; char *contents, *url; gsize size; TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED; if (data != NULL && totem_pl_parser_is_uri_list (data, strlen (data)) != FALSE) { return totem_pl_parser_add_ram (parser, file, data); } if (g_file_load_contents (file, NULL, &contents, &size, NULL, NULL) == FALSE) return TOTEM_PL_PARSER_RESULT_ERROR; xml_parser_init (contents, size, XML_PARSER_CASE_INSENSITIVE); if (xml_parser_build_tree_with_options (&doc, XML_PARSER_RELAXED | XML_PARSER_MULTI_TEXT) < 0) { g_free (contents); return TOTEM_PL_PARSER_RESULT_ERROR; } /* If the document has no name */ if (doc->name == NULL || g_ascii_strcasecmp (doc->name , "asx") != 0) { g_free (contents); xml_parser_free_tree (doc); return TOTEM_PL_PARSER_RESULT_ERROR; } url = g_file_get_uri (file); if (parse_asx_entries (parser, url, base_file, doc) != FALSE) retval = TOTEM_PL_PARSER_RESULT_SUCCESS; g_free (url); g_free (contents); xml_parser_free_tree (doc); return retval; } TotemPlParserResult totem_pl_parser_add_asf (TotemPlParser *parser, GFile *file, GFile *base_file, gpointer data) { if (data == NULL) { totem_pl_parser_add_one_file (parser, file, NULL); return TOTEM_PL_PARSER_RESULT_SUCCESS; } if (totem_pl_parser_is_asf (data, strlen (data)) == FALSE) { totem_pl_parser_add_one_file (parser, file, NULL); return TOTEM_PL_PARSER_RESULT_SUCCESS; } return totem_pl_parser_add_asf_parser (parser, file, base_file, data); } #endif /* !TOTEM_PL_PARSER_MINI */