"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libburn/structure.c" (30 Jan 2021, 52955 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 "structure.c" see the Fossies "Dox" file reference documentation.

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