libburn/libburn/structure.c

1759 lines
42 KiB
C
Raw Normal View History

/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
Copyright (c) 2006 - 2011 Thomas Schmitt <scdbackup@gmx.net>
Provided under GPL version 2 or later.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
/* ts A61008 */
/* #include <a ssert.h> */
2006-08-15 20:37:04 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2011-12-12 09:26:41 +00:00
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
2006-08-15 20:37:04 +00:00
#include "libburn.h"
#include "structure.h"
#include "write.h"
#include "debug.h"
#include "init.h"
#include "util.h"
2006-08-15 20:37:04 +00:00
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
/* ts A61008 : replaced Assert by if and return 0 */
/* a ssert(!(pos > BURN_POS_END)); */
2006-08-15 20:37:04 +00:00
#define RESIZE(TO, NEW, pos) {\
void *tmp;\
\
if (pos > BURN_POS_END)\
return 0;\
2006-08-15 20:37:04 +00:00
if (pos == BURN_POS_END)\
pos = TO->NEW##s;\
if ((int) pos > TO->NEW##s)\
2006-08-15 20:37:04 +00:00
return 0;\
\
tmp = realloc(TO->NEW, sizeof(struct NEW *) * (TO->NEW##s + 1));\
if (!tmp)\
return 0;\
TO->NEW = tmp;\
memmove(TO->NEW + pos + 1, TO->NEW + pos,\
sizeof(struct NEW *) * (TO->NEW##s - pos));\
TO->NEW##s++;\
}
struct burn_disc *burn_disc_create(void)
{
struct burn_disc *d;
d = calloc(1, sizeof(struct burn_disc));
if (d == NULL) /* ts A70825 */
return NULL;
2006-08-15 20:37:04 +00:00
d->refcnt = 1;
d->sessions = 0;
d->session = NULL;
return d;
}
void burn_disc_free(struct burn_disc *d)
{
d->refcnt--;
if (d->refcnt == 0) {
/* dec refs on all elements */
int i;
for (i = 0; i < d->sessions; i++)
burn_session_free(d->session[i]);
free(d->session);
free(d);
}
}
struct burn_session *burn_session_create(void)
{
struct burn_session *s;
2011-12-12 09:26:41 +00:00
int i;
s = calloc(1, sizeof(struct burn_session));
if (s == NULL) /* ts A70825 */
return NULL;
2006-08-15 20:37:04 +00:00
s->refcnt = 1;
s->tracks = 0;
s->track = NULL;
s->hidefirst = 0;
2011-12-12 09:26:41 +00:00
for (i = 0; i < 8; i++) {
s->cdtext[i] = NULL;
s->cdtext_language[i] = 0x00; /* Unknown */
s->cdtext_char_code[i] = 0x00; /* ISO-8859-1 */
s->cdtext_copyright[i] = 0x00;
}
s->cdtext_language[0] = 0x09; /* Single-block default is English */
2006-08-15 20:37:04 +00:00
return s;
}
void burn_session_hide_first_track(struct burn_session *s, int onoff)
{
s->hidefirst = onoff;
}
void burn_session_free(struct burn_session *s)
{
2011-12-12 09:26:41 +00:00
int i;
2006-08-15 20:37:04 +00:00
s->refcnt--;
if (s->refcnt == 0) {
/* dec refs on all elements */
for (i = 0; i < s->tracks; i++)
burn_track_free(s->track[i]);
2011-12-12 09:26:41 +00:00
for (i = 0; i < 8; i++)
burn_cdtext_free(&(s->cdtext[i]));
2006-08-15 20:37:04 +00:00
free(s->track);
free(s);
}
}
int burn_disc_add_session(struct burn_disc *d, struct burn_session *s,
unsigned int pos)
{
RESIZE(d, session, pos);
d->session[pos] = s;
s->refcnt++;
return 1;
}
/* ts A81202: this function was in the API but not implemented.
*/
int burn_disc_remove_session(struct burn_disc *d, struct burn_session *s)
{
int i, skip = 0;
if (d->session == NULL)
return 0;
for (i = 0; i < d->sessions; i++) {
if (s == d->session[i]) {
skip++;
continue;
}
d->session[i - skip] = d->session[i];
}
if (!skip)
return 0;
burn_session_free(s);
d->sessions--;
return 1;
}
2006-08-15 20:37:04 +00:00
struct burn_track *burn_track_create(void)
{
struct burn_track *t;
2011-12-12 09:26:41 +00:00
int i;
t = calloc(1, sizeof(struct burn_track));
if (t == NULL) /* ts A70825 */
return NULL;
2006-08-15 20:37:04 +00:00
t->refcnt = 1;
t->indices = 0;
t->offset = 0;
t->offsetcount = 0;
t->tail = 0;
t->tailcount = 0;
t->mode = BURN_MODE1;
t->isrc.has_isrc = 0;
t->pad = 1;
/* ts A70213 */
t->fill_up_media = 0;
/* ts A70218 */
t->default_size = 0;
2006-08-15 20:37:04 +00:00
t->entry = NULL;
t->source = NULL;
t->eos = 0;
/* ts A61101 */
t->sourcecount = 0;
t->writecount = 0;
t->written_sectors = 0;
/* ts A61031 */
t->open_ended = 0;
t->track_data_done = 0;
/* ts B10103 */
t->end_on_premature_eoi = 0;
2006-08-15 20:37:04 +00:00
t->postgap = 0;
t->pregap1 = 0;
t->pregap2 = 0;
/* ts A61024 */
t->swap_source_bytes = 0;
2011-12-12 09:26:41 +00:00
/* ts B11206 */
for (i = 0; i < 8; i++)
t->cdtext[i] = NULL;
2006-08-15 20:37:04 +00:00
return t;
}
void burn_track_free(struct burn_track *t)
{
2011-12-12 09:26:41 +00:00
int i;
2006-08-15 20:37:04 +00:00
t->refcnt--;
if (t->refcnt == 0) {
/* dec refs on all elements */
if (t->source)
burn_source_free(t->source);
2011-12-12 09:26:41 +00:00
for (i = 0; i < 8; i++)
burn_cdtext_free(&(t->cdtext[i]));
2006-08-15 20:37:04 +00:00
free(t);
}
}
int burn_session_add_track(struct burn_session *s, struct burn_track *t,
unsigned int pos)
{
RESIZE(s, track, pos);
s->track[pos] = t;
t->refcnt++;
return 1;
}
int burn_session_remove_track(struct burn_session *s, struct burn_track *t)
{
struct burn_track **tmp;
int i, pos = -1;
/* ts A61008 */
/* a ssert(s->track != NULL); */
if (s->track == NULL)
return 0;
2006-08-15 20:37:04 +00:00
burn_track_free(t);
/* Find the position */
for (i = 0; i < s->tracks; i++) {
2006-10-12 17:31:58 +00:00
if (t == s->track[i]) {
2006-08-15 20:37:04 +00:00
pos = i;
2006-10-12 17:31:58 +00:00
break;
}
2006-08-15 20:37:04 +00:00
}
if (pos == -1)
return 0;
/* Is it the last track? */
2006-10-12 17:31:58 +00:00
if (pos != s->tracks - 1) {
memmove(&s->track[pos], &s->track[pos + 1],
2006-08-15 20:37:04 +00:00
sizeof(struct burn_track *) * (s->tracks - (pos + 1)));
}
s->tracks--;
tmp = realloc(s->track, sizeof(struct burn_track *) * s->tracks);
2006-10-12 17:31:58 +00:00
if (tmp)
s->track = tmp;
2006-08-15 20:37:04 +00:00
return 1;
}
void burn_structure_print_disc(struct burn_disc *d)
{
int i;
2011-10-12 10:01:28 +00:00
char msg[40];
2006-08-15 20:37:04 +00:00
2011-10-12 10:01:28 +00:00
sprintf(msg, "This disc has %d sessions", d->sessions);
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
2006-08-15 20:37:04 +00:00
for (i = 0; i < d->sessions; i++) {
burn_structure_print_session(d->session[i]);
}
}
void burn_structure_print_session(struct burn_session *s)
{
int i;
2011-10-12 10:01:28 +00:00
char msg[40];
2006-08-15 20:37:04 +00:00
2011-10-12 10:01:28 +00:00
sprintf(msg, " Session has %d tracks", s->tracks);
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
2006-08-15 20:37:04 +00:00
for (i = 0; i < s->tracks; i++) {
burn_structure_print_track(s->track[i]);
}
}
void burn_structure_print_track(struct burn_track *t)
{
2011-10-12 10:01:28 +00:00
char msg[80];
sprintf(msg, " track size %d sectors",
burn_track_get_sectors(t));
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
2006-08-15 20:37:04 +00:00
}
void burn_track_define_data(struct burn_track *t, int offset, int tail,
int pad, int mode)
{
int type_to_form(int mode, unsigned char *ctladr, int *form);
int burn_sector_length(int tracktype);
unsigned char ctladr;
int form = -1; /* unchanged form will be considered an error too */
char msg[80];
type_to_form(mode, &ctladr, &form);
if (form == -1 || burn_sector_length(mode) <= 0) {
sprintf(msg,
"Attempt to set track mode to unusable value 0x%X",
(unsigned int) mode);
libdax_msgs_submit(libdax_messenger, -1, 0x00020115,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return;
}
2006-08-15 20:37:04 +00:00
t->offset = offset;
t->pad = pad;
t->mode = mode;
t->tail = tail;
}
/* ts A61024 */
int burn_track_set_byte_swap(struct burn_track *t, int swap_source_bytes)
{
if (swap_source_bytes != 0 && swap_source_bytes != 1)
return 0;
t->swap_source_bytes = swap_source_bytes;
return 1;
}
/* ts A90911 : API */
int burn_track_set_cdxa_conv(struct burn_track *t, int value)
{
if (value < 0 || value > 1)
return 0;
t->cdxa_conversion = value;
return 1;
}
2006-08-15 20:37:04 +00:00
void burn_track_set_isrc(struct burn_track *t, char *country, char *owner,
unsigned char year, unsigned int serial)
{
int i;
for (i = 0; i < 2; ++i) {
/* ts A61008 : This is always true */
/* a ssert((country[i] >= '0' || country[i] < '9') &&
2006-08-15 20:37:04 +00:00
(country[i] >= 'a' || country[i] < 'z') &&
(country[i] >= 'A' || country[i] < 'Z')); */
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
if (! ((country[i] >= '0' && country[i] <= '9') ||
(country[i] >= 'a' && country[i] <= 'z') ||
(country[i] >= 'A' && country[i] <= 'Z') ) )
goto is_not_allowed;
2006-08-15 20:37:04 +00:00
t->isrc.country[i] = country[i];
}
for (i = 0; i < 3; ++i) {
/* ts A61008 : This is always true */
/* a ssert((owner[i] >= '0' || owner[i] < '9') &&
2006-08-15 20:37:04 +00:00
(owner[i] >= 'a' || owner[i] < 'z') &&
(owner[i] >= 'A' || owner[i] < 'Z')); */
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
if (! ((owner[i] >= '0' && owner[i] <= '9') ||
(owner[i] >= 'a' && owner[i] <= 'z') ||
(owner[i] >= 'A' && owner[i] <= 'Z') ) )
goto is_not_allowed;
2006-08-15 20:37:04 +00:00
t->isrc.owner[i] = owner[i];
}
/* ts A61008 */
/* a ssert(year <= 99); */
if (year > 99)
goto is_not_allowed;
2006-08-15 20:37:04 +00:00
t->isrc.year = year;
/* ts A61008 */
/* a ssert(serial <= 99999); */
if (serial > 99999)
goto is_not_allowed;
2006-08-15 20:37:04 +00:00
t->isrc.serial = serial;
/* ts A61008 */
t->isrc.has_isrc = 1;
return;
is_not_allowed:;
libdax_msgs_submit(libdax_messenger, -1, 0x00020114,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Attempt to set ISRC with bad data", 0, 0);
return;
2006-08-15 20:37:04 +00:00
}
void burn_track_clear_isrc(struct burn_track *t)
{
t->isrc.has_isrc = 0;
}
int burn_track_get_sectors(struct burn_track *t)
{
2007-01-25 18:52:50 +00:00
/* ts A70125 : was int */
off_t size = 0;
2006-08-15 20:37:04 +00:00
int sectors, seclen;
seclen = burn_sector_length(t->mode);
if (t->cdxa_conversion == 1)
/* ts A90911 : will read blocks of 2056 bytes and write 2048 */
seclen += 8;
if (t->source != NULL) /* ts A80808 : mending sigsegv */
size = t->offset + t->source->get_size(t->source) + t->tail;
else if(t->entry != NULL) {
/* ts A80808 : all burn_toc_entry of track starts should now
have (extensions_valid & 1), even those from CD.
*/
if (t->entry->extensions_valid & 1)
size = ((off_t) t->entry->track_blocks) * (off_t) 2048;
}
2006-08-15 20:37:04 +00:00
sectors = size / seclen;
if (size % seclen)
sectors++;
return sectors;
}
2007-01-25 18:52:50 +00:00
/* ts A70125 */
int burn_track_set_sectors(struct burn_track *t, int sectors)
{
off_t size, seclen;
int ret;
seclen = burn_sector_length(t->mode);
size = seclen * (off_t) sectors - (off_t) t->offset - (off_t) t->tail;
if (size < 0)
return 0;
ret = t->source->set_size(t->source, size);
t->open_ended = (t->source->get_size(t->source) <= 0);
2007-01-25 18:52:50 +00:00
return ret;
}
/* ts A70218 , API since A70328 */
int burn_track_set_size(struct burn_track *t, off_t size)
{
if (t->source == NULL)
return 0;
if (t->source->set_size == NULL)
return 0;
t->open_ended = (size <= 0);
return t->source->set_size(t->source, size);
}
/* ts A70213 */
int burn_track_set_fillup(struct burn_track *t, int fill_up_media)
{
t->fill_up_media = fill_up_media;
2007-02-17 08:52:07 +00:00
if (fill_up_media)
t->open_ended = 0;
return 1;
}
/* ts A70213 */
/**
@param flag bit0= force new size even if existing track size is larger
*/
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag)
{
int max_sectors, ret = 2;
char msg[80];
if (t->fill_up_media <= 0)
return 2;
max_sectors = max_size / 2048;
if (burn_track_get_sectors(t) < max_sectors || (flag & 1)) {
sprintf(msg, "Setting total track size to %ds (payload %ds)\n",
max_sectors & 0x7fffffff,
(int) ((t->source->get_size(t->source) / 2048)
& 0x7fffffff));
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg, 0, 0);
ret = burn_track_set_sectors(t, max_sectors);
t->open_ended = 0;
}
return ret;
}
/* ts A61031 */
int burn_track_is_open_ended(struct burn_track *t)
{
return !!t->open_ended;
}
/* ts A70218 : API */
int burn_track_set_default_size(struct burn_track *t, off_t size)
{
t->default_size = size;
return 1;
}
/* ts A70218 */
off_t burn_track_get_default_size(struct burn_track *t)
{
return t->default_size;
}
/* ts A61101 : API function */
int burn_track_get_counters(struct burn_track *t,
off_t *read_bytes, off_t *written_bytes)
{
/*
fprintf(stderr, "libburn_experimental: sizeof(off_t)=%d\n",
sizeof(off_t));
*/
*read_bytes = t->sourcecount;
*written_bytes = t->writecount;
return 1;
}
/* ts A61031 */
int burn_track_is_data_done(struct burn_track *t)
{
return !!t->track_data_done;
}
2006-08-15 20:37:04 +00:00
int burn_track_get_shortage(struct burn_track *t)
{
int size;
int seclen;
seclen = burn_sector_length(t->mode);
size = t->offset + t->source->get_size(t->source) + t->tail;
if (size % seclen)
return seclen - size % seclen;
return 0;
}
int burn_session_get_sectors(struct burn_session *s)
{
int sectors = 0, i;
for (i = 0; i < s->tracks; i++)
sectors += burn_track_get_sectors(s->track[i]);
return sectors;
}
2006-08-15 20:37:04 +00:00
int burn_disc_get_sectors(struct burn_disc *d)
{
int sectors = 0, i;
for (i = 0; i < d->sessions; i++)
sectors += burn_session_get_sectors(d->session[i]);
return sectors;
}
void burn_track_get_entry(struct burn_track *t, struct burn_toc_entry *entry)
{
if (t->entry == NULL)
memset(entry, 0, sizeof(struct burn_toc_entry));
else
memcpy(entry, t->entry, sizeof(struct burn_toc_entry));
2006-08-15 20:37:04 +00:00
}
void burn_session_get_leadout_entry(struct burn_session *s,
struct burn_toc_entry *entry)
{
if (s->leadout_entry == NULL)
memset(entry, 0, sizeof(struct burn_toc_entry));
else
memcpy(entry, s->leadout_entry, sizeof(struct burn_toc_entry));
2006-08-15 20:37:04 +00:00
}
struct burn_session **burn_disc_get_sessions(struct burn_disc *d, int *num)
{
*num = d->sessions;
return d->session;
}
struct burn_track **burn_session_get_tracks(struct burn_session *s, int *num)
{
*num = s->tracks;
return s->track;
}
int burn_track_get_mode(struct burn_track *track)
{
return track->mode;
}
int burn_session_get_hidefirst(struct burn_session *session)
{
return session->hidefirst;
}
/* ts A80808 : Enhance CD toc to DVD toc */
int burn_disc_cd_toc_extensions(struct burn_disc *d, int flag)
{
int sidx= 0, tidx= 0, ret;
2008-08-19 12:36:10 +00:00
struct burn_toc_entry *entry, *prev_entry= NULL;
/* ts A81126 : ticket 146 : There was a SIGSEGV in here */
char *msg_data = NULL, *msg;
BURN_ALLOC_MEM(msg_data, char, 321);
strcpy(msg_data,
"Damaged CD table-of-content detected and truncated.");
strcat(msg_data, " In burn_disc_cd_toc_extensions: ");
msg = msg_data + strlen(msg_data);
if (d->session == NULL) {
strcpy(msg, "d->session == NULL");
goto failure;
}
for (sidx = 0; sidx < d->sessions; sidx++) {
if (d->session[sidx] == NULL) {
sprintf(msg, "d->session[%d of %d] == NULL",
sidx, d->sessions);
goto failure;
}
if (d->session[sidx]->track == NULL) {
sprintf(msg, "d->session[%d of %d]->track == NULL",
sidx, d->sessions);
goto failure;
}
if (d->session[sidx]->leadout_entry == NULL) {
sprintf(msg,
" Session %d of %d: Leadout entry missing.",
sidx, d->sessions);
goto failure;
}
for (tidx = 0; tidx < d->session[sidx]->tracks + 1; tidx++) {
if (tidx < d->session[sidx]->tracks) {
if (d->session[sidx]->track[tidx] == NULL) {
sprintf(msg,
"d->session[%d of %d]->track[%d of %d] == NULL",
sidx, d->sessions, tidx, d->session[sidx]->tracks);
goto failure;
}
entry = d->session[sidx]->track[tidx]->entry;
if (entry == NULL) {
sprintf(msg,
"session %d of %d, track %d of %d, entry == NULL",
sidx, d->sessions, tidx,
d->session[sidx]->tracks);
goto failure;
}
} else
entry = d->session[sidx]->leadout_entry;
entry->session_msb = 0;
entry->point_msb = 0;
entry->start_lba = burn_msf_to_lba(entry->pmin,
entry->psec, entry->pframe);
if (tidx > 0) {
prev_entry->track_blocks =
entry->start_lba
- prev_entry->start_lba;
prev_entry->extensions_valid |= 1;
}
if (tidx == d->session[sidx]->tracks) {
entry->session_msb = 0;
entry->point_msb = 0;
entry->track_blocks = 0;
entry->extensions_valid |= 1;
}
prev_entry = entry;
}
}
{ret = 1; goto ex;}
failure:
libdax_msgs_submit(libdax_messenger, -1, 0x0002015f,
LIBDAX_MSGS_SEV_MISHAP, LIBDAX_MSGS_PRIO_HIGH, msg_data, 0, 0);
d->sessions= sidx;
ret = 0;
ex:;
BURN_FREE_MEM(msg_data);
return ret;
}
2011-12-12 09:26:41 +00:00
struct burn_cdtext *burn_cdtext_create(void)
{
struct burn_cdtext *t;
int i;
t = burn_alloc_mem(sizeof(struct burn_cdtext), 1, 0);
if (t == NULL)
return NULL;
for(i = 0; i < Libburn_pack_num_typeS; i ++) {
t->payload[i] = NULL;
t->length[i] = 0;
}
return t;
}
void burn_cdtext_free(struct burn_cdtext **cdtext)
{
struct burn_cdtext *t;
int i;
t = *cdtext;
if (t == NULL)
return;
for (i = 0; i < Libburn_pack_num_typeS; i++)
if (t->payload[i] != NULL)
free(t->payload[i]);
free(t);
}
static int burn_cdtext_name_to_type(char *pack_type_name)
{
int i, j;
static char *pack_type_names[] = {
Libburn_pack_type_nameS
};
for (i = 0; i < Libburn_pack_num_typeS; i++) {
if (pack_type_names[i][0] == 0)
continue;
for (j = 0; pack_type_names[i][j]; j++)
if (pack_type_names[i][j] != pack_type_name[j] &&
tolower(pack_type_names[i][j]) !=
pack_type_name[j])
break;
if (pack_type_names[i][j] == 0)
return Libburn_pack_type_basE + i;
}
return -1;
}
/* @param flag bit0= double byte characters
*/
static int burn_cdtext_set(struct burn_cdtext **cdtext,
int pack_type, char *pack_type_name,
unsigned char *payload, int length, int flag)
{
int i;
struct burn_cdtext *t;
if (pack_type_name != NULL)
if (pack_type_name[0])
pack_type = burn_cdtext_name_to_type(pack_type_name);
if (pack_type < Libburn_pack_type_basE ||
pack_type >= Libburn_pack_type_basE + Libburn_pack_num_typeS) {
libdax_msgs_submit(libdax_messenger, -1, 0x0002018c,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"CD-TEXT pack type out of range", 0, 0);
return 0;
}
t = *cdtext;
if (t == NULL) {
*cdtext = t = burn_cdtext_create();
if (t == NULL)
return -1;
}
i = pack_type - Libburn_pack_type_basE;
if (t->payload[i] != NULL)
free(t->payload[i]);
t->payload[i] = burn_alloc_mem((size_t) length, 1, 0);
if (t->payload[i] == NULL)
return -1;
memcpy(t->payload[i], payload, length);
t->length[i] = length;
t->flags = (t->flags & ~(1 << i)) | (flag & (1 << i));
return 1;
}
/* @return 1=single byte char , 2= double byte char , <=0 error */
static int burn_cdtext_get(struct burn_cdtext *t, int pack_type,
char *pack_type_name,
unsigned char **payload, int *length, int flag)
{
if (pack_type_name != NULL)
if (pack_type_name[0])
pack_type = burn_cdtext_name_to_type(pack_type_name);
if (pack_type < Libburn_pack_type_basE ||
pack_type >= Libburn_pack_type_basE + Libburn_pack_num_typeS) {
libdax_msgs_submit(libdax_messenger, -1, 0x0002018c,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"CD-TEXT pack type out of range", 0, 0);
return 0;
}
*payload = t->payload[pack_type - Libburn_pack_type_basE];
*length = t->length[pack_type - Libburn_pack_type_basE];
return 1 + ((t->flags >> (pack_type - Libburn_pack_type_basE)) & 1);
}
static int burn_cdtext_check_blockno(int block)
{
if (block < 0 || block > 7) {
libdax_msgs_submit(libdax_messenger, -1, 0x0002018d,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"CD-TEXT block number out of range", 0, 0);
return 0;
}
return 1;
}
/* ts B11206 API */
/* @param flag bit0= double byte characters
*/
int burn_track_set_cdtext(struct burn_track *t, int block,
int pack_type, char *pack_type_name,
unsigned char *payload, int length, int flag)
{
int ret;
if (burn_cdtext_check_blockno(block) <= 0)
return 0;
ret = burn_cdtext_set(&(t->cdtext[block]), pack_type, pack_type_name,
payload, length, flag & 1);
return ret;
}
/* ts B11206 API */
/* @return 1=single byte char , 2= double byte char , <=0 error */
int burn_track_get_cdtext(struct burn_track *t, int block,
int pack_type, char *pack_type_name,
unsigned char **payload, int *length, int flag)
{
int ret;
if (burn_cdtext_check_blockno(block) <= 0)
return 0;
if (t->cdtext[block] == NULL) {
*payload = NULL;
*length = 0;
return 1;
}
2011-12-12 09:26:41 +00:00
ret = burn_cdtext_get(t->cdtext[block], pack_type, pack_type_name,
payload, length, 0);
return ret;
}
/* ts B11206 API */
int burn_track_dispose_cdtext(struct burn_track *t, int block)
{
int i;
if (block == -1) {
for (i= 0; i < 8; i++)
burn_cdtext_free(&(t->cdtext[i]));
return 1;
}
if (burn_cdtext_check_blockno(block) <= 0)
return 0;
burn_cdtext_free(&(t->cdtext[0]));
return 1;
}
/* ts B11206 API */
/* @param flag bit0= double byte characters
*/
int burn_session_set_cdtext(struct burn_session *s, int block,
int pack_type, char *pack_type_name,
unsigned char *payload, int length, int flag)
{
int ret;
if (burn_cdtext_check_blockno(block) <= 0)
return 0;
ret = burn_cdtext_set(&(s->cdtext[block]), pack_type, pack_type_name,
payload, length, flag & 1);
return ret;
}
/* ts B11206 API */
/* @return 1=single byte char , 2= double byte char , <=0 error */
int burn_session_get_cdtext(struct burn_session *s, int block,
int pack_type, char *pack_type_name,
unsigned char **payload, int *length, int flag)
{
int ret;
if (burn_cdtext_check_blockno(block) <= 0)
return 0;
if (s->cdtext[block] == NULL) {
*payload = NULL;
*length = 0;
return 1;
}
2011-12-12 09:26:41 +00:00
ret = burn_cdtext_get(s->cdtext[block], pack_type, pack_type_name,
payload, length, 0);
return ret;
}
/* ts B11206 API */
int burn_session_set_cdtext_par(struct burn_session *s,
int char_codes[8], int copyrights[8],
int block_languages[8], int flag)
{
int i;
for (i = 0; i < 8; i++) {
if (char_codes[i] >= 0 && char_codes[i] <= 255)
s->cdtext_char_code[i] = char_codes[i];
if (copyrights[i] >= 0 && copyrights[i] <= 255)
s->cdtext_copyright[i] = copyrights[i];
if (block_languages[i] >= 0 && block_languages[i] <= 255)
s->cdtext_language[i] = block_languages[i];
}
return 1;
}
/* ts B11206 API */
int burn_session_get_cdtext_par(struct burn_session *s,
int char_codes[8], int copyrights[8],
int block_languages[8], int flag)
{
int i;
for (i = 0; i < 8; i++) {
char_codes[i] = s->cdtext_char_code[i];
copyrights[i] = s->cdtext_copyright[i];
block_languages[i]= s->cdtext_language[i];
}
return 1;
}
/* ts B11206 API */
int burn_session_dispose_cdtext(struct burn_session *s, int block)
{
int i;
if (block == -1) {
for (i= 0; i < 8; i++) {
burn_session_dispose_cdtext(s, i);
s->cdtext_char_code[i] = 0x01; /* 7 bit ASCII */
s->cdtext_copyright[i] = 0;
s->cdtext_language[i] = 0;
}
return 1;
}
if (burn_cdtext_check_blockno(block) <= 0)
return 0;
burn_cdtext_free(&(s->cdtext[block]));
s->cdtext_language[block] = 0x09; /* english */
return 1;
}
/* --------------------- Reading CDRWIN cue sheet files ----------------- */
struct burn_cue_file_cursor {
char *cdtextfile;
char *source_file;
off_t source_size;
struct burn_source *file_source;
int fifo_size;
struct burn_source *fifo;
int swap_audio_bytes;
int no_cdtext;
struct burn_source *offst_source;
int current_file_ba;
struct burn_track *prev_track;
int prev_file_ba;
int prev_block_size;
struct burn_track *track;
int track_no;
int track_has_index;
int track_has_source;
int block_size;
int block_size_locked;
int flags;
};
static int cue_crs_new(struct burn_cue_file_cursor **reply, int flag)
{
int ret;
struct burn_cue_file_cursor *crs;
BURN_ALLOC_MEM(crs, struct burn_cue_file_cursor, 1);
crs->cdtextfile = NULL;
crs->source_file = NULL;
crs->source_size = -1;
crs->file_source = NULL;
crs->fifo_size = 0;
crs->fifo = NULL;
crs->swap_audio_bytes = 0;
crs->no_cdtext = 0;
crs->offst_source = NULL;
crs->current_file_ba = -1000000000;
crs->prev_track = NULL;
crs->prev_file_ba = -1000000000;
crs->prev_block_size = 0;
crs->track = NULL;
crs->track_no = 0;
crs->track_has_index = 0;
crs->track_has_source = 0;
crs->block_size = 0;
crs->block_size_locked = 0;
crs->flags = 0;
*reply = crs;
ret = 1;
ex:;
return ret;
}
static int cue_crs_destroy(struct burn_cue_file_cursor **victim, int flag)
{
struct burn_cue_file_cursor *crs;
if (*victim == NULL)
return 2;
crs = *victim;
if (crs->cdtextfile != NULL)
free(crs->cdtextfile);
if (crs->source_file != NULL)
free(crs->source_file);
if (crs->file_source != NULL)
burn_source_free(crs->file_source);
if (crs->fifo != NULL)
burn_source_free(crs->fifo);
if (crs->offst_source != NULL)
burn_source_free(crs->offst_source);
if (crs->prev_track != NULL)
burn_track_free(crs->prev_track);
if (crs->track != NULL)
burn_track_free(crs->track);
BURN_FREE_MEM(crs);
*victim = NULL;
return 1;
}
static char *cue_unquote_text(char *text, int flag)
{
char *ept, *spt;
spt = text;
for (ept = text + strlen(text); ept > text; ept--)
if (*(ept - 1) != 32 && *(ept - 1) != 9)
break;
if (text[0] == '"') {
spt = text + 1;
if (ept > spt)
if (*(ept - 1) == '"')
ept--;
}
*ept = 0;
return spt;
}
/* @param flag bit0= insist in having a track object
bit1= remove quotation marks if present
*/
static int cue_set_cdtext(struct burn_session *session,
struct burn_track *track, int pack_type, char *text,
struct burn_cue_file_cursor *crs, int flag)
{
int ret;
char *payload;
if (crs->no_cdtext == 1) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020195,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: Being set to ignore all CD-TEXT aspects",
0, 0);
crs->no_cdtext = 2;
}
if (crs->no_cdtext)
return 2;
if ((flag & 1) && track == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"Track attribute set before first track in cue sheet file",
0, 0);
ret = 0; goto ex;
}
if (flag & 2)
payload = cue_unquote_text(text, 0);
else
payload = text;
if (track != NULL) {
ret = burn_track_set_cdtext(track, 0, pack_type, "",
(unsigned char *) payload,
strlen(payload) + 1, 0);
} else {
ret = burn_session_set_cdtext(session, 0, pack_type, "",
(unsigned char *) payload,
strlen(payload) + 1, 0);
}
ex:;
return ret;
}
static int cue_attach_track(struct burn_session *session,
struct burn_cue_file_cursor *crs, int flag)
{
int ret;
if (crs->track == NULL)
return 2;
if (!crs->track_has_source) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: TRACK without INDEX 01", 0, 0);
return 0;
}
if (crs->track_no > 1 && session->tracks == 0) {
/* >>> ??? implement ? */;
libdax_msgs_submit(libdax_messenger, -1, 0x00020195,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: TRACK numbering does not start with 01",
0, 0);
}
ret = burn_session_add_track(session, crs->track, BURN_POS_END);
if (ret <= 0)
return ret;
if (crs->prev_track != NULL)
burn_track_free(crs->prev_track); /* release reference */
crs->prev_track = crs->track;
crs->prev_file_ba = crs->current_file_ba;
crs->prev_block_size = crs->block_size;
crs->track = NULL;
crs->track_has_index = crs->track_has_source = 0;
crs->current_file_ba = -1;
if (!crs->block_size_locked)
crs->block_size = 0;
return 1;
}
/* @param flag bit0= do not alter the content of *payload
do not change *payload
*/
static int cue_read_number(char **payload, int *number, int flag)
{
int ret, at_end = 0;
char *apt, *msg = NULL;
for(apt = *payload; *apt != 0 && *apt != 32 && *apt != 9; apt++);
if (*apt == 0)
at_end = 1;
else if (!(flag & 1))
*apt = 0;
ret = sscanf(*payload, "%d", number);
if (ret != 1) {
BURN_ALLOC_MEM(msg, char, 4096);
sprintf(msg,
"Unsuitable number in cue sheet file: '%.4000s'",
*payload);
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
/* Find start of next argument */
if (!at_end)
for (apt++; *apt == 32 || *apt == 9; apt++);
if (!(flag & 1))
*payload = apt;
ret = 1;
ex:
BURN_FREE_MEM(msg);
return ret;
}
static int cue_create_file_source(char *path, struct burn_cue_file_cursor *crs,
int flag)
{
int fd, ret;
char *msg = NULL;
BURN_ALLOC_MEM(msg, char, 4096);
fd = open(path, O_RDONLY);
if (fd == -1) {
sprintf(msg, "In cue sheet: Cannot open FILE '%.4000s'", path);
libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), errno, 0);
ret = 0; goto ex;
}
crs->file_source = burn_fd_source_new(fd, -1, crs->source_size);
if (crs->file_source == NULL) {
ret = -1; goto ex;
}
ret = 1;
ex:;
BURN_FREE_MEM(msg);
return ret;
}
static int cue_interpret_line(struct burn_session *session, char *line,
struct burn_cue_file_cursor *crs, int flag)
{
int ret, mode, index_no, minute, second, frame, file_ba, chunks;
int block_size;
off_t size;
char *cmd, *apt, *msg = NULL, msf[3], *msf_pt, *cpt, *filetype;
struct burn_source *src, *inp_src;
enum burn_source_status source_status;
struct stat stbuf;
BURN_ALLOC_MEM(msg, char, 4096);
if (line[0] == 0 || line[0] == '#') {
ret = 1; goto ex;
}
for (cmd = line; *cmd == 32 || *cmd == 9; cmd++);
for(apt = cmd; *apt != 0 && *apt != 32 && *apt != 9; apt++);
if (*apt != 0) {
*apt = 0;
for (apt++; *apt == 32 || *apt == 9; apt++);
}
if (strcmp(cmd, "CATALOG") == 0) {
ret = cue_set_cdtext(session, NULL, 0x8e, apt, crs, 0);
if (ret <= 0)
goto ex;
/* >>> ??? data for burn_write_opts_set_mediacatalog ?
(not implemented yet in SAO) */
} else if (strcmp(cmd, "CDTEXTFILE") == 0) {
if (crs->no_cdtext) {
ret = 1; goto ex;
}
apt = cue_unquote_text(apt, 0);
if (crs->cdtextfile != NULL)
free(crs->cdtextfile);
crs->cdtextfile = strdup(apt);
if (crs->cdtextfile == NULL) {
out_of_mem:;
libdax_msgs_submit(libdax_messenger, -1, 0x00000003,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Out of virtual memory", 0, 0);
ret = -1; goto ex;
}
} else if (strcmp(cmd, "FILE") == 0) {
if (crs->file_source != NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: Multiple occurences of FILE",
0, 0);
ret = 0; goto ex;
}
/* Obtain type */
for (cpt = apt + (strlen(apt) - 1);
cpt > apt && (*cpt == 32 || *cpt == 9); cpt--);
cpt[1] = 0;
for (; cpt > apt && *cpt != 32 && *cpt != 9; cpt--);
if (cpt <= apt) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: FILE without type word",
0, 0);
ret = 0; goto ex;
}
*cpt = 0;
filetype = cpt + 1;
if (strcmp(filetype, "BINARY") == 0) {
crs->swap_audio_bytes = 0;
} else if (strcmp(filetype, "MOTOROLA") == 0) {
crs->swap_audio_bytes = 1;
} else if (strcmp(filetype, "WAVE") == 0 && 0 ) {
/* >>> Use libdax_audioxtr_* functions to extract */;
} else {
sprintf(msg,
"In cue sheet file: Unsupported FILE type '%.4000s'",
filetype);
libdax_msgs_submit(libdax_messenger, -1, 0x00020197,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
apt = cue_unquote_text(apt, 0);
if (*apt == 0)
ret = -1;
else
ret = stat(apt, &stbuf);
if (ret == -1) {
not_usable_file:;
sprintf(msg,
"In cue sheet file: Unusable FILE '%.4000s'",
apt);
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
if (!S_ISREG(stbuf.st_mode))
goto not_usable_file;
crs->source_size = stbuf.st_size;
if (crs->source_file != NULL)
free(crs->source_file);
crs->source_file = strdup(apt);
if (crs->source_file == NULL)
goto out_of_mem;
ret = cue_create_file_source(apt, crs, 0);
if (ret <= 0)
goto ex;
} else if (strcmp(cmd, "FLAGS") == 0) {
/* >>> Interpret DCP 4CH PRE SCMS into crs->flags */;
} else if (strcmp(cmd, "INDEX") == 0) {
if (crs->track == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: INDEX found before TRACK",
0, 0);
ret = 0; goto ex;
}
ret = cue_read_number(&apt, &index_no, 0);
if (ret <= 0)
goto ex;
/* Obtain time point */
if (strlen(apt) < 8) {
no_time_point:;
sprintf(msg,
"Inappropriate cue sheet file index time point '%.4000s'",
apt);
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
if (apt[2] != ':' || apt[5] != ':' ||
(apt[8] != 0 && apt[8] != 32 && apt[8] != 9))
goto no_time_point;
msf[2] = 0;
msf_pt = msf;
strncpy(msf, apt, 2);
ret = cue_read_number(&msf_pt, &minute, 1);
if (ret <= 0)
goto ex;
strncpy(msf, apt + 3, 2);
ret = cue_read_number(&msf_pt, &second, 1);
if (ret <= 0)
goto ex;
strncpy(msf, apt + 6, 2);
ret = cue_read_number(&msf_pt, &frame, 1);
if (ret <= 0)
goto ex;
file_ba = ((minute * 60) + second ) * 75 + frame;
if (file_ba <= crs->prev_file_ba) {
overlapping_ba:;
libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"Overlapping INDEX addresses in cue sheet file",
0, 0);
ret = 0; goto ex;
}
if (crs->prev_track != NULL && !crs->track_has_index) {
size = (file_ba - crs->prev_file_ba) *
crs->prev_block_size;
if (size <= 0)
goto overlapping_ba;
burn_track_set_size(crs->prev_track, size);
}
crs->track_has_index = 1;
if (index_no != 1) {
/* >>> what to do with index != 1 ? */;
/* >>> INDEX 00 defines start of a track pregap
Pregap and postgap still has to be properly
mapped onto track
*/;
ret = 1; goto ex;
}
if (crs->block_size_locked && crs->fifo == NULL &&
crs->fifo_size > 0) {
/* Now that the block size is known from TRACK:
Create fifo and use it for creating the offset
sources. This will fixate the block size to one
common value.
*/
chunks = crs->fifo_size / crs->block_size +
!!(crs->fifo_size % crs->block_size);
if (chunks < 4)
chunks = 4;
crs->fifo = burn_fifo_source_new(crs->file_source,
crs->block_size, chunks, 0);
if (crs->fifo == NULL) {
ret = -1; goto ex;
}
}
if (crs->fifo != NULL)
inp_src = crs->fifo;
else
inp_src = crs->file_source;
src = burn_offst_source_new(inp_src, crs->offst_source,
(off_t) (file_ba * crs->block_size), (off_t) 0, 0);
if (src == NULL)
goto out_of_mem;
/* >>> Alternative to above fifo creation:
Create a fifo for each track track.
This will be necessary if mixed-mode sessions get supporded.
*/;
source_status = burn_track_set_source(crs->track, src);
if (source_status != BURN_SOURCE_OK) {
ret = -1; goto ex;
}
/* Switch current source in crs */
if (crs->offst_source != NULL)
burn_source_free(crs->offst_source);
crs->offst_source = src;
crs->current_file_ba = file_ba;
crs->track_has_source = 1;
} else if (strcmp(cmd, "ISRC") == 0) {
ret = cue_set_cdtext(session, crs->track, 0x8e, apt, crs,
1 | 2);
if (ret <= 0)
goto ex;
/* >>> ??? burn_track_set_isrc ?
(not implemented yet in SAO) */
} else if (strcmp(cmd, "PERFORMER") == 0) {
ret = cue_set_cdtext(session, crs->track, 0x81, apt, crs, 2);
if (ret <= 0)
goto ex;
} else if (strcmp(cmd, "POSTGAP") == 0) {
/* >>> ??? implement ? */;
libdax_msgs_submit(libdax_messenger, -1, 0x00020195,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: POSTGAP command not supported",
0, 0);
} else if (strcmp(cmd, "PREGAP") == 0) {
/* >>> ??? implement ? */;
libdax_msgs_submit(libdax_messenger, -1, 0x00020195,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: PREGAP command not supported",
0, 0);
} else if (strcmp(cmd, "REM") == 0) {
;
} else if (strcmp(cmd, "SONGWRITER") == 0) {
ret = cue_set_cdtext(session, crs->track, 0x82, apt, crs, 2);
if (ret <= 0)
goto ex;
} else if (strcmp(cmd, "TITLE") == 0) {
ret = cue_set_cdtext(session, crs->track, 0x80, apt, crs, 2);
if (ret <= 0)
goto ex;
} else if (strcmp(cmd, "TRACK") == 0) {
if (crs->file_source == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"No FILE defined before TRACK in cue sheet file",
0, 0);
ret = 0; goto ex;
}
/* Attach previous track to session */
ret = cue_attach_track(session, crs, 0);
if (ret <= 0)
goto ex;
/* Create new track */;
ret = cue_read_number(&apt, &(crs->track_no), 0);
if (ret <= 0)
goto ex;
if (crs->track_no < 1 || crs->track_no > 99) {
sprintf(msg,
"Inappropriate cue sheet file track number %d",
crs->track_no);
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
if (strcmp(apt, "AUDIO") == 0) {
mode = BURN_AUDIO;
block_size = 2352;
} else if (strcmp(apt, "MODE1/2048") == 0) {
mode = BURN_MODE1;
block_size = 2048;
} else {
sprintf(msg,
"Unsupported cue sheet file track datatype '%.4000s'",
apt);
libdax_msgs_submit(libdax_messenger, -1, 0x00020197,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
if (block_size != crs->block_size && crs->block_size > 0 &&
crs->block_size_locked) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020197,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"In cue sheet file: Unsupported mix track block sizes",
0, 0);
ret = 0; goto ex;
}
crs->block_size = block_size;
crs->track = burn_track_create();
if (crs->track == NULL)
goto out_of_mem;
crs->track_has_source = 0;
burn_track_define_data(crs->track, 0, 0, 1, mode);
if (mode == BURN_AUDIO)
burn_track_set_byte_swap(crs->track,
!!crs->swap_audio_bytes);
} else {
sprintf(msg, "Unknown cue sheet file command '%.4000s'", line);
libdax_msgs_submit(libdax_messenger, -1, 0x00020191,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
ret = 1;
ex:;
BURN_FREE_MEM(msg);
return ret;
}
/* ts B11216 API */
/* @param flag bit0= do not attach CD-TEXT information to session and tracks
*/
int burn_session_by_cue_file(struct burn_session *session, char *path,
int fifo_size, struct burn_source **fifo,
unsigned char **text_packs, int *num_packs, int flag)
{
int ret, num_tracks, i, pack_type, length, double_byte = 0;
struct burn_track **tracks;
char *msg = NULL, *line = NULL;
unsigned char *payload;
struct stat stbuf;
FILE *fp = NULL;
struct burn_cue_file_cursor *crs;
static unsigned char dummy_cdtext[2] = {0, 0};
if (fifo != NULL)
*fifo = NULL;
if (text_packs != NULL)
*text_packs = NULL;
*num_packs = 0;
BURN_ALLOC_MEM(msg, char, 4096);
BURN_ALLOC_MEM(line, char, 4096);
ret = cue_crs_new(&crs, 0);
if (ret <= 0)
goto ex;
crs->no_cdtext = (flag & 1);
crs->fifo_size = fifo_size;
crs->block_size_locked = 1; /* No mixed sessions for now */
tracks = burn_session_get_tracks(session, &num_tracks);
if (num_tracks > 0) {
sprintf(msg,
"Cue sheet file reader called while session has already defined tracks");
libdax_msgs_submit(libdax_messenger, -1, 0x00020196,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
if (stat(path, &stbuf) == -1) {
cannot_open:;
sprintf(msg, "Cannot open cue sheet file '%.4000s'",
path);
libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), errno, 0);
ret = 0; goto ex;
}
if (!S_ISREG(stbuf.st_mode)) {
sprintf(msg,
"File is not of usable type: Cue sheet file '%.4000s'",
path);
libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
fp = fopen(path, "rb");
if (fp == NULL)
goto cannot_open;
while (1) {
if (burn_sfile_fgets(line, 4095, fp) == NULL) {
if (!ferror(fp))
break;
sprintf(msg,
"Cannot read all bytes from cue sheet file '%.4000s'",
path);
libdax_msgs_submit(libdax_messenger, -1, 0x00020193,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
burn_printify(msg), 0, 0);
ret = 0; goto ex;
}
ret = cue_interpret_line(session, line, crs, 0);
if (ret <= 0)
goto ex;
}
/* Attach last track to session */
if (crs->track != NULL) {
/* Set track size up to end of file */
if (crs->current_file_ba < 0) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020192,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"No INDEX 01 defined for last TRACK in cue sheet file",
0, 0);
ret = 0; goto ex;
}
if (crs->current_file_ba * crs->block_size >=
crs->source_size) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020194,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"INDEX 01 time point exceeds size of FILE from cue sheet file",
0, 0);
ret = 0; goto ex;
}
burn_track_set_size(crs->track, crs->source_size -
(off_t) (crs->current_file_ba * crs->block_size));
ret = cue_attach_track(session, crs, 0);
if (ret <= 0)
goto ex;
}
if (crs->cdtextfile != NULL) {
if (text_packs == NULL) {
/* >>> Warn of ignored text packs */;
} else {
ret = burn_cdtext_from_packfile(crs->cdtextfile,
text_packs, num_packs, 0);
if (ret <= 0)
goto ex;
}
}
/* Check which tracks have data of pack types where session has not */
tracks = burn_session_get_tracks(session, &num_tracks);
for (pack_type = 0x80; pack_type < 0x8f; pack_type++) {
if (pack_type > 0x86 && pack_type != 0x8e)
continue;
ret = burn_session_get_cdtext(session, 0, pack_type, "",
&payload, &length, 0);
if (ret <= 0)
goto ex;
if (payload != NULL)
continue;
for (i = 0; i < num_tracks; i++) {
ret = burn_track_get_cdtext(tracks[i], 0, pack_type,
"", &payload, &length, 0);
if (ret <= 0)
goto ex;
double_byte = (ret > 1);
if (payload != NULL)
break;
}
if (i < num_tracks) {
ret = burn_session_set_cdtext(session, 0, pack_type,
"", dummy_cdtext, 1 + double_byte,
double_byte);
if (ret <= 0)
goto ex;
}
}
ret = 1;
ex:
if (ret <= 0) {
tracks = burn_session_get_tracks(session, &num_tracks);
for (i = 0; i < num_tracks; i++)
burn_track_free(tracks[i]);
} else {
if (fifo != NULL) {
*fifo = crs->fifo;
crs->fifo = NULL;
}
}
cue_crs_destroy(&crs, 0);
BURN_FREE_MEM(line);
BURN_FREE_MEM(msg);
return ret;
}