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