|
|
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
|
|
|
|
|
|
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
|
|
|
|
Copyright (c) 2006 - 2012 Thomas Schmitt <scdbackup@gmx.net>
|
|
|
|
Provided under GPL version 2 or later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "../config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* #include <a ssert.h> */
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61106 : Deliberate defect provocation macros
|
|
|
|
DO NOT DEFINE THESE IF YOU WANT SUCCESSFUL TAO !
|
|
|
|
#define Libburn_experimental_no_close_tracK 1
|
|
|
|
#define Libburn_experimental_no_close_sessioN 1
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ts A61114 : Highly experimental : try to achieve SAO on appendables
|
|
|
|
THIS DOES NOT WORK YET !
|
|
|
|
#define Libburn_sao_can_appenD 1
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
#include "error.h"
|
|
|
|
#include "sector.h"
|
|
|
|
#include "libburn.h"
|
|
|
|
#include "drive.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "init.h"
|
|
|
|
#include "toc.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "sg.h"
|
|
|
|
#include "write.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "structure.h"
|
|
|
|
#include "source.h"
|
|
|
|
#include "mmc.h"
|
|
|
|
#include "spc.h"
|
|
|
|
|
|
|
|
#include "libdax_msgs.h"
|
|
|
|
extern struct libdax_msgs *libdax_messenger;
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A91120 : <<< experimental */
|
|
|
|
#ifdef Libburn_mmap_write_buffeR
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* The maximum output size to be used with CD media. This is also curbed
|
|
|
|
by BURN_OS_TRANSPORT_BUFFER_SIZE. The smaller number gets into effect.
|
|
|
|
*/
|
|
|
|
#define Libburn_cd_obS (32 * 1024)
|
|
|
|
|
|
|
|
/* The size to be used with DVD media.
|
|
|
|
*/
|
|
|
|
#define Libburn_dvd_obS (32 * 1024)
|
|
|
|
|
|
|
|
/* The size to be used with BD-RE media in normal, not streamed mode.
|
|
|
|
*/
|
|
|
|
#define Libburn_bd_re_obS (32 * 1024)
|
|
|
|
|
|
|
|
/* The size to be used with BD-RE media in streamed mode.
|
|
|
|
*/
|
|
|
|
#define Libburn_bd_re_streamed_obS (64 * 1024)
|
|
|
|
|
|
|
|
|
|
|
|
static int type_to_ctrl(int mode)
|
|
|
|
{
|
|
|
|
int ctrl = 0;
|
|
|
|
|
|
|
|
int data = BURN_MODE2 | BURN_MODE1 | BURN_MODE0;
|
|
|
|
|
|
|
|
if (mode & data) {
|
|
|
|
ctrl |= 4;
|
|
|
|
} else if (mode & BURN_AUDIO) {
|
|
|
|
if (mode & BURN_4CH)
|
|
|
|
ctrl |= 8;
|
|
|
|
if (mode & BURN_PREEMPHASIS)
|
|
|
|
ctrl |= 1;
|
|
|
|
} else
|
|
|
|
/* ts A61008 */
|
|
|
|
/* a ssert(0); */
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (mode & BURN_COPY)
|
|
|
|
ctrl |= 2;
|
|
|
|
|
|
|
|
return ctrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only the ctrl nibble is set here (not adr) */
|
|
|
|
/* ts A61009 : removed "static" , reacted on type_to_ctrl() == -1
|
|
|
|
preserved ignorance towards unknown modes (for now) */
|
|
|
|
void type_to_form(int mode, unsigned char *ctladr, int *form)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = type_to_ctrl(mode) << 4;
|
|
|
|
if (ret == -1) {
|
|
|
|
*ctladr = 0xff;
|
|
|
|
*form = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*ctladr = ret;
|
|
|
|
|
|
|
|
if (mode & BURN_AUDIO)
|
|
|
|
*form = 0;
|
|
|
|
if (mode & BURN_MODE0) {
|
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(0); */
|
|
|
|
*form = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode & BURN_MODE1)
|
|
|
|
*form = 0x10;
|
|
|
|
if (mode & BURN_MODE2) {
|
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(0); */ /* XXX someone's gonna want this sometime */
|
|
|
|
*form = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode & BURN_MODE_RAW)
|
|
|
|
*form = 0;
|
|
|
|
if (mode & BURN_SUBCODE_P16) /* must be expanded to R96 */
|
|
|
|
*form |= 0x40;
|
|
|
|
if (mode & BURN_SUBCODE_P96)
|
|
|
|
*form |= 0xC0;
|
|
|
|
if (mode & BURN_SUBCODE_R96)
|
|
|
|
*form |= 0x40;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A71002 : outsourced from burn_write_flush() : no sync cache here */
|
|
|
|
int burn_write_flush_buffer(struct burn_write_opts *o,struct burn_track *track)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
|
|
|
|
if (d->buffer->bytes && !d->cancel) {
|
|
|
|
int err;
|
|
|
|
err = d->write(d, d->nwa, d->buffer);
|
|
|
|
if (err == BE_CANCELLED)
|
|
|
|
return 0;
|
|
|
|
/* A61101 */
|
|
|
|
if(track != NULL) {
|
|
|
|
track->writecount += d->buffer->bytes;
|
|
|
|
track->written_sectors += d->buffer->sectors;
|
|
|
|
}
|
|
|
|
/* ts A61119 */
|
|
|
|
d->progress.buffered_bytes += d->buffer->bytes;
|
|
|
|
|
|
|
|
d->nwa += d->buffer->sectors;
|
|
|
|
d->buffer->bytes = 0;
|
|
|
|
d->buffer->sectors = 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
|
|
|
|
ret = burn_write_flush_buffer(o, track);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
d->sync_cache(d);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A71002 : outsourced from burn_write_close_track() */
|
|
|
|
int burn_write_track_minsize(struct burn_write_opts *o, struct burn_session *s,
|
|
|
|
int tnum)
|
|
|
|
{
|
|
|
|
char msg[81];
|
|
|
|
struct burn_drive *d;
|
|
|
|
struct burn_track *t;
|
|
|
|
int todo, step, cancelled, seclen;
|
|
|
|
|
|
|
|
d = o->drive;
|
|
|
|
t = s->track[tnum];
|
|
|
|
|
|
|
|
/* ts A61103 : pad up track to minimum size of 600 sectors */
|
|
|
|
if (t->written_sectors < 300) {
|
|
|
|
todo = 300 - t->written_sectors;
|
|
|
|
sprintf(msg,"Padding up track to minimum size (+ %d sectors)",
|
|
|
|
todo);
|
|
|
|
libdax_msgs_submit(libdax_messenger, o->drive->global_index,
|
|
|
|
0x0002011a,
|
|
|
|
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
|
|
|
step = BUFFER_SIZE / 4096; /* shall fit any sector size */
|
|
|
|
if (step <= 0)
|
|
|
|
step = 1;
|
|
|
|
seclen = burn_sector_length(t->mode);
|
|
|
|
if (seclen <= 0)
|
|
|
|
seclen = 2048;
|
|
|
|
memset(d->buffer, 0, sizeof(struct buffer));
|
|
|
|
cancelled = d->cancel;
|
|
|
|
for (; todo > 0; todo -= step) {
|
|
|
|
if (step > todo)
|
|
|
|
step = todo;
|
|
|
|
d->buffer->bytes = step*seclen;
|
|
|
|
d->buffer->sectors = step;
|
|
|
|
d->cancel = 0;
|
|
|
|
d->write(d, d->nwa, d->buffer);
|
|
|
|
d->nwa += d->buffer->sectors;
|
|
|
|
t->writecount += d->buffer->bytes;
|
|
|
|
t->written_sectors += d->buffer->sectors;
|
|
|
|
d->progress.buffered_bytes += d->buffer->bytes;
|
|
|
|
}
|
|
|
|
d->cancel = cancelled;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61030 */
|
|
|
|
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
|
|
|
int tnum)
|
|
|
|
{
|
|
|
|
char msg[81];
|
|
|
|
struct burn_drive *d;
|
|
|
|
|
|
|
|
/* ts A61106 */
|
|
|
|
#ifdef Libburn_experimental_no_close_tracK
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
d = o->drive;
|
|
|
|
|
|
|
|
d->busy = BURN_DRIVE_CLOSING_TRACK;
|
|
|
|
|
|
|
|
sprintf(msg, "Closing track %2.2d", tnum+1);
|
|
|
|
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
|
|
|
|
|
|
|
/* MMC-1 mentions track number 0xFF for "the incomplete track",
|
|
|
|
MMC-3 does not. I tried both. 0xFF was in effect when other
|
|
|
|
bugs finally gave up and made way for readable tracks. */
|
|
|
|
/* ts A70129
|
|
|
|
Probably the right value for appendables is d->last_track_no
|
|
|
|
*/
|
|
|
|
d->close_track_session(o->drive, 0, 0xff);
|
|
|
|
|
|
|
|
d->busy = BURN_DRIVE_WRITING;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61030 */
|
|
|
|
int burn_write_close_session(struct burn_write_opts *o)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* ts A61106 */
|
|
|
|
#ifdef Libburn_experimental_no_close_sessioN
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Closing session", 0, 0);
|
|
|
|
|
|
|
|
/* ts A61102 */
|
|
|
|
o->drive->busy = BURN_DRIVE_CLOSING_SESSION;
|
|
|
|
|
|
|
|
o->drive->close_track_session(o->drive, 1, 0);
|
|
|
|
|
|
|
|
/* ts A61102 */
|
|
|
|
o->drive->busy = BURN_DRIVE_WRITING;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A60819, B20101:
|
|
|
|
This is useful only when changes about CD SAO get tested.
|
|
|
|
# define Libburn_write_with_function_print_cuE yes
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef Libburn_write_with_function_print_cuE
|
|
|
|
|
|
|
|
|
|
|
|
static char cue_printify(char c)
|
|
|
|
{
|
|
|
|
if (c >= 32 && c < 127)
|
|
|
|
return c;
|
|
|
|
return '#';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void print_cue(struct cue_sheet *sheet)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char *unit;
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
printf("ctladr|trno|indx|form|scms| msf | text\n");
|
|
|
|
printf("------+----+----+----+----+----------+--------\n");
|
|
|
|
for (i = 0; i < sheet->count; i++) {
|
|
|
|
unit = sheet->data + 8 * i;
|
|
|
|
if ((unit[0] & 0xf) == 2) {
|
|
|
|
printf(
|
|
|
|
" %1X %1X | | | | | | %c%c%c%c%c%c%c\n",
|
|
|
|
(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
|
|
|
|
cue_printify(unit[1]), cue_printify(unit[2]),
|
|
|
|
cue_printify(unit[3]), cue_printify(unit[4]),
|
|
|
|
cue_printify(unit[5]), cue_printify(unit[6]),
|
|
|
|
unit[7] == 0 ? ' ' : cue_printify(unit[7]));
|
|
|
|
} else if ((unit[0] & 0xf) == 3) {
|
|
|
|
printf(
|
|
|
|
" %1X %1X | %02X | | | | | %c%c%c%c%c%c\n",
|
|
|
|
(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
|
|
|
|
unit[1], cue_printify(unit[2]),
|
|
|
|
cue_printify(unit[3]), cue_printify(unit[4]),
|
|
|
|
cue_printify(unit[5]), cue_printify(unit[6]),
|
|
|
|
cue_printify(unit[7]));
|
|
|
|
} else {
|
|
|
|
printf(" %1X %1X | %02X | %02X | %02X | %02X |",
|
|
|
|
(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
|
|
|
|
unit[1], unit[2], unit[3], unit[4]);
|
|
|
|
printf(" %02d:%02d:%02d |\n",
|
|
|
|
unit[5], unit[6], unit[7]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* Libburn_write_with_print_cuE */
|
|
|
|
|
|
|
|
|
|
|
|
/* ts B11226 */
|
|
|
|
static int new_cue(struct cue_sheet *sheet, int number, int flag)
|
|
|
|
{
|
|
|
|
unsigned char *ptr;
|
|
|
|
|
|
|
|
ptr = realloc(sheet->data, (sheet->count + number) * 8);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Could not allocate new auxiliary object (cue_sheet->data)",
|
|
|
|
0, 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
sheet->data = ptr;
|
|
|
|
sheet->count += number;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts B11226 : outsourced new_cue() */
|
|
|
|
/** @return 1 = success , <=0 failure */
|
|
|
|
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
|
|
|
|
unsigned char tno, unsigned char indx,
|
|
|
|
unsigned char form, unsigned char scms, int lba)
|
|
|
|
{
|
|
|
|
unsigned char *unit;
|
|
|
|
int m, s, f, ret;
|
|
|
|
|
|
|
|
burn_lba_to_msf(lba, &m, &s, &f);
|
|
|
|
|
|
|
|
ret = new_cue(sheet, 1, 0);
|
|
|
|
if (ret <= 0)
|
|
|
|
return -1;
|
|
|
|
unit = sheet->data + (sheet->count - 1) * 8;
|
|
|
|
unit[0] = ctladr;
|
|
|
|
unit[1] = tno;
|
|
|
|
unit[2] = indx;
|
|
|
|
unit[3] = form;
|
|
|
|
unit[4] = scms;
|
|
|
|
unit[5] = m;
|
|
|
|
unit[6] = s;
|
|
|
|
unit[7] = f;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts B11226 */
|
|
|
|
static int add_catalog_cue(struct cue_sheet *sheet, unsigned char catalog[13])
|
|
|
|
{
|
|
|
|
unsigned char *unit;
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
ret = new_cue(sheet, 2, 0);
|
|
|
|
if (ret <= 0)
|
|
|
|
return -1;
|
|
|
|
unit = sheet->data + (sheet->count - 2) * 8;
|
|
|
|
unit[0] = unit[8] = 0x02;
|
|
|
|
for (i = 0; i < 13; i++)
|
|
|
|
unit[1 + (i >= 7) * 8 + (i % 7)] = catalog[i];
|
|
|
|
unit[15] = 0x00;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts B11226 */
|
|
|
|
static int add_isrc_cue(struct cue_sheet *sheet, unsigned char ctladr, int tno,
|
|
|
|
struct isrc *isrc)
|
|
|
|
{
|
|
|
|
unsigned char *unit;
|
|
|
|
int i, ret;
|
|
|
|
char text[8];
|
|
|
|
|
|
|
|
ret = new_cue(sheet, 2, 0);
|
|
|
|
if (ret <= 0)
|
|
|
|
return -1;
|
|
|
|
unit = sheet->data + (sheet->count - 2) * 8;
|
|
|
|
unit[0] = unit[8] = (ctladr & 0xf0) | 0x03;
|
|
|
|
unit[1] = unit[9] = tno;
|
|
|
|
unit[2] = isrc->country[0];
|
|
|
|
unit[3] = isrc->country[1];
|
|
|
|
unit[4] = isrc->owner[0];
|
|
|
|
unit[5] = isrc->owner[1];
|
|
|
|
unit[6] = isrc->owner[2];
|
|
|
|
sprintf(text, "%-2.2u%-5.5u", (unsigned int) isrc->year, isrc->serial);
|
|
|
|
unit[7] = text[0];
|
|
|
|
for (i = 1; i < 7; i++)
|
|
|
|
unit[9 + i] = text[i];
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61114: added parameter nwa */
|
|
|
|
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
|
|
|
struct burn_session *session,
|
|
|
|
int nwa)
|
|
|
|
{
|
|
|
|
int i, m, s, f, form, pform, runtime = -150, ret, track_length;
|
|
|
|
int leadin_form, leadin_start, pregap;
|
|
|
|
unsigned char ctladr, scms;
|
|
|
|
struct burn_drive *d;
|
|
|
|
struct burn_toc_entry *e;
|
|
|
|
struct cue_sheet *sheet;
|
|
|
|
struct burn_track **tar = session->track;
|
|
|
|
int ntr = session->tracks;
|
|
|
|
int rem = 0;
|
|
|
|
|
|
|
|
#define Libburn_track_multi_indeX yes
|
|
|
|
|
|
|
|
#ifdef Libburn_track_multi_indeX
|
|
|
|
int j;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d = o->drive;
|
|
|
|
|
|
|
|
#ifdef Libburn_sao_can_appenD
|
|
|
|
if (d->status == BURN_DISC_APPENDABLE)
|
|
|
|
runtime = nwa-150;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sheet = calloc(1, sizeof(struct cue_sheet));
|
|
|
|
|
|
|
|
/* ts A61009 : react on failures of calloc(), add_cue_sheet()
|
|
|
|
type_to_form() */
|
|
|
|
if (sheet == NULL) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Could not allocate new auxiliary object (cue_sheet)",
|
|
|
|
0, 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sheet->data = NULL;
|
|
|
|
sheet->count = 0;
|
|
|
|
type_to_form(tar[0]->mode, &ctladr, &form);
|
|
|
|
if (form == -1) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020116,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Track mode has unusable value", 0, 0);
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
if (o->num_text_packs > 0) {
|
|
|
|
leadin_form = 0x41;
|
|
|
|
} else {
|
|
|
|
leadin_form = 0x01;
|
|
|
|
|
|
|
|
/* Check for CD-TEXT in session. Not the final creation,
|
|
|
|
because the cue sheet content might be needed for CD-TEXT
|
|
|
|
pack type 0x88 "TOC".
|
|
|
|
*/
|
|
|
|
if (o->text_packs == NULL) {
|
|
|
|
ret = burn_cdtext_from_session(session, NULL, NULL, 1);
|
|
|
|
if (ret < 0)
|
|
|
|
goto failed;
|
|
|
|
else if (ret > 0)
|
|
|
|
leadin_form = 0x41;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (o->has_mediacatalog)
|
|
|
|
ret = add_catalog_cue(sheet, o->mediacatalog);
|
|
|
|
else if (session->mediacatalog[0])
|
|
|
|
ret = add_catalog_cue(sheet, session->mediacatalog);
|
|
|
|
else
|
|
|
|
ret = 1;
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
/* ts B11225
|
|
|
|
MMC-5 6.33.3.15 Data Form of Sub-channel
|
|
|
|
seems to indicate that for leadin_form 0x41 one should announce
|
|
|
|
d->start_lba as start of the leadin (e.g. -12490) and that data
|
|
|
|
block type should 2 or 3 with mode page 05h. But my drives refuse
|
|
|
|
on that.
|
|
|
|
It works with LBA -150 and data block type 0. Shrug.
|
|
|
|
*/
|
|
|
|
leadin_start = runtime;
|
|
|
|
ret = add_cue(sheet, (ctladr & 64) | 1, 0, 0, leadin_form, 0,
|
|
|
|
leadin_start);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
d->toc_entries = ntr + 3;
|
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(d->toc_entry == NULL); */
|
|
|
|
if (d->toc_entry != NULL) {
|
|
|
|
|
|
|
|
/* ts A61109 : this happens with appendable CDs
|
|
|
|
>>> Open question: is the existing TOC needed ? */
|
|
|
|
|
|
|
|
/* ts A61109 : for non-SAO, this sheet is thrown away later */
|
|
|
|
free((char *) d->toc_entry);
|
|
|
|
|
|
|
|
/*
|
|
|
|
libdax_msgs_submit(libdax_messenger,
|
|
|
|
d->global_index, 0x00020117,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"toc_entry of drive is already in use", 0, 0);
|
|
|
|
goto failed;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
if (session->firsttrack + ntr - 1 > 99) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x0002019b,
|
|
|
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"CD track number exceeds 99", 0, 0);
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
session->lasttrack = session->firsttrack + ntr - 1;
|
|
|
|
|
|
|
|
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
|
|
|
|
e = d->toc_entry;
|
|
|
|
e[0].point = 0xA0;
|
|
|
|
if (tar[0]->mode & BURN_AUDIO)
|
|
|
|
e[0].control = TOC_CONTROL_AUDIO;
|
|
|
|
else
|
|
|
|
e[0].control = TOC_CONTROL_DATA;
|
|
|
|
e[0].pmin = session->firsttrack;
|
|
|
|
e[0].psec = o->format;
|
|
|
|
e[0].adr = 1;
|
|
|
|
e[1].point = 0xA1;
|
|
|
|
e[1].pmin = session->lasttrack;
|
|
|
|
e[1].adr = 1;
|
|
|
|
if (tar[ntr - 1]->mode & BURN_AUDIO)
|
|
|
|
e[1].control = TOC_CONTROL_AUDIO;
|
|
|
|
else
|
|
|
|
e[1].control = TOC_CONTROL_DATA;
|
|
|
|
e[2].point = 0xA2;
|
|
|
|
e[2].control = e[1].control;
|
|
|
|
e[2].adr = 1;
|
|
|
|
|
|
|
|
/* ts A70121 : The pause before the first track is not really Pre-gap.
|
|
|
|
To count it as part 2 of a Pre-gap is a dirty hack. It also seems
|
|
|
|
to have caused confusion in dealing with part 1 of an eventual
|
|
|
|
real Pre-gap. mmc5r03c.pdf 6.33.3.2, 6.33.3.18 .
|
|
|
|
ts B20103 : It is not really Pre-gap with audio tracks.
|
|
|
|
*/
|
|
|
|
tar[0]->pregap2 = 1;
|
|
|
|
pregap = 150;
|
|
|
|
|
|
|
|
pform = form;
|
|
|
|
for (i = 0; i < ntr; i++) {
|
|
|
|
type_to_form(tar[i]->mode, &ctladr, &form);
|
|
|
|
if (tar[i]->mode & BURN_SCMS)
|
|
|
|
scms = 0x80;
|
|
|
|
else
|
|
|
|
scms = 0;
|
|
|
|
|
|
|
|
if (tar[i]->isrc.has_isrc) {
|
|
|
|
ret = add_isrc_cue(sheet, ctladr,
|
|
|
|
i + session->firsttrack, &(tar[i]->isrc));
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef Libburn_track_multi_indeX
|
|
|
|
|
|
|
|
for(j = 0; j < tar[i]->indices || j < 2; j++) {
|
|
|
|
if(tar[i]->index[j] == 0x7fffffff) {
|
|
|
|
if (j > 1)
|
|
|
|
break;
|
|
|
|
if (j == 0 && i > 0)
|
|
|
|
continue;
|
|
|
|
/* force existence of mandatory index */
|
|
|
|
tar[i]->index[j] = 0;
|
|
|
|
} else if (j == 0) {
|
|
|
|
tar[i]->index[j] = 0;
|
|
|
|
} else if (j == 1 && tar[i]->index[0] == 0x7fffffff) {
|
|
|
|
tar[i]->index[j] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == 1) {
|
|
|
|
tar[i]->entry = &e[3 + i];
|
|
|
|
e[3 + i].point = i + session->firsttrack;
|
|
|
|
burn_lba_to_msf(runtime, &m, &s, &f);
|
|
|
|
e[3 + i].pmin = m;
|
|
|
|
e[3 + i].psec = s;
|
|
|
|
e[3 + i].pframe = f;
|
|
|
|
e[3 + i].adr = 1;
|
|
|
|
e[3 + i].control = type_to_ctrl(tar[i]->mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* >>> ??? else if j == 0 && mode change to -data :
|
|
|
|
Extended pregap */;
|
|
|
|
|
|
|
|
/* >>> ??? user defined pregap ? */;
|
|
|
|
|
|
|
|
/* >>> check index with track size */;
|
|
|
|
|
|
|
|
tar[i]->index[j] += runtime;
|
|
|
|
ret = add_cue(sheet, ctladr | 1,
|
|
|
|
i + session->firsttrack, j, form, scms,
|
|
|
|
tar[i]->index[j]);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
runtime += pregap;
|
|
|
|
pregap = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* Libburn_track_multi_indeX */
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
ret = add_cue(sheet, ctladr | 1, session->firsttrack,
|
|
|
|
0, form, 0, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
runtime += 150;
|
|
|
|
} else if (pform != form) {
|
|
|
|
|
|
|
|
/* ts A70121 : This seems to be thw wrong test. Correct would
|
|
|
|
be to compare tar[]->mode or bit2 of ctladr.
|
|
|
|
*/
|
|
|
|
|
|
|
|
ret = add_cue(sheet, ctladr | 1,
|
|
|
|
i + session->firsttrack, 0, form, scms,
|
|
|
|
runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
runtime += 150;
|
|
|
|
/* XXX fix pregap interval 1 for data tracks */
|
|
|
|
/* ts A60813 silence righteous compiler warning about C++ style comments
|
|
|
|
This is possibly not a comment but rather a trace of Derek Foreman
|
|
|
|
experiments. Thus not to be beautified - but to be preserved rectified.
|
|
|
|
/ / if (!(form & BURN_AUDIO))
|
|
|
|
/ / tar[i]->pregap1 = 1;
|
|
|
|
*/
|
|
|
|
/* ts A70121 : it is unclear why (form & BURN_AUDIO) should prevent pregap1.
|
|
|
|
I believe, correct would be:
|
|
|
|
runtime += 75;
|
|
|
|
tar[i]->pregap1 = 1;
|
|
|
|
|
|
|
|
The test for pform != form is wrong anyway.
|
|
|
|
|
|
|
|
Next one has to care for Post-gap: table 555 in mmc5r03c.pdf does not
|
|
|
|
show any although 6.33.3.19 would prescribe some.
|
|
|
|
|
|
|
|
Nobody seems to have ever tested this situation, up to now.
|
|
|
|
It is banned for now in burn_disc_write().
|
|
|
|
Warning have been placed in libburn.h .
|
|
|
|
*/
|
|
|
|
|
|
|
|
tar[i]->pregap2 = 1;
|
|
|
|
}
|
|
|
|
/* XXX HERE IS WHERE WE DO INDICES IN THE CUE SHEET */
|
|
|
|
/* XXX and we should make sure the gaps conform to ecma-130... */
|
|
|
|
tar[i]->entry = &e[3 + i];
|
|
|
|
e[3 + i].point = i + session->firsttrack;
|
|
|
|
burn_lba_to_msf(runtime, &m, &s, &f);
|
|
|
|
e[3 + i].pmin = m;
|
|
|
|
e[3 + i].psec = s;
|
|
|
|
e[3 + i].pframe = f;
|
|
|
|
e[3 + i].adr = 1;
|
|
|
|
e[3 + i].control = type_to_ctrl(tar[i]->mode);
|
|
|
|
|
|
|
|
ret = add_cue(sheet, ctladr | 1, i + session->firsttrack,
|
|
|
|
1, form, scms, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
#endif /* ! Libburn_track_multi_indeX */
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70125 :
|
|
|
|
Still not understanding the sense behind linking tracks,
|
|
|
|
i decided to at least enforce the MMC specs' minimum
|
|
|
|
track length.
|
|
|
|
*/
|
|
|
|
track_length = burn_track_get_sectors(tar[i]);
|
|
|
|
if (track_length < 300 && !burn_track_is_open_ended(tar[i])) {
|
|
|
|
track_length = 300;
|
|
|
|
if (!tar[i]->pad)
|
|
|
|
tar[i]->pad = 1;
|
|
|
|
burn_track_set_sectors(tar[i], track_length);
|
|
|
|
}
|
|
|
|
runtime += track_length;
|
|
|
|
|
|
|
|
/* if we're padding, we'll clear any current shortage.
|
|
|
|
if we're not, we'll slip toc entries by a sector every time our
|
|
|
|
shortage is more than a sector
|
|
|
|
XXX this is untested :)
|
|
|
|
*/
|
|
|
|
if (!tar[i]->pad) {
|
|
|
|
rem += burn_track_get_shortage(tar[i]);
|
|
|
|
|
|
|
|
/* ts A61101 : I doubt that linking would yield a
|
|
|
|
desireable effect. With TAO it is
|
|
|
|
counterproductive in any way.
|
|
|
|
*/
|
|
|
|
if (o->write_type == BURN_WRITE_TAO)
|
|
|
|
tar[i]->source->next = NULL;
|
|
|
|
else
|
|
|
|
|
|
|
|
if (i +1 != ntr)
|
|
|
|
tar[i]->source->next = tar[i+1]->source;
|
|
|
|
} else if (rem) {
|
|
|
|
rem = 0;
|
|
|
|
runtime++;
|
|
|
|
}
|
|
|
|
if (rem > burn_sector_length(tar[i]->mode)) {
|
|
|
|
rem -= burn_sector_length(tar[i]->mode);
|
|
|
|
runtime--;
|
|
|
|
}
|
|
|
|
pform = form;
|
|
|
|
}
|
|
|
|
burn_lba_to_msf(runtime, &m, &s, &f);
|
|
|
|
e[2].pmin = m;
|
|
|
|
e[2].psec = s;
|
|
|
|
e[2].pframe = f;
|
|
|
|
ret = add_cue(sheet, ctladr | 1, 0xAA, 1, 1, 0, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
return sheet;
|
|
|
|
|
|
|
|
failed:;
|
|
|
|
if (sheet != NULL)
|
|
|
|
free((char *) sheet);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_sector_length(int tracktype)
|
|
|
|
{
|
|
|
|
if (tracktype & BURN_AUDIO)
|
|
|
|
return 2352;
|
|
|
|
if (tracktype & BURN_MODE_RAW)
|
|
|
|
return 2352;
|
|
|
|
if (tracktype & BURN_MODE1)
|
|
|
|
return 2048;
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(0); */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_subcode_length(int tracktype)
|
|
|
|
{
|
|
|
|
if (tracktype & BURN_SUBCODE_P16)
|
|
|
|
return 16;
|
|
|
|
if ((tracktype & BURN_SUBCODE_P96) || (tracktype & BURN_SUBCODE_R96))
|
|
|
|
return 96;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_leadin(struct burn_write_opts *o,
|
|
|
|
struct burn_session *s, int first)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
d->busy = BURN_DRIVE_WRITING_LEADIN;
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
count = 0 - d->alba - 150;
|
|
|
|
else
|
|
|
|
count = 4500;
|
|
|
|
|
|
|
|
d->progress.start_sector = d->alba;
|
|
|
|
d->progress.sectors = count;
|
|
|
|
d->progress.sector = 0;
|
|
|
|
|
|
|
|
while (count != 0) {
|
|
|
|
if (!sector_toc(o, s->track[0]->mode))
|
|
|
|
return 0;
|
|
|
|
count--;
|
|
|
|
d->progress.sector++;
|
|
|
|
}
|
|
|
|
d->busy = BURN_DRIVE_WRITING;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_leadout(struct burn_write_opts *o,
|
|
|
|
int first, unsigned char control, int mode)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
d->busy = BURN_DRIVE_WRITING_LEADOUT;
|
|
|
|
|
|
|
|
d->rlba = -150;
|
|
|
|
if (first)
|
|
|
|
count = 6750;
|
|
|
|
else
|
|
|
|
count = 2250;
|
|
|
|
d->progress.start_sector = d->alba;
|
|
|
|
d->progress.sectors = count;
|
|
|
|
d->progress.sector = 0;
|
|
|
|
|
|
|
|
while (count != 0) {
|
|
|
|
if (!sector_lout(o, control, mode))
|
|
|
|
return 0;
|
|
|
|
count--;
|
|
|
|
d->progress.sector++;
|
|
|
|
}
|
|
|
|
d->busy = BURN_DRIVE_WRITING;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int burn_create_text_packs(struct burn_write_opts *o,
|
|
|
|
struct burn_session *s,
|
|
|
|
int flag)
|
|
|
|
{
|
|
|
|
int ret, num_packs = 0;
|
|
|
|
unsigned char *text_packs = NULL;
|
|
|
|
|
|
|
|
ret = burn_cdtext_from_session(s, &text_packs, &num_packs, 0);
|
|
|
|
if (ret > 0) {
|
|
|
|
if (o->text_packs != NULL)
|
|
|
|
free(o->text_packs);
|
|
|
|
o->text_packs = text_packs;
|
|
|
|
o->num_text_packs = num_packs;
|
|
|
|
}
|
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int burn_write_leadin_cdtext(struct burn_write_opts *o,
|
|
|
|
struct burn_session *s, int flag)
|
|
|
|
{
|
|
|
|
int ret, i, j, si, lba, sub_cursor = 0, err, write_lba, sectors = 0;
|
|
|
|
int self_made_text_packs = 0;
|
|
|
|
unsigned char *subdata = NULL;
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
struct buffer *buf = NULL;
|
|
|
|
enum burn_drive_status was_busy = o->drive->busy;
|
|
|
|
#ifdef Libburn_debug_cd_texT
|
|
|
|
unsigned char *packs;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (o->num_text_packs <= 0) {
|
|
|
|
if (o->text_packs != NULL)
|
|
|
|
{ret = 1; goto ex;}
|
|
|
|
/* Try to create CD-TEXT from .cdtext_* of session and track */
|
|