1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /***************************************************************************
4 * brasero-project-parse.c
5 *
6 * dim nov 27 14:58:13 2008
7 * Copyright 2005-2008 Rouquier Philippe
8 * brasero-app@wanadoo.fr
9 ***************************************************************************/
10
11 /*
12 * Brasero is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * Brasero is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to:
24 * The Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor
26 * Boston, MA 02110-1301, USA.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <glib.h>
34 #include <glib/gstdio.h>
35 #include <glib/gi18n.h>
36
37 #include <libxml/xmlerror.h>
38 #include <libxml/xmlwriter.h>
39 #include <libxml/parser.h>
40 #include <libxml/xmlstring.h>
41 #include <libxml/uri.h>
42
43 #ifdef BUILD_PLAYLIST
44 #include <totem-pl-parser.h>
45 #endif
46
47 #include "brasero-project-parse.h"
48 #include "brasero-app.h"
49
50 #include "brasero-units.h"
51 #include "brasero-track-stream-cfg.h"
52 #include "brasero-track-data-cfg.h"
53 #include "brasero-session.h"
54 #include "brasero-tags.h"
55
56 #define BRASERO_PROJECT_VERSION "0.2"
57
58 static void
brasero_project_invalid_project_dialog(const char * reason)59 brasero_project_invalid_project_dialog (const char *reason)
60 {
61 brasero_app_alert (brasero_app_get_default (),
62 _("Error while loading the project."),
63 reason,
64 GTK_MESSAGE_ERROR);
65 }
66
67 static GSList *
_read_graft_point(xmlDocPtr project,xmlNodePtr graft,GSList * grafts)68 _read_graft_point (xmlDocPtr project,
69 xmlNodePtr graft,
70 GSList *grafts)
71 {
72 BraseroGraftPt *retval;
73
74 retval = g_new0 (BraseroGraftPt, 1);
75 grafts = g_slist_prepend (grafts, retval);
76 while (graft) {
77 if (!xmlStrcmp (graft->name, (const xmlChar *) "uri")) {
78 xmlChar *uri;
79
80 if (retval->uri)
81 goto error;
82
83 uri = xmlNodeListGetString (project,
84 graft->xmlChildrenNode,
85 1);
86 retval->uri = g_uri_unescape_string ((char *)uri, NULL);
87 g_free (uri);
88 if (!retval->uri)
89 goto error;
90 }
91 else if (!xmlStrcmp (graft->name, (const xmlChar *) "path")) {
92 if (retval->path)
93 goto error;
94
95 retval->path = (char *) xmlNodeListGetString (project,
96 graft->xmlChildrenNode,
97 1);
98 if (!retval->path)
99 goto error;
100 }
101 else if (graft->type == XML_ELEMENT_NODE)
102 goto error;
103
104 graft = graft->next;
105 }
106
107 return grafts;
108
109 error:
110
111 g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
112 g_slist_free (grafts);
113
114 return NULL;
115 }
116
117 static BraseroTrack *
_read_data_track(xmlDocPtr project,xmlNodePtr item)118 _read_data_track (xmlDocPtr project,
119 xmlNodePtr item)
120 {
121 BraseroTrackDataCfg *track;
122 GSList *grafts= NULL;
123 GSList *excluded = NULL;
124
125 track = brasero_track_data_cfg_new ();
126
127 while (item) {
128 if (!xmlStrcmp (item->name, (const xmlChar *) "graft")) {
129 if (!(grafts = _read_graft_point (project, item->xmlChildrenNode, grafts)))
130 goto error;
131 }
132 else if (!xmlStrcmp (item->name, (const xmlChar *) "icon")) {
133 xmlChar *icon_path;
134
135 icon_path = xmlNodeListGetString (project,
136 item->xmlChildrenNode,
137 1);
138 if (!icon_path)
139 goto error;
140
141 brasero_track_data_cfg_set_icon (track, (gchar *) icon_path, NULL);
142 g_free (icon_path);
143 }
144 else if (!xmlStrcmp (item->name, (const xmlChar *) "restored")) {
145 xmlChar *restored;
146
147 restored = xmlNodeListGetString (project,
148 item->xmlChildrenNode,
149 1);
150 if (!restored)
151 goto error;
152
153 brasero_track_data_cfg_dont_filter_uri (track, (gchar *) restored);
154 g_free (restored);
155 }
156 else if (!xmlStrcmp (item->name, (const xmlChar *) "excluded")) {
157 xmlChar *excluded_uri;
158
159 excluded_uri = xmlNodeListGetString (project,
160 item->xmlChildrenNode,
161 1);
162 if (!excluded_uri)
163 goto error;
164
165 excluded = g_slist_prepend (excluded, xmlURIUnescapeString ((char*) excluded_uri, 0, NULL));
166 g_free (excluded_uri);
167 }
168 else if (item->type == XML_ELEMENT_NODE)
169 goto error;
170
171 item = item->next;
172 }
173
174 grafts = g_slist_reverse (grafts);
175 excluded = g_slist_reverse (excluded);
176 brasero_track_data_set_source (BRASERO_TRACK_DATA (track),
177 grafts,
178 excluded);
179 return BRASERO_TRACK (track);
180
181 error:
182
183 g_slist_foreach (grafts, (GFunc) brasero_graft_point_free, NULL);
184 g_slist_free (grafts);
185
186 g_slist_foreach (excluded, (GFunc) g_free, NULL);
187 g_slist_free (excluded);
188
189 g_object_unref (track);
190
191 return NULL;
192 }
193
194 static BraseroTrack *
_read_audio_track(xmlDocPtr project,xmlNodePtr uris,gboolean is_video)195 _read_audio_track (xmlDocPtr project,
196 xmlNodePtr uris,
197 gboolean is_video)
198 {
199 BraseroTrackStreamCfg *track;
200
201 track = brasero_track_stream_cfg_new ();
202
203 while (uris) {
204 if (!xmlStrcmp (uris->name, (const xmlChar *) "uri")) {
205 xmlChar *uri;
206 gchar *unescaped_uri;
207
208 uri = xmlNodeListGetString (project,
209 uris->xmlChildrenNode,
210 1);
211 if (!uri)
212 goto error;
213
214 unescaped_uri = g_uri_unescape_string ((char *) uri, NULL);
215 g_free (uri);
216
217 /* Note: this must come before brasero_track_stream_set_boundaries ()
218 * or we will reset the end point to 0 */
219 brasero_track_stream_set_source (BRASERO_TRACK_STREAM (track), unescaped_uri);
220
221 /* For the moment pretend it is a video file. Since it is BraseroTrackStreamCfg, that
222 * will be set properly afterwards. */
223 if (is_video)
224 brasero_track_stream_set_format (BRASERO_TRACK_STREAM (track),
225 BRASERO_VIDEO_FORMAT_UNDEFINED);
226
227 g_free (unescaped_uri);
228 }
229 else if (!xmlStrcmp (uris->name, (const xmlChar *) "silence")) {
230 gchar *silence;
231
232 /* impossible to have two gaps in a row */
233 if (brasero_track_stream_get_gap (BRASERO_TRACK_STREAM (track)) > 0)
234 goto error;
235
236 silence = (gchar *) xmlNodeListGetString (project,
237 uris->xmlChildrenNode,
238 1);
239 if (!silence)
240 goto error;
241
242 brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track),
243 -1,
244 -1,
245 g_ascii_strtoull (silence, NULL, 10));
246 g_free (silence);
247 }
248 else if (!xmlStrcmp (uris->name, (const xmlChar *) "start")) {
249 gchar *start;
250
251 start = (gchar *) xmlNodeListGetString (project,
252 uris->xmlChildrenNode,
253 1);
254 if (!start)
255 goto error;
256
257 brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track),
258 g_ascii_strtoull (start, NULL, 10),
259 -1,
260 -1);
261 g_free (start);
262 }
263 else if (!xmlStrcmp (uris->name, (const xmlChar *) "end")) {
264 gchar *end;
265
266 end = (gchar *) xmlNodeListGetString (project,
267 uris->xmlChildrenNode,
268 1);
269 if (!end)
270 goto error;
271
272 brasero_track_stream_set_boundaries (BRASERO_TRACK_STREAM (track),
273 -1,
274 g_ascii_strtoull (end, NULL, 10),
275 -1);
276 g_free (end);
277 }
278 else if (!xmlStrcmp (uris->name, (const xmlChar *) "title")) {
279 xmlChar *title;
280 gchar *unescaped_title;
281
282 title = xmlNodeListGetString (project,
283 uris->xmlChildrenNode,
284 1);
285 if (!title)
286 goto error;
287
288 unescaped_title = g_uri_unescape_string ((char *) title, NULL);
289 g_free (title);
290
291 brasero_track_tag_add_string (BRASERO_TRACK (track),
292 BRASERO_TRACK_STREAM_TITLE_TAG,
293 unescaped_title);
294 g_free (unescaped_title);
295 }
296 else if (!xmlStrcmp (uris->name, (const xmlChar *) "artist")) {
297 xmlChar *artist;
298 gchar *unescaped_artist;
299
300 artist = xmlNodeListGetString (project,
301 uris->xmlChildrenNode,
302 1);
303 if (!artist)
304 goto error;
305
306 unescaped_artist = g_uri_unescape_string ((char *) artist, NULL);
307 g_free (artist);
308
309 brasero_track_tag_add_string (BRASERO_TRACK (track),
310 BRASERO_TRACK_STREAM_ARTIST_TAG,
311 unescaped_artist);
312 g_free (unescaped_artist);
313 }
314 else if (!xmlStrcmp (uris->name, (const xmlChar *) "composer")) {
315 xmlChar *composer;
316 gchar *unescaped_composer;
317
318 composer = xmlNodeListGetString (project,
319 uris->xmlChildrenNode,
320 1);
321 if (!composer)
322 goto error;
323
324 unescaped_composer = g_uri_unescape_string ((char *) composer, NULL);
325 g_free (composer);
326
327 brasero_track_tag_add_string (BRASERO_TRACK (track),
328 BRASERO_TRACK_STREAM_COMPOSER_TAG,
329 unescaped_composer);
330 g_free (unescaped_composer);
331 }
332 else if (!xmlStrcmp (uris->name, (const xmlChar *) "isrc")) {
333 xmlChar *isrc;
334 gchar *unescaped_isrc;
335
336 isrc = xmlNodeListGetString (project,
337 uris->xmlChildrenNode,
338 1);
339 if (!isrc)
340 goto error;
341
342 unescaped_isrc = g_uri_unescape_string ((char *) isrc, NULL);
343 g_free (isrc);
344
345 brasero_track_tag_add_string (BRASERO_TRACK (track),
346 BRASERO_TRACK_STREAM_ISRC_TAG,
347 unescaped_isrc);
348 g_free (unescaped_isrc);
349 }
350 else if (uris->type == XML_ELEMENT_NODE)
351 goto error;
352
353 uris = uris->next;
354 }
355
356 return BRASERO_TRACK (track);
357
358 error:
359
360 g_object_unref (track);
361
362 return NULL;
363 }
364
365 static gboolean
_get_tracks(xmlDocPtr project,xmlNodePtr track_node,BraseroBurnSession * session)366 _get_tracks (xmlDocPtr project,
367 xmlNodePtr track_node,
368 BraseroBurnSession *session)
369 {
370 GSList *tracks = NULL;
371 GSList *iter;
372
373 track_node = track_node->xmlChildrenNode;
374
375 while (track_node) {
376 BraseroTrack *newtrack;
377
378 if (!xmlStrcmp (track_node->name, (const xmlChar *) "audio")) {
379 newtrack = _read_audio_track (project, track_node->xmlChildrenNode, FALSE);
380 if (!newtrack)
381 goto error;
382
383 tracks = g_slist_append (tracks, newtrack);
384 }
385 else if (!xmlStrcmp (track_node->name, (const xmlChar *) "data")) {
386 newtrack = _read_data_track (project, track_node->xmlChildrenNode);
387
388 if (!newtrack)
389 goto error;
390
391 tracks = g_slist_append (tracks, newtrack);
392 }
393 else if (!xmlStrcmp (track_node->name, (const xmlChar *) "video")) {
394 newtrack = _read_audio_track (project, track_node->xmlChildrenNode, TRUE);
395
396 if (!newtrack)
397 goto error;
398
399 tracks = g_slist_append (tracks, newtrack);
400 }
401 else if (track_node->type == XML_ELEMENT_NODE)
402 goto error;
403
404 track_node = track_node->next;
405 }
406
407 if (!tracks)
408 goto error;
409
410 for (iter = tracks; iter; iter = iter->next) {
411 BraseroTrack *newtrack;
412
413 newtrack = iter->data;
414 brasero_burn_session_add_track (session, newtrack, NULL);
415 g_object_unref (newtrack);
416 }
417
418 g_slist_free (tracks);
419
420 return TRUE;
421
422 error :
423
424 if (tracks) {
425 g_slist_foreach (tracks, (GFunc) g_object_unref, NULL);
426 g_slist_free (tracks);
427 }
428
429 return FALSE;
430 }
431
432 gboolean
brasero_project_open_project_xml(const gchar * uri,BraseroBurnSession * session,gboolean warn_user)433 brasero_project_open_project_xml (const gchar *uri,
434 BraseroBurnSession *session,
435 gboolean warn_user)
436 {
437 xmlNodePtr track_node = NULL;
438 gchar *label = NULL;
439 gchar *cover = NULL;
440 xmlDocPtr project;
441 xmlNodePtr item;
442 gboolean retval;
443 GFile *file;
444 gchar *path;
445
446 file = g_file_new_for_commandline_arg (uri);
447 path = g_file_get_path (file);
448 g_object_unref (file);
449 if (!path)
450 return FALSE;
451
452 /* start parsing xml doc */
453 project = xmlParseFile (path);
454 g_free (path);
455
456 if (!project) {
457 if (warn_user)
458 brasero_project_invalid_project_dialog (_("The project could not be opened"));
459
460 return FALSE;
461 }
462
463 /* parses the "header" */
464 item = xmlDocGetRootElement (project);
465 if (!item) {
466 if (warn_user)
467 brasero_project_invalid_project_dialog (_("The file is empty"));
468
469 xmlFreeDoc (project);
470 return FALSE;
471 }
472
473 if (xmlStrcmp (item->name, (const xmlChar *) "braseroproject")
474 || item->next)
475 goto error;
476
477 item = item->children;
478 while (item) {
479 if (!xmlStrcmp (item->name, (const xmlChar *) "version")) {
480 /* simply ignore it */
481 }
482 else if (!xmlStrcmp (item->name, (const xmlChar *) "label")) {
483 label = (gchar *) xmlNodeListGetString (project,
484 item->xmlChildrenNode,
485 1);
486 if (!(label))
487 goto error;
488 }
489 else if (!xmlStrcmp (item->name, (const xmlChar *) "cover")) {
490 xmlChar *escaped;
491
492 escaped = xmlNodeListGetString (project,
493 item->xmlChildrenNode,
494 1);
495 if (!escaped)
496 goto error;
497
498 cover = g_uri_unescape_string ((char *) escaped, NULL);
499 g_free (escaped);
500 }
501 else if (!xmlStrcmp (item->name, (const xmlChar *) "track")) {
502 if (track_node)
503 goto error;
504
505 track_node = item;
506 }
507 else if (item->type == XML_ELEMENT_NODE)
508 goto error;
509
510 item = item->next;
511 }
512
513 retval = _get_tracks (project, track_node, session);
514 if (!retval)
515 goto error;
516
517 xmlFreeDoc (project);
518
519 brasero_burn_session_set_label (session, label);
520 g_free (label);
521
522 if (cover) {
523 GValue *value;
524
525 value = g_new0 (GValue, 1);
526 g_value_init (value, G_TYPE_STRING);
527 g_value_set_string (value, cover);
528 brasero_burn_session_tag_add (session,
529 BRASERO_COVER_URI,
530 value);
531
532 g_free (cover);
533 }
534
535 return retval;
536
537 error:
538
539 if (cover)
540 g_free (cover);
541 if (label)
542 g_free (label);
543
544 xmlFreeDoc (project);
545 if (warn_user)
546 brasero_project_invalid_project_dialog (_("It does not seem to be a valid Brasero project"));
547
548 return FALSE;
549 }
550
551 #ifdef BUILD_PLAYLIST
552
553 static void
brasero_project_playlist_playlist_started(TotemPlParser * parser,const gchar * uri,GHashTable * metadata,gpointer user_data)554 brasero_project_playlist_playlist_started (TotemPlParser *parser,
555 const gchar *uri,
556 GHashTable *metadata,
557 gpointer user_data)
558 {
559 BraseroBurnSession *session = user_data;
560
561 brasero_burn_session_set_label (session, g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE));
562 }
563
564 static void
brasero_project_playlist_entry_parsed(TotemPlParser * parser,const gchar * uri,GHashTable * metadata,gpointer user_data)565 brasero_project_playlist_entry_parsed (TotemPlParser *parser,
566 const gchar *uri,
567 GHashTable *metadata,
568 gpointer user_data)
569 {
570 BraseroBurnSession *session = user_data;
571 BraseroTrackStreamCfg *track;
572
573 track = brasero_track_stream_cfg_new ();
574 brasero_track_stream_set_source (BRASERO_TRACK_STREAM (track), uri);
575 brasero_burn_session_add_track (session, BRASERO_TRACK (track), NULL);
576 }
577
578 gboolean
brasero_project_open_audio_playlist_project(const gchar * uri,BraseroBurnSession * session,gboolean warn_user)579 brasero_project_open_audio_playlist_project (const gchar *uri,
580 BraseroBurnSession *session,
581 gboolean warn_user)
582 {
583 TotemPlParser *parser;
584 TotemPlParserResult result;
585 GFile *file;
586 char *_uri;
587
588 file = g_file_new_for_commandline_arg (uri);
589 _uri = g_file_get_uri (file);
590 g_object_unref (file);
591
592 parser = totem_pl_parser_new ();
593 g_object_set (parser,
594 "recurse", FALSE,
595 "disable-unsafe", TRUE,
596 NULL);
597
598 g_signal_connect (parser,
599 "playlist-started",
600 G_CALLBACK (brasero_project_playlist_playlist_started),
601 session);
602
603 g_signal_connect (parser,
604 "entry-parsed",
605 G_CALLBACK (brasero_project_playlist_entry_parsed),
606 session);
607
608 result = totem_pl_parser_parse (parser, _uri, FALSE);
609 if (result != TOTEM_PL_PARSER_RESULT_SUCCESS) {
610 if (warn_user)
611 brasero_project_invalid_project_dialog (_("It does not seem to be a valid Brasero project"));
612 }
613
614 g_free (_uri);
615 g_object_unref (parser);
616
617 return (result == TOTEM_PL_PARSER_RESULT_SUCCESS);
618 }
619
620 #endif
621
622 /**
623 * Project saving
624 */
625
626 static gboolean
_save_audio_track_xml(xmlTextWriter * project,BraseroTrackStream * track)627 _save_audio_track_xml (xmlTextWriter *project,
628 BraseroTrackStream *track)
629 {
630 xmlChar *escaped;
631 gchar *start;
632 gint success;
633 gchar *uri;
634 gchar *end;
635
636 uri = brasero_track_stream_get_source (track, TRUE);
637 escaped = (unsigned char *) g_uri_escape_string (uri, NULL, FALSE);
638 g_free (uri);
639
640 success = xmlTextWriterWriteElement (project,
641 (xmlChar *) "uri",
642 escaped);
643 g_free (escaped);
644
645 if (success == -1)
646 return FALSE;
647
648 if (brasero_track_stream_get_gap (track) > 0) {
649 gchar *silence;
650
651 silence = g_strdup_printf ("%"G_GINT64_FORMAT, brasero_track_stream_get_gap (track));
652 success = xmlTextWriterWriteElement (project,
653 (xmlChar *) "silence",
654 (xmlChar *) silence);
655
656 g_free (silence);
657 if (success == -1)
658 return FALSE;
659 }
660
661 if (brasero_track_stream_get_end (track) > 0) {
662 /* start of the song */
663 start = g_strdup_printf ("%"G_GINT64_FORMAT, brasero_track_stream_get_start (track));
664 success = xmlTextWriterWriteElement (project,
665 (xmlChar *) "start",
666 (xmlChar *) start);
667
668 g_free (start);
669 if (success == -1)
670 return FALSE;
671
672 /* end of the song */
673 end = g_strdup_printf ("%"G_GINT64_FORMAT, brasero_track_stream_get_end (track));
674 success = xmlTextWriterWriteElement (project,
675 (xmlChar *) "end",
676 (xmlChar *) end);
677
678 g_free (end);
679 if (success == -1)
680 return FALSE;
681 }
682
683 if (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_TITLE_TAG)) {
684 escaped = (unsigned char *) g_uri_escape_string (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_TITLE_TAG), NULL, FALSE);
685 success = xmlTextWriterWriteElement (project,
686 (xmlChar *) "title",
687 escaped);
688 g_free (escaped);
689
690 if (success == -1)
691 return FALSE;
692 }
693
694 if (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ARTIST_TAG)) {
695 escaped = (unsigned char *) g_uri_escape_string (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ARTIST_TAG), NULL, FALSE);
696 success = xmlTextWriterWriteElement (project,
697 (xmlChar *) "artist",
698 escaped);
699 g_free (escaped);
700
701 if (success == -1)
702 return FALSE;
703 }
704
705 if (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_COMPOSER_TAG)) {
706 escaped = (unsigned char *) g_uri_escape_string (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_COMPOSER_TAG), NULL, FALSE);
707 success = xmlTextWriterWriteElement (project,
708 (xmlChar *) "composer",
709 escaped);
710 g_free (escaped);
711 if (success == -1)
712 return FALSE;
713 }
714
715 if (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ISRC_TAG)) {
716 escaped = (unsigned char *) g_uri_escape_string (brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ISRC_TAG), NULL, FALSE);
717 success = xmlTextWriterWriteElement (project,
718 (xmlChar *) "isrc",
719 escaped);
720
721 g_free (escaped);
722 if (success == -1)
723 return FALSE;
724 }
725
726 return TRUE;
727 }
728
729 static gboolean
_save_data_track_xml(xmlTextWriter * project,BraseroBurnSession * session)730 _save_data_track_xml (xmlTextWriter *project,
731 BraseroBurnSession *session)
732 {
733 gchar *uri;
734 gint success;
735 GSList *iter;
736 GSList *tracks;
737 GSList *grafts;
738 gchar *filename;
739 BraseroTrackDataCfg *track;
740
741 tracks = brasero_burn_session_get_tracks (session);
742 track = BRASERO_TRACK_DATA_CFG (tracks->data);
743
744 filename = brasero_track_data_cfg_get_icon_path (track);
745 if (filename) {
746 /* Write the icon if any */
747 success = xmlTextWriterWriteElement (project, (xmlChar *) "icon", (xmlChar *) filename);
748 g_free (filename);
749 if (success < 0)
750 return FALSE;
751 }
752
753 grafts = brasero_track_data_get_grafts (BRASERO_TRACK_DATA (track));
754 for (; grafts; grafts = grafts->next) {
755 BraseroGraftPt *graft;
756
757 graft = grafts->data;
758
759 success = xmlTextWriterStartElement (project, (xmlChar *) "graft");
760 if (success < 0)
761 return FALSE;
762
763 success = xmlTextWriterWriteElement (project, (xmlChar *) "path", (xmlChar *) graft->path);
764 if (success < 0)
765 return FALSE;
766
767 if (graft->uri) {
768 xmlChar *escaped;
769
770 escaped = (unsigned char *) g_uri_escape_string (graft->uri, NULL, FALSE);
771 success = xmlTextWriterWriteElement (project, (xmlChar *) "uri", escaped);
772 g_free (escaped);
773 if (success < 0)
774 return FALSE;
775 }
776
777 success = xmlTextWriterEndElement (project); /* graft */
778 if (success < 0)
779 return FALSE;
780 }
781
782 /* save excluded uris */
783 iter = brasero_track_data_get_excluded_list (BRASERO_TRACK_DATA (track));
784 for (; iter; iter = iter->next) {
785 xmlChar *escaped;
786
787 escaped = xmlURIEscapeStr ((xmlChar *) iter->data, NULL);
788 success = xmlTextWriterWriteElement (project, (xmlChar *) "excluded", (xmlChar *) escaped);
789 g_free (escaped);
790 if (success < 0)
791 return FALSE;
792 }
793
794 /* save restored uris */
795 iter = brasero_track_data_cfg_get_restored_list (track);
796 for (; iter; iter = iter->next) {
797 uri = iter->data;
798 success = xmlTextWriterWriteElement (project, (xmlChar *) "restored", (xmlChar *) uri);
799 if (success < 0)
800 return FALSE;
801 }
802
803 /* NOTE: we don't write symlinks and unreadable they are useless */
804 return TRUE;
805 }
806
807 gboolean
brasero_project_save_project_xml(BraseroBurnSession * session,const gchar * uri)808 brasero_project_save_project_xml (BraseroBurnSession *session,
809 const gchar *uri)
810 {
811 BraseroTrackType *track_type = NULL;
812 xmlTextWriter *project;
813 gboolean retval;
814 GSList *tracks;
815 GValue *value;
816 gint success;
817 gchar *path;
818
819 path = g_filename_from_uri (uri, NULL, NULL);
820 if (!path)
821 return FALSE;
822
823 project = xmlNewTextWriterFilename (path, 0);
824 if (!project) {
825 g_free (path);
826 return FALSE;
827 }
828
829 xmlTextWriterSetIndent (project, 1);
830 xmlTextWriterSetIndentString (project, (xmlChar *) "\t");
831
832 success = xmlTextWriterStartDocument (project,
833 NULL,
834 "UTF-8",
835 NULL);
836 if (success < 0)
837 goto error;
838
839 success = xmlTextWriterStartElement (project, (xmlChar *) "braseroproject");
840 if (success < 0)
841 goto error;
842
843 /* write the name of the version */
844 success = xmlTextWriterWriteElement (project,
845 (xmlChar *) "version",
846 (xmlChar *) BRASERO_PROJECT_VERSION);
847 if (success < 0)
848 goto error;
849
850 if (brasero_burn_session_get_label (session)) {
851 success = xmlTextWriterWriteElement (project,
852 (xmlChar *) "label",
853 (xmlChar *) brasero_burn_session_get_label (session));
854
855 if (success < 0)
856 goto error;
857 }
858
859 value = NULL;
860 brasero_burn_session_tag_lookup (session,
861 BRASERO_COVER_URI,
862 &value);
863 if (value) {
864 gchar *escaped;
865
866 escaped = g_uri_escape_string (g_value_get_string (value), NULL, FALSE);
867 success = xmlTextWriterWriteElement (project,
868 (xmlChar *) "cover",
869 (xmlChar *) escaped);
870 g_free (escaped);
871
872 if (success < 0)
873 goto error;
874 }
875
876 success = xmlTextWriterStartElement (project, (xmlChar *) "track");
877 if (success < 0)
878 goto error;
879
880 track_type = brasero_track_type_new ();
881 tracks = brasero_burn_session_get_tracks (session);
882
883 for (; tracks; tracks = tracks->next) {
884 BraseroTrack *track;
885
886 track = tracks->data;
887
888 brasero_track_get_track_type (track, track_type);
889 if (brasero_track_type_get_has_stream (track_type)) {
890 if (BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (track_type)))
891 success = xmlTextWriterStartElement (project, (xmlChar *) "video");
892 else
893 success = xmlTextWriterStartElement (project, (xmlChar *) "audio");
894
895 if (success < 0)
896 goto error;
897
898 retval = _save_audio_track_xml (project, BRASERO_TRACK_STREAM (track));
899 if (!retval)
900 goto error;
901
902 success = xmlTextWriterEndElement (project); /* audio/video */
903 if (success < 0)
904 goto error;
905 }
906 else if (brasero_track_type_get_has_data (track_type)) {
907 success = xmlTextWriterStartElement (project, (xmlChar *) "data");
908 if (success < 0)
909 goto error;
910
911 retval = _save_data_track_xml (project, session);
912 if (!retval)
913 goto error;
914
915 success = xmlTextWriterEndElement (project); /* data */
916 if (success < 0)
917 goto error;
918 }
919 else
920 retval = FALSE;
921 }
922
923 success = xmlTextWriterEndElement (project); /* track */
924 if (success < 0)
925 goto error;
926
927 brasero_track_type_free (track_type);
928
929 success = xmlTextWriterEndElement (project); /* braseroproject */
930 if (success < 0)
931 goto error;
932
933 xmlTextWriterEndDocument (project);
934 xmlFreeTextWriter (project);
935 g_free (path);
936 return TRUE;
937
938 error:
939
940 if (track_type)
941 brasero_track_type_free (track_type);
942
943 xmlTextWriterEndDocument (project);
944 xmlFreeTextWriter (project);
945
946 g_remove (path);
947 g_free (path);
948
949 return FALSE;
950 }
951
952 gboolean
brasero_project_save_audio_project_plain_text(BraseroBurnSession * session,const gchar * uri)953 brasero_project_save_audio_project_plain_text (BraseroBurnSession *session,
954 const gchar *uri)
955 {
956 const gchar *title;
957 guint written;
958 GSList *iter;
959 gchar *path;
960 FILE *file;
961
962 path = g_filename_from_uri (uri, NULL, NULL);
963 if (!path)
964 return FALSE;
965
966 file = fopen (path, "w+");
967 g_free (path);
968 if (!file)
969 return FALSE;
970
971 /* write title */
972 title = brasero_burn_session_get_label (session);
973 written = fwrite (title, strlen (title), 1, file);
974 if (written != 1)
975 goto error;
976
977 written = fwrite ("\n", 1, 1, file);
978 if (written != 1)
979 goto error;
980
981 iter = brasero_burn_session_get_tracks (session);
982 for (; iter; iter = iter->next) {
983 BraseroTrackStream *track;
984 const gchar *text;
985 gchar *time;
986 guint64 len;
987 gchar *uri;
988
989 track = iter->data;
990
991 text = brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_TITLE_TAG);
992 written = fwrite (title, 1, strlen (title), file);
993 if (written != strlen (title))
994 goto error;
995
996 len = 0;
997 brasero_track_stream_get_length (track, &len);
998 time = brasero_units_get_time_string (len, TRUE, FALSE);
999 if (time) {
1000 written = fwrite ("\t", 1, 1, file);
1001 if (written != 1)
1002 goto error;
1003
1004 written = fwrite (time, 1, strlen (time), file);
1005 if (written != strlen (time)) {
1006 g_free (time);
1007 goto error;
1008 }
1009 g_free (time);
1010 }
1011
1012 text = brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_ARTIST_TAG);
1013 if (text) {
1014 gchar *string;
1015
1016 written = fwrite ("\t", 1, 1, file);
1017 if (written != 1)
1018 goto error;
1019
1020 /* Translators: %s is an artist */
1021 string = g_strdup_printf (" by %s", text);
1022 written = fwrite (string, 1, strlen (string), file);
1023 if (written != strlen (string)) {
1024 g_free (string);
1025 goto error;
1026 }
1027 g_free (string);
1028 }
1029
1030 written = fwrite ("\n(", 1, 2, file);
1031 if (written != 2)
1032 goto error;
1033
1034 uri = brasero_track_stream_get_source (track, TRUE);
1035 written = fwrite (uri, 1, strlen (uri), file);
1036 if (written != strlen (uri)) {
1037 g_free (uri);
1038 goto error;
1039 }
1040
1041 g_free (uri);
1042
1043 written = fwrite (")", 1, 1, file);
1044 if (written != 1)
1045 goto error;
1046
1047 written = fwrite ("\n\n", 1, 2, file);
1048 if (written != 2)
1049 goto error;
1050 }
1051
1052 fclose (file);
1053 return TRUE;
1054
1055 error:
1056
1057 fclose (file);
1058
1059 return FALSE;
1060 }
1061
1062 #ifdef BUILD_PLAYLIST
1063
1064 gboolean
brasero_project_save_audio_project_playlist(BraseroBurnSession * session,const gchar * uri,BraseroProjectSave type)1065 brasero_project_save_audio_project_playlist (BraseroBurnSession *session,
1066 const gchar *uri,
1067 BraseroProjectSave type)
1068 {
1069 TotemPlParserType pl_type;
1070 TotemPlParser *parser;
1071 TotemPlPlaylist *playlist;
1072 TotemPlPlaylistIter pl_iter;
1073 gboolean result;
1074 GFile *file;
1075 GSList *iter;
1076
1077 file = g_file_new_for_uri (uri);
1078 parser = totem_pl_parser_new ();
1079 playlist = totem_pl_playlist_new ();
1080
1081 /* populate playlist */
1082 iter = brasero_burn_session_get_tracks (session);
1083 for (; iter; iter = iter->next) {
1084 BraseroTrackStream *track;
1085 const gchar *title;
1086 gchar *uri;
1087
1088 track = iter->data;
1089
1090 uri = brasero_track_stream_get_source (track, TRUE);
1091 title = brasero_track_tag_lookup_string (BRASERO_TRACK (track), BRASERO_TRACK_STREAM_TITLE_TAG);
1092
1093 totem_pl_playlist_append (playlist, &pl_iter);
1094 totem_pl_playlist_set (playlist, &pl_iter,
1095 TOTEM_PL_PARSER_FIELD_URI, uri,
1096 TOTEM_PL_PARSER_FIELD_TITLE, title,
1097 NULL);
1098 g_free (uri);
1099 }
1100
1101 switch (type) {
1102 case BRASERO_PROJECT_SAVE_PLAYLIST_M3U:
1103 pl_type = TOTEM_PL_PARSER_M3U;
1104 break;
1105 case BRASERO_PROJECT_SAVE_PLAYLIST_XSPF:
1106 pl_type = TOTEM_PL_PARSER_XSPF;
1107 break;
1108 case BRASERO_PROJECT_SAVE_PLAYLIST_IRIVER_PLA:
1109 pl_type = TOTEM_PL_PARSER_IRIVER_PLA;
1110 break;
1111
1112 case BRASERO_PROJECT_SAVE_PLAYLIST_PLS:
1113 default:
1114 pl_type = TOTEM_PL_PARSER_PLS;
1115 break;
1116 }
1117
1118 result = totem_pl_parser_save (parser, playlist, file,
1119 brasero_burn_session_get_label (session),
1120 pl_type, NULL);
1121
1122 g_object_unref (playlist);
1123 g_object_unref (parser);
1124 g_object_unref (file);
1125
1126 return result;
1127 }
1128
1129 #endif
1130