1
2 /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
3 Copyright (c) 2006 - 2014 Thomas Schmitt <scdbackup@gmx.net>
4 Provided under GPL version 2 or later.
5 */
6
7 #ifdef HAVE_CONFIG_H
8 #include "../config.h"
9 #endif
10
11 /* ts A61008 */
12 /* #include <a ssert.h> */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <errno.h>
23
24 /* ts B41126 : O_BINARY is needed for Cygwin but undefined elsewhere */
25 #ifndef O_BINARY
26 #define O_BINARY 0
27 #endif
28
29 #include "libburn.h"
30 #include "structure.h"
31 #include "write.h"
32 #include "debug.h"
33 #include "init.h"
34 #include "util.h"
35 #include "transport.h"
36 #include "mmc.h"
37
38 #include "libdax_msgs.h"
39 extern struct libdax_msgs *libdax_messenger;
40
41
42 /* ts A61008 : replaced Assert by if and return 0 */
43 /* a ssert(!(pos > BURN_POS_END)); */
44
45 #define RESIZE(TO, NEW, pos) {\
46 void *tmp;\
47 \
48 if (pos > BURN_POS_END)\
49 return 0;\
50 if (pos == BURN_POS_END)\
51 pos = TO->NEW##s;\
52 if ((int) pos > TO->NEW##s)\
53 return 0;\
54 \
55 tmp = realloc(TO->NEW, sizeof(struct NEW *) * (TO->NEW##s + 1));\
56 if (!tmp)\
57 return 0;\
58 TO->NEW = tmp;\
59 memmove(TO->NEW + pos + 1, TO->NEW + pos,\
60 sizeof(struct NEW *) * (TO->NEW##s - pos));\
61 TO->NEW##s++;\
62 }
63
burn_disc_create(void)64 struct burn_disc *burn_disc_create(void)
65 {
66 struct burn_disc *d;
67 d = calloc(1, sizeof(struct burn_disc));
68 if (d == NULL) /* ts A70825 */
69 return NULL;
70 d->refcnt = 1;
71 d->sessions = 0;
72 d->session = NULL;
73
74 #ifdef Libburn_disc_with_incomplete_sessioN
75 d->incomplete_sessions= 0;
76 #endif
77
78 return d;
79 }
80
burn_disc_free(struct burn_disc * d)81 void burn_disc_free(struct burn_disc *d)
82 {
83 d->refcnt--;
84 if (d->refcnt == 0) {
85 /* dec refs on all elements */
86 int i;
87
88 for (i = 0; i < d->sessions; i++)
89 burn_session_free(d->session[i]);
90 free(d->session);
91 free(d);
92 }
93 }
94
burn_session_create(void)95 struct burn_session *burn_session_create(void)
96 {
97 struct burn_session *s;
98 int i;
99
100 s = calloc(1, sizeof(struct burn_session));
101 if (s == NULL) /* ts A70825 */
102 return NULL;
103 s->firsttrack = 1;
104 s->lasttrack = 0;
105 s->refcnt = 1;
106 s->tracks = 0;
107 s->track = NULL;
108 s->hidefirst = 0;
109 for (i = 0; i < 8; i++) {
110 s->cdtext[i] = NULL;
111 s->cdtext_language[i] = 0x00; /* Unknown */
112 s->cdtext_char_code[i] = 0x00; /* ISO-8859-1 */
113 s->cdtext_copyright[i] = 0x00;
114 }
115 s->cdtext_language[0] = 0x09; /* Single-block default is English */
116 s->mediacatalog[0] = 0;
117 return s;
118 }
119
burn_session_hide_first_track(struct burn_session * s,int onoff)120 void burn_session_hide_first_track(struct burn_session *s, int onoff)
121 {
122 s->hidefirst = onoff;
123 }
124
burn_session_free(struct burn_session * s)125 void burn_session_free(struct burn_session *s)
126 {
127 int i;
128
129 s->refcnt--;
130 if (s->refcnt == 0) {
131 /* dec refs on all elements */
132 for (i = 0; i < s->tracks; i++)
133 burn_track_free(s->track[i]);
134 for (i = 0; i < 8; i++)
135 burn_cdtext_free(&(s->cdtext[i]));
136 free(s->track);
137 free(s);
138 }
139
140 }
141
burn_disc_add_session(struct burn_disc * d,struct burn_session * s,unsigned int pos)142 int burn_disc_add_session(struct burn_disc *d, struct burn_session *s,
143 unsigned int pos)
144 {
145 RESIZE(d, session, pos);
146 d->session[pos] = s;
147 s->refcnt++;
148 return 1;
149 }
150
151
152 /* ts A81202: this function was in the API but not implemented.
153 */
burn_disc_remove_session(struct burn_disc * d,struct burn_session * s)154 int burn_disc_remove_session(struct burn_disc *d, struct burn_session *s)
155 {
156 int i, skip = 0;
157
158 if (d->session == NULL)
159 return 0;
160 for (i = 0; i < d->sessions; i++) {
161 if (s == d->session[i]) {
162 skip++;
163 continue;
164 }
165 d->session[i - skip] = d->session[i];
166 }
167 if (!skip)
168 return 0;
169 burn_session_free(s);
170 d->sessions--;
171 return 1;
172 }
173
174
burn_track_create(void)175 struct burn_track *burn_track_create(void)
176 {
177 struct burn_track *t;
178 int i;
179
180 t = calloc(1, sizeof(struct burn_track));
181 if (t == NULL) /* ts A70825 */
182 return NULL;
183 t->refcnt = 1;
184 t->indices = 0;
185 for (i = 0; i < 100; i++)
186 t->index[i] = 0x7fffffff;
187 t->offset = 0;
188 t->offsetcount = 0;
189 t->tail = 0;
190 t->tailcount = 0;
191 t->mode = BURN_MODE1;
192 t->isrc.has_isrc = 0;
193 t->pad = 1;
194
195 /* ts A70213 */
196 t->fill_up_media = 0;
197 /* ts A70218 */
198 t->default_size = 0;
199
200 t->entry = NULL;
201 t->source = NULL;
202 t->eos = 0;
203
204 /* ts A61101 */
205 t->sourcecount = 0;
206 t->writecount = 0;
207 t->written_sectors = 0;
208
209 /* ts A61031 */
210 t->open_ended = 0;
211 t->track_data_done = 0;
212 /* ts B10103 */
213 t->end_on_premature_eoi = 0;
214
215 t->pregap1 = 0;
216 t->pregap2 = 0;
217 t->pregap2_size = 150;
218
219 t->postgap = 0;
220 t->postgap_size = 150;
221
222 /* ts A61024 */
223 t->swap_source_bytes = 0;
224
225 /* ts B11206 */
226 for (i = 0; i < 8; i++)
227 t->cdtext[i] = NULL;
228
229 return t;
230 }
231
burn_track_free(struct burn_track * t)232 void burn_track_free(struct burn_track *t)
233 {
234 int i;
235
236 t->refcnt--;
237 if (t->refcnt == 0) {
238 /* dec refs on all elements */
239 if (t->source)
240 burn_source_free(t->source);
241 for (i = 0; i < 8; i++)
242 burn_cdtext_free(&(t->cdtext[i]));
243 free(t);
244 }
245 }
246
burn_session_add_track(struct burn_session * s,struct burn_track * t,unsigned int pos)247 int burn_session_add_track(struct burn_session *s, struct burn_track *t,
248 unsigned int pos)
249 {
250 RESIZE(s, track, pos);
251 s->track[pos] = t;
252 t->refcnt++;
253 return 1;
254 }
255
burn_session_remove_track(struct burn_session * s,struct burn_track * t)256 int burn_session_remove_track(struct burn_session *s, struct burn_track *t)
257 {
258 struct burn_track **tmp;
259 int i, pos = -1;
260
261 /* ts A61008 */
262 /* a ssert(s->track != NULL); */
263 if (s->track == NULL)
264 return 0;
265
266 burn_track_free(t);
267
268 /* Find the position */
269 for (i = 0; i < s->tracks; i++) {
270 if (t == s->track[i]) {
271 pos = i;
272 break;
273 }
274 }
275
276 if (pos == -1)
277 return 0;
278
279 /* Is it the last track? */
280 if (pos != s->tracks - 1) {
281 memmove(&s->track[pos], &s->track[pos + 1],
282 sizeof(struct burn_track *) * (s->tracks - (pos + 1)));
283 }
284
285 s->tracks--;
286 tmp = realloc(s->track, sizeof(struct burn_track *) * s->tracks);
287 if (tmp)
288 s->track = tmp;
289 return 1;
290 }
291
burn_structure_print_disc(struct burn_disc * d)292 void burn_structure_print_disc(struct burn_disc *d)
293 {
294 int i;
295 char msg[40];
296
297 sprintf(msg, "This disc has %d sessions", d->sessions);
298 libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
299 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
300 msg, 0, 0);
301 for (i = 0; i < d->sessions; i++) {
302 burn_structure_print_session(d->session[i]);
303 }
304 }
burn_structure_print_session(struct burn_session * s)305 void burn_structure_print_session(struct burn_session *s)
306 {
307 int i;
308 char msg[40];
309
310 sprintf(msg, " Session has %d tracks", s->tracks);
311 libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
312 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
313 msg, 0, 0);
314 for (i = 0; i < s->tracks; i++) {
315 burn_structure_print_track(s->track[i]);
316 }
317 }
burn_structure_print_track(struct burn_track * t)318 void burn_structure_print_track(struct burn_track *t)
319 {
320 char msg[80];
321
322 sprintf(msg, " track size %d sectors",
323 burn_track_get_sectors(t));
324 libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
325 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
326 msg, 0, 0);
327 }
328
burn_track_define_data(struct burn_track * t,int offset,int tail,int pad,int mode)329 void burn_track_define_data(struct burn_track *t, int offset, int tail,
330 int pad, int mode)
331 {
332 int type_to_form(int mode, unsigned char *ctladr, int *form);
333 int burn_sector_length(int tracktype);
334 unsigned char ctladr;
335 int form = -1; /* unchanged form will be considered an error too */
336 char msg[80];
337
338 type_to_form(mode, &ctladr, &form);
339 if (form == -1 || burn_sector_length(mode) <= 0) {
340
341 sprintf(msg,
342 "Attempt to set track mode to unusable value 0x%X",
343 (unsigned int) mode);
344 libdax_msgs_submit(libdax_messenger, -1, 0x00020115,
345 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
346 msg, 0, 0);
347 return;
348 }
349
350 t->offset = offset;
351 t->pad = pad;
352 t->mode = mode;
353 t->tail = tail;
354 }
355
356
357 /* ts A61024 */
burn_track_set_byte_swap(struct burn_track * t,int swap_source_bytes)358 int burn_track_set_byte_swap(struct burn_track *t, int swap_source_bytes)
359 {
360 if (swap_source_bytes != 0 && swap_source_bytes != 1)
361 return 0;
362 t->swap_source_bytes = swap_source_bytes;
363 return 1;
364 }
365
366
367 /* ts A90911 : API */
burn_track_set_cdxa_conv(struct burn_track * t,int value)368 int burn_track_set_cdxa_conv(struct burn_track *t, int value)
369 {
370 if (value < 0 || value > 1)
371 return 0;
372 t->cdxa_conversion = value;
373 return 1;
374 }
375
376
burn_track_set_isrc(struct burn_track * t,char * country,char * owner,unsigned char year,unsigned int serial)377 void burn_track_set_isrc(struct burn_track *t, char *country, char *owner,
378 unsigned char year, unsigned int serial)
379 {
380 int i;
381
382 /* ts B11226 */
383 t->isrc.has_isrc = 0;
384
385 for (i = 0; i < 2; ++i) {
386
387 /* ts A61008 : This is always true */
388 /* a ssert((country[i] >= '0' || country[i] < '9') &&
389 (country[i] >= 'a' || country[i] < 'z') &&
390 (country[i] >= 'A' || country[i] < 'Z')); */
391 /* ts A61008 : now coordinated with sector.c: char_to_isrc() */
392 if (! ((country[i] >= '0' && country[i] <= '9') ||
393 (country[i] >= 'a' && country[i] <= 'z') ||
394 (country[i] >= 'A' && country[i] <= 'Z') ) )
395 goto is_not_allowed;
396
397 t->isrc.country[i] = country[i];
398 }
399 for (i = 0; i < 3; ++i) {
400
401 /* ts A61008 : This is always true */
402 /* a ssert((owner[i] >= '0' || owner[i] < '9') &&
403 (owner[i] >= 'a' || owner[i] < 'z') &&
404 (owner[i] >= 'A' || owner[i] < 'Z')); */
405 /* ts A61008 : now coordinated with sector.c: char_to_isrc() */
406 if (! ((owner[i] >= '0' && owner[i] <= '9') ||
407 (owner[i] >= 'a' && owner[i] <= 'z') ||
408 (owner[i] >= 'A' && owner[i] <= 'Z') ) )
409 goto is_not_allowed;
410
411 t->isrc.owner[i] = owner[i];
412 }
413
414 /* ts A61008 */
415 /* a ssert(year <= 99); */
416 if (year > 99)
417 goto is_not_allowed;
418
419 t->isrc.year = year;
420
421 /* ts A61008 */
422 /* a ssert(serial <= 99999); */
423 if (serial > 99999)
424 goto is_not_allowed;
425
426 t->isrc.serial = serial;
427
428 /* ts A61008 */
429 t->isrc.has_isrc = 1;
430 return;
431 is_not_allowed:;
432 libdax_msgs_submit(libdax_messenger, -1, 0x00020114,
433 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
434 "Attempt to set ISRC with bad data", 0, 0);
435 return;
436 }
437
438 /* ts B11226 API */
burn_track_set_isrc_string(struct burn_track * t,char isrc[13],int flag)439 int burn_track_set_isrc_string(struct burn_track *t, char isrc[13], int flag)
440 {
441 unsigned char year;
442 unsigned int serial = 2000000000;
443
444 if (strlen(isrc) != 12 ||
445 isrc[5] < '0' || isrc[5] > '9' || isrc[6] < '0' || isrc[6] > '9') {
446 libdax_msgs_submit(libdax_messenger, -1, 0x00020114,
447 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
448 "Attempt to set ISRC with bad data", 0, 0);
449 return 0;
450 }
451 year = (isrc[5] - '0') * 10 + (isrc[6] - '0');
452 isrc[12] = 0;
453 sscanf(isrc + 7, "%u", &serial);
454 burn_track_set_isrc(t, isrc, isrc + 2, year, serial);
455 return t->isrc.has_isrc;
456 }
457
burn_track_clear_isrc(struct burn_track * t)458 void burn_track_clear_isrc(struct burn_track *t)
459 {
460 t->isrc.has_isrc = 0;
461 }
462
463 /* ts B20103 API */
burn_track_set_index(struct burn_track * t,int index_number,unsigned int relative_lba,int flag)464 int burn_track_set_index(struct burn_track *t, int index_number,
465 unsigned int relative_lba, int flag)
466 {
467 if (index_number < 0 || index_number > 99) {
468 libdax_msgs_submit(libdax_messenger, -1, 0x0002019a,
469 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
470 "Bad track index number", 0, 0);
471 return 0;
472 }
473
474 /* >>> if track size known : check index */;
475
476 t->index[index_number] = relative_lba;
477 if (index_number >= t->indices)
478 t->indices = index_number + 1;
479 return 1;
480 }
481
482 /* ts B20103 API */
burn_track_clear_indice(struct burn_track * t,int flag)483 int burn_track_clear_indice(struct burn_track *t, int flag)
484 {
485 int i;
486
487 for (i = 0; i < 100; i++)
488 t->index[i] = 0x7fffffff;
489 t->indices = 0;
490 return 1;
491 }
492
493 /* ts B20110 API */
burn_track_set_pregap_size(struct burn_track * t,int size,int flag)494 int burn_track_set_pregap_size(struct burn_track *t, int size, int flag)
495 {
496 t->pregap2 = (size >= 0);
497 t->pregap2_size = size;
498 return 1;
499 }
500
501 /* ts B20111 API */
burn_track_set_postgap_size(struct burn_track * t,int size,int flag)502 int burn_track_set_postgap_size(struct burn_track *t, int size, int flag)
503 {
504 t->postgap = (size >= 0);
505 t->postgap_size = size;
506 return 1;
507 }
508
509 /* ts B20119: outsourced from burn_track_get_sectors()
510 @param flag bit0= do not add post-gap
511 */
burn_track_get_sectors_2(struct burn_track * t,int flag)512 int burn_track_get_sectors_2(struct burn_track *t, int flag)
513 {
514 /* ts A70125 : was int */
515 off_t size = 0;
516 int sectors, seclen;
517
518 seclen = burn_sector_length(t->mode);
519
520 if (t->cdxa_conversion == 1)
521 /* ts A90911 : will read blocks of 2056 bytes and write 2048 */
522 seclen += 8;
523
524 if (t->source != NULL) { /* ts A80808 : mending sigsegv */
525 size = t->offset + t->source->get_size(t->source) + t->tail;
526 /* ts B20119 : adding post-gap */
527 if (t->postgap && !(flag & 1))
528 size += t->postgap_size;
529 } else if(t->entry != NULL) {
530 /* ts A80808 : all burn_toc_entry of track starts should now
531 have (extensions_valid & 1), even those from CD.
532 */
533 if (t->entry->extensions_valid & 1)
534 size = ((off_t) t->entry->track_blocks) * (off_t) 2048;
535 }
536 sectors = size / seclen;
537 if (size % seclen)
538 sectors++;
539 return sectors;
540 }
541
542
burn_track_get_sectors(struct burn_track * t)543 int burn_track_get_sectors(struct burn_track *t)
544 {
545 return burn_track_get_sectors_2(t, 0);
546 }
547
548 /* ts A70125 */
burn_track_set_sectors(struct burn_track * t,int sectors)549 int burn_track_set_sectors(struct burn_track *t, int sectors)
550 {
551 off_t size, seclen;
552 int ret;
553
554 seclen = burn_sector_length(t->mode);
555 size = seclen * (off_t) sectors - (off_t) t->offset - (off_t) t->tail;
556 if (size < 0)
557 return 0;
558 ret = t->source->set_size(t->source, size);
559 t->open_ended = (t->source->get_size(t->source) <= 0);
560 return ret;
561 }
562
563
564 /* ts A70218 , API since A70328 */
burn_track_set_size(struct burn_track * t,off_t size)565 int burn_track_set_size(struct burn_track *t, off_t size)
566 {
567 if (t->source == NULL)
568 return 0;
569 if (t->source->set_size == NULL)
570 return 0;
571 t->open_ended = (size <= 0);
572 return t->source->set_size(t->source, size);
573 }
574
575
576 /* ts A70213 */
burn_track_set_fillup(struct burn_track * t,int fill_up_media)577 int burn_track_set_fillup(struct burn_track *t, int fill_up_media)
578 {
579 t->fill_up_media = fill_up_media;
580 if (fill_up_media)
581 t->open_ended = 0;
582 return 1;
583 }
584
585
586 /* ts A70213 */
587 /**
588 @param flag bit0= force new size even if existing track size is larger
589 */
burn_track_apply_fillup(struct burn_track * t,off_t max_size,int flag)590 int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag)
591 {
592 int max_sectors, ret = 2;
593 char msg[80];
594
595 if (t->fill_up_media <= 0)
596 return 2;
597 max_sectors = max_size / 2048;
598 if (burn_track_get_sectors(t) < max_sectors || (flag & 1)) {
599 sprintf(msg, "Setting total track size to %ds (payload %ds)\n",
600 max_sectors & 0x7fffffff,
601 (int) ((t->source->get_size(t->source) / 2048)
602 & 0x7fffffff));
603 libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
604 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
605 msg, 0, 0);
606 ret = burn_track_set_sectors(t, max_sectors);
607 t->open_ended = 0;
608 }
609 return ret;
610 }
611
612
613 /* ts A61031 */
burn_track_is_open_ended(struct burn_track * t)614 int burn_track_is_open_ended(struct burn_track *t)
615 {
616 return !!t->open_ended;
617 }
618
619
620 /* ts A70218 : API */
burn_track_set_default_size(struct burn_track * t,off_t size)621 int burn_track_set_default_size(struct burn_track *t, off_t size)
622 {
623 t->default_size = size;
624 return 1;
625 }
626
627
628 /* ts A70218 */
burn_track_get_default_size(struct burn_track * t)629 off_t burn_track_get_default_size(struct burn_track *t)
630 {
631 return t->default_size;
632 }
633
634
635 /* ts A61101 : API function */
burn_track_get_counters(struct burn_track * t,off_t * read_bytes,off_t * written_bytes)636 int burn_track_get_counters(struct burn_track *t,
637 off_t *read_bytes, off_t *written_bytes)
638 {
639 /*
640 fprintf(stderr, "libburn_experimental: sizeof(off_t)=%d\n",
641 sizeof(off_t));
642 */
643 *read_bytes = t->sourcecount;
644 *written_bytes = t->writecount;
645 return 1;
646 }
647
648 /* ts A61031 */
burn_track_is_data_done(struct burn_track * t)649 int burn_track_is_data_done(struct burn_track *t)
650 {
651 return !!t->track_data_done;
652 }
653
burn_track_get_shortage(struct burn_track * t)654 int burn_track_get_shortage(struct burn_track *t)
655 {
656 int size;
657 int seclen;
658
659 seclen = burn_sector_length(t->mode);
660 size = t->offset + t->source->get_size(t->source) + t->tail;
661 if (size % seclen)
662 return seclen - size % seclen;
663 return 0;
664 }
665
burn_session_get_sectors(struct burn_session * s)666 int burn_session_get_sectors(struct burn_session *s)
667 {
668 int sectors = 0, i;
669
670 for (i = 0; i < s->tracks; i++)
671 sectors += burn_track_get_sectors(s->track[i]);
672 return sectors;
673 }
674
675
burn_disc_get_sectors(struct burn_disc * d)676 int burn_disc_get_sectors(struct burn_disc *d)
677 {
678 int sectors = 0, i;
679
680 for (i = 0; i < d->sessions; i++)
681 sectors += burn_session_get_sectors(d->session[i]);
682 return sectors;
683 }
684
burn_track_get_entry(struct burn_track * t,struct burn_toc_entry * entry)685 void burn_track_get_entry(struct burn_track *t, struct burn_toc_entry *entry)
686 {
687 if (t->entry == NULL)
688 memset(entry, 0, sizeof(struct burn_toc_entry));
689 else
690 memcpy(entry, t->entry, sizeof(struct burn_toc_entry));
691 }
692
burn_session_get_leadout_entry(struct burn_session * s,struct burn_toc_entry * entry)693 void burn_session_get_leadout_entry(struct burn_session *s,
694 struct burn_toc_entry *entry)
695 {
696 if (s->leadout_entry == NULL)
697 memset(entry, 0, sizeof(struct burn_toc_entry));
698 else
699 memcpy(entry, s->leadout_entry, sizeof(struct burn_toc_entry));
700 }
701
burn_disc_get_sessions(struct burn_disc * d,int * num)702 struct burn_session **burn_disc_get_sessions(struct burn_disc *d, int *num)
703 {
704
705 #ifdef Libburn_disc_with_incomplete_sessioN
706
707 *num = d->sessions - d->incomplete_sessions;
708
709 #else
710
711 *num = d->sessions;
712
713 #endif
714
715
716 return d->session;
717 }
718
719
720 /* ts B30112 : API */
burn_disc_get_incomplete_sessions(struct burn_disc * d)721 int burn_disc_get_incomplete_sessions(struct burn_disc *d)
722 {
723 #ifdef Libburn_disc_with_incomplete_sessioN
724
725 return d->incomplete_sessions;
726
727 #else
728
729 return 0;
730
731 #endif
732 }
733
734
burn_session_get_tracks(struct burn_session * s,int * num)735 struct burn_track **burn_session_get_tracks(struct burn_session *s, int *num)
736 {
737 *num = s->tracks;
738 return s->track;
739 }
740
burn_track_get_mode(struct burn_track * track)741 int burn_track_get_mode(struct burn_track *track)
742 {
743 return track->mode;
744 }
745
burn_session_get_hidefirst(struct burn_session * session)746 int burn_session_get_hidefirst(struct burn_session *session)
747 {
748 return session->hidefirst;
749 }
750
751
752 /* ts A80808 : Enhance CD toc to DVD toc */
burn_disc_cd_toc_extensions(struct burn_drive * drive,int flag)753 int burn_disc_cd_toc_extensions(struct burn_drive *drive, int flag)
754 {
755 int sidx= 0, tidx= 0, ret, track_offset, alloc_len = 34;
756 struct burn_toc_entry *entry, *prev_entry= NULL;
757 struct burn_disc *d;
758 /* ts A81126 : ticket 146 : There was a SIGSEGV in here */
759 char *msg_data = NULL, *msg;
760 struct buffer *buf = NULL;
761
762 d = drive->disc;
763 BURN_ALLOC_MEM(msg_data, char, 321);
764 BURN_ALLOC_MEM(buf, struct buffer, 1);
765 strcpy(msg_data,
766 "Damaged CD table-of-content detected and truncated.");
767 strcat(msg_data, " In burn_disc_cd_toc_extensions: ");
768 msg = msg_data + strlen(msg_data);
769 if (d->session == NULL) {
770 strcpy(msg, "d->session == NULL");
771 goto failure;
772 }
773 if (d->sessions <= 0) {
774 ret = 1;
775 goto ex;
776 }
777
778 for (sidx = 0; sidx < d->sessions; sidx++) {
779 track_offset = burn_session_get_start_tno(d->session[sidx], 0);
780 if (track_offset <= 0)
781 track_offset = 1;
782 if (d->session[sidx] == NULL) {
783 sprintf(msg, "d->session[%d of %d] == NULL",
784 sidx, d->sessions);
785 goto failure;
786 }
787 if (d->session[sidx]->track == NULL) {
788 sprintf(msg, "d->session[%d of %d]->track == NULL",
789 sidx, d->sessions);
790 goto failure;
791 }
792 if (d->session[sidx]->leadout_entry == NULL) {
793 sprintf(msg,
794 " Session %d of %d: Leadout entry missing.",
795 sidx, d->sessions);
796 goto failure;
797 }
798 for (tidx = 0; tidx < d->session[sidx]->tracks + 1; tidx++) {
799 if (tidx < d->session[sidx]->tracks) {
800 if (d->session[sidx]->track[tidx] == NULL) {
801 sprintf(msg,
802 "d->session[%d of %d]->track[%d of %d] == NULL",
803 sidx, d->sessions, tidx, d->session[sidx]->tracks);
804 goto failure;
805 }
806 entry = d->session[sidx]->track[tidx]->entry;
807 if (entry == NULL) {
808 sprintf(msg,
809 "session %d of %d, track %d of %d, entry == NULL",
810 sidx, d->sessions, tidx,
811 d->session[sidx]->tracks);
812 goto failure;
813 }
814 } else
815 entry = d->session[sidx]->leadout_entry;
816 entry->session_msb = 0;
817 entry->point_msb = 0;
818 entry->start_lba = burn_msf_to_lba(entry->pmin,
819 entry->psec, entry->pframe);
820 if (tidx > 0) {
821 prev_entry->track_blocks =
822 entry->start_lba
823 - prev_entry->start_lba;
824
825 /* The drive might know size restrictions
826 like pre-gaps
827 */
828 ret = mmc_read_track_info(drive,
829 tidx - 1 + track_offset, buf,
830 alloc_len);
831 if (ret > 0) {
832 ret = mmc_four_char_to_int(
833 buf->data + 24);
834 if (ret < prev_entry->track_blocks &&
835 ((!drive->current_is_cd_profile) ||
836 ret < prev_entry->track_blocks - 2))
837 prev_entry->track_blocks = ret;
838 }
839 prev_entry->extensions_valid |= 1;
840 }
841 if (tidx == d->session[sidx]->tracks) {
842 entry->session_msb = 0;
843 entry->point_msb = 0;
844 entry->track_blocks = 0;
845 entry->extensions_valid |= 1;
846 }
847 prev_entry = entry;
848 }
849 }
850 {ret = 1; goto ex;}
851 failure:
852 libdax_msgs_submit(libdax_messenger, -1, 0x0002015f,
853 LIBDAX_MSGS_SEV_MISHAP, LIBDAX_MSGS_PRIO_HIGH, msg_data, 0, 0);
854 d->sessions= sidx;
855 ret = 0;
856 ex:;
857 BURN_FREE_MEM(buf);
858 BURN_FREE_MEM(msg_data);
859 return ret;
860 }
861
862
863 /* ts B20107 API */
burn_session_set_start_tno(struct burn_session * session,int tno,int flag)864 int burn_session_set_start_tno(struct burn_session *session, int tno, int flag)
865 {
866 if (tno < 1 || tno > 99) {
867 libdax_msgs_submit(libdax_messenger, -1, 0x0002019b,
868 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
869 "CD start track number exceeds range of 1 to 99",
870 0, 0);
871 return 0;
872 }
873 if (tno + session->tracks - 1 > 99) {
874 libdax_msgs_submit(libdax_messenger, -1, 0x0002019b,
875 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
876 "CD track number exceeds 99", 0, 0);
877 return 0;
878 }
879 session->firsttrack = tno;
880 return 1;
881 }
882
883
884 /* ts B20108 API */
burn_session_get_start_tno(struct burn_session * session,int flag)885 int burn_session_get_start_tno(struct burn_session *session, int flag)
886 {
887 return (int) session->firsttrack;
888 }
889
890
burn_cdtext_create(void)891 struct burn_cdtext *burn_cdtext_create(void)
892 {
893 struct burn_cdtext *t;
894 int i;
895
896 t = burn_alloc_mem(sizeof(struct burn_cdtext), 1, 0);
897 if (t == NULL)
898 return NULL;
899 for(i = 0; i < Libburn_pack_num_typeS; i ++) {
900 t->payload[i] = NULL;
901 t->length[i] = 0;
902 }
903 return t;
904 }
905
906
burn_cdtext_free(struct burn_cdtext ** cdtext)907 void burn_cdtext_free(struct burn_cdtext **cdtext)
908 {
909 struct burn_cdtext *t;
910 int i;
911
912 t = *cdtext;
913 if (t == NULL)
914 return;
915 for (i = 0; i < Libburn_pack_num_typeS; i++)
916 if (t->payload[i] != NULL)
917 free(t->payload[i]);
918 free(t);
919 }
920
921
burn_cdtext_name_to_type(char * pack_type_name)922 static int burn_cdtext_name_to_type(char *pack_type_name)
923 {
924 int i, j;
925 static char *pack_type_names[] = {
926 Libburn_pack_type_nameS
927 };
928
929 for (i = 0; i < Libburn_pack_num_typeS; i++) {
930 if (pack_type_names[i][0] == 0)
931 continue;
932 for (j = 0; pack_type_names[i][j]; j++)
933 if (pack_type_names[i][j] != pack_type_name[j] &&
934 tolower(pack_type_names[i][j]) !=
935 pack_type_name[j])
936 break;
937 if (pack_type_names[i][j] == 0)
938 return Libburn_pack_type_basE + i;
939 }
940 return -1;
941 }
942
943
944 /* @param flag bit0= double byte characters
945 */
burn_cdtext_set(struct burn_cdtext ** cdtext,int pack_type,char * pack_type_name,unsigned char * payload,int length,int flag)946 static int burn_cdtext_set(struct burn_cdtext **cdtext,
947 int pack_type, char *pack_type_name,
948 unsigned char *payload, int length, int flag)
949 {
950 int i;
951 struct burn_cdtext *t;
952
953 if (pack_type_name != NULL)
954 if (pack_type_name[0])
955 pack_type = burn_cdtext_name_to_type(pack_type_name);
956 if (pack_type < Libburn_pack_type_basE ||
957 pack_type >= Libburn_pack_type_basE + Libburn_pack_num_typeS) {
958 libdax_msgs_submit(libdax_messenger, -1, 0x0002018c,
959 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
960 "CD-TEXT pack type out of range", 0, 0);
961 return 0;
962 }
963 t = *cdtext;
964 if (t == NULL) {
965 *cdtext = t = burn_cdtext_create();
966 if (t == NULL)
967 return -1;
968 }
969 i = pack_type - Libburn_pack_type_basE;
970 if (t->payload[i] != NULL)
971 free(t->payload[i]);
972 t->payload[i] = burn_alloc_mem((size_t) length, 1, 0);
973 if (t->payload[i] == NULL)
974 return -1;
975 memcpy(t->payload[i], payload, length);
976 t->length[i] = length;
977 t->flags = (t->flags & ~(1 << i)) | (flag & (1 << i));
978 return 1;
979 }
980
981
982 /* @return 1=single byte char , 2= double byte char , <=0 error */
burn_cdtext_get(struct burn_cdtext * t,int pack_type,char * pack_type_name,unsigned char ** payload,int * length,int flag)983 static int burn_cdtext_get(struct burn_cdtext *t, int pack_type,
984 char *pack_type_name,
985 unsigned char **payload, int *length, int flag)
986 {
987 if (pack_type_name != NULL)
988 if (pack_type_name[0])
989 pack_type = burn_cdtext_name_to_type(pack_type_name);
990 if (pack_type < Libburn_pack_type_basE ||
991 pack_type >= Libburn_pack_type_basE + Libburn_pack_num_typeS) {
992 libdax_msgs_submit(libdax_messenger, -1, 0x0002018c,
993 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
994 "CD-TEXT pack type out of range", 0, 0);
995 return 0;
996 }
997 *payload = t->payload[pack_type - Libburn_pack_type_basE];
998 *length = t->length[pack_type - Libburn_pack_type_basE];
999 return 1 + ((t->flags >> (pack_type - Libburn_pack_type_basE)) & 1);
1000 }
1001
1002
burn_cdtext_check_blockno(int block)1003 static int burn_cdtext_check_blockno(int block)
1004 {
1005 if (block < 0 || block > 7) {
1006 libdax_msgs_submit(libdax_messenger, -1, 0x0002018d,
1007 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1008 "CD-TEXT block number out of range", 0, 0);
1009 return 0;
1010 }
1011 return 1;
1012 }
1013
1014
1015 /* ts B11206 API */
1016 /* @param flag bit0= double byte characters
1017 */
burn_track_set_cdtext(struct burn_track * t,int block,int pack_type,char * pack_type_name,unsigned char * payload,int length,int flag)1018 int burn_track_set_cdtext(struct burn_track *t, int block,
1019 int pack_type, char *pack_type_name,
1020 unsigned char *payload, int length, int flag)
1021 {
1022 int ret;
1023
1024 if (burn_cdtext_check_blockno(block) <= 0)
1025 return 0;
1026 ret = burn_cdtext_set(&(t->cdtext[block]), pack_type, pack_type_name,
1027 payload, length, flag & 1);
1028 return ret;
1029 }
1030
1031
1032 /* ts B11206 API */
1033 /* @return 1=single byte char , 2= double byte char , <=0 error */
burn_track_get_cdtext(struct burn_track * t,int block,int pack_type,char * pack_type_name,unsigned char ** payload,int * length,int flag)1034 int burn_track_get_cdtext(struct burn_track *t, int block,
1035 int pack_type, char *pack_type_name,
1036 unsigned char **payload, int *length, int flag)
1037 {
1038 int ret;
1039
1040 if (burn_cdtext_check_blockno(block) <= 0)
1041 return 0;
1042 if (t->cdtext[block] == NULL) {
1043 *payload = NULL;
1044 *length = 0;
1045 return 1;
1046 }
1047 ret = burn_cdtext_get(t->cdtext[block], pack_type, pack_type_name,
1048 payload, length, 0);
1049 return ret;
1050 }
1051
1052
1053 /* ts B11206 API */
burn_track_dispose_cdtext(struct burn_track * t,int block)1054 int burn_track_dispose_cdtext(struct burn_track *t, int block)
1055 {
1056 int i;
1057
1058 if (block == -1) {
1059 for (i= 0; i < 8; i++)
1060 burn_cdtext_free(&(t->cdtext[i]));
1061 return 1;
1062 }
1063 if (burn_cdtext_check_blockno(block) <= 0)
1064 return 0;
1065 burn_cdtext_free(&(t->cdtext[0]));
1066 return 1;
1067 }
1068
1069
1070 /* ts B11206 API */
1071 /* @param flag bit0= double byte characters
1072 */
burn_session_set_cdtext(struct burn_session * s,int block,int pack_type,char * pack_type_name,unsigned char * payload,int length,int flag)1073 int burn_session_set_cdtext(struct burn_session *s, int block,
1074 int pack_type, char *pack_type_name,
1075 unsigned char *payload, int length, int flag)
1076 {
1077 int ret;
1078
1079 if (burn_cdtext_check_blockno(block) <= 0)
1080 return 0;
1081 ret = burn_cdtext_set(&(s->cdtext[block]), pack_type, pack_type_name,
1082 payload, length, flag & 1);
1083 return ret;
1084 }
1085
1086
1087 /* ts B11206 API */
1088 /* @return 1=single byte char , 2= double byte char , <=0 error */
burn_session_get_cdtext(struct burn_session * s,int block,int pack_type,char * pack_type_name,unsigned char ** payload,int * length,int flag)1089 int burn_session_get_cdtext(struct burn_session *s, int block,
1090 int pack_type, char *pack_type_name,
1091 unsigned char **payload, int *length, int flag)
1092 {
1093 int ret;
1094
1095 if (burn_cdtext_check_blockno(block) <= 0)
1096 return 0;
1097
1098 if (s->cdtext[block] == NULL) {
1099 *payload = NULL;
1100 *length = 0;
1101 return 1;
1102 }
1103 ret = burn_cdtext_get(s->cdtext[block], pack_type, pack_type_name,
1104 payload, length, 0);
1105 return ret;
1106 }
1107
1108
1109 /* ts B11206 API */
burn_session_set_cdtext_par(struct burn_session * s,int char_codes[8],int copyrights[8],int block_languages[8],int flag)1110 int burn_session_set_cdtext_par(struct burn_session *s,
1111 int char_codes[8], int copyrights[8],
1112 int block_languages[8], int flag)
1113 {
1114 int i;
1115
1116 for (i = 0; i < 8; i++) {
1117 if (char_codes[i] >= 0 && char_codes[i] <= 255)
1118 s->cdtext_char_code[i] = char_codes[i];
1119 if (copyrights[i] >= 0 && copyrights[i] <= 255)
1120 s->cdtext_copyright[i] = copyrights[i];
1121 if (block_languages[i] >= 0 && block_languages[i] <= 255)
1122 s->cdtext_language[i] = block_languages[i];
1123 }
1124 return 1;
1125 }
1126
1127
1128 /* ts B11206 API */
burn_session_get_cdtext_par(struct burn_session * s,int char_codes[8],int copyrights[8],int block_languages[8],int flag)1129 int burn_session_get_cdtext_par(struct burn_session *s,
1130 int char_codes[8], int copyrights[8],
1131 int block_languages[8], int flag)
1132 {
1133 int i;
1134
1135 for (i = 0; i < 8; i++) {
1136 char_codes[i] = s->cdtext_char_code[i];
1137 copyrights[i] = s->cdtext_copyright[i];
1138 block_languages[i]= s->cdtext_language[i];
1139 }
1140 return 1;
1141 }
1142
1143
1144 /* ts B11206 API */
burn_session_dispose_cdtext(struct burn_session * s,int block)1145 int burn_session_dispose_cdtext(struct burn_session *s, int block)
1146 {
1147 int i;
1148
1149 if (block == -1) {
1150 for (i= 0; i < 8; i++) {
1151 burn_session_dispose_cdtext(s, i);
1152 s->cdtext_char_code[i] = 0x01; /* 7 bit ASCII */
1153 s->cdtext_copyright[i] = 0;
1154 s->cdtext_language[i] = 0;
1155 }
1156 return 1;
1157 }
1158 if (burn_cdtext_check_blockno(block) <= 0)
1159 return 0;
1160 burn_cdtext_free(&(s->cdtext[block]));
1161 s->cdtext_language[block] = 0x09; /* english */
1162 return 1;
1163 }
1164
1165
1166 /* --------------------- Reading CDRWIN cue sheet files ----------------- */
1167
1168
1169 struct burn_cue_file_cursor {
1170 char *cdtextfile;
1171 char *source_file;
1172 off_t source_size;
1173 struct burn_source *file_source;
1174 int fifo_size;
1175 struct burn_source *fifo;
1176 int swap_audio_bytes;
1177 int no_cdtext;
1178 int no_catalog_isrc;
1179 int start_track_no;
1180 struct burn_source *offst_source;
1181 int current_file_ba;
1182 int current_index_ba;
1183 struct burn_track *prev_track;
1184 int prev_file_ba;
1185 int prev_block_size;
1186 struct burn_track *track;
1187 int track_no;
1188 int track_current_index;
1189 int track_has_source;
1190 int block_size;
1191 int block_size_locked;
1192 int track_mode;
1193 int flags;
1194 };
1195
1196
cue_crs_new(struct burn_cue_file_cursor ** reply,int flag)1197 static int cue_crs_new(struct burn_cue_file_cursor **reply, int flag)
1198 {
1199 int ret;
1200 struct burn_cue_file_cursor *crs;
1201
1202 BURN_ALLOC_MEM(crs, struct burn_cue_file_cursor, 1);
1203 crs->cdtextfile = NULL;
1204 crs->source_file = NULL;
1205 crs->source_size = -1;
1206 crs->file_source = NULL;
1207 crs->fifo_size = 0;
1208 crs->fifo = NULL;
1209 crs->swap_audio_bytes = 0;
1210 crs->no_cdtext = 0;
1211 crs->no_catalog_isrc = 0;
1212 crs->start_track_no = 1;
1213 crs->offst_source = NULL;
1214 crs->current_file_ba = -1000000000;
1215 crs->current_index_ba = -1000000000;
1216 crs->prev_track = NULL;
1217 crs->prev_file_ba = -1000000000;
1218 crs->prev_block_size = 0;
1219 crs->track = NULL;
1220 crs->track_no = 0;
1221 crs->track_current_index = -1;
1222 crs->track_has_source = 0;
1223 crs->block_size = 0;
1224 crs->block_size_locked = 0;
1225 crs->track_mode = 0;
1226 crs->flags = 0;
1227
1228 *reply = crs;
1229 ret = 1;
1230 ex:;
1231 return ret;
1232 }
1233
1234
cue_crs_destroy(struct burn_cue_file_cursor ** victim,int flag)1235 static int cue_crs_destroy(struct burn_cue_file_cursor **victim, int flag)
1236 {
1237 struct burn_cue_file_cursor *crs;
1238
1239 if (*victim == NULL)
1240 return 2;
1241 crs = *victim;
1242 if (crs->cdtextfile != NULL)
1243 free(crs->cdtextfile);
1244 if (crs->source_file != NULL)
1245 free(crs->source_file);
1246 if (crs->file_source != NULL)
1247 burn_source_free(crs->file_source);
1248 if (crs->fifo != NULL)
1249 burn_source_free(crs->fifo);
1250 if (crs->offst_source != NULL)
1251 burn_source_free(crs->offst_source);
1252 if (crs->prev_track != NULL)
1253 burn_track_free(crs->prev_track);
1254 if (crs->track != NULL)
1255 burn_track_free(crs->track);
1256 BURN_FREE_MEM(crs);
1257 *victim = NULL;
1258 return 1;
1259 }
1260
1261
cue_unquote_text(char * text,int flag)1262 static char *cue_unquote_text(char *text, int flag)
1263 {
1264 char *ept, *spt;
1265
1266 spt = text;
1267 for (ept = text + strlen(text); ept > text; ept--)
1268 if (*(ept - 1) != 32 && *(ept - 1) != 9)
1269 break;
1270 if (text[0] == '"') {
1271 spt = text + 1;
1272 if (ept > spt)
1273 if (*(ept - 1) == '"')
1274 ept--;
1275 }
1276 *ept = 0;
1277 return spt;
1278 }
1279
1280
1281 /* @param flag bit0= insist in having a track object
1282 bit1= remove quotation marks if present
1283 */
cue_set_cdtext(struct burn_session * session,struct burn_track * track,int pack_type,char * text,struct burn_cue_file_cursor * crs,int flag)1284 static int cue_set_cdtext(struct burn_session *session,
1285 struct burn_track *track, int pack_type, char *text,
1286 struct burn_cue_file_cursor *crs, int flag)
1287 {
1288 int ret;
1289 char *payload;
1290
1291 if (crs->no_cdtext == 1) {
1292 libdax_msgs_submit(libdax_messenger, -1, 0x00020195,
1293 LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
1294 "In cue sheet file: Being set to ignore all CD-TEXT aspects",
1295 0, 0);
1296 crs->no_cdtext = 2;
1297 }
1298 if (crs->no_cdtext)
1299 return 2;
1300 if ((flag & 1) && track == NULL) {
1301 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1302 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1303 "Track attribute set before first track in cue sheet file",
1304 0, 0);
1305 ret = 0; goto ex;
1306 }
1307 if (flag & 2)
1308 payload = cue_unquote_text(text, 0);
1309 else
1310 payload = text;
1311 if (track != NULL) {
1312 ret = burn_track_set_cdtext(track, 0, pack_type, "",
1313 (unsigned char *) payload,
1314 strlen(payload) + 1, 0);
1315 } else {
1316 ret = burn_session_set_cdtext(session, 0, pack_type, "",
1317 (unsigned char *) payload,
1318 strlen(payload) + 1, 0);
1319 }
1320 ex:;
1321 return ret;
1322 }
1323
1324
cue_attach_track(struct burn_session * session,struct burn_cue_file_cursor * crs,int flag)1325 static int cue_attach_track(struct burn_session *session,
1326 struct burn_cue_file_cursor *crs, int flag)
1327 {
1328 int ret;
1329
1330 if (crs->track == NULL)
1331 return 2;
1332
1333 if (!crs->track_has_source) {
1334 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1335 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1336 "In cue sheet file: TRACK without INDEX 01", 0, 0);
1337 return 0;
1338 }
1339 if (crs->track_current_index < 1) {
1340 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1341 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1342 "No INDEX 01 defined for last TRACK in cue sheet file",
1343 0, 0);
1344 return 0;
1345 }
1346 if (session->tracks == 0) {
1347 crs->start_track_no = crs->track_no;
1348 ret = burn_session_set_start_tno(session, crs->track_no, 0);
1349 if (ret <= 0)
1350 return ret;
1351 }
1352 if (session->tracks + crs->start_track_no - 1 > 99) {
1353 libdax_msgs_submit(libdax_messenger, -1, 0x0002019b,
1354 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
1355 "CD track number exceeds 99",
1356 0, 0);
1357 return 0;
1358 }
1359 ret = burn_session_add_track(session, crs->track, BURN_POS_END);
1360 if (ret <= 0)
1361 return ret;
1362 if (crs->prev_track != NULL)
1363 burn_track_free(crs->prev_track); /* release reference */
1364 crs->prev_track = crs->track;
1365 crs->prev_file_ba = crs->current_file_ba;
1366 crs->prev_block_size = crs->block_size;
1367 crs->track = NULL;
1368 crs->track_current_index = -1;
1369 crs->track_has_source = 0;
1370 crs->current_file_ba = -1;
1371 crs->current_index_ba = -1;
1372 if (!crs->block_size_locked)
1373 crs->block_size = 0;
1374 return 1;
1375 }
1376
1377
1378 /* @param flag bit0= do not alter the content of *payload
1379 do not change *payload
1380 */
cue_read_number(char ** payload,int * number,int flag)1381 static int cue_read_number(char **payload, int *number, int flag)
1382 {
1383 int ret, at_end = 0;
1384 char *apt, *msg = NULL;
1385
1386 for(apt = *payload; *apt != 0 && *apt != 32 && *apt != 9; apt++);
1387 if (*apt == 0)
1388 at_end = 1;
1389 else if (!(flag & 1))
1390 *apt = 0;
1391 ret = sscanf(*payload, "%d", number);
1392 if (ret != 1) {
1393 BURN_ALLOC_MEM(msg, char, 4096);
1394 sprintf(msg,
1395 "Unsuitable number in cue sheet file: '%.4000s'",
1396 *payload);
1397 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1398 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1399 burn_printify(msg), 0, 0);
1400 ret = 0; goto ex;
1401 }
1402 /* Find start of next argument */
1403 if (!at_end)
1404 for (apt++; *apt == 32 || *apt == 9; apt++);
1405 if (!(flag & 1))
1406 *payload = apt;
1407
1408 ret = 1;
1409 ex:
1410 BURN_FREE_MEM(msg);
1411 return ret;
1412 }
1413
1414
1415 /* @param flag bit0-7: desired type : 0=any , 1=.wav
1416 */
cue_open_audioxtr(char * path,struct burn_cue_file_cursor * crs,int * fd,int flag)1417 static int cue_open_audioxtr(char *path, struct burn_cue_file_cursor *crs,
1418 int *fd, int flag)
1419 {
1420 struct libdax_audioxtr *xtr= NULL;
1421 char *fmt, *fmt_info;
1422 int ret, num_channels, sample_rate, bits_per_sample, msb_first;
1423 char *msg = NULL;
1424
1425 BURN_ALLOC_MEM(msg, char, 4096);
1426
1427 ret= libdax_audioxtr_new(&xtr, path, 0);
1428 if (ret <= 0)
1429 goto ex;
1430 libdax_audioxtr_get_id(xtr, &fmt, &fmt_info, &num_channels,
1431 &sample_rate, &bits_per_sample, &msb_first, 0);
1432 if ((flag & 255) == 1) {
1433 if (strcmp(fmt, ".wav") != 0) {
1434 sprintf(msg,
1435 "In cue sheet: Not recognized as WAVE : FILE '%.4000s'",
1436 path);
1437 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
1438 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1439 burn_printify(msg), 0, 0);
1440 ret = 0; goto ex;
1441 }
1442 }
1443 ret = libdax_audioxtr_get_size(xtr, &(crs->source_size), 0);
1444 if (ret <= 0) {
1445 sprintf(msg,
1446 "In cue sheet: Cannot get payload size of FILE '%.4000s'",
1447 path);
1448 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
1449 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1450 burn_printify(msg), 0, 0);
1451 ret = 0; goto ex;
1452 }
1453 ret = libdax_audioxtr_detach_fd(xtr, fd, 0);
1454 if (ret <= 0) {
1455 sprintf(msg,
1456 "In cue sheet: Cannot represent payload as plain fd: FILE '%.4000s'",
1457 path);
1458 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
1459 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1460 burn_printify(msg), 0, 0);
1461 ret = 0; goto ex;
1462 }
1463 crs->swap_audio_bytes = (msb_first == 1);
1464
1465 ret = 1;
1466 ex:
1467 if (xtr != NULL)
1468 libdax_audioxtr_destroy(&xtr, 0);
1469 BURN_FREE_MEM(msg);
1470 return ret;
1471 }
1472
1473
1474 /* @param flag bit0-7: desired type : 0=any , 1=.wav
1475 bit8= open by libdax_audioxtr functions
1476
1477 */
cue_create_file_source(char * path,struct burn_cue_file_cursor * crs,int flag)1478 static int cue_create_file_source(char *path, struct burn_cue_file_cursor *crs,
1479 int flag)
1480 {
1481 int fd, ret;
1482 char *msg = NULL;
1483
1484 BURN_ALLOC_MEM(msg, char, 4096);
1485
1486 if (flag & 256) {
1487 ret = cue_open_audioxtr(path, crs, &fd, flag & 255);
1488 if (ret <= 0)
1489 goto ex;
1490 } else {
1491 fd = open(path, O_RDONLY | O_BINARY);
1492 if (fd == -1) {
1493 sprintf(msg,
1494 "In cue sheet: Cannot open FILE '%.4000s'",
1495 path);
1496 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
1497 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1498 burn_printify(msg), errno, 0);
1499 ret = 0; goto ex;
1500 }
1501 }
1502 crs->file_source = burn_fd_source_new(fd, -1, crs->source_size);
1503 if (crs->file_source == NULL) {
1504 ret = -1; goto ex;
1505 }
1506
1507 ret = 1;
1508 ex:;
1509 BURN_FREE_MEM(msg);
1510 return ret;
1511 }
1512
1513
cue_read_timepoint_lba(char * apt,char * purpose,int * file_ba,int flag)1514 static int cue_read_timepoint_lba(char *apt, char *purpose, int *file_ba,
1515 int flag)
1516 {
1517 int ret, minute, second, frame;
1518 char *msg = NULL, msf[3], *msf_pt;
1519
1520 BURN_ALLOC_MEM(msg, char, 4096);
1521 if (strlen(apt) < 8) {
1522 no_time_point:;
1523 sprintf(msg,
1524 "Inappropriate cue sheet file %s '%.4000s'",
1525 purpose, apt);
1526 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1527 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1528 burn_printify(msg), 0, 0);
1529 ret = 0; goto ex;
1530 }
1531 if (apt[2] != ':' || apt[5] != ':' ||
1532 (apt[8] != 0 && apt[8] != 32 && apt[8] != 9))
1533 goto no_time_point;
1534 msf[2] = 0;
1535 msf_pt = msf;
1536 strncpy(msf, apt, 2);
1537 ret = cue_read_number(&msf_pt, &minute, 1);
1538 if (ret <= 0)
1539 goto ex;
1540 strncpy(msf, apt + 3, 2);
1541 ret = cue_read_number(&msf_pt, &second, 1);
1542 if (ret <= 0)
1543 goto ex;
1544 strncpy(msf, apt + 6, 2);
1545 ret = cue_read_number(&msf_pt, &frame, 1);
1546 if (ret <= 0)
1547 goto ex;
1548
1549 *file_ba = ((minute * 60) + second ) * 75 + frame;
1550 ret = 1;
1551 ex:;
1552 BURN_FREE_MEM(msg);
1553 return ret;
1554 }
1555
cue_check_for_track(struct burn_cue_file_cursor * crs,char * cmd,int flag)1556 static int cue_check_for_track(struct burn_cue_file_cursor *crs, char *cmd,
1557 int flag)
1558 {
1559 int ret;
1560 char *msg = NULL;
1561
1562 if (crs->track == NULL) {
1563 BURN_ALLOC_MEM(msg, char, 4096);
1564 sprintf(msg, "In cue sheet file: %s found before TRACK",
1565 cmd);
1566 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1567 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1568 msg, 0, 0);
1569 ret = 0; goto ex;
1570 }
1571 ret = 1;
1572 ex:;
1573 BURN_FREE_MEM(msg);
1574 return ret;
1575 }
1576
1577
cue_interpret_line(struct burn_session * session,char * line,struct burn_cue_file_cursor * crs,int flag)1578 static int cue_interpret_line(struct burn_session *session, char *line,
1579 struct burn_cue_file_cursor *crs, int flag)
1580 {
1581 int ret, mode, index_no, file_ba, chunks;
1582 int block_size, step, audio_xtr = 0;
1583 off_t size;
1584 char *cmd, *apt, *msg = NULL, *cpt, *filetype;
1585 struct burn_source *src, *inp_src;
1586 enum burn_source_status source_status;
1587 struct stat stbuf;
1588
1589 BURN_ALLOC_MEM(msg, char, 4096);
1590
1591 if (line[0] == 0 || line[0] == '#') {
1592 ret = 1; goto ex;
1593 }
1594
1595 for (cmd = line; *cmd == 32 || *cmd == 9; cmd++);
1596 for(apt = cmd; *apt != 0 && *apt != 32 && *apt != 9; apt++);
1597 if (*apt != 0) {
1598 *apt = 0;
1599 for (apt++; *apt == 32 || *apt == 9; apt++);
1600 }
1601
1602 if (strcmp(cmd, "ARRANGER") == 0) {
1603 ret = cue_set_cdtext(session, crs->track, 0x84, apt, crs, 2);
1604 if (ret <= 0)
1605 goto ex;
1606
1607 } else if (strcmp(cmd, "CATALOG") == 0) {
1608 for (cpt = apt; (cpt - apt) < 13 && *cpt == (*cpt & 0x7f);
1609 cpt++);
1610 if ((cpt - apt) < 13) {
1611 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1612 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1613 "In cue sheet file: Inappropriate content of CATALOG",
1614 0, 0);
1615 ret = 0; goto ex;
1616 }
1617 ret = cue_set_cdtext(session, NULL, 0x8e, apt, crs, 0);
1618 if (ret <= 0)
1619 goto ex;
1620 if (!crs->no_catalog_isrc) {
1621 memcpy(session->mediacatalog, apt, 13);
1622 session->mediacatalog[13] = 0;
1623 }
1624
1625 } else if (strcmp(cmd, "CDTEXTFILE") == 0) {
1626 if (crs->no_cdtext) {
1627 ret = 1; goto ex;
1628 }
1629 apt = cue_unquote_text(apt, 0);
1630 if (crs->cdtextfile != NULL)
1631 free(crs->cdtextfile);
1632 crs->cdtextfile = strdup(apt);
1633 if (crs->cdtextfile == NULL) {
1634 out_of_mem:;
1635 libdax_msgs_submit(libdax_messenger, -1, 0x00000003,
1636 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1637 "Out of virtual memory", 0, 0);
1638 ret = -1; goto ex;
1639 }
1640
1641 } else if (strcmp(cmd, "COMPOSER") == 0) {
1642 ret = cue_set_cdtext(session, crs->track, 0x83, apt, crs, 2);
1643 if (ret <= 0)
1644 goto ex;
1645
1646 } else if (strcmp(cmd, "FILE") == 0) {
1647 if (crs->file_source != NULL) {
1648 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1649 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1650 "In cue sheet file: Multiple occurrences of FILE",
1651 0, 0);
1652 ret = 0; goto ex;
1653 }
1654 /* Obtain type */
1655 for (cpt = apt + (strlen(apt) - 1);
1656 cpt > apt && (*cpt == 32 || *cpt == 9); cpt--);
1657 cpt[1] = 0;
1658 for (; cpt > apt && *cpt != 32 && *cpt != 9; cpt--);
1659 if (cpt <= apt) {
1660 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1661 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1662 "In cue sheet file: FILE without type word",
1663 0, 0);
1664 ret = 0; goto ex;
1665 }
1666 *cpt = 0;
1667 filetype = cpt + 1;
1668 if (strcmp(filetype, "BINARY") == 0) {
1669 crs->swap_audio_bytes = 0;
1670 } else if (strcmp(filetype, "MOTOROLA") == 0) {
1671 crs->swap_audio_bytes = 1;
1672 } else if (strcmp(filetype, "WAVE") == 0) {
1673 audio_xtr = 0x101;
1674 } else {
1675 sprintf(msg,
1676 "In cue sheet file: Unsupported FILE type '%.4000s'",
1677 filetype);
1678 libdax_msgs_submit(libdax_messenger, -1, 0x00020197,
1679 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1680 burn_printify(msg), 0, 0);
1681 ret = 0; goto ex;
1682 }
1683
1684 apt = cue_unquote_text(apt, 0);
1685 if (*apt == 0)
1686 ret = -1;
1687 else
1688 ret = stat(apt, &stbuf);
1689 if (ret == -1) {
1690 not_usable_file:;
1691 sprintf(msg,
1692 "In cue sheet file: Unusable FILE '%.4000s'",
1693 apt);
1694 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1695 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1696 burn_printify(msg), 0, 0);
1697 ret = 0; goto ex;
1698 }
1699 if (!S_ISREG(stbuf.st_mode))
1700 goto not_usable_file;
1701 crs->source_size = stbuf.st_size;
1702 if (crs->source_file != NULL)
1703 free(crs->source_file);
1704 crs->source_file = strdup(apt);
1705 if (crs->source_file == NULL)
1706 goto out_of_mem;
1707 ret = cue_create_file_source(apt, crs, audio_xtr);
1708 if (ret <= 0)
1709 goto ex;
1710
1711 } else if (strcmp(cmd, "FLAGS") == 0) {
1712 ret = cue_check_for_track(crs, cmd, 0);
1713 if (ret <= 0)
1714 goto ex;
1715 while (*apt) {
1716 if (strncmp(apt, "DCP", 3) == 0) {
1717 crs->track_mode |= BURN_COPY;
1718 step = 3;
1719 } else if (strncmp(apt, "4CH", 3) == 0) {
1720 crs->track_mode |= BURN_4CH;
1721 step = 3;
1722 } else if (strncmp(apt, "PRE", 3) == 0) {
1723 crs->track_mode |= BURN_PREEMPHASIS;
1724 step = 3;
1725 } else if (strncmp(apt, "SCMS", 4) == 0) {
1726 crs->track_mode |= BURN_SCMS;
1727 step = 4;
1728 } else {
1729 bad_flags:;
1730 for (cpt = apt;
1731 *cpt != 32 && *cpt != 9 && *cpt != 0; cpt++);
1732 *cpt = 0;
1733 sprintf(msg,
1734 "In cue sheet file: Unknown FLAGS option '%.4000s'",
1735 apt);
1736 libdax_msgs_submit(libdax_messenger, -1,
1737 0x00020194,
1738 LIBDAX_MSGS_SEV_FAILURE,
1739 LIBDAX_MSGS_PRIO_HIGH,
1740 burn_printify(msg), 0, 0);
1741 ret = 0; goto ex;
1742 }
1743
1744 /* Look for start of next word */
1745 if (apt[step] != 0 && apt[step] != 32 &&
1746 apt[step] != 9)
1747 goto bad_flags;
1748 for (apt += step; *apt == 32 || *apt == 9; apt++);
1749 }
1750 burn_track_define_data(crs->track, 0, 0, 1, crs->track_mode);
1751
1752 } else if (strcmp(cmd, "INDEX") == 0) {
1753 ret = cue_check_for_track(crs, cmd, 0);
1754 if (ret <= 0)
1755 goto ex;
1756 ret = cue_read_number(&apt, &index_no, 0);
1757 if (ret <= 0)
1758 goto ex;
1759 ret = cue_read_timepoint_lba(apt, "index time point",
1760 &file_ba, 0);
1761 if (ret <= 0)
1762 goto ex;
1763 if (file_ba < crs->prev_file_ba) {
1764 overlapping_ba:;
1765 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1766 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1767 "Backward INDEX address in cue sheet file",
1768 0, 0);
1769 ret = 0; goto ex;
1770 }
1771 if (file_ba < crs->current_index_ba)
1772 goto overlapping_ba;
1773 if (crs->prev_track != NULL && crs->track_current_index < 0) {
1774 size = (file_ba - crs->prev_file_ba) *
1775 crs->prev_block_size;
1776 if (size <= 0)
1777 goto overlapping_ba;
1778 burn_track_set_size(crs->prev_track, size);
1779 }
1780 if (crs->track_current_index + 1 != index_no &&
1781 !(crs->track_current_index < 0 && index_no <= 1)) {
1782 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1783 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1784 "Unacceptable INDEX number in cue sheet file",
1785 0, 0);
1786 ret = 0; goto ex;
1787 }
1788 crs->track_current_index = index_no;
1789
1790 if (crs->current_file_ba < 0)
1791 crs->current_file_ba = file_ba;
1792 crs->current_index_ba = file_ba;
1793
1794 /* Set index address relative to track source start */
1795 ret = burn_track_set_index(crs->track, index_no,
1796 file_ba - crs->current_file_ba, 0);
1797 if (ret <= 0)
1798 goto ex;
1799
1800 if (crs->track_has_source) {
1801 ret = 1; goto ex;
1802 }
1803
1804 if (crs->block_size_locked && crs->fifo == NULL &&
1805 crs->fifo_size > 0) {
1806 /* Now that the block size is known from TRACK:
1807 Create fifo and use it for creating the offset
1808 sources. This will fixate the block size to one
1809 common value.
1810 */
1811 chunks = crs->fifo_size / crs->block_size +
1812 !!(crs->fifo_size % crs->block_size);
1813 if (chunks < 4)
1814 chunks = 4;
1815 crs->fifo = burn_fifo_source_new(crs->file_source,
1816 crs->block_size, chunks, 0);
1817 if (crs->fifo == NULL) {
1818 ret = -1; goto ex;
1819 }
1820 }
1821 if (crs->fifo != NULL)
1822 inp_src = crs->fifo;
1823 else
1824 inp_src = crs->file_source;
1825 src = burn_offst_source_new(inp_src, crs->offst_source,
1826 (off_t) (file_ba * crs->block_size), (off_t) 0, 1);
1827 if (src == NULL)
1828 goto out_of_mem;
1829
1830 /* >>> Alternative to above fifo creation:
1831 Create a fifo for each track track.
1832 This will be necessary if mixed-mode sessions get supporded.
1833 */;
1834
1835 source_status = burn_track_set_source(crs->track, src);
1836 if (source_status != BURN_SOURCE_OK) {
1837 ret = -1; goto ex;
1838 }
1839
1840 /* Switch current source in crs */
1841 if (crs->offst_source != NULL)
1842 burn_source_free(crs->offst_source);
1843 crs->offst_source = src;
1844 crs->track_has_source = 1;
1845
1846 } else if (strcmp(cmd, "ISRC") == 0) {
1847 ret = cue_check_for_track(crs, cmd, 0);
1848 if (ret <= 0)
1849 goto ex;
1850 ret = cue_set_cdtext(session, crs->track, 0x8e, apt, crs,
1851 1 | 2);
1852 if (ret <= 0)
1853 goto ex;
1854 if (!crs->no_catalog_isrc) {
1855 ret = burn_track_set_isrc_string(crs->track, apt, 0);
1856 if (ret <= 0)
1857 goto ex;
1858 }
1859
1860 } else if (strcmp(cmd, "MESSAGE") == 0) {
1861 ret = cue_set_cdtext(session, crs->track, 0x85, apt, crs, 2);
1862 if (ret <= 0)
1863 goto ex;
1864
1865 } else if (strcmp(cmd, "PERFORMER") == 0) {
1866 ret = cue_set_cdtext(session, crs->track, 0x81, apt, crs, 2);
1867 if (ret <= 0)
1868 goto ex;
1869
1870 } else if (strcmp(cmd, "POSTGAP") == 0) {
1871 ret = cue_check_for_track(crs, cmd, 0);
1872 if (ret <= 0)
1873 goto ex;
1874 ret = cue_read_timepoint_lba(apt, "post-gap duration",
1875 &file_ba, 0);
1876 if (ret <= 0)
1877 goto ex;
1878 ret = burn_track_set_postgap_size(crs->track, file_ba, 0);
1879 if (ret <= 0)
1880 goto ex;
1881
1882 } else if (strcmp(cmd, "PREGAP") == 0) {
1883 ret = cue_check_for_track(crs, cmd, 0);
1884 if (ret <= 0)
1885 goto ex;
1886 ret = cue_read_timepoint_lba(apt, "pre-gap duration",
1887 &file_ba, 0);
1888 if (ret <= 0)
1889 goto ex;
1890 ret = burn_track_set_pregap_size(crs->track, file_ba, 0);
1891 if (ret <= 0)
1892 goto ex;
1893
1894 } else if (strcmp(cmd, "REM") == 0) {
1895 ;
1896
1897 } else if (strcmp(cmd, "SONGWRITER") == 0) {
1898 ret = cue_set_cdtext(session, crs->track, 0x82, apt, crs, 2);
1899 if (ret <= 0)
1900 goto ex;
1901
1902 } else if (strcmp(cmd, "TITLE") == 0) {
1903 ret = cue_set_cdtext(session, crs->track, 0x80, apt, crs, 2);
1904 if (ret <= 0)
1905 goto ex;
1906
1907 } else if (strcmp(cmd, "TRACK") == 0) {
1908 if (crs->file_source == NULL) {
1909 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
1910 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1911 "No FILE defined before TRACK in cue sheet file",
1912 0, 0);
1913 ret = 0; goto ex;
1914 }
1915 /* Attach previous track to session */
1916 ret = cue_attach_track(session, crs, 0);
1917 if (ret <= 0)
1918 goto ex;
1919 /* Create new track */;
1920 ret = cue_read_number(&apt, &(crs->track_no), 0);
1921 if (ret <= 0)
1922 goto ex;
1923 if (crs->track_no < 1 || crs->track_no > 99) {
1924 sprintf(msg,
1925 "Inappropriate cue sheet file track number %d",
1926 crs->track_no);
1927 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
1928 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1929 burn_printify(msg), 0, 0);
1930 ret = 0; goto ex;
1931 }
1932 if (strcmp(apt, "AUDIO") == 0) {
1933 mode = BURN_AUDIO;
1934 block_size = 2352;
1935 } else if (strcmp(apt, "MODE1/2048") == 0) {
1936 mode = BURN_MODE1;
1937 block_size = 2048;
1938 } else {
1939 sprintf(msg,
1940 "Unsupported cue sheet file track datatype '%.4000s'",
1941 apt);
1942 libdax_msgs_submit(libdax_messenger, -1, 0x00020197,
1943 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1944 burn_printify(msg), 0, 0);
1945 ret = 0; goto ex;
1946 }
1947 if (block_size != crs->block_size && crs->block_size > 0 &&
1948 crs->block_size_locked) {
1949 libdax_msgs_submit(libdax_messenger, -1, 0x00020197,
1950 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1951 "In cue sheet file: Unsupported mix track block sizes",
1952 0, 0);
1953 ret = 0; goto ex;
1954 }
1955 crs->block_size = block_size;
1956
1957 crs->track = burn_track_create();
1958 if (crs->track == NULL)
1959 goto out_of_mem;
1960 crs->track_has_source = 0;
1961 crs->track_mode = mode;
1962 burn_track_define_data(crs->track, 0, 0, 1, mode);
1963 if (mode & BURN_AUDIO)
1964 burn_track_set_byte_swap(crs->track,
1965 !!crs->swap_audio_bytes);
1966
1967 } else {
1968 sprintf(msg, "Unknown cue sheet file command '%.4000s'", line);
1969 libdax_msgs_submit(libdax_messenger, -1, 0x00020191,
1970 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1971 burn_printify(msg), 0, 0);
1972 ret = 0; goto ex;
1973 }
1974
1975 ret = 1;
1976 ex:;
1977 BURN_FREE_MEM(msg);
1978 return ret;
1979 }
1980
1981
1982 /* ts B11216 API */
1983 /* @param flag bit0= do not attach CD-TEXT information to session and tracks
1984 bit1= do not attach CATALOG to session or ISRC to track for
1985 writing to Q sub-channel
1986 */
burn_session_by_cue_file(struct burn_session * session,char * path,int fifo_size,struct burn_source ** fifo,unsigned char ** text_packs,int * num_packs,int flag)1987 int burn_session_by_cue_file(struct burn_session *session, char *path,
1988 int fifo_size, struct burn_source **fifo,
1989 unsigned char **text_packs, int *num_packs, int flag)
1990 {
1991 int ret, num_tracks, i, pack_type, length, double_byte = 0;
1992 int line_counter = 0;
1993 struct burn_track **tracks;
1994 char *msg = NULL, *line = NULL;
1995 unsigned char *payload;
1996 struct stat stbuf;
1997 FILE *fp = NULL;
1998 struct burn_cue_file_cursor *crs = NULL;
1999
2000 static unsigned char dummy_cdtext[2] = {0, 0};
2001
2002 if (fifo != NULL)
2003 *fifo = NULL;
2004 if (text_packs != NULL)
2005 *text_packs = NULL;
2006 *num_packs = 0;
2007
2008 BURN_ALLOC_MEM(msg, char, 4096);
2009 BURN_ALLOC_MEM(line, char, 4096);
2010 ret = cue_crs_new(&crs, 0);
2011 if (ret <= 0)
2012 goto ex;
2013 crs->no_cdtext = (flag & 1);
2014 crs->no_catalog_isrc = !!(flag & 2);
2015 crs->fifo_size = fifo_size;
2016 crs->block_size_locked = 1; /* No mixed sessions for now */
2017
2018 tracks = burn_session_get_tracks(session, &num_tracks);
2019 if (num_tracks > 0) {
2020 sprintf(msg,
2021 "Cue sheet file reader called while session has already defined tracks");
2022 libdax_msgs_submit(libdax_messenger, -1, 0x00020196,
2023 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2024 burn_printify(msg), 0, 0);
2025 ret = 0; goto ex;
2026 }
2027 if (stat(path, &stbuf) == -1) {
2028 cannot_open:;
2029 sprintf(msg, "Cannot open cue sheet file '%.4000s'",
2030 path);
2031 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
2032 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2033 burn_printify(msg), errno, 0);
2034 ret = 0; goto ex;
2035 }
2036 if (!S_ISREG(stbuf.st_mode)) {
2037 sprintf(msg,
2038 "File is not of usable type: Cue sheet file '%.4000s'",
2039 path);
2040 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
2041 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2042 burn_printify(msg), 0, 0);
2043 ret = 0; goto ex;
2044 }
2045
2046 fp = fopen(path, "rb");
2047 if (fp == NULL)
2048 goto cannot_open;
2049
2050 while (1) {
2051 if (burn_sfile_fgets(line, 4095, fp) == NULL) {
2052 if (!ferror(fp))
2053 break;
2054 sprintf(msg,
2055 "Cannot read all bytes from cue sheet file '%.4000s'",
2056 path);
2057 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
2058 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2059 burn_printify(msg), 0, 0);
2060 ret = 0; goto ex;
2061 }
2062 line_counter++;
2063 ret = cue_interpret_line(session, line, crs, 0);
2064 if (ret <= 0) {
2065 sprintf(msg,
2066 "Cue sheet file '%.4000s': Reading aborted after line %d",
2067 path, line_counter);
2068 libdax_msgs_submit(libdax_messenger, -1, 0x00020199,
2069 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
2070 burn_printify(msg), 0, 0);
2071 goto ex;
2072 }
2073 }
2074
2075 /* Attach last track to session */
2076 if (crs->track != NULL) {
2077 /* Set track size up to end of file */
2078 if (crs->current_file_ba < 0 || crs->track_current_index < 1) {
2079 libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
2080 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2081 "No INDEX 01 defined for last TRACK in cue sheet file",
2082 0, 0);
2083 ret = 0; goto ex;
2084 }
2085 if (crs->current_file_ba * crs->block_size >=
2086 crs->source_size) {
2087 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
2088 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
2089 "TRACK start time point exceeds size of FILE from cue sheet file",
2090 0, 0);
2091 ret = 0; goto ex;
2092 }
2093 ret = burn_track_set_size(crs->track, crs->source_size -
2094 (off_t) (crs->current_file_ba * crs->block_size));
2095 if (ret <= 0)
2096 goto ex;
2097
2098 ret = cue_attach_track(session, crs, 0);
2099 if (ret <= 0)
2100 goto ex;
2101 }
2102 if (crs->cdtextfile != NULL) {
2103 if (text_packs == NULL) {
2104
2105 /* >>> Warn of ignored text packs */;
2106
2107 } else {
2108 ret = burn_cdtext_from_packfile(crs->cdtextfile,
2109 text_packs, num_packs, 0);
2110 if (ret <= 0)
2111 goto ex;
2112 }
2113 }
2114
2115 /* Check which tracks have data of pack types where session has not */
2116 tracks = burn_session_get_tracks(session, &num_tracks);
2117 for (pack_type = 0x80; pack_type < 0x8f; pack_type++) {
2118 if (pack_type > 0x86 && pack_type != 0x8e)
2119 continue;
2120 ret = burn_session_get_cdtext(session, 0, pack_type, "",
2121 &payload, &length, 0);
2122 if (ret <= 0)
2123 goto ex;
2124 if (payload != NULL)
2125 continue;
2126 for (i = 0; i < num_tracks; i++) {
2127 ret = burn_track_get_cdtext(tracks[i], 0, pack_type,
2128 "", &payload, &length, 0);
2129 if (ret <= 0)
2130 goto ex;
2131 double_byte = (ret > 1);
2132 if (payload != NULL)
2133 break;
2134 }
2135 if (i < num_tracks) {
2136 ret = burn_session_set_cdtext(session, 0, pack_type,
2137 "", dummy_cdtext, 1 + double_byte,
2138 double_byte);
2139 if (ret <= 0)
2140 goto ex;
2141 }
2142 }
2143 ret = 1;
2144 ex:
2145 if (ret <= 0) {
2146 tracks = burn_session_get_tracks(session, &num_tracks);
2147 for (i = 0; i < num_tracks; i++)
2148 burn_track_free(tracks[i]);
2149 if(text_packs != NULL) {
2150 if(*text_packs != NULL)
2151 free(*text_packs);
2152 *text_packs = NULL;
2153 *num_packs = 0;
2154 }
2155 } else {
2156 if (fifo != NULL) {
2157 *fifo = crs->fifo;
2158 crs->fifo = NULL;
2159 }
2160 }
2161 cue_crs_destroy(&crs, 0);
2162 BURN_FREE_MEM(line);
2163 BURN_FREE_MEM(msg);
2164 if (fp != NULL)
2165 fclose(fp);
2166 return ret;
2167 }
2168
2169