"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