xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

cdtext.c
Go to the documentation of this file.
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 
34  unsigned char *packs;
35  int num_packs;
36  int td_used;
37  int hiseq[8];
38  int pack_count[16];
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 
52  libdax_msgs_submit(libdax_messenger, -1, 0x0002018b,
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,
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 */
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 */
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,
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,
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,
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] = {
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,
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] = {
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,
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 */
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,
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,
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,
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,
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) {
760  0x00020192, LIBDAX_MSGS_SEV_FAILURE,
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);
869  0x00020194, LIBDAX_MSGS_SEV_FAILURE,
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) {
881  libdax_messenger, -1, 0x000201a0,
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);
916  0x00020191, LIBDAX_MSGS_SEV_FAILURE,
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);
932  0x00020194, LIBDAX_MSGS_SEV_FAILURE,
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);
972  0x00020194, LIBDAX_MSGS_SEV_FAILURE,
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)) {
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);
1011  0x00020191, LIBDAX_MSGS_SEV_FAILURE,
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)) {
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,
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,
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,
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,
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,
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,
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[] = {
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] = {
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,
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,
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,
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,
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,
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,
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 
int burn_make_input_sheet_v07t(unsigned char *text_packs, int num_packs, int start_tno, int track_count, char **result, int *char_code, int flag)
Definition: cdtext.c:1714
static int is_payload_text_end(unsigned char *payload, int payload_count, int i, int flag)
Definition: cdtext.c:1273
static int v07t_cdtext_to_session(struct burn_session *session, int block, char *payload, int *char_code, int pack_type, char *pack_type_name, int flag)
Definition: cdtext.c:587
int burn_cdtext_from_session(struct burn_session *s, unsigned char **text_packs, int *num_packs, int flag)
Definition: cdtext.c:359
int burn_cdtext_crc_mismatches(unsigned char *packs, int num_packs, int flag)
Definition: cdtext.c:103
static int burn_create_tybl_s_packs(struct burn_session *s, int pack_type, int block, struct burn_pack_cursor *crs, int flag)
Definition: cdtext.c:313
static int report_block(unsigned char *text_packs, int num_packs, int block, int first_tno, int last_tno, int char_code, char *result, int result_size, int flag)
Definition: cdtext.c:1435
static int burn_create_tybl_packs(unsigned char *payload, int length, int track_no, int pack_type, int block, struct burn_pack_cursor *crs, int flag)
Definition: cdtext.c:159
static void write_v07t_line(char **respt, char *spec, char *value, int vlen, int *result_len, int flag)
Definition: cdtext.c:1203
static int v07t_hexcode(char *payload, int flag)
Definition: cdtext.c:453
static int report_track(unsigned char *text_packs, int num_packs, int block, int tno, int first_tno, char **respt, int *result_len, int flag)
Definition: cdtext.c:1396
struct libdax_msgs * libdax_messenger
Definition: init.c:42
static int burn_finalize_text_pack(struct burn_pack_cursor *crs, int flag)
Definition: cdtext.c:135
static int v07t_cdtext_lang_code(char *payload, int flag)
Definition: cdtext.c:519
static int pick_payload_text(unsigned char *payload, int payload_count, int tno, unsigned char **text_start, int *text_len, int flag)
Definition: cdtext.c:1295
static int v07t_cdtext_genre_code(char *payload, int flag)
Definition: cdtext.c:549
static int burn_decide_cdtext_tab(int block, int pack_type, struct burn_cdtext *cdt_curr, struct burn_cdtext *cdt_prev, int flag)
Definition: cdtext.c:287
static int v07t_apply_to_session(struct burn_session *session, int block, int char_codes[8], int copyrights[8], int languages[8], int session_attr_seen[16], int track_attr_seen[16], int genre_code, char *genre_text, int flag)
Definition: cdtext.c:618
static int v07t_cdtext_char_code(char *payload, int flag)
Definition: cdtext.c:492
static int v07t_cdtext_to_track(struct burn_track *track, int block, char *payload, int *char_code, int pack_type, char *pack_type_name, int flag)
Definition: cdtext.c:603
static int burn_create_bl_size_packs(int block, unsigned char *char_codes, unsigned char *copyrights, unsigned char *languages, int num_tracks, struct burn_pack_cursor *crs, int flag)
Definition: cdtext.c:192
static int collect_payload(unsigned char *text_packs, int num_packs, int pack_type, int block, unsigned char **payload, int *payload_count, int flag)
Definition: cdtext.c:1233
static int burn_create_tybl_t_packs(struct burn_track *t, int track_no, int pack_type, int block, struct burn_pack_cursor *crs, int flag)
Definition: cdtext.c:245
int burn_create_new_pack(int pack_type, int track_no, int double_byte, int block, int char_pos, struct burn_pack_cursor *crs, int flag)
Definition: cdtext.c:45
static int burn_make_v07t(unsigned char *text_packs, int num_packs, int first_tno, int track_count, char *result, int result_size, int *char_code, int flag)
Definition: cdtext.c:1592
static int search_pack(unsigned char *text_packs, int num_packs, int start_no, int pack_type, int block, unsigned char **found_pack, int *found_no, int flag)
Definition: cdtext.c:1180
int burn_cdtext_from_packfile(char *path, unsigned char **text_packs, int *num_packs, int flag)
Definition: cdtext.c:1077
static int v07t_cdtext_len_db(char *payload, int *char_code, int *length, int *double_byte, int flag)
Definition: cdtext.c:576
static int crc_11021(unsigned char *data, int count, int flag)
Definition: cdtext.c:83
static int write_v07t_textline(unsigned char *text_packs, int num_packs, int pack_type, int block, int tno, int first_tno, char *spec, char **respt, int *result_len, int flag)
Definition: cdtext.c:1359
int burn_session_input_sheet_v07t(struct burn_session *session, char *path, int block, int flag)
Definition: cdtext.c:669
void * burn_alloc_mem(size_t size, size_t count, int flag)
Definition: init.c:653
#define BURN_FREE_MEM(pt)
Definition: init.h:52
#define BURN_ALLOC_MEM(pt, typ, count)
Definition: init.h:40
char * burn_sfile_fgets(char *line, int maxl, FILE *fp)
Definition: util.c:307
char * burn_printify(char *msg)
Definition: util.c:329
#define BURN_CDTEXT_NUM_GENRES
Definition: libburn.h:2290
int burn_session_set_cdtext(struct burn_session *s, int block, int pack_type, char *pack_type_name, unsigned char *payload, int length, int flag)
Definition: structure.c:1073
#define BURN_CDTEXT_LANGUAGES_0X00
Definition: libburn.h:2151
#define BURN_CDTEXT_FILLER
Definition: libburn.h:2197
int burn_track_set_isrc_string(struct burn_track *t, char isrc[13], int flag)
Definition: structure.c:439
int burn_track_set_cdtext(struct burn_track *t, int block, int pack_type, char *pack_type_name, unsigned char *payload, int length, int flag)
Definition: structure.c:1018
#define BURN_CDTEXT_LANGUAGES_0X45
Definition: libburn.h:2172
struct burn_track ** burn_session_get_tracks(struct burn_session *s, int *num)
Definition: structure.c:735
int burn_session_set_cdtext_par(struct burn_session *s, int char_codes[8], int copyrights[8], int languages[8], int flag)
Definition: structure.c:1110
int burn_session_set_start_tno(struct burn_session *session, int tno, int flag)
Definition: structure.c:864
#define BURN_CDTEXT_GENRE_LIST
Definition: libburn.h:2279
int libdax_msgs_submit(struct libdax_msgs *m, int origin, int error_code, int severity, int priority, char *msg_text, int os_errno, int flag)
Definition: libdax_msgs.c:334
#define LIBDAX_MSGS_PRIO_HIGH
Definition: libdax_msgs.h:237
#define LIBDAX_MSGS_SEV_WARNING
Definition: libdax_msgs.h:154
#define LIBDAX_MSGS_SEV_FAILURE
Definition: libdax_msgs.h:205
#define Libburn_leadin_cdtext_packs_maX
Definition: options.h:108
int length[0x10]
Definition: structure.h:31
unsigned char * payload[0x10]
Definition: structure.h:30
int pack_count[16]
Definition: cdtext.c:38
int track_offset
Definition: cdtext.c:39
unsigned char * packs
Definition: cdtext.c:34
int hiseq[8]
Definition: cdtext.c:37
unsigned char cdtext_char_code[8]
Definition: structure.h:135
unsigned char cdtext_language[8]
Definition: structure.h:137
unsigned char cdtext_copyright[8]
Definition: structure.h:136
unsigned char mediacatalog[14]
Definition: structure.h:140
struct burn_cdtext * cdtext[8]
Definition: structure.h:134
struct burn_track ** track
Definition: structure.h:130
unsigned char firsttrack
Definition: structure.h:121
struct burn_cdtext * cdtext[8]
Definition: structure.h:115
#define Libburn_pack_num_typeS
Definition: structure.h:21
#define Libburn_pack_type_basE
Definition: structure.h:20