"Fossies" - the Fresh Open Source Software Archive 
Member "xorriso-1.5.4/libburn/cdtext.c" (30 Jan 2021, 48731 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "cdtext.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1
2 /* Copyright (c) 2011 - 2016 Thomas Schmitt <scdbackup@gmx.net>
3 Provided under GPL version 2 or later.
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include "../config.h"
8 #endif
9
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include <errno.h>
19
20 #include "libburn.h"
21 #include "init.h"
22 #include "structure.h"
23 #include "options.h"
24 #include "util.h"
25
26 #include "libdax_msgs.h"
27 extern struct libdax_msgs *libdax_messenger;
28
29
30 /* --------------------- Production of CD-TEXT packs -------------------- */
31
32
33 struct burn_pack_cursor {
34 unsigned char *packs;
35 int num_packs;
36 int td_used;
37 int hiseq[8];
38 int pack_count[16];
39 int track_offset;
40 };
41
42
43 /* @param flag bit0= double_byte characters
44 */
45 int burn_create_new_pack(int pack_type, int track_no, int double_byte,
46 int block, int char_pos,
47 struct burn_pack_cursor *crs, int flag)
48 {
49 int idx;
50
51 if (crs->num_packs >= Libburn_leadin_cdtext_packs_maX) {
52 libdax_msgs_submit(libdax_messenger, -1, 0x0002018b,
53 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
54 "Too many CD-TEXT packs", 0, 0);
55 return 0;
56 }
57 if (crs->hiseq[block] >= 255) {
58 libdax_msgs_submit(libdax_messenger, -1, 0x0002018e,
59 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
60 "Too many CD-TEXT packs in block", 0, 0);
61 return 0;
62 }
63 if (char_pos > 15)
64 char_pos = 15;
65 else if (char_pos < 0)
66 char_pos = 0;
67 idx = crs->num_packs * 18;
68 crs->packs[idx++] = pack_type;
69 crs->packs[idx++] = track_no;
70 crs->packs[idx++] = crs->hiseq[block];
71 crs->packs[idx++] = ((flag & 1) << 7) | (block << 4) | char_pos;
72 crs->hiseq[block]++;
73 crs->td_used = 0;
74 crs->pack_count[pack_type - Libburn_pack_type_basE]++;
75 return 1;
76 }
77
78
79 /* Plain implementation of polynomial division on a Galois field, where
80 addition and subtraction both are binary exor. Euclidean algorithm.
81 Divisor is x^16 + x^12 + x^5 + 1 = 0x11021.
82 */
83 static int crc_11021(unsigned char *data, int count, int flag)
84 {
85 int acc = 0, i;
86
87 for (i = 0; i < count * 8 + 16; i++) {
88 acc = (acc << 1);
89 if (i < count * 8)
90 acc |= ((data[i / 8] >> (7 - (i % 8))) & 1);
91 if (acc & 0x10000)
92 acc ^= 0x11021;
93 }
94 return acc;
95 }
96
97
98 /* @param flag bit0= repair mismatching checksums
99 bit1= repair checksums if all pack CRCs are 0
100 @return 0= no mismatch , >0 number of unrepaired mismatches
101 <0 number of repaired mismatches that were not 0
102 */
103 int burn_cdtext_crc_mismatches(unsigned char *packs, int num_packs, int flag)
104 {
105 int i, residue, count = 0, repair;
106 unsigned char crc[2];
107
108 repair = flag & 1;
109 if (flag & 2) {
110 for (i = 0; i < num_packs * 18; i += 18)
111 if (packs[i + 16] || packs[i + 17])
112 break;
113 if (i == num_packs * 18)
114 repair = 1;
115 }
116 for (i = 0; i < num_packs * 18; i += 18) {
117 residue = crc_11021(packs + i, 16, 0);
118 crc[0] = ((residue >> 8) & 0xff) ^ 0xff;
119 crc[1] = ((residue ) & 0xff) ^ 0xff;
120 if(crc[0] != packs[i + 16] || crc[1] != packs[i + 17]) {
121 if (repair) {
122 if (packs[i + 16] || packs[i + 17])
123 count--;
124 packs[i + 16] = crc[0];
125 packs[i + 17] = crc[1];
126 } else
127 count++;
128 }
129
130 }
131 return count;
132 }
133
134
135 static int burn_finalize_text_pack(struct burn_pack_cursor *crs, int flag)
136 {
137 int residue = 0, i, idx;
138
139 idx = 18 * crs->num_packs;
140 for(i = 4 + crs->td_used; i < 16; i++)
141 crs->packs[idx + i] = 0;
142 crs->td_used = 12;
143
144 /* MMC-3 Annex J : CRC Field consists of 2 bytes.
145 The polynomial is X16 + X12 + X5 + 1. All bits shall be inverted.
146 */
147 residue = crc_11021(crs->packs + idx, 16, 0) ^ 0xffff;
148
149 crs->packs[idx + 16] = (residue >> 8) & 0xff;
150 crs->packs[idx + 17] = residue & 0xff;
151 crs->num_packs++;
152 crs->td_used = 0;
153 return 1;
154 }
155
156
157 /* @param flag bit0= double_byte characters
158 */
159 static int burn_create_tybl_packs(unsigned char *payload, int length,
160 int track_no, int pack_type, int block,
161 struct burn_pack_cursor *crs, int flag)
162 {
163 int i, ret, binary_part = 0, char_pos;
164
165 if (pack_type == 0x87)
166 binary_part = 2;
167 else if ((pack_type >= 0x88 && pack_type <= 0x8c) || pack_type == 0x8f)
168 binary_part = length;
169 for(i = 0; i < length; i++) {
170 if (crs->td_used == 0 || crs->td_used >= 12) {
171 if (crs->td_used > 0) {
172 ret = burn_finalize_text_pack(crs, 0);
173 if (ret <= 0)
174 return ret;
175 }
176 char_pos = (i - binary_part) / (1 + (flag & 1));
177 ret = burn_create_new_pack(pack_type, track_no,
178 (flag & 1), block, char_pos,
179 crs, flag & 1);
180 if (ret <= 0)
181 return ret;
182 }
183 crs->packs[crs->num_packs * 18 + 4 + crs->td_used] =
184 payload[i];
185 crs->td_used++;
186 }
187 return 1;
188 }
189
190
191 /* Finalize block by 0x8f. Set bytes 20 to 27 to 0 for now. */
192 static int burn_create_bl_size_packs(int block, unsigned char *char_codes,
193 unsigned char *copyrights,
194 unsigned char *languages,
195 int num_tracks,
196 struct burn_pack_cursor *crs, int flag)
197 {
198 int i, ret;
199 unsigned char payload[12];
200
201 payload[0] = char_codes[block];
202 payload[1] = crs->track_offset;
203 payload[2] = num_tracks + crs->track_offset - 1;
204 payload[3] = copyrights[block];
205 for (i = 0; i < 8; i++)
206 payload[i + 4] = crs->pack_count[i];
207 ret = burn_create_tybl_packs(payload, 12, 0, 0x8f, block, crs, 0);
208 if (ret <= 0)
209 return ret;
210
211 for (i = 0; i < 7; i++)
212 payload[i] = crs->pack_count[i + 8];
213 payload[7] = 3; /* always 3 packs of type 0x8f */
214 for (i = 0; i < 4; i++) {
215 /* Will be set when all blocks are done */
216 payload[i + 8] = 0;
217 }
218 ret = burn_create_tybl_packs(payload, 12, 1, 0x8f, block, crs, 0);
219 if (ret <= 0)
220 return ret;
221
222 for (i = 0; i < 4; i++) {
223 /* Will be set when all blocks are done */
224 payload[i] = 0;
225 }
226 for (i = 0; i < 8; i++) {
227 payload[i + 4] = languages[i];
228 }
229 ret = burn_create_tybl_packs(payload, 12, 2, 0x8f, block, crs, 0);
230 if (ret <= 0)
231 return ret;
232 ret = burn_finalize_text_pack(crs, 0);
233 if (ret <= 0)
234 return ret;
235
236 for (i = 0; i < 16; i++)
237 crs->pack_count[i] = 0;
238 return 1;
239 }
240
241
242 /* Text packs of track for type and block
243 @param flag bit0= write TAB, because content is identical to previous track
244 */
245 static int burn_create_tybl_t_packs(struct burn_track *t, int track_no,
246 int pack_type, int block,
247 struct burn_pack_cursor *crs, int flag)
248 {
249 int ret, length = 0, idx, double_byte, flags= 0;
250 unsigned char *payload = NULL, dummy[8];
251 struct burn_cdtext *cdt;
252
253 cdt = t->cdtext[block];
254 idx = pack_type - Libburn_pack_type_basE;
255 if (cdt != NULL) {
256 if (cdt->length[idx] > 0) {
257 payload = cdt->payload[idx];
258 length = cdt->length[idx];
259 }
260 flags = cdt->flags;
261 }
262 if (payload == NULL) {
263 dummy[0]= 0;
264 payload = dummy;
265 length = strlen((char *) dummy) + 1;
266 }
267 double_byte = !!(flags & (1 <<(pack_type - Libburn_pack_type_basE)));
268 if (flag & 1) {
269 length = 0;
270 dummy[length++] = 9;
271 if (double_byte)
272 dummy[length++] = 9;
273 dummy[length++] = 0;
274 if (double_byte)
275 dummy[length++] = 0;
276 payload = dummy;
277 }
278 ret = burn_create_tybl_packs(payload, length, track_no,
279 pack_type, block, crs, double_byte);
280 return ret;
281 }
282
283
284 /* Check whether the content is the same as in the previous pack. If so,
285 advise to use the TAB abbreviation.
286 */
287 static int burn_decide_cdtext_tab(int block, int pack_type,
288 struct burn_cdtext *cdt_curr,
289 struct burn_cdtext *cdt_prev, int flag)
290 {
291 int length, j, idx;
292
293 idx = pack_type - Libburn_pack_type_basE;
294 if (cdt_curr == NULL || cdt_prev == NULL)
295 return 0;
296 if (((cdt_curr->flags >> idx) & 1) != ((cdt_prev->flags >> idx) & 1))
297 return 0;
298 length = cdt_curr->length[idx];
299 if (length != cdt_prev->length[idx] ||
300 length <= 1 + ((cdt_curr->flags >> idx) & 1))
301 return 0;
302 for (j = 0; j < length; j++)
303 if (cdt_curr->payload[idx][j] != cdt_prev->payload[idx][j])
304 break;
305 if (j < length)
306 return 0;
307 return 1;
308 }
309
310
311 /* Text packs of session and of tracks (if applicable), for type and block
312 */
313 static int burn_create_tybl_s_packs(struct burn_session *s,
314 int pack_type, int block,
315 struct burn_pack_cursor *crs, int flag)
316 {
317 int i, ret, idx, double_byte, use_tab;
318 struct burn_cdtext *cdt;
319
320 cdt = s->cdtext[block];
321 idx = pack_type - Libburn_pack_type_basE;
322 if (cdt->length[idx] == 0 || cdt->payload[idx] == NULL)
323 return 1;
324
325 double_byte = !!(cdt->flags &
326 (1 <<(pack_type - Libburn_pack_type_basE)));
327 ret = burn_create_tybl_packs(cdt->payload[idx], cdt->length[idx], 0,
328 pack_type, block, crs, double_byte);
329 if (ret <= 0)
330 return ret;
331
332 if ((pack_type < 0x80 || pack_type > 0x85) && pack_type != 0x8e) {
333 ret = burn_finalize_text_pack(crs, 0);
334 return ret;
335 }
336
337 for (i = 0; i < s->tracks; i++) {
338 if (i > 0)
339 use_tab = burn_decide_cdtext_tab(block, pack_type,
340 s->track[i]->cdtext[block],
341 s->track[i - 1]->cdtext[block], 0);
342 else
343 use_tab = 0;
344 ret = burn_create_tybl_t_packs(s->track[i],
345 i + crs->track_offset, pack_type,
346 block, crs, use_tab);
347 if (ret <= 0)
348 return ret;
349 }
350 /* Fill up last pack with 0s */
351 ret = burn_finalize_text_pack(crs, 0);
352 return ret;
353 }
354
355
356 /* ts B11210 : API */
357 /* @param flag bit0= do not return CD-TEXT packs, but return number of packs
358 */
359 int burn_cdtext_from_session(struct burn_session *s,
360 unsigned char **text_packs, int *num_packs,
361 int flag)
362 {
363 int pack_type, block, ret, i, idx, j, residue;
364 struct burn_pack_cursor crs;
365
366 if (text_packs == NULL || num_packs == NULL) {
367 flag |= 1;
368 } else if (!(flag & 1)) {
369 *text_packs = NULL;
370 *num_packs = 0;
371 }
372 memset(&crs, 0, sizeof(struct burn_pack_cursor));
373 crs.track_offset = s->firsttrack;
374 BURN_ALLOC_MEM(crs.packs, unsigned char,
375 Libburn_leadin_cdtext_packs_maX * 18);
376
377 for (block = 0; block < 8; block++)
378 if (s->cdtext[block] != NULL)
379 break;
380 if (block == 8)
381 {ret = 1; goto ex;}
382
383 for (block= 0; block < 8; block++) {
384 if (s->cdtext[block] == NULL)
385 continue;
386 for (pack_type = 0x80;
387 pack_type < 0x80 + Libburn_pack_num_typeS; pack_type++) {
388 if (pack_type == 0x8f)
389 continue;
390 ret = burn_create_tybl_s_packs(s,
391 pack_type, block, &crs, 0);
392 if (ret <= 0)
393 goto ex;
394 }
395 ret = burn_create_bl_size_packs(block,
396 s->cdtext_char_code, s->cdtext_copyright,
397 s->cdtext_language, s->tracks, &crs, 0);
398 if (ret <= 0)
399 goto ex;
400 }
401
402 /* Insert the highest sequence numbers of each block into
403 the 0x8f packs 2 and 3 (bytes 20 to 27)
404 */
405 for (i = 0; i < crs.num_packs; i++) {
406 idx = i * 18;
407 if (crs.packs[idx] == 0x8f && crs.packs[idx + 1] == 1) {
408 for (j = 0; j < 4; j++)
409 if (crs.hiseq[j] > 0)
410 crs.packs[idx + 4 + 8 + j] =
411 crs.hiseq[j] - 1;
412 else
413 crs.packs[idx + 4 + 8 + j] = 0;
414 } else if (crs.packs[idx] == 0x8f && crs.packs[idx + 1] == 2) {
415 for (j = 0; j < 4; j++)
416 if (crs.hiseq[j + 4] > 0)
417 crs.packs[idx + 4 + j] =
418 crs.hiseq[j + 4] - 1;
419 else
420 crs.packs[idx + 4 + j] = 0;
421 } else
422 continue;
423 /* Re-compute checksum */
424 residue = crc_11021(crs.packs + idx, 16, 0) ^ 0xffff;
425 crs.packs[idx + 16] = (residue >> 8) & 0xff;
426 crs.packs[idx + 17] = residue & 0xff;
427 }
428
429 ret = 1;
430 ex:;
431 if (ret <= 0 || (flag & 1)) {
432 if (ret > 0)
433 ret = crs.num_packs;
434 else if (flag & 1)
435 ret = -1;
436 BURN_FREE_MEM(crs.packs);
437 } else {
438 if (crs.num_packs > 0)
439 *text_packs = crs.packs;
440 else
441 BURN_FREE_MEM(crs.packs);
442 *num_packs = crs.num_packs;
443 }
444 return(ret);
445 }
446
447
448 /* ---------------- Reader of Sony Input Sheet Version 0.7T ------------- */
449
450
451 /* @param flag bit0= allow two byte codes 0xNNNN or 0xNN 0xNN
452 */
453 static int v07t_hexcode(char *payload, int flag)
454 {
455 unsigned int x;
456 int lo, hi, l;
457 char buf[10], *cpt;
458
459 l = strlen(payload);
460 if (strncmp(payload, "0x", 2) != 0)
461 return -1;
462 if ((l == 6 || l == 9) && (flag & 1))
463 goto double_byte;
464 if (strlen(payload) != 4)
465 return -1;
466 if (!(isxdigit(payload[2]) && isxdigit(payload[3])))
467 return -1;
468 sscanf(payload + 2, "%x", &x);
469 return x;
470
471 double_byte:;
472 strcpy(buf, payload);
473 buf[4] = 0;
474 hi = v07t_hexcode(buf, 0);
475 if (strlen(payload) == 6) {
476 buf[4] = payload[4];
477 buf[2] = '0';
478 buf[3] = 'x';
479 cpt = buf + 2;
480 } else {
481 if(payload[4] != 32 && payload[4] != 9)
482 return(-1);
483 cpt = buf + 5;
484 }
485 lo = v07t_hexcode(cpt, 0);
486 if (lo < 0 || hi < 0)
487 return -1;
488 return ((hi << 8) | lo);
489 }
490
491
492 static int v07t_cdtext_char_code(char *payload, int flag)
493 {
494 int ret;
495 char *msg = NULL;
496
497 ret = v07t_hexcode(payload, 0);
498 if (ret >= 0)
499 return ret;
500 if (strstr(payload, "8859") != NULL)
501 return 0x00;
502 else if(strstr(payload, "ASCII") != NULL)
503 return 0x01;
504 else if(strstr(payload, "JIS") != NULL)
505 return 0x80;
506
507 BURN_ALLOC_MEM(msg, char, 160);
508 sprintf(msg, "Unknown v07t Text Code '%.80s'", payload);
509 libdax_msgs_submit(libdax_messenger, -1, 0x00020191,
510 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
511 burn_printify(msg), 0, 0);
512 ret = -1;
513 ex:;
514 BURN_FREE_MEM(msg);
515 return ret;
516 }
517
518
519 static int v07t_cdtext_lang_code(char *payload, int flag)
520 {
521 int i, ret;
522 static char *languages[128] = {
523 BURN_CDTEXT_LANGUAGES_0X00,
524 BURN_CDTEXT_FILLER,
525 BURN_CDTEXT_LANGUAGES_0X45
526 };
527 char *msg = NULL;
528
529 ret = v07t_hexcode(payload, 0);
530 if (ret >= 0)
531 return ret;
532 if (payload[0] != 0)
533 for(i = 0; i < 128; i++)
534 if(strcmp(languages[i], payload) == 0)
535 return i;
536
537 BURN_ALLOC_MEM(msg, char, 160);
538 sprintf(msg, "Unknown v07t Language Code '%.80s'", payload);
539 libdax_msgs_submit(libdax_messenger, -1, 0x00020191,
540 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
541 burn_printify(msg), 0, 0);
542 ret = -1;
543 ex:;
544 BURN_FREE_MEM(msg);
545 return ret;
546 }
547
548
549 static int v07t_cdtext_genre_code(char *payload, int flag)
550 {
551 int i, ret;
552 static char *genres[BURN_CDTEXT_NUM_GENRES] = {
553 BURN_CDTEXT_GENRE_LIST
554 };
555 char *msg = NULL;
556
557 ret = v07t_hexcode(payload, 1);
558 if(ret >= 0)
559 return ret;
560 for (i= 0; i < BURN_CDTEXT_NUM_GENRES; i++)
561 if (strcmp(genres[i], payload) == 0)
562 return i;
563
564 BURN_ALLOC_MEM(msg, char, 160);
565 sprintf(msg, "Unknown v07t Genre Code '%.80s'", payload);
566 libdax_msgs_submit(libdax_messenger, -1, 0x00020191,
567 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
568 burn_printify(msg), 0, 0);
569 ret = -1;
570 ex:;
571 BURN_FREE_MEM(msg);
572 return ret;
573 }
574
575
576 static int v07t_cdtext_len_db(char *payload, int *char_code,
577 int *length, int *double_byte, int flag)
578 {
579 if (*char_code < 0)
580 *char_code = 0x00;
581 *double_byte = (*char_code == 0x80);
582 *length = strlen(payload) + 1 + *double_byte;
583 return 1;
584 }
585
586
587 static int v07t_cdtext_to_session(struct burn_session *session, int block,
588 char *payload, int *char_code, int pack_type,
589 char *pack_type_name, int flag)
590 {
591 int length, double_byte, ret;
592
593 ret = v07t_cdtext_len_db(payload, char_code, &length, &double_byte, 0);
594 if (ret <= 0)
595 return ret;
596 ret = burn_session_set_cdtext(session, block, pack_type,
597 pack_type_name, (unsigned char *) payload, length,
598 double_byte);
599 return ret;
600 }
601
602
603 static int v07t_cdtext_to_track(struct burn_track *track, int block,
604 char *payload, int *char_code, int pack_type,
605 char *pack_type_name, int flag)
606 {
607 int length, double_byte, ret;
608
609 ret = v07t_cdtext_len_db(payload, char_code, &length, &double_byte, 0);
610 if (ret <= 0)
611 return ret;
612 ret = burn_track_set_cdtext(track, block, pack_type, pack_type_name,
613 (unsigned char *) payload, length, double_byte);
614 return ret;
615 }
616
617
618 static int v07t_apply_to_session(struct burn_session *session, int block,
619 int char_codes[8], int copyrights[8], int languages[8],
620 int session_attr_seen[16], int track_attr_seen[16],
621 int genre_code, char *genre_text, int flag)
622 {
623 int i, ret, length;
624 char *line = NULL;
625
626 BURN_ALLOC_MEM(line, char, 4096);
627
628 for (i= 0x80; i <= 0x8e; i++) {
629 if (i > 0x85 && i != 0x8e)
630 continue;
631 if (session_attr_seen[i - 0x80] || !track_attr_seen[i - 0x80])
632 continue;
633 ret = v07t_cdtext_to_session(session, block, "",
634 char_codes + block, i, NULL, 0);
635 if (ret <= 0)
636 goto ex;
637 }
638 if (genre_code >= 0 && genre_text[0]) {
639 line[0] = (genre_code >> 8) & 0xff;
640 line[1] = genre_code & 0xff;
641 strcpy(line + 2, genre_text);
642 length = 2 + strlen(line + 2) + 1;
643 ret = burn_session_set_cdtext(session, block, 0, "GENRE",
644 (unsigned char *) line, length, 0);
645 if (ret <= 0)
646 goto ex;
647 }
648 ret = burn_session_set_cdtext_par(session, char_codes, copyrights,
649 languages, 0);
650 if (ret <= 0)
651 goto ex;
652 for (i = 0; i < 8; i++)
653 char_codes[i] = copyrights[i] = languages[i]= -1;
654 for (i = 0; i < 16; i++)
655 session_attr_seen[i] = track_attr_seen[i] = 0;
656 genre_text[0] = 0;
657 ret = 1;
658 ex:
659 BURN_FREE_MEM(line);
660 return ret;
661 }
662
663
664 /* ts B11215 API */
665 /* @param flag bit0= permission to read multiple blocks from the same sheet
666 bit1= do not attach CATALOG to session or ISRC to track for
667 writing to Q sub-channel
668 */
669 int burn_session_input_sheet_v07t(struct burn_session *session,
670 char *path, int block, int flag)
671 {
672 int ret = 0, num_tracks, char_codes[8], copyrights[8], languages[8], i;
673 int genre_code = -1, track_offset = 1, pack_type, tno, tnum;
674 int session_attr_seen[16], track_attr_seen[16];
675 int int0x00 = 0x00, int0x01 = 0x01;
676 int additional_blocks = -1, line_count = 0, enable_multi_block = 0;
677 struct stat stbuf;
678 FILE *fp = NULL;
679 char *line = NULL, *eq_pos, *payload, *genre_text = NULL, track_txt[3];
680 char *msg = NULL;
681 struct burn_track **tracks;
682
683 BURN_ALLOC_MEM(msg, char, 4096);
684 BURN_ALLOC_MEM(line, char, 4096);
685 BURN_ALLOC_MEM(genre_text, char, 160);
686
687 for (i = 0; i < 8; i++)
688 char_codes[i] = copyrights[i] = languages[i]= -1;
689 for (i = 0; i < 16; i++)
690 session_attr_seen[i] = track_attr_seen[i] = 0;
691 genre_text[0] = 0;
692
693 tracks = burn_session_get_tracks(session, &num_tracks);
694 if (stat(path, &stbuf) == -1) {
695 cannot_open:;
696 sprintf(msg, "Cannot open CD-TEXT input sheet v07t '%.4000s'",
697 path);
698 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
699 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
700 burn_printify(msg), errno, 0);
701 ret = 0; goto ex;
702 }
703 if (!S_ISREG(stbuf.st_mode)) {
704 sprintf(msg,
705 "File is not of usable type: CD-TEXT input sheet v07t '%s'",
706 path);
707 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
708 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
709 burn_printify(msg), 0, 0);
710 ret = 0; goto ex;
711 }
712
713 fp = fopen(path, "rb");
714 if (fp == NULL)
715 goto cannot_open;
716
717 while (1) {
718 if (burn_sfile_fgets(line, 4095, fp) == NULL) {
719 if (!ferror(fp))
720 break;
721 sprintf(msg,
722 "Cannot read all bytes from CD-TEXT input sheet v07t '%.4000s'",
723 path);
724 libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
725 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
726 burn_printify(msg), 0, 0);
727 ret = 0; goto ex;
728 }
729 line_count++;
730 if (strlen(line) == 0)
731 continue;
732 eq_pos = strchr(line, '=');
733 if (eq_pos == NULL) {
734 sprintf(msg,
735 "CD-TEXT v07t input sheet line without '=' : '%.4000s'",
736 line);
737 libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
738 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
739 burn_printify(msg), 0, 0);
740 ret = 0; goto ex;
741 }
742 for (payload = eq_pos + 1; *payload == 32 || *payload == 9;
743 payload++);
744 *eq_pos = 0;
745 for (eq_pos--;
746 (*eq_pos == 32 || *eq_pos == 9) && eq_pos > line;
747 eq_pos--)
748 *eq_pos= 0;
749
750 if (payload[0] == 0)
751 continue;
752
753 if (strcmp(line, "Text Code") == 0) {
754 ret = v07t_cdtext_char_code(payload, 0);
755 if (ret < 0)
756 goto ex;
757 if (char_codes[block] >= 0 &&
758 char_codes[block] != ret) {
759 libdax_msgs_submit(libdax_messenger, -1,
760 0x00020192, LIBDAX_MSGS_SEV_FAILURE,
761 LIBDAX_MSGS_PRIO_HIGH,
762 "Unexpected v07t Text Code change",
763 0, 0);
764 ret = 0; goto ex;
765 }
766 char_codes[block] = ret;
767
768 } else if (strcmp(line, "Language Code") == 0) {
769 ret = v07t_cdtext_lang_code(payload, 0);
770 if(ret < 0)
771 goto ex;
772 languages[block] = ret;
773
774 } else if (strcmp(line, "0x80") == 0 ||
775 strcmp(line, "Album Title") == 0) {
776 ret = v07t_cdtext_to_session(session, block, payload,
777 char_codes + block, 0, "TITLE", 0);
778 if (ret <= 0)
779 goto ex;
780 session_attr_seen[0x0] = 1;
781
782 } else if (strcmp(line, "0x81") == 0 ||
783 strcmp(line, "Artist Name") == 0) {
784 ret = v07t_cdtext_to_session(session, block, payload,
785 char_codes + block, 0, "PERFORMER", 0);
786 if (ret <= 0)
787 goto ex;
788 session_attr_seen[0x1] = 1;
789
790 } else if (strcmp(line, "0x82") == 0 ||
791 strcmp(line, "Songwriter") == 0) {
792 ret = v07t_cdtext_to_session(session, block, payload,
793 char_codes + block, 0, "SONGWRITER",
794 0);
795 if (ret <= 0)
796 goto ex;
797 session_attr_seen[0x2] = 1;
798
799 } else if (strcmp(line, "0x83") == 0 ||
800 strcmp(line, "Composer") == 0) {
801 ret = v07t_cdtext_to_session(session, block, payload,
802 char_codes + block, 0, "COMPOSER", 0);
803 if (ret <= 0)
804 goto ex;
805 session_attr_seen[0x3] = 1;
806
807 } else if (strcmp(line, "0x84") == 0 ||
808 strcmp(line, "Arranger") == 0) {
809 ret = v07t_cdtext_to_session(session, block, payload,
810 char_codes + block, 0, "ARRANGER", 0);
811 if (ret <= 0)
812 goto ex;
813 session_attr_seen[0x4] = 1;
814
815 } else if (strcmp(line, "0x85") == 0 ||
816 strcmp(line, "Album Message") == 0) {
817 ret = v07t_cdtext_to_session(session, block, payload,
818 char_codes + block, 0, "MESSAGE", 0);
819 if (ret <= 0)
820 goto ex;
821 session_attr_seen[0x5] = 1;
822
823 } else if (strcmp(line, "0x86") == 0 ||
824 strcmp(line, "Catalog Number") == 0) {
825 ret = v07t_cdtext_to_session(session, block, payload,
826 &int0x01, 0, "DISCID", 0);
827 if(ret <= 0)
828 goto ex;
829
830 } else if (strcmp(line, "Genre Code") == 0) {
831 genre_code = v07t_cdtext_genre_code(payload, 0);
832 if (genre_code < 0) {
833 ret = 0; goto ex;
834 }
835
836 } else if (strcmp(line, "Genre Information") == 0) {
837 strncpy(genre_text, payload, 159);
838 genre_text[159] = 0;
839
840 } else if (strcmp(line, "0x8d") == 0 ||
841 strcmp(line, "Closed Information") == 0) {
842 ret = v07t_cdtext_to_session(session, block, payload,
843 &int0x00, 0, "CLOSED", 0);
844 if (ret <= 0)
845 goto ex;
846
847 } else if(strcmp(line, "0x8e") == 0 ||
848 strcmp(line, "UPC / EAN") == 0) {
849 ret = v07t_cdtext_to_session(session, block, payload,
850 &int0x01, 0, "UPC_ISRC", 0);
851 if (ret <= 0)
852 goto ex;
853 if (!(flag & 2)) {
854 memcpy(session->mediacatalog, payload, 13);
855 session->mediacatalog[13] = 0;
856 }
857 session_attr_seen[0xe] = 1;
858
859 } else if (strncmp(line, "Disc Information ", 17) == 0) {
860
861 /* >>> ??? is this good for anything ? */;
862
863 } else if (strcmp(line, "Input Sheet Version") == 0) {
864 if (strcmp(payload, "0.7T") != 0) {
865 sprintf(msg,
866 "Wrong Input Sheet Version '%.4000s'. Expected '0.7T'.",
867 payload);
868 libdax_msgs_submit(libdax_messenger, -1,
869 0x00020194, LIBDAX_MSGS_SEV_FAILURE,
870 LIBDAX_MSGS_PRIO_HIGH,
871 burn_printify(msg), 0, 0);
872 ret = 0; goto ex;
873 }
874 if (flag & 1)
875 if (line_count == 1)
876 enable_multi_block = 1;
877 if (enable_multi_block) {
878 if (additional_blocks >= 0) {
879 if (block == 7) {
880 libdax_msgs_submit(
881 libdax_messenger, -1, 0x000201a0,
882 LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
883 "Maximum number of CD-TEXT blocks exceeded",
884 0, 0);
885 break;
886 }
887 ret = v07t_apply_to_session(
888 session, block, char_codes,
889 copyrights, languages,
890 session_attr_seen,
891 track_attr_seen,
892 genre_code, genre_text, 0);
893 if (ret <= 0)
894 goto ex;
895 block++;
896 }
897 additional_blocks++;
898 }
899
900 } else if (strcmp(line, "Remarks") == 0) {
901 ;
902
903 } else if (strcmp(line, "Text Data Copy Protection") == 0) {
904 ret = v07t_hexcode(payload, 0);
905 if (ret >= 0)
906 copyrights[block] = ret;
907 else if (strcmp(payload, "ON") == 0)
908 copyrights[block] = 0x03;
909 else if (strcmp(payload, "OFF") == 0)
910 copyrights[block] = 0x00;
911 else {
912 sprintf(msg,
913 "Unknown v07t Text Data Copy Protection '%.4000s'",
914 payload);
915 libdax_msgs_submit(libdax_messenger, -1,
916 0x00020191, LIBDAX_MSGS_SEV_FAILURE,
917 LIBDAX_MSGS_PRIO_HIGH,
918 burn_printify(msg), 0, 0);
919
920 ret = 0; goto ex;
921 }
922
923 } else if (strcmp(line, "First Track Number") == 0) {
924 ret = -1;
925 sscanf(payload, "%d", &ret);
926 if (ret <= 0 || ret > 99) {
927 bad_tno:;
928 sprintf(msg,
929 "Inappropriate v07t First Track Number '%.4000s'",
930 payload);
931 libdax_msgs_submit(libdax_messenger, -1,
932 0x00020194, LIBDAX_MSGS_SEV_FAILURE,
933 LIBDAX_MSGS_PRIO_HIGH,
934 burn_printify(msg), 0, 0);
935 ret = 0; goto ex;
936 } else {
937 track_offset = ret;
938 ret = burn_session_set_start_tno(session,
939 track_offset, 0);
940 if (ret <= 0)
941 goto ex;
942 }
943
944 } else if (strcmp(line, "Last Track Number") == 0) {
945 ret = -1;
946 sscanf(payload, "%d", &ret);
947 if (ret < 0) {
948 goto bad_tno;
949 } else {
950
951 /* >>> ??? Is it good for anything ? */;
952
953 }
954
955 } else if (strncmp(line, "Track ", 6) == 0) {
956 tno = -1;
957 sscanf(line + 6, "%d", &tno);
958 if (tno < 1 || tno - track_offset < 0 ||
959 tno - track_offset >= num_tracks) {
960 track_txt[0] = line[6];
961 track_txt[1] = line[7];
962 track_txt[2] = 0;
963 bad_track_no:;
964 sprintf(msg,
965 "Inappropriate v07t Track number '%.3900s'",
966 track_txt);
967 sprintf(msg + strlen(msg),
968 " (acceptable range: %2.2d to %2.2d)",
969 track_offset,
970 num_tracks + track_offset - 1);
971 libdax_msgs_submit(libdax_messenger, -1,
972 0x00020194, LIBDAX_MSGS_SEV_FAILURE,
973 LIBDAX_MSGS_PRIO_HIGH,
974 burn_printify(msg), 0, 0);
975 ret = 0; goto ex;
976 }
977 tnum = tno - track_offset;
978
979 if (strcmp(line, "0x80") == 0 ||
980 strcmp(line + 9, "Title") == 0)
981 pack_type = 0x80;
982 else if (strcmp(line + 9, "0x81") == 0 ||
983 strcmp(line + 9, "Artist") == 0)
984 pack_type = 0x81;
985 else if (strcmp(line + 9, "0x82") == 0 ||
986 strcmp(line + 9, "Songwriter") == 0)
987 pack_type = 0x82;
988 else if (strcmp(line + 9, "0x83") == 0 ||
989 strcmp(line + 9, "Composer") == 0)
990 pack_type = 0x83;
991 else if (strcmp(line + 9, "0x84") == 0 ||
992 strcmp(line + 9, "Arranger") == 0)
993 pack_type = 0x84;
994 else if (strcmp(line + 9, "0x85") == 0 ||
995 strcmp(line + 9, "Message") == 0)
996 pack_type = 0x85;
997 else if (strcmp(line + 9, "0x8e") == 0 ||
998 strcmp(line + 9, "ISRC") == 0) {
999 pack_type = 0x8e;
1000 if (!(flag & 2)) {
1001 ret = burn_track_set_isrc_string(
1002 tracks[tnum], payload, 0);
1003 if (ret <= 0)
1004 goto ex;
1005 }
1006 } else {
1007 sprintf(msg,
1008 "Unknown v07t Track purpose specifier '%s'",
1009 line + 9);
1010 libdax_msgs_submit(libdax_messenger, -1,
1011 0x00020191, LIBDAX_MSGS_SEV_FAILURE,
1012 LIBDAX_MSGS_PRIO_HIGH,
1013 burn_printify(msg), 0, 0);
1014 ret = 0; goto ex;
1015 }
1016 ret = v07t_cdtext_to_track(tracks[tnum], block,
1017 payload, &int0x00, pack_type, "", 0);
1018 if (ret <= 0)
1019 goto ex;
1020 track_attr_seen[pack_type - 0x80] = 1;
1021
1022 } else if (strncmp(line, "ISRC ", 5) == 0) {
1023 /* Track variation of UPC EAN = 0x8e */
1024 tno = -1;
1025 sscanf(line + 5, "%d", &tno);
1026 if (tno <= 0 || tno - track_offset < 0 ||
1027 tno - track_offset >= num_tracks) {
1028 track_txt[0] = line[5];
1029 track_txt[1] = line[6];
1030 track_txt[2] = 0;
1031 goto bad_track_no;
1032 }
1033 tnum = tno - track_offset;
1034 if (!(flag & 2)) {
1035 ret = burn_track_set_isrc_string(
1036 tracks[tnum], payload, 0);
1037 if (ret <= 0)
1038 goto ex;
1039 }
1040 ret = v07t_cdtext_to_track(tracks[tnum], block,
1041 payload, &int0x00, 0x8e, "", 0);
1042 if (ret <= 0)
1043 goto ex;
1044 track_attr_seen[0xe] = 1;
1045
1046 } else {
1047 sprintf(msg,
1048 "Unknown v07t purpose specifier '%.4000s'",
1049 line);
1050 libdax_msgs_submit(libdax_messenger, -1, 0x00020191,
1051 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1052 burn_printify(msg), 0, 0);
1053 ret = 0; goto ex;
1054 }
1055 }
1056 ret = v07t_apply_to_session(session, block,
1057 char_codes, copyrights, languages,
1058 session_attr_seen, track_attr_seen,
1059 genre_code, genre_text, 0);
1060 if (ret <= 0)
1061 goto ex;
1062
1063 ret = 1;
1064 if (additional_blocks > 0)
1065 ret += additional_blocks;;
1066 ex:;
1067 if(fp != NULL)
1068 fclose(fp);
1069 BURN_FREE_MEM(genre_text);
1070 BURN_FREE_MEM(line);
1071 BURN_FREE_MEM(msg);
1072 return ret;
1073 }
1074
1075
1076 /* ts B11221 API */
1077 int burn_cdtext_from_packfile(char *path, unsigned char **text_packs,
1078 int *num_packs, int flag)
1079 {
1080 int ret = 0, residue = 0;
1081 struct stat stbuf;
1082 FILE *fp = NULL;
1083 unsigned char head[4], tail[1];
1084 char *msg = NULL;
1085
1086 BURN_ALLOC_MEM(msg, char, 4096);
1087
1088 *text_packs = NULL;
1089 if (stat(path, &stbuf) == -1) {
1090 cannot_open:;
1091 sprintf(msg, "Cannot open CD-TEXT pack file '%.4000s'", path);
1092 libdax_msgs_submit(libdax_messenger, -1, 0x00020198,
1093 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1094 burn_printify(msg), errno, 0);
1095 ret = 0; goto ex;
1096 }
1097 if (!S_ISREG(stbuf.st_mode))
1098 goto not_a_textfile;
1099 residue = (stbuf.st_size % 18);
1100 if(residue != 4 && residue != 0 && residue != 1) {
1101 not_a_textfile:;
1102 sprintf(msg,
1103 "File is not of usable type or content for CD-TEXT packs: '%.4000s'",
1104 path);
1105 libdax_msgs_submit(libdax_messenger, -1, 0x00020198,
1106 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1107 burn_printify(msg), 0, 0);
1108 ret = 0; goto ex;
1109 }
1110 if (stbuf.st_size < 18)
1111 goto not_a_textfile;
1112
1113 fp = fopen(path, "rb");
1114 if (fp == NULL)
1115 goto cannot_open;
1116 if (residue == 4) { /* This is for files from cdrecord -vv -toc */
1117 ret = fread(head, 4, 1, fp);
1118 if (ret != 1) {
1119 cannot_read:;
1120 sprintf(msg,
1121 "Cannot read all bytes from CD-TEXT pack file '%.4000s'",
1122 path);
1123 libdax_msgs_submit(libdax_messenger, -1, 0x00020198,
1124 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1125 burn_printify(msg), errno, 0);
1126 ret = 0; goto ex;
1127 }
1128 if (head[0] * 256 + head[1] != stbuf.st_size - 2)
1129 goto not_a_textfile;
1130 }
1131 *num_packs = (stbuf.st_size - residue) / 18;
1132 if (*num_packs > 2048) {
1133 /* Each block can have 256 text packs.
1134 There are 8 blocks at most. */
1135 sprintf(msg,
1136 "CD-Text pack file too large (max. 36864 bytes): '%.4000s'",
1137 path);
1138 libdax_msgs_submit(libdax_messenger, -1, 0x0002018b,
1139 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1140 burn_printify(msg), 0, 0);
1141 ret = 0; goto ex;
1142 } if (*num_packs <= 0) {
1143 strcpy(msg,
1144 "CD-Text pack file contains no complete text pack");
1145 libdax_msgs_submit(libdax_messenger, -1, 0x000201aa,
1146 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1147 burn_printify(msg), 0, 0);
1148 ret = 0; goto ex;
1149 }
1150
1151 BURN_ALLOC_MEM(*text_packs, unsigned char, *num_packs * 18);
1152 ret = fread(*text_packs, *num_packs * 18, 1, fp);
1153 if (ret != 1)
1154 goto cannot_read;
1155 if (residue == 1) { /* This is for Sony CDTEXT files */
1156 ret = fread(tail, 1, 1, fp);
1157 if (ret != 1)
1158 goto cannot_read;
1159 if (tail[0] != 0)
1160 goto not_a_textfile;
1161 }
1162
1163 ret= 1;
1164 ex:;
1165 if (ret <= 0) {
1166 BURN_FREE_MEM(*text_packs);
1167 *text_packs = NULL;
1168 *num_packs = 0;
1169 }
1170 if (fp != NULL)
1171 fclose(fp);
1172 BURN_FREE_MEM(msg);
1173 return ret;
1174 }
1175
1176
1177 /* --------------------------------- make_v07t -------------------------- */
1178
1179
1180 static int search_pack(unsigned char *text_packs, int num_packs,
1181 int start_no, int pack_type, int block,
1182 unsigned char **found_pack, int *found_no, int flag)
1183 {
1184 int i;
1185
1186 for (i = start_no; i < num_packs; i++) {
1187 if (pack_type >= 0)
1188 if (text_packs[i * 18] != pack_type)
1189 continue;
1190 if (block >= 0)
1191 if (((text_packs[i * 18 + 3] >> 4) & 7) != block)
1192 continue;
1193 *found_pack = text_packs + i * 18;
1194 *found_no = i;
1195 return 1;
1196 }
1197 *found_pack = NULL;
1198 *found_no = num_packs;
1199 return 0;
1200 }
1201
1202
1203 static void write_v07t_line(char **respt, char *spec, char *value, int vlen,
1204 int *result_len, int flag)
1205 {
1206 int len;
1207
1208 if (vlen == -1)
1209 vlen = strlen(value);
1210 len = strlen(spec);
1211 if (len < 19)
1212 len = 19;
1213 len += 3 + vlen + 1;
1214 if(flag & 1) {
1215 *result_len += len;
1216 return;
1217 }
1218 sprintf(*respt, "%-19s = ", spec);
1219 if (vlen > 0)
1220 memcpy(*respt + strlen(*respt), value, vlen);
1221 (*respt)[len - 1] = '\n';
1222 (*respt)[len] = 0;
1223 *respt+= len;
1224 }
1225
1226
1227 /*
1228 @return -1 error
1229 0 no pack of block,pack_type found
1230 1 packs found, delimiter is single 0-byte
1231 2 packs found, delimiter is double 0-byte
1232 */
1233 static int collect_payload(unsigned char *text_packs, int num_packs,
1234 int pack_type, int block,
1235 unsigned char **payload, int *payload_count,
1236 int flag)
1237 {
1238 unsigned char *pack;
1239 int pack_no, ret, double_byte = 0;
1240
1241 *payload_count = 0;
1242 for (pack_no = 0; ; pack_no++) {
1243 ret = search_pack(text_packs, num_packs, pack_no, pack_type,
1244 block, &pack, &pack_no, 0);
1245 if (ret <= 0)
1246 break;
1247 *payload_count += 12;
1248 }
1249 if (*payload_count == 0)
1250 return 0;
1251 *payload = burn_alloc_mem(*payload_count + 1, 1, 0);
1252 if (*payload == NULL)
1253 return -1;
1254 *payload_count = 0;
1255 for (pack_no = 0; ; pack_no++) {
1256 ret = search_pack(text_packs, num_packs, pack_no, pack_type,
1257 block, &pack, &pack_no, 0);
1258 if (ret <= 0)
1259 break;
1260 memcpy(*payload + *payload_count, pack + 4, 12);
1261 *payload_count += 12;
1262 if (pack[3] & 128)
1263 double_byte = 1;
1264 }
1265 (*payload)[*payload_count] = 0;
1266 return 1 + double_byte;
1267 }
1268
1269
1270 /*
1271 @param flag bit0= use double 0 as delimiter
1272 */
1273 static int is_payload_text_end(unsigned char *payload, int payload_count,
1274 int i, int flag)
1275 {
1276 if (i >= payload_count)
1277 return 1;
1278 if (payload[i])
1279 return 0;
1280 if (!(flag & 1))
1281 return 1;
1282 if (i + 1 >= payload_count)
1283 return 1;
1284 if (payload[i + 1] == 0)
1285 return 1;
1286 return 0;
1287 }
1288
1289
1290 /*
1291 @param flag Bitfield for control purposes.
1292 bit0= use double 0 as delimiter
1293 bit1= replace TAB resp. TAB TAB by text of previous tno
1294 */
1295 static int pick_payload_text(unsigned char *payload, int payload_count,
1296 int tno,
1297 unsigned char **text_start, int *text_len,
1298 int flag)
1299 {
1300 int i, skipped = 0, end_found = 0;
1301
1302 again:;
1303 if (tno <= 0) {
1304 *text_start = payload;
1305 *text_len = 0;
1306 for (i = 0; i < payload_count; i += 1 + (flag & 1)) {
1307 end_found = is_payload_text_end(payload, payload_count,
1308 i, flag & 1);
1309 if (end_found) {
1310 *text_len = i;
1311 break;
1312 }
1313 }
1314 return 1;
1315 }
1316 *text_start = NULL;
1317 *text_len = 0;
1318 for (i = 0; i < payload_count; i += 1 + (flag & 1)) {
1319 end_found = is_payload_text_end(payload, payload_count,
1320 i, flag & 1);
1321 if (end_found) {
1322 skipped++;
1323 if (skipped == tno) {
1324 *text_start = payload + (i + 1 + (flag & 1));
1325 } else if (skipped == tno + 1) {
1326 *text_len = i - (*text_start - payload);
1327 goto found;
1328 }
1329 }
1330 }
1331 if (*text_start == NULL)
1332 return 0;
1333 *text_len = payload_count - (*text_start - payload);
1334
1335 found:;
1336 if (flag & 2) {
1337 /* If TAB resp. TAB TAB, then look back */
1338 if (flag & 1) {
1339 if (*text_len == 2) {
1340 if ((*text_start)[0] == '\t' &&
1341 (*text_start)[1] == '\t') {
1342 skipped = 0;
1343 tno--;
1344 goto again;
1345 }
1346 }
1347 } else if (*text_len == 1) {
1348 if ((*text_start)[0] == '\t') {
1349 skipped = 0;
1350 tno--;
1351 goto again;
1352 }
1353 }
1354 }
1355 return 1;
1356 }
1357
1358
1359 static int write_v07t_textline(unsigned char *text_packs, int num_packs,
1360 int pack_type, int block,
1361 int tno, int first_tno, char *spec,
1362 char **respt, int *result_len, int flag)
1363 {
1364 unsigned char *payload = NULL, *text_start;
1365 int ret, payload_count = 0, text_len, tab_flag = 0;
1366 char msg[80];
1367
1368 if ((pack_type >= 0x80 && pack_type <= 0x85) || pack_type == 0x8e)
1369 tab_flag = 2;
1370 ret = collect_payload(text_packs, num_packs, pack_type, block,
1371 &payload, &payload_count, 0);
1372 if(ret > 0) {
1373 ret = pick_payload_text(payload, payload_count, tno,
1374 &text_start, &text_len,
1375 (ret == 2) | tab_flag);
1376 if (ret > 0) {
1377 if (tno > 0 && strcmp(spec, "ISRC") == 0)
1378 sprintf(msg, "%s %-2.2d",
1379 spec, tno + first_tno - 1);
1380 else if (tno > 0)
1381 sprintf(msg, "Track %-2.2d %s",
1382 tno + first_tno - 1, spec);
1383 else
1384 strcpy(msg, spec);
1385 write_v07t_line(respt, msg,
1386 (char *) text_start, text_len,
1387 result_len, flag & 1);
1388 ret = 1;
1389 }
1390 }
1391 BURN_FREE_MEM(payload);
1392 return ret;
1393 }
1394
1395
1396 static int report_track(unsigned char *text_packs, int num_packs,
1397 int block, int tno, int first_tno,
1398 char **respt, int *result_len, int flag)
1399 {
1400 int ret, i;
1401 static char *track_specs[6] = {
1402 "Title", "Artist", "Songwriter", "Composer",
1403 "Arranger", "Message"
1404 };
1405
1406 for (i = 0; i < 6; i++) {
1407 ret = write_v07t_textline(text_packs, num_packs, 0x80 + i,
1408 block, tno, first_tno,
1409 track_specs[i], respt, result_len,
1410 flag & 1);
1411 if (ret < 0)
1412 return -1;
1413 }
1414 ret = write_v07t_textline(text_packs, num_packs, 0x8e, block,
1415 tno, first_tno,
1416 "ISRC", respt, result_len, flag & 1);
1417 if (ret < 0)
1418 return -1;
1419 return 1;
1420 }
1421
1422
1423 /*
1424 @param flag Bitfield for control purposes.
1425 bit0= Do not store text in result but only determine
1426 the minimum size for the result array.
1427 It is permissible to submit result == NULL.
1428 Submit the already occupied size as result_size.
1429 @return > 0 tells the number of valid text bytes in result resp.
1430 with flag bit0 the prediction of that number.
1431 This does not include the trailing 0-byte.
1432 = 0 indicates that the block is not present
1433 < 0 indicates failure.
1434 */
1435 static int report_block(unsigned char *text_packs, int num_packs,
1436 int block, int first_tno, int last_tno, int char_code,
1437 char *result, int result_size, int flag)
1438 {
1439 char *respt = NULL;
1440 unsigned char *pack, *payload = NULL;
1441 int result_len = 0, pack_no, ret, i, lang, payload_count = 0, genre;
1442 char msg[80];
1443 static char *languages[] = {
1444 BURN_CDTEXT_LANGUAGES_0X00,
1445 BURN_CDTEXT_FILLER,
1446 BURN_CDTEXT_LANGUAGES_0X45
1447 };
1448 static char *volume_specs[7] = {
1449 "Album Title", "Artist Name", "Songwriter", "Composer",
1450 "Arranger", "Album Message", "Catalog Number",
1451 };
1452 static char *genres[BURN_CDTEXT_NUM_GENRES] = {
1453 BURN_CDTEXT_GENRE_LIST
1454 };
1455
1456 /* Search for any pack of the block. But do not accept 0x8f as first.*/
1457 ret = search_pack(text_packs, num_packs, 0, -1, block,
1458 &pack, &pack_no, 0);
1459 if (ret <= 0)
1460 return 0;
1461 if (pack[0] == 0x8f)
1462 return 0;
1463
1464 if (flag & 1) {
1465 result_len = result_size;
1466 } else {
1467 respt = result + result_size;
1468 }
1469 write_v07t_line(&respt, "Input Sheet Version", "0.7T", -1, &result_len,
1470 flag & 1);
1471 sprintf(msg, "Libburn report of CD-TEXT Block %d", block);
1472 write_v07t_line(&respt, "Remarks ", msg, -1, &result_len,
1473 flag & 1);
1474 write_v07t_line(&respt, "Text Code ",
1475 char_code == 0 ? "8859" : char_code == 0x01 ? "ASCII" : "MS-JIS",
1476 -1, &result_len, flag & 1);
1477
1478 pack_no = 0;
1479 for (i = 0; i < 3; i++) {
1480 ret = search_pack(text_packs, num_packs, pack_no, 0x8f, -1,
1481 &pack, &pack_no, 0);
1482 if (ret <= 0) {
1483 libdax_msgs_submit(libdax_messenger, -1, 0x0002019f,
1484 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1485 "No third CD-TEXT pack 0x8f found. No language code defined",
1486 0, 0);
1487 goto failure;
1488 }
1489 pack_no++;
1490 }
1491 lang = pack[8 + block];
1492 if (lang > 127) {
1493 sprintf(msg, "CD-TEXT with unknown language code %2.2x",
1494 (unsigned int) lang);
1495 libdax_msgs_submit(libdax_messenger, -1, 0x0002019f,
1496 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1497 msg, 0, 0);
1498 goto failure;
1499 }
1500 write_v07t_line(&respt, "Language Code", languages[lang], -1,
1501 &result_len, flag & 1);
1502
1503 for (i = 0; i < 7; i++) {
1504 ret = write_v07t_textline(text_packs, num_packs, 0x80 + i,
1505 block, 0, 0, volume_specs[i],
1506 &respt, &result_len,
1507 flag & 1);
1508 if (ret < 0)
1509 goto failure;
1510 }
1511
1512 ret = collect_payload(text_packs, num_packs, 0x87, block,
1513 &payload, &payload_count, 0);
1514 if(ret > 0) {
1515 genre = (payload[0] << 8) | payload[1];
1516 if (genre < BURN_CDTEXT_NUM_GENRES)
1517 strcpy(msg, genres[genre]);
1518 else
1519 sprintf(msg, "0x%-4.4x", (unsigned int) genre);
1520 write_v07t_line(&respt, "Genre Code", msg,
1521 -1, &result_len, flag & 1);
1522 write_v07t_line(&respt, "Genre Information",
1523 (char *) payload + 2,
1524 -1, &result_len, flag & 1);
1525 BURN_FREE_MEM(payload); payload = NULL;
1526 }
1527 ret = collect_payload(text_packs, num_packs, 0x8d, block,
1528 &payload, &payload_count, 0);
1529 if(ret > 0) {
1530 write_v07t_line(&respt, "Closed Information", (char *) payload,
1531 -1, &result_len, flag & 1);
1532 BURN_FREE_MEM(payload); payload = NULL;
1533 }
1534 ret = write_v07t_textline(text_packs, num_packs, 0x8e, block, 0, 0,
1535 "UPC / EAN", &respt, &result_len, flag & 1);
1536 if (ret < 0)
1537 goto failure;
1538 ret = search_pack(text_packs, num_packs, 0, 0x8f, -1,
1539 &pack, &pack_no, 0);
1540 if (ret < 0)
1541 goto failure;
1542 if (pack[7] == 0x00)
1543 strcpy(msg, "OFF");
1544 else if (pack[7] == 0x03)
1545 strcpy(msg, "ON");
1546 else
1547 sprintf(msg, "0x%2.2x", (unsigned int) pack[7]);
1548 write_v07t_line(&respt, "Text Data Copy Protection", msg,
1549 -1, &result_len, flag & 1);
1550 sprintf(msg, "%d", first_tno);
1551 write_v07t_line(&respt, "First Track Number", msg,
1552 -1, &result_len, flag & 1);
1553 sprintf(msg, "%d", last_tno);
1554 write_v07t_line(&respt, "Last Track Number", msg,
1555 -1, &result_len, flag & 1);
1556
1557 for (i = 0; i < last_tno - first_tno + 1; i++) {
1558 ret = report_track(text_packs, num_packs, block,
1559 i + 1, first_tno,
1560 &respt, &result_len, flag & 1);
1561 if (ret < 0)
1562 goto failure;
1563 }
1564
1565 if (flag & 1)
1566 return result_len;
1567 return respt - result;
1568
1569 failure:;
1570 BURN_FREE_MEM(payload);
1571 return -1;
1572 }
1573
1574
1575 /*
1576 @param result A byte buffer of sufficient size.
1577 It will be filled by the text for the v07t sheet file
1578 plus a trailing 0-byte. (Be aware that double-byte
1579 characters might contain 0-bytes, too.)
1580 @param result_size The number of bytes in result.
1581 To be determined by a run with flag bit0 set.
1582 @param flag Bitfield for control purposes.
1583 bit0= Do not store text in result but only determine
1584 the minimum size for the result array.
1585 It is permissible to submit result == NULL and
1586 result_size == 0.
1587 @return > 0 tells the number of valid text bytes in result resp.
1588 with flag bit0 the prediction of that number.
1589 This does not include the trailing 0-byte.
1590 <= 0 indicates failure.
1591 */
1592 static int burn_make_v07t(unsigned char *text_packs, int num_packs,
1593 int first_tno, int track_count,
1594 char *result, int result_size,
1595 int *char_code, int flag)
1596 {
1597 int pack_no = 0, ret, block, last_tno = 0;
1598 unsigned char *pack;
1599 char msg[80];
1600
1601 /* >>> ??? Verify checksums ? */;
1602
1603 /* Check character code, reject unknown ones */
1604 ret = search_pack(text_packs, num_packs, 0, 0x8f, -1,
1605 &pack, &pack_no, 0);
1606 if (ret <= 0) {
1607 libdax_msgs_submit(libdax_messenger, -1, 0x0002019f,
1608 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1609 "No CD-TEXT pack 0x8f found. No character code defined",
1610 0, 0);
1611 return 0;
1612 }
1613 *char_code = pack[4];
1614 if (*char_code != 0x00 && *char_code != 0x01 && *char_code != 0x80) {
1615 sprintf(msg, "CD-TEXT with unknown character code %2.2x",
1616 (unsigned int) *char_code);
1617 libdax_msgs_submit(libdax_messenger, -1, 0x0002019f,
1618 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1619 msg, 0, 0);
1620 return 0;
1621 }
1622
1623 /* Obtain first_tno and last_tno from type 0x8f if present. */
1624 if (first_tno <= 0) {
1625 if (pack[5] > 0 && pack[5] + pack[6] < 100 &&
1626 pack[5] <= pack[6]) {
1627 first_tno = pack[5];
1628 last_tno = pack[6];
1629 } else {
1630 sprintf(msg,
1631 "CD-TEXT with illegal track range %d to %d",
1632 (int) pack[5], (int) pack[6]);
1633 libdax_msgs_submit(libdax_messenger, -1, 0x0002019f,
1634 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
1635 msg, 0, 0);
1636 return 0;
1637 }
1638 }
1639 if (last_tno <= 0) {
1640 if (track_count > 0) {
1641 last_tno = first_tno + track_count - 1;
1642 } else {
1643 last_tno = 99;
1644 }
1645 }
1646
1647 /* Report content */
1648 result_size = 0;
1649 for (block = 0; block < 8; block++) {
1650 /* Obtain character code, reject unknown ones */
1651 ret = search_pack(text_packs, num_packs, 0, 0x8f, block,
1652 &pack, &pack_no, 0);
1653 if (ret > 0)
1654 *char_code = pack[4];
1655 if (*char_code != 0x00 && *char_code != 0x01 &&
1656 *char_code != 0x80) {
1657 sprintf(msg,
1658 "CD-TEXT block %d with unknown character code %2.2x",
1659 block, (unsigned int) *char_code);
1660 libdax_msgs_submit(libdax_messenger, -1, 0x0002019f,
1661 LIBDAX_MSGS_SEV_FAILURE,
1662 LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
1663 return 0;
1664 }
1665 ret = report_block(text_packs, num_packs, block,
1666 first_tno, last_tno, *char_code,
1667 result, result_size, flag & 1);
1668 if (ret < 0)
1669 return ret;
1670 if (ret == 0)
1671 continue;
1672 result_size = ret;
1673 }
1674 return result_size;
1675 }
1676
1677
1678 /* Convert an array of CD-TEXT packs into the text format of
1679 Sony CD-TEXT Input Sheet Version 0.7T .
1680
1681 @param text_packs Array of bytes which form CD-TEXT packs of 18 bytes
1682 each. For a description of the format of the array,
1683 see file doc/cdtext.txt.
1684 No header of 4 bytes must be prepended which would
1685 tell the number of pack bytes + 2.
1686 This parameter may be NULL if the currently attached
1687 array of packs shall be removed.
1688 @param num_packs The number of 18 byte packs in text_packs.
1689 @param start_tno The start number of track counting, if known from
1690 CD table-of-content or orther sources.
1691 Submit 0 to enable the attempt to read it and the
1692 track_count from pack type 0x8f.
1693 @param track_count The number of tracks, if known from CD table-of-content
1694 or orther sources.
1695 @param result Will return the buffer with Sheet text.
1696 Dispose by free() when no longer needed.
1697 It will be filled by the text for the v07t sheet file
1698 plus a trailing 0-byte. (Be aware that double-byte
1699 characters might contain 0-bytes, too.)
1700 Each CD-TEXT language block starts by the line
1701 "Input Sheet Version = 0.7T"
1702 and a "Remarks" line that tells the block number.
1703 @param char_code Returns the character code of the pack array:
1704 0x00 = ISO-8859-1
1705 0x01 = 7 bit ASCII
1706 0x80 = MS-JIS (japanese Kanji, double byte characters)
1707 The presence of a code value that is not in this list
1708 will cause this function to fail.
1709 @param flag Bitfield for control purposes. Unused yet. Submit 0.
1710 @return > 0 tells the number of valid text bytes in result.
1711 This does not include the trailing 0-byte.
1712 <= 0 indicates failure.
1713 */
1714 int burn_make_input_sheet_v07t(unsigned char *text_packs, int num_packs,
1715 int start_tno, int track_count,
1716 char **result, int *char_code, int flag)
1717 {
1718 int ret, result_size = 0;
1719
1720 ret = burn_make_v07t(text_packs, num_packs, start_tno, track_count,
1721 NULL, 0, char_code, 1);
1722 if (ret <= 0)
1723 return ret;
1724 result_size = ret + 1;
1725 *result = burn_alloc_mem(result_size, 1, 0);
1726 if (*result == NULL)
1727 return -1;
1728 ret = burn_make_v07t(text_packs, num_packs, start_tno, track_count,
1729 *result, result_size, char_code, 0);
1730 if (ret <= 0) {
1731 free(*result);
1732 return ret;
1733 }
1734 return result_size - 1;
1735 }
1736
1737