1 /*
2 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Bastien Nocera
3 Copyright (C) 2003, 2004 Colin Walters <walters@rhythmbox.org>
4
5 The Gnome Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The Gnome Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the Gnome Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA.
19
20 Author: Bastien Nocera <hadess@hadess.net>
21 */
22
23 #include "config.h"
24
25 #ifndef TOTEM_PL_PARSER_MINI
26 #include <string.h>
27 #include <glib.h>
28 #include <stdio.h>
29
30 #include "totem-pl-parser.h"
31 #include "totem-disc.h"
32 #endif /* !TOTEM_PL_PARSER_MINI */
33
34 #include "totem-pl-parser-mini.h"
35 #include "totem-pl-parser-media.h"
36 #include "totem-pl-parser-private.h"
37
38 /* Files that start with these characters sort after files that don't. */
39 #define SORT_LAST_CHAR1 '.'
40 #define SORT_LAST_CHAR2 '#'
41
42 #ifndef TOTEM_PL_PARSER_MINI
43 /* Returns NULL if we don't have an ISO image,
44 * or an empty string if it's non-UTF-8 data */
45 static char *
totem_pl_parser_iso_get_title(GFile * _file)46 totem_pl_parser_iso_get_title (GFile *_file)
47 {
48 char *fname;
49 FILE *file;
50 #define BUFFER_SIZE 128
51 char buf [BUFFER_SIZE+1];
52 int res;
53 char *str;
54
55 fname = g_file_get_path (_file);
56 if (fname == NULL)
57 return NULL;
58
59 file = fopen (fname, "rb");
60 g_free (fname);
61 if (file == NULL)
62 return NULL;
63
64 /* Verify we have an ISO image */
65 /* This check is for the raw sector images */
66 res = fseek (file, 37633L, SEEK_SET);
67 if (res != 0) {
68 fclose (file);
69 return NULL;
70 }
71
72 res = fread (buf, sizeof (char), 5, file);
73 if (res != 5 || strncmp (buf, "CD001", 5) != 0) {
74 /* Standard ISO images */
75 res = fseek (file, 32769L, SEEK_SET);
76 if (res != 0) {
77 fclose (file);
78 return NULL;
79 }
80 res = fread (buf, sizeof (char), 5, file);
81 if (res != 5 || strncmp (buf, "CD001", 5) != 0) {
82 /* High Sierra images */
83 res = fseek (file, 32776L, SEEK_SET);
84 if (res != 0) {
85 fclose (file);
86 return NULL;
87 }
88 res = fread (buf, sizeof (char), 5, file);
89 if (res != 5 || strncmp (buf, "CDROM", 5) != 0) {
90 fclose (file);
91 return NULL;
92 }
93 }
94 }
95 /* Extract the volume label from the image */
96 res = fseek (file, 32808L, SEEK_SET);
97 if (res != 0) {
98 fclose (file);
99 return NULL;
100 }
101 res = fread (buf, sizeof(char), BUFFER_SIZE, file);
102 fclose (file);
103 if (res != BUFFER_SIZE)
104 return NULL;
105
106 buf [BUFFER_SIZE] = '\0';
107 str = g_strdup (g_strstrip (buf));
108 if (!g_utf8_validate (str, -1, NULL)) {
109 g_free (str);
110 return g_strdup ("");
111 }
112
113 return str;
114 }
115
116 TotemPlParserResult
totem_pl_parser_add_iso(TotemPlParser * parser,GFile * file,GFile * base_file,TotemPlParseData * parse_data,gpointer data)117 totem_pl_parser_add_iso (TotemPlParser *parser,
118 GFile *file,
119 GFile *base_file,
120 TotemPlParseData *parse_data,
121 gpointer data)
122 {
123 TotemDiscMediaType type;
124 char *uri, *retval;
125
126 uri = g_file_get_uri (file);
127 type = totem_cd_detect_type_with_url (uri, &retval, NULL);
128 g_free (uri);
129 if (type == MEDIA_TYPE_DVD || type == MEDIA_TYPE_VCD) {
130 char *label;
131
132 label = totem_pl_parser_iso_get_title (file);
133 totem_pl_parser_add_one_uri (parser, retval, label);
134 g_free (label);
135 g_free (retval);
136 return TOTEM_PL_PARSER_RESULT_SUCCESS;
137 }
138
139 return TOTEM_PL_PARSER_RESULT_IGNORED;
140 }
141
142 TotemPlParserResult
totem_pl_parser_add_cue(TotemPlParser * parser,GFile * file,GFile * base_file,TotemPlParseData * parse_data,gpointer data)143 totem_pl_parser_add_cue (TotemPlParser *parser,
144 GFile *file,
145 GFile *base_file,
146 TotemPlParseData *parse_data,
147 gpointer data)
148 {
149 char *vcduri, *path;
150
151 path = g_file_get_path (file);
152 if (path == NULL)
153 return TOTEM_PL_PARSER_RESULT_IGNORED;
154
155 vcduri = totem_cd_mrl_from_type ("vcd", path);
156 g_free (path);
157 totem_pl_parser_add_one_uri (parser, vcduri, NULL);
158 g_free (vcduri);
159
160 return TOTEM_PL_PARSER_RESULT_SUCCESS;
161 }
162
163 static int
totem_pl_parser_dir_compare(GFileInfo * a,GFileInfo * b)164 totem_pl_parser_dir_compare (GFileInfo *a, GFileInfo *b)
165 {
166 const char *name_1, *name_2;
167 char *key_1, *key_2;
168 gboolean sort_last_1, sort_last_2;
169 int compare;
170
171 name_1 = g_file_info_get_name (a);
172 name_2 = g_file_info_get_name (b);
173
174 if (name_1 == NULL) {
175 if (name_2 == NULL)
176 compare = 0;
177 else
178 compare = -1;
179 } else {
180 sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2;
181 sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2;
182
183 if (sort_last_1 && !sort_last_2) {
184 compare = +1;
185 } else if (!sort_last_1 && sort_last_2) {
186 compare = -1;
187 } else {
188 key_1 = g_utf8_collate_key_for_filename (name_1, -1);
189 key_2 = g_utf8_collate_key_for_filename (name_2, -1);
190 compare = strcmp (key_1, key_2);
191 g_free (key_1);
192 g_free (key_2);
193 }
194 }
195
196 return compare;
197 }
198
199 static gboolean
totem_pl_parser_load_directory(GFile * file,GList ** list,gboolean * unhandled)200 totem_pl_parser_load_directory (GFile *file, GList **list, gboolean *unhandled)
201 {
202 GFileEnumerator *e;
203 GFileInfo *info;
204 GError *err = NULL;
205
206 *list = NULL;
207 *unhandled = FALSE;
208
209 e = g_file_enumerate_children (file,
210 G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
211 G_FILE_QUERY_INFO_NONE,
212 NULL, &err);
213 if (e == NULL) {
214 if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED) != FALSE)
215 *unhandled = TRUE;
216 g_error_free (err);
217 return FALSE;
218 }
219
220 while ((info = g_file_enumerator_next_file (e, NULL, NULL)) != NULL)
221 *list = g_list_prepend (*list, info);
222
223 g_file_enumerator_close (e, NULL, NULL);
224 g_object_unref (e);
225 return TRUE;
226 }
227
228 TotemPlParserResult
totem_pl_parser_add_directory(TotemPlParser * parser,GFile * file,GFile * base_file,TotemPlParseData * parse_data,gpointer data)229 totem_pl_parser_add_directory (TotemPlParser *parser,
230 GFile *file,
231 GFile *base_file,
232 TotemPlParseData *parse_data,
233 gpointer data)
234 {
235 TotemDiscMediaType type;
236 GList *list, *l;
237 char *media_uri, *uri;
238 gboolean unhandled;
239
240 uri = g_file_get_uri (file);
241 media_uri = NULL;
242 type = totem_cd_detect_type_from_dir (uri, &media_uri, NULL);
243 g_free (uri);
244
245 if (type != MEDIA_TYPE_DATA && type != MEDIA_TYPE_ERROR && media_uri != NULL) {
246 char *base_name = NULL, *fname;
247
248 fname = g_file_get_path (file);
249 if (fname != NULL) {
250 base_name = g_filename_display_basename (fname);
251 g_free (fname);
252 }
253 totem_pl_parser_add_one_uri (parser, media_uri, base_name);
254 g_free (base_name);
255 g_free (media_uri);
256 return TOTEM_PL_PARSER_RESULT_SUCCESS;
257 }
258 g_free (media_uri);
259
260 if (totem_pl_parser_load_directory (file, &list, &unhandled) == FALSE) {
261 if (unhandled != FALSE)
262 return TOTEM_PL_PARSER_RESULT_UNHANDLED;
263 return TOTEM_PL_PARSER_RESULT_ERROR;
264 }
265
266 list = g_list_sort (list, (GCompareFunc) totem_pl_parser_dir_compare);
267 l = list;
268
269 while (l != NULL) {
270 GFileInfo *info = l->data;
271 GFile *item;
272 TotemPlParserResult ret;
273 const char *content_type;
274
275 item = g_file_get_child (file, g_file_info_get_name (info));
276
277 /* Ignore partial files */
278 content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
279 if (g_strcmp0 ("application/x-partial-download", content_type) == 0)
280 ret = TOTEM_PL_PARSER_RESULT_IGNORED;
281 else
282 ret = totem_pl_parser_parse_internal (parser, item, NULL, parse_data);
283
284 if (ret != TOTEM_PL_PARSER_RESULT_SUCCESS &&
285 ret != TOTEM_PL_PARSER_RESULT_IGNORED &&
286 ret != TOTEM_PL_PARSER_RESULT_ERROR) {
287 char *item_uri;
288
289 item_uri = g_file_get_uri (item);
290 totem_pl_parser_add_one_uri (parser, item_uri, NULL);
291 g_free (item_uri);
292 }
293
294 g_object_unref (item);
295 g_object_unref (info);
296
297 l = l->next;
298 }
299
300 g_list_free (list);
301
302 return TOTEM_PL_PARSER_RESULT_SUCCESS;
303 }
304
305 TotemPlParserResult
totem_pl_parser_add_block(TotemPlParser * parser,GFile * file,GFile * base_file,TotemPlParseData * parse_data,gpointer data)306 totem_pl_parser_add_block (TotemPlParser *parser,
307 GFile *file,
308 GFile *base_file,
309 TotemPlParseData *parse_data,
310 gpointer data)
311 {
312 TotemDiscMediaType type;
313 char *media_uri, *path;
314 GError *err = NULL;
315
316 path = g_file_get_path (file);
317 if (path == NULL)
318 return TOTEM_PL_PARSER_RESULT_UNHANDLED;
319
320 type = totem_cd_detect_type_with_url (path, &media_uri, &err);
321 g_free (path);
322 if (err != NULL) {
323 DEBUG(file, g_print ("Couldn't get CD type for URI '%s': %s\n", uri, err->message));
324 g_error_free (err);
325 }
326 if (media_uri == NULL)
327 return TOTEM_PL_PARSER_RESULT_UNHANDLED;
328 else if (type == MEDIA_TYPE_ERROR)
329 return TOTEM_PL_PARSER_RESULT_ERROR;
330
331 totem_pl_parser_add_one_uri (parser, media_uri, NULL);
332 g_free (media_uri);
333 return TOTEM_PL_PARSER_RESULT_SUCCESS;
334 }
335
336 #endif /* !TOTEM_PL_PARSER_MINI */
337
338
339