summaryrefslogtreecommitdiff
path: root/wodim/cue.c
diff options
context:
space:
mode:
Diffstat (limited to 'wodim/cue.c')
-rw-r--r--wodim/cue.c1198
1 files changed, 1198 insertions, 0 deletions
diff --git a/wodim/cue.c b/wodim/cue.c
new file mode 100644
index 0000000..0eb88b3
--- /dev/null
+++ b/wodim/cue.c
@@ -0,0 +1,1198 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)cue.c 1.20 04/03/02 Copyright 2001-2004 J. Schilling */
+/*
+ * Cue sheet parser
+ *
+ * Copyright (c) 2001-2004 J. Schilling
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <mconfig.h>
+#include <stdio.h>
+#include <stdxlib.h>
+#include <unixstd.h>
+#include <standard.h>
+#include <fctldefs.h>
+#include <statdefs.h>
+#include <vadefs.h>
+#include <schily.h>
+#include <strdefs.h>
+#include <utypes.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "xio.h"
+#include "cdtext.h"
+#include "wodim.h"
+#include "auheader.h"
+#include "libport.h"
+
+typedef struct state {
+ char *filename;
+ void *xfp;
+ Llong trackoff;
+ Llong filesize;
+ int filetype;
+ int tracktype;
+ int sectype;
+ int dbtype;
+ int secsize;
+ int dataoff;
+ int state;
+ int track;
+ int index;
+ long index0;
+ long index1; /* Current index 1 value */
+ long secoff; /* Old index 1 value */
+ long pregapsize;
+ long postgapsize;
+ int flags;
+} state_t;
+
+static char linebuf[4096];
+static char *fname;
+static char *linep;
+static char *wordendp;
+static char wordendc;
+static int olinelen;
+static int linelen;
+static int lineno;
+
+static char worddelim[] = "=:,/";
+static char nulldelim[] = "";
+
+#define STATE_NONE 0
+#define STATE_POSTGAP 1
+#define STATE_TRACK 2
+#define STATE_FLAGS 3
+#define STATE_INDEX0 4
+#define STATE_INDEX1 5
+
+typedef struct keyw {
+ char *k_name;
+ int k_type;
+} keyw_t;
+
+/*
+ * Keywords (first word on line):
+ * CATALOG - global CATALOG <MCN>
+ * CDTEXTFILE - global CDTEXTFILE <fname>
+ * FILE - track static FILE <fame> <type>
+ * FLAGS - track static FLAGS <flag> ...
+ * INDEX - track static INDEX <#> <mm:ss:ff>
+ * ISRC - track static ISRC <ISRC>
+ * PERFORMER - global/static PERFORMER <string>
+ * POSTGAP - track locak POSTGAP <mm:ss:ff>
+ * PREGAP - track static PREGAP <mm:ss:ff>
+ * REM - anywhere REM <comment>
+ * SONGWRITER - global/static SONGWRITER <string>
+ * TITLE - global/static TITLE <string>
+ * TRACK - track static TRACK <#> <datatype>
+ *
+ * Order of keywords:
+ * CATALOG
+ * CDTEXTFILE
+ * PERFORMER | SONGWRITER | TITLE Doc says past FILE...
+ * FILE Must be past CATALOG
+ * ------- Repeat the following: mehrere FILE Commands?
+ * TRACK
+ * FLAGS | ISRC | PERFORMER | PREGAP | SONGWRITER | TITLE
+ * INDEX
+ * POSTGAP
+ */
+
+#define K_G 0x10000 /* Global */
+#define K_T 0x20000 /* Track static */
+#define K_A (K_T | K_G) /* Global & Track static */
+
+#define K_MCN (0 | K_G) /* Media catalog number */
+#define K_TEXTFILE (1 | K_G) /* CD-Text binary file */
+#define K_FILE (2 | K_T) /* Input data file */
+#define K_FLAGS (3 | K_T) /* Flags for ctrl nibble */
+#define K_INDEX (4 | K_T) /* Index marker for track */
+#define K_ISRC (5 | K_T) /* ISRC string for track */
+#define K_PERFORMER (6 | K_A) /* CD-Text Performer */
+#define K_POSTGAP (7 | K_T) /* Post gap for track (autogen) */
+#define K_PREGAP (8 | K_T) /* Pre gap for track (autogen) */
+#define K_REM (9 | K_A) /* Remark (Comment) */
+#define K_SONGWRITER (10| K_A) /* CD-Text Songwriter */
+#define K_TITLE (11| K_A) /* CD-Text Title */
+#define K_TRACK (12| K_T) /* Track marker */
+
+
+static keyw_t keywords[] = {
+ { "CATALOG", K_MCN },
+ { "CDTEXTFILE", K_TEXTFILE },
+ { "FILE", K_FILE },
+ { "FLAGS", K_FLAGS },
+ { "INDEX", K_INDEX },
+ { "ISRC", K_ISRC },
+ { "PERFORMER", K_PERFORMER },
+ { "POSTGAP", K_POSTGAP },
+ { "PREGAP", K_PREGAP },
+ { "REM", K_REM },
+ { "SONGWRITER", K_SONGWRITER },
+ { "TITLE", K_TITLE },
+ { "TRACK", K_TRACK },
+ { NULL, 0 },
+};
+
+
+/*
+ * Filetypes - argument to FILE Keyword (one only):
+ *
+ * BINARY - Intel binary file (least significant byte first)
+ * MOTOTOLA - Motorola binary file (most significant byte first)
+ * AIFF - Audio AIFF file
+ * AU - Sun Audio file
+ * WAVE - Audio WAVE file
+ * MP3 - Audio MP3 file
+ */
+#define K_BINARY 100
+#define K_MOTOROLA 101
+#define K_AIFF 102
+#define K_AU 103
+#define K_WAVE 104
+#define K_MP3 105
+#define K_OGG 106
+
+static keyw_t filetypes[] = {
+ { "BINARY", K_BINARY },
+ { "MOTOROLA", K_MOTOROLA },
+ { "AIFF", K_AIFF },
+ { "AU", K_AU },
+ { "WAVE", K_WAVE },
+ { "MP3", K_MP3 },
+ { "OGG", K_OGG },
+ { NULL, 0 },
+};
+
+/*
+ * Flags - argument to FLAGS Keyword (more than one allowed):
+ * DCP - Digital copy permitted
+ * 4CH - Four channel audio
+ * PRE - Pre-emphasis enabled (audio tracks only)
+ * SCMS - Serial copy management system (not supported by all recorders)
+ */
+#define K_DCP 1000
+#define K_4CH 1001
+#define K_PRE 1002
+#define K_SCMS 1003
+
+static keyw_t flags[] = {
+ { "DCP", K_DCP },
+ { "4CH", K_4CH },
+ { "PRE", K_PRE },
+ { "SCMS", K_SCMS },
+ { NULL, 0 },
+};
+
+/*
+ * Datatypes - argument to TRACK Keyword (one only):
+ * AUDIO - Audio/Music (2352)
+ * CDG - Karaoke CD+G (2448)
+ * MODE1/2048 - CDROM Mode1 Data (cooked)
+ * MODE1/2352 - CDROM Mode1 Data (raw)
+ * MODE2/2336 - CDROM-XA Mode2 Data
+ * MODE2/2352 - CDROM-XA Mode2 Data
+ * CDI/2336 - CDI Mode2 Data
+ * CDI/2352 - CDI Mode2 Data
+ */
+#define K_AUDIO 10000
+#define K_CDG 10001
+#define K_MODE1 10002
+#define K_MODE2 10003
+#define K_CDI 10004
+
+static keyw_t dtypes[] = {
+ { "AUDIO", K_AUDIO },
+ { "CDG", K_CDG },
+ { "MODE1", K_MODE1 },
+ { "MODE2", K_MODE2 },
+ { "CDI", K_CDI },
+ { NULL, 0 },
+};
+
+
+int parsecue(char *cuefname, track_t trackp[]);
+void fparsecue(FILE *f, track_t trackp[]);
+static void parse_mcn(track_t trackp[], state_t *sp);
+static void parse_textfile(track_t trackp[], state_t *sp);
+static void parse_file(track_t trackp[], state_t *sp);
+static void parse_flags(track_t trackp[], state_t *sp);
+static void parse_index(track_t trackp[], state_t *sp);
+static void parse_isrc(track_t trackp[], state_t *sp);
+static void parse_performer(track_t trackp[], state_t *sp);
+static void parse_postgap(track_t trackp[], state_t *sp);
+static void parse_pregap(track_t trackp[], state_t *sp);
+static void parse_songwriter(track_t trackp[], state_t *sp);
+static void parse_title(track_t trackp[], state_t *sp);
+static void parse_track(track_t trackp[], state_t *sp);
+static void parse_offset(long *lp);
+static void newtrack(track_t trackp[], state_t *sp);
+
+static keyw_t *lookup(char *word, keyw_t table[]);
+static void wdebug(void);
+static FILE *cueopen(char *name);
+static char *cuename(void);
+static char *nextline(FILE *f);
+static void ungetline(void);
+static char *skipwhite(const char *s);
+static char *peekword(void);
+static char *lineend(void);
+static char *markword(char *delim);
+static char *getnextitem(char *delim);
+static char *neednextitem(char *delim);
+static char *nextword(void);
+static char *needword(void);
+static char *curword(void);
+static char *nextitem(void);
+static char *needitem(void);
+static void checkextra(void);
+static void cueabort(const char *fmt, ...);
+
+#ifdef CUE_MAIN
+int debug;
+int xdebug = 1;
+
+int write_secs(void);
+int write_secs() { return (-1); }
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ track_t track[MAX_TRACK+2]; /* Max tracks + track 0 + track AA */
+
+ save_args(argc, argv);
+
+ fillbytes(track, sizeof (track), '\0');
+ for (i = 0; i < MAX_TRACK+2; i++)
+ track[i].track = track[i].trackno = i;
+ track[0].tracktype = TOC_MASK;
+
+
+ parsecue(argv[1], track);
+ return (0);
+}
+#else
+extern int xdebug;
+#endif
+
+int
+parsecue(char *cuefname, track_t trackp[])
+{
+ FILE *f = cueopen(cuefname);
+
+ fparsecue(f, trackp);
+ return (0);
+}
+
+void
+fparsecue(FILE *f, track_t trackp[])
+{
+ char *word;
+ struct keyw *kp;
+ BOOL isglobal = TRUE;
+ state_t state;
+
+ state.filename = NULL;
+ state.xfp = NULL;
+ state.trackoff = 0;
+ state.filesize = 0;
+ state.filetype = 0;
+ state.tracktype = 0;
+ state.sectype = 0;
+ state.dbtype = 0;
+ state.secsize = 0;
+ state.dataoff = 0;
+ state.state = STATE_NONE;
+ state.track = 0;
+ state.index = -1;
+ state.index0 = -1;
+ state.index1 = -1;
+ state.secoff = 0;
+ state.pregapsize = -1;
+ state.postgapsize = -1;
+ state.flags = 0;
+
+ if (xdebug > 1)
+ printf("---> Entering CUE Parser...\n");
+ do {
+ if (nextline(f) == NULL) {
+ /*
+ * EOF on CUE File
+ * Do post processing here
+ */
+ if (state.state < STATE_INDEX1)
+ cueabort("Incomplete CUE file");
+ if (state.xfp)
+ xclose(state.xfp);
+ if (xdebug > 1) {
+ printf("---> CUE Parser got EOF, found %d tracks.\n",
+ state.track);
+ }
+ return;
+ }
+ word = nextitem();
+ if (*word == '\0') /* empty line */
+ continue;
+
+ if (xdebug > 1)
+ printf("\nKEY: '%s' %s\n", word, peekword());
+ kp = lookup(word, keywords);
+ if (kp == NULL)
+ cueabort("Unknown CUE keyword '%s'", word);
+
+ if ((kp->k_type & K_G) == 0) {
+ if (isglobal)
+ isglobal = FALSE;
+ }
+ if ((kp->k_type & K_T) == 0) {
+ if (!isglobal)
+ cueabort("Badly placed CUE keyword '%s'", word);
+ }
+/* printf("%s-", isglobal ? "G" : "T");*/
+/* wdebug();*/
+
+ switch (kp->k_type) {
+
+ case K_MCN: parse_mcn(trackp, &state); break;
+ case K_TEXTFILE: parse_textfile(trackp, &state); break;
+ case K_FILE: parse_file(trackp, &state); break;
+ case K_FLAGS: parse_flags(trackp, &state); break;
+ case K_INDEX: parse_index(trackp, &state); break;
+ case K_ISRC: parse_isrc(trackp, &state); break;
+ case K_PERFORMER: parse_performer(trackp, &state); break;
+ case K_POSTGAP: parse_postgap(trackp, &state); break;
+ case K_PREGAP: parse_pregap(trackp, &state); break;
+ case K_REM: break;
+ case K_SONGWRITER: parse_songwriter(trackp, &state); break;
+ case K_TITLE: parse_title(trackp, &state); break;
+ case K_TRACK: parse_track(trackp, &state); break;
+
+ default:
+ cueabort("Panic: unknown CUE command '%s'", word);
+ }
+ } while (1);
+}
+
+static void
+parse_mcn(track_t trackp[], state_t *sp)
+{
+ char *word;
+ textptr_t *txp;
+
+ if (sp->track != 0)
+ cueabort("CATALOG keyword must be before first TRACK");
+
+ word = needitem();
+ setmcn(word, &trackp[0]);
+ txp = gettextptr(0, trackp); /* MCN is isrc for trk 0 */
+ txp->tc_isrc = strdup(word);
+
+ checkextra();
+}
+
+static void
+parse_textfile(track_t trackp[], state_t *sp)
+{
+ char *word;
+
+ if (sp->track != 0)
+ cueabort("CDTEXTFILE keyword must be before first TRACK");
+
+ word = needitem();
+
+ if (trackp[MAX_TRACK+1].flags & TI_TEXT) {
+ if (!checktextfile(word)) {
+ comerrno(EX_BAD,
+ "Cannot use '%s' as CD-Text file.\n",
+ word);
+ }
+ trackp[0].flags |= TI_TEXT;
+ } else {
+ errmsgno(EX_BAD, "Ignoring CDTEXTFILE '%s'.\n", word);
+ errmsgno(EX_BAD, "If you like to write CD-Text, call wodim -text.\n");
+ }
+
+ checkextra();
+}
+
+static void
+parse_file(track_t trackp[], state_t *sp)
+{
+ char cname[1024];
+ char newname[1024];
+ struct keyw *kp;
+ char *word;
+ char *filetype;
+ struct stat st;
+#ifdef hint
+ Llong lsize;
+#endif
+
+ if (sp->filename != NULL)
+ cueabort("Only one FILE allowed");
+
+ word = needitem();
+ if (sp->xfp)
+ xclose(sp->xfp);
+ sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0);
+ if (sp->xfp == NULL && geterrno() == ENOENT) {
+ char *p;
+
+ if (strchr(word, '/') == 0 &&
+ strchr(cuename(), '/') != 0) {
+ snprintf(cname, sizeof (cname),
+ "%s", cuename());
+ p = strrchr(cname, '/');
+ if (p)
+ *p = '\0';
+ snprintf(newname, sizeof (newname),
+ "%s/%s", cname, word);
+ word = newname;
+ sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0);
+ }
+ }
+ if (sp->xfp == NULL)
+ comerr("Cannot open FILE '%s'.\n", word);
+
+ sp->filename = strdup(word);
+ sp->trackoff = 0;
+ sp->filesize = 0;
+ sp->flags &= ~TI_SWAB; /* Reset what we might set for FILE */
+
+ filetype = needitem();
+ kp = lookup(filetype, filetypes);
+ if (kp == NULL)
+ cueabort("Unknown filetype '%s'", filetype);
+
+ switch (kp->k_type) {
+
+ case K_BINARY:
+ case K_MOTOROLA:
+ if (fstat(xfileno(sp->xfp), &st) >= 0 &&
+ S_ISREG(st.st_mode)) {
+ sp->filesize = st.st_size;
+ } else {
+ cueabort("Unknown file size for FILE '%s'",
+ sp->filename);
+ }
+ break;
+ case K_AIFF:
+ cueabort("Unsupported filetype '%s'", kp->k_name);
+ break;
+ case K_AU:
+ sp->filesize = ausize(xfileno(sp->xfp));
+ break;
+ case K_WAVE:
+ sp->filesize = wavsize(xfileno(sp->xfp));
+ sp->flags |= TI_SWAB;
+ break;
+ case K_MP3:
+ case K_OGG:
+ cueabort("Unsupported filetype '%s'", kp->k_name);
+ break;
+
+ default: cueabort("Panic: unknown filetype '%s'", filetype);
+ }
+
+ if (sp->filesize == AU_BAD_CODING) {
+ cueabort("Inappropriate audio coding in '%s'",
+ sp->filename);
+ }
+ if (xdebug > 0)
+ printf("Track %d File '%s' Filesize %lld\n",
+ sp->track, sp->filename, sp->filesize);
+
+ sp->filetype = kp->k_type;
+
+ checkextra();
+
+
+#ifdef hint
+ trackp->itracksize = lsize;
+ if (trackp->itracksize != lsize)
+ comerrno(EX_BAD, "This OS cannot handle large audio images.\n");
+#endif
+}
+
+static void
+parse_flags(track_t trackp[], state_t *sp)
+{
+ struct keyw *kp;
+ char *word;
+
+ if ((sp->state < STATE_TRACK) ||
+ (sp->state >= STATE_INDEX0))
+ cueabort("Badly placed FLAGS keyword");
+ sp->state = STATE_FLAGS;
+
+ do {
+ word = needitem();
+ kp = lookup(word, flags);
+ if (kp == NULL)
+ cueabort("Unknown flag '%s'", word);
+
+ switch (kp->k_type) {
+
+ case K_DCP: sp->flags |= TI_COPY; break;
+ case K_4CH: sp->flags |= TI_QUADRO; break;
+ case K_PRE: sp->flags |= TI_PREEMP; break;
+ case K_SCMS: sp->flags |= TI_SCMS; break;
+ default: cueabort("Panic: unknown FLAG '%s'", word);
+ }
+
+ } while (peekword() < lineend());
+
+ if (xdebug > 0)
+ printf("Track %d flags 0x%08X\n", sp->track, sp->flags);
+}
+
+static void
+parse_index(track_t trackp[], state_t *sp)
+{
+ char *word;
+ long l;
+ int track = sp->track;
+
+ if (sp->state < STATE_TRACK)
+ cueabort("Badly placed INDEX keyword");
+
+
+ word = needitem();
+ if (*astolb(word, &l, 10) != '\0')
+ cueabort("Not a number '%s'", word);
+ if (l < 0 || l > 99)
+ cueabort("Illegal index '%s'", word);
+
+ if ((sp->index < l) &&
+ (((sp->index + 1) == l) || l == 1))
+ sp->index = l;
+ else
+ cueabort("Badly placed INDEX %ld number", l);
+
+ if (l > 0)
+ sp->state = STATE_INDEX1;
+ else
+ sp->state = STATE_INDEX0;
+
+ parse_offset(&l);
+
+ if (xdebug > 1)
+ printf("Track %d Index %d %ld\n", sp->track, sp->index, l);
+
+ if (sp->index == 0)
+ sp->index0 = l;
+ if (sp->index == 1) {
+ sp->index1 = l;
+ trackp[track].nindex = 1;
+ newtrack(trackp, sp);
+
+ if (xdebug > 1) {
+ printf("Track %d pregapsize %ld\n",
+ sp->track, trackp[track].pregapsize);
+ }
+ }
+ if (sp->index == 2) {
+ trackp[track].tindex = malloc(100*sizeof (long));
+ trackp[track].tindex[1] = 0;
+ trackp[track].tindex[2] = l - sp->index1;
+ trackp[track].nindex = 2;
+ }
+ if (sp->index > 2) {
+ trackp[track].tindex[sp->index] = l - sp->index1;
+ trackp[track].nindex = sp->index;
+ }
+
+ checkextra();
+}
+
+static void
+parse_isrc(track_t trackp[], state_t *sp)
+{
+ char *word;
+ textptr_t *txp;
+ int track = sp->track;
+
+ if (track == 0)
+ cueabort("ISRC keyword must be past first TRACK");
+
+ if ((sp->state < STATE_TRACK) ||
+ (sp->state >= STATE_INDEX0))
+ cueabort("Badly placed ISRC keyword");
+ sp->state = STATE_FLAGS;
+
+ word = needitem();
+ setisrc(word, &trackp[track]);
+ txp = gettextptr(track, trackp);
+ txp->tc_isrc = strdup(word);
+
+ checkextra();
+}
+
+static void
+parse_performer(track_t trackp[], state_t *sp)
+{
+ char *word;
+ textptr_t *txp;
+
+ word = needitem();
+ txp = gettextptr(sp->track, trackp);
+ txp->tc_performer = strdup(word);
+
+ checkextra();
+}
+
+static void
+parse_postgap(track_t trackp[], state_t *sp)
+{
+ long l;
+
+ if (sp->state < STATE_INDEX1)
+ cueabort("Badly placed POSTGAP keyword");
+ sp->state = STATE_POSTGAP;
+
+ parse_offset(&l);
+ sp->postgapsize = l;
+
+ checkextra();
+}
+
+static void
+parse_pregap(track_t trackp[], state_t *sp)
+{
+ long l;
+
+ if ((sp->state < STATE_TRACK) ||
+ (sp->state >= STATE_INDEX0))
+ cueabort("Badly placed PREGAP keyword");
+ sp->state = STATE_FLAGS;
+
+ parse_offset(&l);
+ sp->pregapsize = l;
+
+ checkextra();
+}
+
+static void
+parse_songwriter(track_t trackp[], state_t *sp)
+{
+ char *word;
+ textptr_t *txp;
+
+ word = needitem();
+ txp = gettextptr(sp->track, trackp);
+ txp->tc_songwriter = strdup(word);
+
+ checkextra();
+}
+
+static void
+parse_title(track_t trackp[], state_t *sp)
+{
+ char *word;
+ textptr_t *txp;
+
+ word = needitem();
+ txp = gettextptr(sp->track, trackp);
+ txp->tc_title = strdup(word);
+
+ checkextra();
+}
+
+static void
+parse_track(track_t trackp[], state_t *sp)
+{
+ struct keyw *kp;
+ char *word;
+ long l;
+ long secsize = -1;
+
+ if ((sp->state >= STATE_TRACK) &&
+ (sp->state < STATE_INDEX1))
+ cueabort("Badly placed TRACK keyword");
+ sp->state = STATE_TRACK;
+ sp->index = -1;
+
+ word = needitem();
+ if (*astolb(word, &l, 10) != '\0')
+ cueabort("Not a number '%s'", word);
+ if (l <= 0 || l > 99)
+ cueabort("Illegal TRACK number '%s'", word);
+
+ if ((sp->track < l) &&
+ (((sp->track + 1) == l) || sp->track == 0))
+ sp->track = l;
+ else
+ cueabort("Badly placed TRACK %ld number", l);
+
+ word = needword();
+ kp = lookup(word, dtypes);
+ if (kp == NULL)
+ cueabort("Unknown filetype '%s'", word);
+
+ if (wordendc == '/') {
+ word = needitem();
+ if (*astol(++word, &secsize) != '\0')
+ cueabort("Not a number '%s'", word);
+ }
+
+ /*
+ * Reset all flags that may be set in TRACK & FLAGS lines
+ */
+ sp->flags &= ~(TI_AUDIO|TI_COPY|TI_QUADRO|TI_PREEMP|TI_SCMS);
+
+ if (kp->k_type == K_AUDIO)
+ sp->flags |= TI_AUDIO;
+
+ switch (kp->k_type) {
+
+ case K_CDG:
+ if (secsize < 0)
+ secsize = 2448;
+ case K_AUDIO:
+ if (secsize < 0)
+ secsize = 2352;
+
+ sp->tracktype = TOC_DA;
+ sp->sectype = SECT_AUDIO;
+ sp->dbtype = DB_RAW;
+ sp->secsize = secsize;
+ sp->dataoff = 0;
+ if (secsize != 2352)
+ cueabort("Unsupported sector size %ld for audio", secsize);
+ break;
+
+ case K_MODE1:
+ if (secsize < 0)
+ secsize = 2048;
+
+ sp->tracktype = TOC_ROM;
+ sp->sectype = SECT_ROM;
+ sp->dbtype = DB_ROM_MODE1;
+ sp->secsize = secsize;
+ sp->dataoff = 16;
+ /*
+ * XXX Sector Size == 2352 ???
+ * XXX It seems that there exist bin/cue pairs with this value
+ */
+ if (secsize != 2048)
+ cueabort("Unsupported sector size %ld for data", secsize);
+ break;
+
+ case K_MODE2:
+ case K_CDI:
+ sp->tracktype = TOC_ROM;
+ sp->sectype = SECT_MODE_2;
+ sp->dbtype = DB_ROM_MODE2;
+ sp->secsize = secsize;
+ sp->dataoff = 16;
+ if (secsize == 2352) {
+ sp->tracktype = TOC_XA2;
+ sp->sectype = SECT_MODE_2_MIX;
+ sp->sectype |= ST_MODE_RAW;
+ sp->dbtype = DB_RAW;
+ sp->dataoff = 0;
+ } else if (secsize != 2336)
+ cueabort("Unsupported sector size %ld for mode2", secsize);
+ if (kp->k_type == K_CDI)
+ sp->tracktype = TOC_CDI;
+ break;
+
+ default: cueabort("Panic: unknown datatype '%s'", word);
+ }
+
+ if (sp->flags & TI_PREEMP)
+ sp->sectype |= ST_PREEMPMASK;
+ sp->secsize = secsize;
+
+ if (xdebug > 1) {
+ printf("Track %d Tracktype %s/%d\n",
+ sp->track, kp->k_name, sp->secsize);
+ }
+
+ checkextra();
+}
+
+static void
+parse_offset(long *lp)
+{
+ char *word;
+ char *p;
+ long m = -1;
+ long s = -1;
+ long f = -1;
+
+ word = needitem();
+
+ if (strchr(word, ':') == NULL) {
+ if (*astol(word, lp) != '\0')
+ cueabort("Not a number '%s'", word);
+ return;
+ }
+ if (*(p = astolb(word, &m, 10)) != ':')
+ cueabort("Not a number '%s'", word);
+ if (m < 0 || m >= 160)
+ cueabort("Illegal minute value in '%s'", word);
+ p++;
+ if (*(p = astolb(p, &s, 10)) != ':')
+ cueabort("Not a number '%s'", p);
+ if (s < 0 || s >= 60)
+ cueabort("Illegal second value in '%s'", word);
+ p++;
+ if (*(p = astolb(p, &f, 10)) != '\0')
+ cueabort("Not a number '%s'", p);
+ if (f < 0 || f >= 75)
+ cueabort("Illegal frame value in '%s'", word);
+
+ m = m * 60 + s;
+ m = m * 75 + f;
+ *lp = m;
+}
+
+/*--------------------------------------------------------------------------*/
+static void
+newtrack(track_t trackp[], state_t *sp)
+{
+ register int i;
+ register int track = sp->track;
+ Llong tracksize;
+
+ if (xdebug > 1)
+ printf("-->Newtrack %d\n", track);
+ if (track > 1) {
+ tracksize = (sp->index1 - sp->secoff) * trackp[track-1].secsize;
+
+ if (xdebug > 1)
+ printf(" trackoff %lld filesize %lld index1 %ld size %ld/%lld\n",
+ sp->trackoff, sp->filesize, sp->index1,
+ sp->index1 - sp->secoff,
+ tracksize);
+
+ trackp[track-1].itracksize = tracksize;
+ trackp[track-1].tracksize = tracksize;
+ trackp[track-1].tracksecs = sp->index1 - sp->secoff;
+
+ sp->trackoff += tracksize;
+ sp->secoff = sp->index1;
+ }
+ /*
+ * Make 'tracks' immediately usable in track structure.
+ */
+ for (i = 0; i < MAX_TRACK+2; i++)
+ trackp[i].tracks = track;
+
+ trackp[track].filename = sp->filename;
+ trackp[track].xfp = xopen(sp->filename, O_RDONLY|O_BINARY, 0);
+ trackp[track].trackstart = 0L;
+/*
+SEtzen wenn tracksecs bekannt sind
+d.h. mit Index0 oder Index 1 vom nächsten track
+
+ trackp[track].itracksize = tracksize;
+ trackp[track].tracksize = tracksize;
+ trackp[track].tracksecs = -1L;
+*/
+ tracksize = sp->filesize - sp->trackoff;
+
+ trackp[track].itracksize = tracksize;
+ trackp[track].tracksize = tracksize;
+ trackp[track].tracksecs = (tracksize + sp->secsize - 1) / sp->secsize;
+
+ if (xdebug > 1)
+ printf(" Remaining Filesize %lld (%lld secs)\n",
+ (sp->filesize-sp->trackoff),
+ (sp->filesize-sp->trackoff +sp->secsize - 1) / sp->secsize);
+
+ if (sp->pregapsize >= 0) {
+/* trackp[track].flags &= ~TI_PREGAP;*/
+ sp->flags &= ~TI_PREGAP;
+ trackp[track].pregapsize = sp->pregapsize;
+ } else {
+/* trackp[track].flags |= TI_PREGAP;*/
+ if (track > 1)
+ sp->flags |= TI_PREGAP;
+ if (track == 1)
+ trackp[track].pregapsize = sp->index1 + 150;
+ else if (sp->index0 < 0)
+ trackp[track].pregapsize = -1;
+ else
+ trackp[track].pregapsize = sp->index1 - sp->index0;
+ }
+/* trackp[track].padsecs = xxx*/
+
+ trackp[track].isecsize = sp->secsize;
+ trackp[track].secsize = sp->secsize;
+ trackp[track].flags = sp->flags | trackp[0].flags;
+
+ trackp[track].secspt = 0; /* transfer size is set up in set_trsizes() */
+/* trackp[track].pktsize = pktsize; */
+ trackp[track].pktsize = 0;
+ trackp[track].trackno = sp->track;
+ trackp[track].sectype = sp->sectype;
+
+ trackp[track].dataoff = sp->dataoff;
+ trackp[track].tracktype = sp->tracktype;
+ trackp[track].dbtype = sp->dbtype;
+
+ if (track == 1) {
+ trackp[0].tracktype &= ~TOC_MASK;
+ trackp[0].tracktype |= sp->tracktype;
+
+ if (xdebug > 1) {
+ printf("Track %d Tracktype %X\n",
+ 0, trackp[0].tracktype);
+ }
+ }
+ if (xdebug > 1) {
+ printf("Track %d Tracktype %X\n",
+ track, trackp[track].tracktype);
+ }
+ trackp[track].nindex = 1;
+ trackp[track].tindex = 0;
+
+ if (xdebug > 1) {
+ printf("Track %d flags 0x%08X\n", 0, trackp[0].flags);
+ printf("Track %d flags 0x%08X\n", track, trackp[track].flags);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+static keyw_t *
+lookup(char *word, keyw_t table[])
+{
+ register keyw_t *kp = table;
+
+ while (kp->k_name) {
+ if (streql(kp->k_name, word))
+ return (kp);
+ kp++;
+ }
+ return (NULL);
+}
+
+/*--------------------------------------------------------------------------*/
+/*
+ * Parser low level functions start here...
+ */
+
+static void
+wdebug()
+{
+/* printf("WORD: '%s' rest '%s'\n", word, peekword());*/
+ printf("WORD: '%s' rest '%s'\n", linep, peekword());
+ printf("linep %lX peekword %lX end %lX\n",
+ (long)linep, (long)peekword(), (long)&linebuf[linelen]);
+}
+
+static FILE *
+cueopen(char *name)
+{
+ FILE *f;
+
+ f = fileopen(name, "r");
+ if (f == NULL)
+ comerr("Cannot open '%s'.\n", name);
+
+ fname = name;
+ return (f);
+}
+
+static char *
+cuename()
+{
+ return (fname);
+}
+
+static char *
+nextline(FILE *f)
+{
+ register int len;
+
+ do {
+ fillbytes(linebuf, sizeof (linebuf), '\0');
+ len = rols_fgetline(f, linebuf, sizeof (linebuf));
+ if (len < 0)
+ return (NULL);
+ if (len > 0 && linebuf[len-1] == '\r') {
+ linebuf[len-1] = '\0';
+ len--;
+ }
+ linelen = len;
+ lineno++;
+ } while (linebuf[0] == '#');
+
+ olinelen = linelen;
+ linep = linebuf;
+ wordendp = linep;
+ wordendc = *linep;
+
+ return (linep);
+}
+
+static void
+ungetline()
+{
+ linelen = olinelen;
+ linep = linebuf;
+ *wordendp = wordendc;
+ wordendp = linep;
+ wordendc = *linep;
+}
+
+static char *
+skipwhite(const char *s)
+{
+ register const Uchar *p = (const Uchar *)s;
+
+ while (*p) {
+ if (!isspace(*p))
+ break;
+ p++;
+ }
+ return ((char *)p);
+}
+
+static char *
+peekword()
+{
+ return (&wordendp[1]);
+}
+
+static char *
+lineend()
+{
+ return (&linebuf[linelen]);
+}
+
+static char *
+markword(char *delim)
+{
+ register BOOL quoted = FALSE;
+ register Uchar c;
+ register Uchar *s;
+ register Uchar *from;
+ register Uchar *to;
+
+ for (s = (Uchar *)linep; (c = *s) != '\0'; s++) {
+ if (c == '"') {
+ quoted = !quoted;
+/* strcpy((char *)s, (char *)&s[1]);*/
+ for (to = s, from = &s[1]; *from; ) {
+ c = *from++;
+ if (c == '\\' && quoted && (*from == '\\' || *from == '"'))
+ c = *from++;
+ *to++ = c;
+ }
+ *to = '\0';
+ c = *s;
+linelen--;
+ }
+ if (!quoted && isspace(c))
+ break;
+ if (!quoted && strchr(delim, c) && s > (Uchar *)linep)
+ break;
+ }
+ wordendp = (char *)s;
+ wordendc = (char)*s;
+ *s = '\0';
+
+ return (linep);
+}
+
+static char *
+getnextitem(char *delim)
+{
+ *wordendp = wordendc;
+
+ linep = skipwhite(wordendp);
+ return (markword(delim));
+}
+
+static char *
+neednextitem(char *delim)
+{
+ char *olinep = linep;
+ char *nlinep;
+
+ nlinep = getnextitem(delim);
+
+ if ((olinep == nlinep) || (*nlinep == '\0'))
+ cueabort("Missing text");
+
+ return (nlinep);
+}
+
+static char *
+nextword()
+{
+ return (getnextitem(worddelim));
+}
+
+static char *
+needword()
+{
+ return (neednextitem(worddelim));
+}
+
+static char *
+curword()
+{
+ return (linep);
+}
+
+static char *
+nextitem()
+{
+ return (getnextitem(nulldelim));
+}
+
+static char *
+needitem()
+{
+ return (neednextitem(nulldelim));
+}
+
+static void
+checkextra()
+{
+ if (peekword() < lineend())
+ cueabort("Extra text '%s'", peekword());
+}
+
+/* VARARGS1 */
+static void cueabort(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, " on line %d in '%s'.\n", lineno, fname);
+ exit(EXIT_FAILURE);
+}