1 /* quvi
2 * Copyright (C) 2012,2013 Toni Gundogdu <legatvs@gmail.com>
3 *
4 * This file is part of quvi <http://quvi.sourceforge.net/>.
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public
8 * License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
10 *
11 * This program 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
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General
17 * Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <libxml/xmlwriter.h>
24 #include <libxml/uri.h>
25 #include <glib/gprintf.h>
26 #include <glib/gi18n.h>
27 #include <quvi.h>
28
29 #include "lutil.h"
30 /* -- */
31 #include "lprint.h"
32
33 struct xml_s
34 {
35 xmlTextWriterPtr w;
36 quvi_media_t qm;
37 xmlDocPtr d;
38 quvi_t q;
39 };
40
41 typedef struct xml_s *xml_t;
42
43 #define _chk_r_e(c)\
44 do {\
45 const gint r = c;\
46 if (r != EXIT_SUCCESS)\
47 return (_xml_handle_free(p, r));\
48 else\
49 return (EXIT_SUCCESS);\
50 } while (0)
51
52 #define _chk_r(c)\
53 do {\
54 const gint r = c;\
55 if (r != EXIT_SUCCESS)\
56 return (_xml_handle_free(p, r));\
57 } while (0)
58
_xml_handle_new(quvi_t q,quvi_media_t qm,gpointer * dst)59 static gint _xml_handle_new(quvi_t q, quvi_media_t qm, gpointer *dst)
60 {
61 xml_t p;
62
63 g_assert(dst != NULL);
64
65 p = g_new0(struct xml_s, 1);
66 p->qm = qm;
67 p->q = q;
68
69 p->w = xmlNewTextWriterDoc(&p->d, 0);
70 if (p->w == NULL)
71 {
72 lprint_xml_errmsg(_("while creating the XML writer"));
73 xmlFreeDoc(p->d);
74 g_free(p);
75 return (EXIT_FAILURE);
76 }
77
78 if (xmlTextWriterStartDocument(p->w, NULL, "UTF-8", NULL) <0)
79 {
80 lprint_xml_errmsg(_("while starting the XML document"));
81 xmlFreeDoc(p->d);
82 g_free(p);
83 return (EXIT_FAILURE);
84 }
85 *dst = p;
86
87 return (EXIT_SUCCESS);
88 }
89
_xml_handle_free(gpointer data,const gint r)90 static gint _xml_handle_free(gpointer data, const gint r)
91 {
92 xml_t p = (xml_t) data;
93
94 if (p == NULL)
95 return (r);
96
97 if (p->w != NULL)
98 {
99 xmlTextWriterEndDocument(p->w);
100 xmlFreeTextWriter(p->w);
101 }
102
103 if (p->d != NULL)
104 xmlFreeDoc(p->d);
105
106 g_free(p);
107 return (r);
108 }
109
110 typedef enum {START_R, END_R, ATTR, START_E, END_E} ErrorMessage;
111
112 static const gchar *_msg[]=
113 {
114 N_("while starting the XML document root element `%s'"),
115 N_("while ending the XML document root element `%s'"),
116 N_("while writing the XML attribute `%s'"),
117 N_("while starting the XML element `%s'"),
118 N_("while ending the XML element `%s'"),
119 NULL
120 };
121
_start_e(const xml_t p,const ErrorMessage e,const gchar * w)122 static gint _start_e(const xml_t p, const ErrorMessage e, const gchar *w)
123 {
124 gint r = EXIT_SUCCESS;
125 if (xmlTextWriterStartElement(p->w, BAD_CAST w) <0)
126 {
127 lprint_xml_errmsg("%s", g_dgettext(GETTEXT_PACKAGE, _msg[e]), w);
128 r = EXIT_FAILURE;
129 }
130 return (r);
131 }
132
_end_e(const xml_t p,const ErrorMessage e,const gchar * w)133 static gint _end_e(const xml_t p, const ErrorMessage e, const gchar *w)
134 {
135 gint r = EXIT_SUCCESS;
136 if (xmlTextWriterEndElement(p->w) <0)
137 {
138 lprint_xml_errmsg("%s", g_dgettext(GETTEXT_PACKAGE, _msg[e]), w);
139 r = EXIT_FAILURE;
140 }
141 return (r);
142 }
143
144 extern const gchar *reserved_chars;
145
_write_attr(const xml_t p,const gchar * n,const gchar * s)146 static gint _write_attr(const xml_t p, const gchar *n, const gchar *s)
147 {
148 xmlChar *e;
149 gint r;
150
151 e = xmlURIEscapeStr(BAD_CAST s, BAD_CAST reserved_chars);
152
153
154 r = (xmlTextWriterWriteAttribute(p->w, BAD_CAST n, e) <0)
155 ? EXIT_FAILURE
156 : EXIT_SUCCESS;
157
158 xmlFree(e);
159
160 if (r != EXIT_SUCCESS)
161 lprint_xml_errmsg("%s", g_dgettext(GETTEXT_PACKAGE, _msg[ATTR]), n);
162
163 return (r);
164 }
165
_attr_new(const xml_t p,const lutilPropertyType pt,const gchar * n,const gchar * s,const gdouble d)166 static gint _attr_new(const xml_t p, const lutilPropertyType pt,
167 const gchar *n, const gchar *s, const gdouble d)
168 {
169 gint r;
170
171 r = lutil_chk_property_ok(p->q, pt, n, lprint_xml_errmsg);
172 if (r != EXIT_SUCCESS)
173 return (EXIT_FAILURE);
174
175 if (s != NULL)
176 r = _write_attr(p, n, s);
177 else
178 {
179 gchar *t = g_strdup_printf("%.0f", d);
180 r = _write_attr(p, n, t);
181 g_free(t);
182 }
183 return (r);
184 }
185
_print_buffer(xml_t p)186 static gint _print_buffer(xml_t p)
187 {
188 xmlChar *b;
189
190 g_assert(p != NULL);
191
192 xmlTextWriterFlush(p->w);
193 xmlDocDumpFormatMemory(p->d, &b, NULL, 0);
194
195 if (b == NULL)
196 {
197 lprint_xml_errmsg(_("while dumping the XML document"));
198 return (EXIT_FAILURE);
199 }
200 g_print("%s", b);
201 xmlFree(b);
202
203 return (EXIT_SUCCESS);
204 }
205
lprint_xml_errmsg(const gchar * fmt,...)206 void lprint_xml_errmsg(const gchar *fmt, ...)
207 {
208 va_list args;
209 gchar *s;
210
211 va_start(args, fmt);
212 if (g_vasprintf(&s, fmt, args) >0)
213 {
214 xmlChar *e = xmlURIEscapeStr(BAD_CAST s, BAD_CAST reserved_chars);
215 g_printerr("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
216 "<error message=\"%s\" />", e);
217 xmlFree(e);
218 g_free(s);
219 }
220 va_end(args);
221 }
222
223 typedef lprint_cb_errmsg cem;
224
225 /* media */
226
lprint_xml_media_new(quvi_t q,quvi_media_t qm,gpointer * dst)227 gint lprint_xml_media_new(quvi_t q, quvi_media_t qm, gpointer *dst)
228 {
229 return (_xml_handle_new(q, qm, dst));
230 }
231
lprint_xml_media_free(gpointer data)232 void lprint_xml_media_free(gpointer data)
233 {
234 _xml_handle_free(data, -1);
235 }
236
lprint_xml_media_print_buffer(gpointer data)237 gint lprint_xml_media_print_buffer(gpointer data)
238 {
239 xml_t p = (xml_t) data;
240
241 g_assert(data != NULL);
242 g_assert(p->w != NULL);
243 g_assert(p->d != NULL);
244
245 if (_end_e(p, END_E, "media") != EXIT_SUCCESS)
246 return (EXIT_FAILURE);
247
248 if (_end_e(p, END_R, "quvi") != EXIT_SUCCESS)
249 return (EXIT_FAILURE);
250 else
251 return (_print_buffer(p));
252 }
253
_mp_attr_s(const xml_t p,const QuviMediaProperty qmp,const gchar * n)254 static gint _mp_attr_s(const xml_t p, const QuviMediaProperty qmp,
255 const gchar *n)
256 {
257 gchar *s = NULL;
258 quvi_media_get(p->qm, qmp, &s);
259 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_MEDIA, n, s, -1));
260 }
261
262 #define _print_mp_attr_s(n)\
263 do {\
264 if (_mp_attr_s(p, n, #n) != EXIT_SUCCESS)\
265 return (EXIT_FAILURE);\
266 } while (0)
267
268 #define _print_mp_attr_set_r_s(n)\
269 do {\
270 r = _mp_attr_s(p, n, #n);\
271 } while (0)
272
_mp_attr_d(const xml_t p,const QuviMediaProperty qmp,const gchar * n)273 static gint _mp_attr_d(const xml_t p, const QuviMediaProperty qmp,
274 const gchar *n)
275 {
276 gdouble d = 0;
277 quvi_media_get(p->qm, qmp, &d);
278 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_MEDIA, n, NULL, d));
279 }
280
281 #define _print_mp_attr_d(n)\
282 do {\
283 if (_mp_attr_d(p, n, #n) != EXIT_SUCCESS)\
284 return (EXIT_FAILURE);\
285 } while (0)
286
_mi_attr_s(const xml_t p,const quvi_http_metainfo_t qmi,const QuviHTTPMetaInfoProperty qmip,const gchar * n)287 static gint _mi_attr_s(const xml_t p, const quvi_http_metainfo_t qmi,
288 const QuviHTTPMetaInfoProperty qmip, const gchar *n)
289 {
290 gchar *s = NULL;
291 quvi_http_metainfo_get(qmi, qmip, &s);
292 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_HTTP_METAINFO, n, s, -1));
293 }
294
295 #define _print_mi_attr_s(n)\
296 do {\
297 if (_mi_attr_s(p, qmi, n, #n) != EXIT_SUCCESS)\
298 return (EXIT_FAILURE);\
299 } while (0)
300
_mi_attr_d(const xml_t p,const quvi_http_metainfo_t qmi,const QuviHTTPMetaInfoProperty qmip,const gchar * n)301 static gint _mi_attr_d(const xml_t p, const quvi_http_metainfo_t qmi,
302 const QuviHTTPMetaInfoProperty qmip, const gchar *n)
303 {
304 gdouble d = 0;
305 quvi_http_metainfo_get(qmi, qmip, &d);
306 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_HTTP_METAINFO, n, NULL, d));
307 }
308
309 #define _print_mi_attr_d(n)\
310 do {\
311 if (_mi_attr_d(p, qmi, n, #n) != EXIT_SUCCESS)\
312 return (EXIT_FAILURE);\
313 } while (0)
314
315 static gint
_print_media_stream_properties(const xml_t p,const quvi_http_metainfo_t qmi)316 _print_media_stream_properties(const xml_t p, const quvi_http_metainfo_t qmi)
317 {
318 g_assert(p->w != NULL);
319 g_assert(p->d != NULL);
320
321 _chk_r(_start_e(p, START_E, "stream"));
322
323 _print_mp_attr_s(QUVI_MEDIA_STREAM_PROPERTY_VIDEO_ENCODING);
324 _print_mp_attr_s(QUVI_MEDIA_STREAM_PROPERTY_AUDIO_ENCODING);
325 _print_mp_attr_s(QUVI_MEDIA_STREAM_PROPERTY_CONTAINER);
326 _print_mp_attr_s(QUVI_MEDIA_STREAM_PROPERTY_URL);
327 _print_mp_attr_s(QUVI_MEDIA_STREAM_PROPERTY_ID);
328
329 _print_mp_attr_d(QUVI_MEDIA_STREAM_PROPERTY_VIDEO_BITRATE_KBIT_S);
330 _print_mp_attr_d(QUVI_MEDIA_STREAM_PROPERTY_AUDIO_BITRATE_KBIT_S);
331 _print_mp_attr_d(QUVI_MEDIA_STREAM_PROPERTY_VIDEO_HEIGHT);
332 _print_mp_attr_d(QUVI_MEDIA_STREAM_PROPERTY_VIDEO_WIDTH);
333
334 if (qmi != NULL)
335 {
336 _print_mi_attr_s(QUVI_HTTP_METAINFO_PROPERTY_FILE_EXTENSION);
337 _print_mi_attr_s(QUVI_HTTP_METAINFO_PROPERTY_CONTENT_TYPE);
338 _print_mi_attr_d(QUVI_HTTP_METAINFO_PROPERTY_LENGTH_BYTES);
339 }
340 return (_end_e(p, END_E, "stream"));
341 }
342
343 #undef _print_mi_s
344 #undef _print_mi_d
345
346 gint
lprint_xml_media_stream_properties(quvi_http_metainfo_t qmi,gpointer data)347 lprint_xml_media_stream_properties(quvi_http_metainfo_t qmi, gpointer data)
348 {
349 g_assert(data != NULL);
350 return (_print_media_stream_properties(data, qmi));
351 }
352
lprint_xml_media_streams_available(quvi_t q,quvi_media_t qm)353 gint lprint_xml_media_streams_available(quvi_t q, quvi_media_t qm)
354 {
355 xml_t p;
356
357 if (_xml_handle_new(q, qm, (gpointer*) &p) != EXIT_SUCCESS)
358 return (EXIT_FAILURE);
359
360 _chk_r(_start_e(p, START_R, "quvi"));
361 _chk_r(_start_e(p, START_E, "media"));
362 _chk_r(_start_e(p, START_E, "streams"));
363
364 while (quvi_media_stream_next(qm) == QUVI_TRUE)
365 {
366 _chk_r(_print_media_stream_properties(p, NULL));
367 }
368
369 _chk_r(_end_e(p, END_E, "streams"));
370 _chk_r(_end_e(p, END_E, "media"));
371 _chk_r(_end_e(p, END_R, "quvi"));
372
373 _chk_r(_print_buffer(p));
374
375 return (_xml_handle_free(p, EXIT_SUCCESS));
376 }
377
lprint_xml_media_properties(gpointer data)378 gint lprint_xml_media_properties(gpointer data)
379 {
380 xml_t p = (xml_t) data;
381
382 g_assert(data != NULL);
383 g_assert(p->w != NULL);
384 g_assert(p->d != NULL);
385
386 _chk_r(_start_e(p, START_R, "quvi"));
387 _chk_r(_start_e(p, START_E, "media"));
388
389 _print_mp_attr_s(QUVI_MEDIA_PROPERTY_THUMBNAIL_URL);
390 _print_mp_attr_s(QUVI_MEDIA_PROPERTY_TITLE);
391 _print_mp_attr_s(QUVI_MEDIA_PROPERTY_ID);
392
393 _print_mp_attr_d(QUVI_MEDIA_PROPERTY_START_TIME_MS);
394 _print_mp_attr_d(QUVI_MEDIA_PROPERTY_DURATION_MS);
395
396 return (EXIT_SUCCESS);
397 }
398
399 #undef _print_mp_s
400 #undef _print_mp_d
401
402 /* playlist */
403
lprint_xml_playlist_new(quvi_t q,gpointer * dst)404 gint lprint_xml_playlist_new(quvi_t q, gpointer *dst)
405 {
406 return (_xml_handle_new(q, NULL, dst));
407 }
408
lprint_xml_playlist_free(gpointer dst)409 void lprint_xml_playlist_free(gpointer dst)
410 {
411 _xml_handle_free(dst, -1);
412 }
413
lprint_xml_playlist_print_buffer(gpointer data)414 gint lprint_xml_playlist_print_buffer(gpointer data)
415 {
416 return (_print_buffer(data));
417 }
418
_pp_attr_s(const xml_t p,const quvi_playlist_t qp,const QuviPlaylistProperty qpp,const gchar * n)419 static gint _pp_attr_s(const xml_t p, const quvi_playlist_t qp,
420 const QuviPlaylistProperty qpp, const gchar *n)
421 {
422 gchar *s = NULL;
423 quvi_playlist_get(qp, qpp, &s);
424 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_PLAYLIST, n, s, -1));
425 }
426
427 #define _print_pp_attr_s(n)\
428 do {\
429 if (_pp_attr_s(p, qp, n, #n) != EXIT_SUCCESS)\
430 return (EXIT_FAILURE);\
431 } while (0)
432
_pp_attr_d(const xml_t p,const quvi_playlist_t qp,const QuviPlaylistProperty qpp,const gchar * n)433 static gint _pp_attr_d(const xml_t p, const quvi_playlist_t qp,
434 const QuviPlaylistProperty qpp, const gchar *n)
435 {
436 gdouble d = 0;
437 quvi_playlist_get(qp, qpp, &d);
438 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_PLAYLIST, n, NULL, d));
439 }
440
441 #define _print_pp_attr_d(n)\
442 do {\
443 if (_pp_attr_d(p, qp, n, #n) != EXIT_SUCCESS)\
444 return (EXIT_FAILURE);\
445 } while (0)
446
lprint_xml_playlist_properties(quvi_playlist_t qp,gpointer data)447 gint lprint_xml_playlist_properties(quvi_playlist_t qp, gpointer data)
448 {
449 xml_t p = (xml_t) data;
450
451 g_assert(data != NULL);
452 g_assert(qp != NULL);
453 g_assert(p->w != NULL);
454 g_assert(p->d != NULL);
455
456 _chk_r(_start_e(p, START_R, "quvi"));
457 _chk_r(_start_e(p, START_E, "playlist"));
458
459 _print_pp_attr_s(QUVI_PLAYLIST_PROPERTY_THUMBNAIL_URL);
460 _print_pp_attr_s(QUVI_PLAYLIST_PROPERTY_TITLE);
461 _print_pp_attr_s(QUVI_PLAYLIST_PROPERTY_ID);
462
463 while (quvi_playlist_media_next(qp) == QUVI_TRUE)
464 {
465 _chk_r(_start_e(p, START_E, "media"));
466 _print_pp_attr_d(QUVI_PLAYLIST_MEDIA_PROPERTY_DURATION_MS);
467 _print_pp_attr_s(QUVI_PLAYLIST_MEDIA_PROPERTY_TITLE);
468 _print_pp_attr_s(QUVI_PLAYLIST_MEDIA_PROPERTY_URL);
469 _chk_r(_end_e(p, END_E, "media"));
470 }
471
472 _chk_r(_end_e(p, END_E, "playlist"));
473 _chk_r_e(_end_e(p, END_R, "quvi"));
474 }
475
476 #undef _print_pp_s
477 #undef _print_pp_d
478
479 /* scan */
480
lprint_xml_scan_new(quvi_t q,gpointer * dst)481 gint lprint_xml_scan_new(quvi_t q, gpointer *dst)
482 {
483 return (_xml_handle_new(q, NULL, dst));
484 }
485
lprint_xml_scan_free(gpointer data)486 void lprint_xml_scan_free(gpointer data)
487 {
488 _xml_handle_free(data, -1);
489 }
490
lprint_xml_scan_print_buffer(gpointer data)491 gint lprint_xml_scan_print_buffer(gpointer data)
492 {
493 return (_print_buffer(data));
494 }
495
lprint_xml_scan_properties(quvi_scan_t qs,gpointer data)496 gint lprint_xml_scan_properties(quvi_scan_t qs, gpointer data)
497 {
498 const gchar *s;
499 xml_t p;
500
501 g_assert(data != NULL);
502 g_assert(qs != NULL);
503
504 p = (xml_t) data;
505
506 _chk_r(_start_e(p, START_R, "quvi"));
507 _chk_r(_start_e(p, START_E, "scan"));
508
509 while ( (s = quvi_scan_next_media_url(qs)) != NULL)
510 {
511 _chk_r(_start_e(p, START_E, "media"));
512 _chk_r(_write_attr(p, "url", s));
513 _chk_r(_end_e(p, END_E, "media"));
514 }
515
516 _chk_r(_end_e(p, END_E, "scan"));
517 _chk_r_e(_end_e(p, END_R, "quvi"));
518 }
519
520 /* subtitle */
521
lprint_xml_subtitle_new(quvi_t q,gpointer * dst)522 gint lprint_xml_subtitle_new(quvi_t q, gpointer *dst)
523 {
524 return (_xml_handle_new(q, NULL, dst));
525 }
526
lprint_xml_subtitle_free(gpointer data)527 void lprint_xml_subtitle_free(gpointer data)
528 {
529 _xml_handle_free(data, -1);
530 }
531
lprint_xml_subtitle_print_buffer(gpointer data)532 gint lprint_xml_subtitle_print_buffer(gpointer data)
533 {
534 return (_print_buffer(data));
535 }
536
_stp_attr_d(const xml_t p,const quvi_subtitle_type_t qst,const QuviSubtitleTypeProperty qstp,const gchar * n)537 static gint _stp_attr_d(const xml_t p, const quvi_subtitle_type_t qst,
538 const QuviSubtitleTypeProperty qstp, const gchar *n)
539 {
540 gdouble d = 0;
541 quvi_subtitle_type_get(qst, qstp, &d);
542 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_SUBTITLE_TYPE, n, NULL, d));
543 }
544
545 #define _print_stp_attr_d(n)\
546 do {\
547 if (_stp_attr_d(p, t, n, #n) != EXIT_SUCCESS)\
548 return (EXIT_FAILURE);\
549 } while (0)
550
_slp_attr_s(const xml_t p,const quvi_subtitle_lang_t qsl,const QuviSubtitleLangProperty qslp,const gchar * n)551 static gint _slp_attr_s(const xml_t p, const quvi_subtitle_lang_t qsl,
552 const QuviSubtitleLangProperty qslp, const gchar *n)
553 {
554 gchar *s = NULL;
555 quvi_subtitle_lang_get(qsl, qslp, &s);
556 _chk_r_e(_attr_new(p, UTIL_PROPERTY_TYPE_SUBTITLE_LANGUAGE, n, s, -1));
557 }
558
559 #define _print_slp_attr_s(n)\
560 do {\
561 if (_slp_attr_s(p, l, n, #n) != EXIT_SUCCESS)\
562 return (EXIT_FAILURE);\
563 } while (0)
564
_write_lang_properties(const quvi_subtitle_lang_t l,const xml_t p)565 static gint _write_lang_properties(const quvi_subtitle_lang_t l,
566 const xml_t p)
567 {
568 _chk_r(_start_e(p, START_E, "language"));
569
570 _print_slp_attr_s(QUVI_SUBTITLE_LANG_PROPERTY_TRANSLATED);
571 _print_slp_attr_s(QUVI_SUBTITLE_LANG_PROPERTY_ORIGINAL);
572 _print_slp_attr_s(QUVI_SUBTITLE_LANG_PROPERTY_CODE);
573 _print_slp_attr_s(QUVI_SUBTITLE_LANG_PROPERTY_URL);
574 _print_slp_attr_s(QUVI_SUBTITLE_LANG_PROPERTY_ID);
575
576 _chk_r_e(_end_e(p, END_E, "language"));
577 }
578
579 gint
lprint_xml_subtitle_lang_properties(quvi_subtitle_lang_t l,gpointer data)580 lprint_xml_subtitle_lang_properties(quvi_subtitle_lang_t l, gpointer data)
581 {
582 xml_t p = (xml_t) data;
583
584 g_assert(p->w != NULL);
585 g_assert(p->d != NULL);
586
587 _chk_r(_start_e(p, START_R, "quvi"));
588 _chk_r(_start_e(p, START_E, "media"));
589 _chk_r(_start_e(p, START_E, "subtitle"));
590 _chk_r(_write_lang_properties(l, p));
591 _chk_r(_end_e(p, END_E, "subtitle"));
592 _chk_r(_end_e(p, END_E, "media"));
593 _chk_r_e(_end_e(p, END_R, "quvi"));
594 }
595
lprint_xml_subtitles_available(quvi_t q,quvi_subtitle_t qsub)596 gint lprint_xml_subtitles_available(quvi_t q, quvi_subtitle_t qsub)
597 {
598 quvi_subtitle_type_t t;
599 quvi_subtitle_lang_t l;
600 xml_t p;
601
602 g_assert(qsub != NULL);
603 g_assert(q != NULL);
604
605 if (_xml_handle_new(q, NULL, (gpointer*) &p) != EXIT_SUCCESS)
606 return (EXIT_FAILURE);
607
608 _chk_r(_start_e(p, START_R, "quvi"));
609 _chk_r(_start_e(p, START_E, "media"));
610 _chk_r(_start_e(p, START_E, "subtitles"));
611
612 while ( (t = quvi_subtitle_type_next(qsub)) != NULL)
613 {
614 _chk_r(_start_e(p, START_E, "type"));
615
616 _print_stp_attr_d(QUVI_SUBTITLE_TYPE_PROPERTY_FORMAT);
617 _print_stp_attr_d(QUVI_SUBTITLE_TYPE_PROPERTY_TYPE);
618
619 while ( (l = quvi_subtitle_lang_next(t)) != NULL)
620 {
621 _chk_r(_write_lang_properties(l, p));
622 }
623 _chk_r(_end_e(p, END_E, "type"));
624 }
625
626 _chk_r(_end_e(p, END_E, "subtitles"));
627 _chk_r(_end_e(p, END_E, "media"));
628 _chk_r(_end_e(p, END_R, "quvi"));
629
630 _chk_r(_print_buffer(p));
631
632 return (_xml_handle_free(p, EXIT_SUCCESS));
633 }
634
635 /* vim: set ts=2 sw=2 tw=72 expandtab: */
636