Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / cue.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)cue.c    1.20 04/03/02 Copyright 2001-2004 J. Schilling */
14 /*
15  *      Cue sheet parser
16  *
17  *      Copyright (c) 2001-2004 J. Schilling
18  */
19 /*
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2
22  * as published by the Free Software Foundation.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along with
30  * this program; see the file COPYING.  If not, write to the Free Software
31  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33
34 #include <mconfig.h>
35 #include <stdio.h>
36 #include <stdxlib.h>
37 #include <unixstd.h>
38 #include <standard.h>
39 #include <fctldefs.h>
40 #include <statdefs.h>
41 #include <vadefs.h>
42 #include <schily.h>
43 #include <strdefs.h>
44 #include <utypes.h>
45 #include <ctype.h>
46 #include <errno.h>
47
48 #include "xio.h"
49 #include "cdtext.h"
50 #include "wodim.h"
51 #include "auheader.h"
52 #include "libport.h"
53
54 typedef struct state {
55         char    *filename;
56         void    *xfp;
57         Llong   trackoff;
58         Llong   filesize;
59         int     filetype;
60         int     tracktype;
61         int     sectype;
62         int     dbtype;
63         int     secsize;
64         int     dataoff;
65         int     state;
66         int     track;
67         int     index;
68         long    index0;
69         long    index1;         /* Current index 1 value        */
70         long    secoff;         /* Old index 1 value            */
71         long    pregapsize;
72         long    postgapsize;
73         int     flags;
74 } state_t;
75
76 static  char    linebuf[4096];
77 static  char    *fname;
78 static  char    *linep;
79 static  char    *wordendp;
80 static  char    wordendc;
81 static  int     olinelen;
82 static  int     linelen;
83 static  int     lineno;
84
85 static  char    worddelim[] = "=:,/";
86 static  char    nulldelim[] = "";
87
88 #define STATE_NONE      0
89 #define STATE_POSTGAP   1
90 #define STATE_TRACK     2
91 #define STATE_FLAGS     3
92 #define STATE_INDEX0    4
93 #define STATE_INDEX1    5
94
95 typedef struct keyw {
96         char    *k_name;
97         int     k_type;
98 } keyw_t;
99
100 /*
101  *      Keywords (first word on line):
102  *              CATALOG         - global        CATALOG         <MCN>
103  *              CDTEXTFILE      - global        CDTEXTFILE      <fname>
104  *              FILE            - track static  FILE            <fame> <type>
105  *              FLAGS           - track static  FLAGS           <flag> ...
106  *              INDEX           - track static  INDEX           <#> <mm:ss:ff>
107  *              ISRC            - track static  ISRC            <ISRC>
108  *              PERFORMER       - global/static PERFORMER       <string>
109  *              POSTGAP         - track locak   POSTGAP         <mm:ss:ff>
110  *              PREGAP          - track static  PREGAP          <mm:ss:ff>
111  *              REM             - anywhere      REM             <comment>
112  *              SONGWRITER      - global/static SONGWRITER      <string>
113  *              TITLE           - global/static TITLE           <string>
114  *              TRACK           - track static  TRACK           <#> <datatype>
115  *
116  *      Order of keywords:
117  *              CATALOG
118  *              CDTEXTFILE
119  *              PERFORMER | SONGWRITER | TITLE          Doc says past FILE...
120  *              FILE                                    Must be past CATALOG
121  *              ------- Repeat the following:           mehrere FILE Commands?
122  *              TRACK
123  *              FLAGS | ISRC | PERFORMER | PREGAP | SONGWRITER | TITLE
124  *              INDEX
125  *              POSTGAP
126  */
127
128 #define K_G             0x10000         /* Global                       */
129 #define K_T             0x20000         /* Track static                 */
130 #define K_A             (K_T | K_G)     /* Global & Track static                */
131
132 #define K_MCN           (0 | K_G)       /* Media catalog number         */
133 #define K_TEXTFILE      (1 | K_G)       /* CD-Text binary file          */
134 #define K_FILE          (2 | K_T)       /* Input data file              */
135 #define K_FLAGS         (3 | K_T)       /* Flags for ctrl nibble        */
136 #define K_INDEX         (4 | K_T)       /* Index marker for track       */
137 #define K_ISRC          (5 | K_T)       /* ISRC string for track        */
138 #define K_PERFORMER     (6 | K_A)       /* CD-Text Performer            */
139 #define K_POSTGAP       (7 | K_T)       /* Post gap for track (autogen) */
140 #define K_PREGAP        (8 | K_T)       /* Pre gap for track (autogen)  */
141 #define K_REM           (9 | K_A)       /* Remark (Comment)             */
142 #define K_SONGWRITER    (10| K_A)       /* CD-Text Songwriter           */
143 #define K_TITLE         (11| K_A)       /* CD-Text Title                */
144 #define K_TRACK         (12| K_T)       /* Track marker                 */
145
146
147 static keyw_t   keywords[] = {
148         { "CATALOG",    K_MCN },
149         { "CDTEXTFILE", K_TEXTFILE },
150         { "FILE",       K_FILE },
151         { "FLAGS",      K_FLAGS },
152         { "INDEX",      K_INDEX },
153         { "ISRC",       K_ISRC },
154         { "PERFORMER",  K_PERFORMER },
155         { "POSTGAP",    K_POSTGAP },
156         { "PREGAP",     K_PREGAP },
157         { "REM",        K_REM },
158         { "SONGWRITER", K_SONGWRITER },
159         { "TITLE",      K_TITLE },
160         { "TRACK",      K_TRACK },
161         { NULL,         0 },
162 };
163
164
165 /*
166  *      Filetypes - argument to FILE Keyword (one only):
167  *
168  *              BINARY          - Intel binary file (least significant byte first)
169  *              MOTOTOLA        - Motorola binary file (most significant byte first)
170  *              AIFF            - Audio AIFF file
171  *              AU              - Sun Audio file
172  *              WAVE            - Audio WAVE file
173  *              MP3             - Audio MP3 file
174  */
175 #define K_BINARY        100
176 #define K_MOTOROLA      101
177 #define K_AIFF          102
178 #define K_AU            103
179 #define K_WAVE          104
180 #define K_MP3           105
181 #define K_OGG           106
182
183 static keyw_t   filetypes[] = {
184         { "BINARY",     K_BINARY },
185         { "MOTOROLA",   K_MOTOROLA },
186         { "AIFF",       K_AIFF },
187         { "AU",         K_AU },
188         { "WAVE",       K_WAVE },
189         { "MP3",        K_MP3 },
190         { "OGG",        K_OGG },
191         { NULL,         0 },
192 };
193
194 /*
195  *      Flags - argument to FLAGS Keyword (more than one allowed):
196  *              DCP             - Digital copy permitted
197  *              4CH             - Four channel audio
198  *              PRE             - Pre-emphasis enabled (audio tracks only)
199  *              SCMS            - Serial copy management system (not supported by all recorders)
200  */
201 #define K_DCP           1000
202 #define K_4CH           1001
203 #define K_PRE           1002
204 #define K_SCMS          1003
205
206 static keyw_t   flags[] = {
207         { "DCP",        K_DCP },
208         { "4CH",        K_4CH },
209         { "PRE",        K_PRE },
210         { "SCMS",       K_SCMS },
211         { NULL,         0 },
212 };
213
214 /*
215  *      Datatypes - argument to TRACK Keyword (one only):
216  *              AUDIO           - Audio/Music (2352)
217  *              CDG             - Karaoke CD+G (2448)
218  *              MODE1/2048      - CDROM Mode1 Data (cooked)
219  *              MODE1/2352      - CDROM Mode1 Data (raw)
220  *              MODE2/2336      - CDROM-XA Mode2 Data
221  *              MODE2/2352      - CDROM-XA Mode2 Data
222  *              CDI/2336        - CDI Mode2 Data
223  *              CDI/2352        - CDI Mode2 Data
224  */
225 #define K_AUDIO         10000
226 #define K_CDG           10001
227 #define K_MODE1         10002
228 #define K_MODE2         10003
229 #define K_CDI           10004
230
231 static keyw_t   dtypes[] = {
232         { "AUDIO",      K_AUDIO },
233         { "CDG",        K_CDG },
234         { "MODE1",      K_MODE1 },
235         { "MODE2",      K_MODE2 },
236         { "CDI",        K_CDI },
237         { NULL,         0 },
238 };
239
240
241 int     parsecue(char *cuefname, track_t trackp[]);
242 void    fparsecue(FILE *f, track_t trackp[]);
243 static  void    parse_mcn(track_t trackp[], state_t *sp);
244 static  void    parse_textfile(track_t trackp[], state_t *sp);
245 static  void    parse_file(track_t trackp[], state_t *sp);
246 static  void    parse_flags(track_t trackp[], state_t *sp);
247 static  void    parse_index(track_t trackp[], state_t *sp);
248 static  void    parse_isrc(track_t trackp[], state_t *sp);
249 static  void    parse_performer(track_t trackp[], state_t *sp);
250 static  void    parse_postgap(track_t trackp[], state_t *sp);
251 static  void    parse_pregap(track_t trackp[], state_t *sp);
252 static  void    parse_songwriter(track_t trackp[], state_t *sp);
253 static  void    parse_title(track_t trackp[], state_t *sp);
254 static  void    parse_track(track_t trackp[], state_t *sp);
255 static  void    parse_offset(long *lp);
256 static  void    newtrack(track_t trackp[], state_t *sp);
257
258 static  keyw_t  *lookup(char *word, keyw_t table[]);
259 static  void    wdebug(void);
260 static  FILE    *cueopen(char *name);
261 static  char    *cuename(void);
262 static  char    *nextline(FILE *f);
263 static  void    ungetline(void);
264 static  char    *skipwhite(const char *s);
265 static  char    *peekword(void);
266 static  char    *lineend(void);
267 static  char    *markword(char *delim);
268 static  char    *getnextitem(char *delim);
269 static  char    *neednextitem(char *delim);
270 static  char    *nextword(void);
271 static  char    *needword(void);
272 static  char    *curword(void);
273 static  char    *nextitem(void);
274 static  char    *needitem(void);
275 static  void    checkextra(void);
276 static  void    cueabort(const char *fmt, ...);
277
278 #ifdef  CUE_MAIN
279 int     debug;
280 int     xdebug = 1;
281
282 int write_secs(void);
283 int write_secs() { return (-1); }
284
285 int 
286 main(int argc, char *argv[])
287 {
288         int     i;
289         track_t track[MAX_TRACK+2];     /* Max tracks + track 0 + track AA */
290
291         save_args(argc, argv);
292
293         fillbytes(track, sizeof (track), '\0');
294         for (i = 0; i < MAX_TRACK+2; i++)
295                 track[i].track = track[i].trackno = i;
296         track[0].tracktype = TOC_MASK;
297
298
299         parsecue(argv[1], track);
300         return (0);
301 }
302 #else
303 extern  int     xdebug;
304 #endif
305
306 int 
307 parsecue(char *cuefname, track_t trackp[])
308 {
309         FILE    *f = cueopen(cuefname);
310
311         fparsecue(f, trackp);
312         return (0);
313 }
314
315 void 
316 fparsecue(FILE *f, track_t trackp[])
317 {
318         char    *word;
319         struct keyw *kp;
320         BOOL    isglobal = TRUE;
321         state_t state;
322
323         state.filename  = NULL;
324         state.xfp       = NULL;
325         state.trackoff  = 0;
326         state.filesize  = 0;
327         state.filetype  = 0;
328         state.tracktype = 0;
329         state.sectype   = 0;
330         state.dbtype    = 0;
331         state.secsize   = 0;
332         state.dataoff   = 0;
333         state.state     = STATE_NONE;
334         state.track     = 0;
335         state.index     = -1;
336         state.index0    = -1;
337         state.index1    = -1;
338         state.secoff    = 0;
339         state.pregapsize = -1;
340         state.postgapsize = -1;
341         state.flags     = 0;
342
343         if (xdebug > 1)
344                 printf("---> Entering CUE Parser...\n");
345         do {
346                 if (nextline(f) == NULL) {
347                         /*
348                          * EOF on CUE File
349                          * Do post processing here
350                          */
351                         if (state.state < STATE_INDEX1)
352                                 cueabort("Incomplete CUE file");
353                         if (state.xfp)
354                                 xclose(state.xfp);
355                         if (xdebug > 1) {
356                                 printf("---> CUE Parser got EOF, found %d tracks.\n",
357                                                                 state.track);
358                         }
359                         return;
360                 }
361                 word = nextitem();
362                 if (*word == '\0')      /* empty line */
363                         continue;
364
365                 if (xdebug > 1)
366                         printf("\nKEY: '%s'     %s\n", word, peekword());
367                 kp = lookup(word, keywords);
368                 if (kp == NULL)
369                         cueabort("Unknown CUE keyword '%s'", word);
370
371                 if ((kp->k_type & K_G) == 0) {
372                         if (isglobal)
373                                 isglobal = FALSE;
374                 }
375                 if ((kp->k_type & K_T) == 0) {
376                         if (!isglobal)
377                                 cueabort("Badly placed CUE keyword '%s'", word);
378                 }
379 /*              printf("%s-", isglobal ? "G" : "T");*/
380 /*              wdebug();*/
381
382                 switch (kp->k_type) {
383
384                 case K_MCN:        parse_mcn(trackp, &state);           break;
385                 case K_TEXTFILE:   parse_textfile(trackp, &state);      break;
386                 case K_FILE:       parse_file(trackp, &state);          break;
387                 case K_FLAGS:      parse_flags(trackp, &state);         break;
388                 case K_INDEX:      parse_index(trackp, &state);         break;
389                 case K_ISRC:       parse_isrc(trackp, &state);          break;
390                 case K_PERFORMER:  parse_performer(trackp, &state);     break;
391                 case K_POSTGAP:    parse_postgap(trackp, &state);       break;
392                 case K_PREGAP:     parse_pregap(trackp, &state);        break;
393                 case K_REM:                                             break;
394                 case K_SONGWRITER: parse_songwriter(trackp, &state);    break;
395                 case K_TITLE:      parse_title(trackp, &state);         break;
396                 case K_TRACK:      parse_track(trackp, &state);         break;
397
398                 default:
399                         cueabort("Panic: unknown CUE command '%s'", word);
400                 }
401         } while (1);
402 }
403
404 static void 
405 parse_mcn(track_t trackp[], state_t *sp)
406 {
407         char    *word;
408         textptr_t *txp;
409
410         if (sp->track != 0)
411                 cueabort("CATALOG keyword must be before first TRACK");
412
413         word = needitem();
414         setmcn(word, &trackp[0]);
415         txp = gettextptr(0, trackp); /* MCN is isrc for trk 0 */
416         txp->tc_isrc = strdup(word);
417
418         checkextra();
419 }
420
421 static void 
422 parse_textfile(track_t trackp[], state_t *sp)
423 {
424         char    *word;
425
426         if (sp->track != 0)
427                 cueabort("CDTEXTFILE keyword must be before first TRACK");
428
429         word = needitem();
430
431         if (trackp[MAX_TRACK+1].flags & TI_TEXT) {
432                 if (!checktextfile(word)) {
433                         comerrno(EX_BAD,
434                                 "Cannot use '%s' as CD-Text file.\n",
435                                 word);
436                 }
437                 trackp[0].flags |= TI_TEXT;
438         } else {
439                 errmsgno(EX_BAD, "Ignoring CDTEXTFILE '%s'.\n", word);
440                 errmsgno(EX_BAD, "If you like to write CD-Text, call wodim -text.\n");
441         }
442
443         checkextra();
444 }
445
446 static void 
447 parse_file(track_t trackp[], state_t *sp)
448 {
449         char    cname[1024];
450         char    newname[1024];
451         struct keyw *kp;
452         char    *word;
453         char    *filetype;
454         struct stat     st;
455 #ifdef  hint
456         Llong           lsize;
457 #endif
458
459         if (sp->filename != NULL)
460                 cueabort("Only one FILE allowed");
461
462         word = needitem();
463         if (sp->xfp)
464                 xclose(sp->xfp);
465         sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0);
466         if (sp->xfp == NULL && geterrno() == ENOENT) {
467                 char    *p;
468
469                 if (strchr(word, '/') == 0 &&
470                     strchr(cuename(), '/') != 0) {
471                         snprintf(cname, sizeof (cname),
472                                 "%s", cuename());
473                         p = strrchr(cname, '/');
474                         if (p)
475                                 *p = '\0';
476                         snprintf(newname, sizeof (newname),
477                                 "%s/%s", cname, word);
478                         word = newname;
479                         sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0);
480                 }
481         }
482         if (sp->xfp == NULL)
483                 comerr("Cannot open FILE '%s'.\n", word);
484
485         sp->filename     = strdup(word);
486         sp->trackoff     = 0;
487         sp->filesize     = 0;
488         sp->flags       &= ~TI_SWAB;    /* Reset what we might set for FILE */
489
490         filetype = needitem();
491         kp = lookup(filetype, filetypes);
492         if (kp == NULL)
493                 cueabort("Unknown filetype '%s'", filetype);
494
495         switch (kp->k_type) {
496
497         case K_BINARY:
498         case K_MOTOROLA:
499                         if (fstat(xfileno(sp->xfp), &st) >= 0 &&
500                             S_ISREG(st.st_mode)) {
501                                 sp->filesize = st.st_size;
502                         } else {
503                                 cueabort("Unknown file size for FILE '%s'",
504                                                                 sp->filename);
505                         }
506                         break;
507         case K_AIFF:
508                         cueabort("Unsupported filetype '%s'", kp->k_name);
509                         break;
510         case K_AU:
511                         sp->filesize = ausize(xfileno(sp->xfp));
512                         break;
513         case K_WAVE:
514                         sp->filesize = wavsize(xfileno(sp->xfp));
515                         sp->flags |= TI_SWAB;
516                         break;
517         case K_MP3:
518         case K_OGG:
519                         cueabort("Unsupported filetype '%s'", kp->k_name);
520                         break;
521
522         default:        cueabort("Panic: unknown filetype '%s'", filetype);
523         }
524
525         if (sp->filesize == AU_BAD_CODING) {
526                 cueabort("Inappropriate audio coding in '%s'",
527                                                         sp->filename);
528         }
529         if (xdebug > 0)
530                 printf("Track %d File '%s' Filesize %lld\n",
531                         sp->track, sp->filename, sp->filesize);
532
533         sp->filetype = kp->k_type;
534
535         checkextra();
536
537
538 #ifdef  hint
539                 trackp->itracksize = lsize;
540                 if (trackp->itracksize != lsize)
541                         comerrno(EX_BAD, "This OS cannot handle large audio images.\n");
542 #endif
543 }
544
545 static void 
546 parse_flags(track_t trackp[], state_t *sp)
547 {
548         struct keyw *kp;
549         char    *word;
550
551         if ((sp->state < STATE_TRACK) ||
552             (sp->state >= STATE_INDEX0))
553                 cueabort("Badly placed FLAGS keyword");
554         sp->state = STATE_FLAGS;
555
556         do {
557                 word = needitem();
558                 kp = lookup(word, flags);
559                 if (kp == NULL)
560                         cueabort("Unknown flag '%s'", word);
561
562                 switch (kp->k_type) {
563
564                 case K_DCP:     sp->flags |= TI_COPY;   break;
565                 case K_4CH:     sp->flags |= TI_QUADRO; break;
566                 case K_PRE:     sp->flags |= TI_PREEMP; break;
567                 case K_SCMS:    sp->flags |= TI_SCMS;   break;
568                 default:        cueabort("Panic: unknown FLAG '%s'", word);
569                 }
570
571         } while (peekword() < lineend());
572
573         if (xdebug > 0)
574                 printf("Track %d flags 0x%08X\n", sp->track, sp->flags);
575 }
576
577 static void 
578 parse_index(track_t trackp[], state_t *sp)
579 {
580         char    *word;
581         long    l;
582         int     track = sp->track;
583
584         if (sp->state < STATE_TRACK)
585                 cueabort("Badly placed INDEX keyword");
586
587
588         word = needitem();
589         if (*astolb(word, &l, 10) != '\0')
590                 cueabort("Not a number '%s'", word);
591         if (l < 0 || l > 99)
592                 cueabort("Illegal index '%s'", word);
593
594         if ((sp->index < l) &&
595             (((sp->index + 1) == l) || l == 1))
596                 sp->index = l;
597         else
598                 cueabort("Badly placed INDEX %ld number", l);
599
600         if (l > 0)
601                 sp->state = STATE_INDEX1;
602         else
603                 sp->state = STATE_INDEX0;
604
605         parse_offset(&l);
606
607         if (xdebug > 1)
608                 printf("Track %d Index %d %ld\n", sp->track, sp->index, l);
609
610         if (sp->index == 0)
611                 sp->index0 = l;
612         if (sp->index == 1) {
613                 sp->index1 = l;
614                 trackp[track].nindex = 1;
615                 newtrack(trackp, sp);
616
617                 if (xdebug > 1) {
618                         printf("Track %d pregapsize %ld\n",
619                                 sp->track, trackp[track].pregapsize);
620                 }
621         }
622         if (sp->index == 2) {
623                 trackp[track].tindex = malloc(100*sizeof (long));
624                 trackp[track].tindex[1] = 0;
625                 trackp[track].tindex[2] = l - sp->index1;
626                 trackp[track].nindex = 2;
627         }
628         if (sp->index > 2) {
629                 trackp[track].tindex[sp->index] = l - sp->index1;
630                 trackp[track].nindex = sp->index;
631         }
632
633         checkextra();
634 }
635
636 static void 
637 parse_isrc(track_t trackp[], state_t *sp)
638 {
639         char    *word;
640         textptr_t *txp;
641         int     track = sp->track;
642
643         if (track == 0)
644                 cueabort("ISRC keyword must be past first TRACK");
645
646         if ((sp->state < STATE_TRACK) ||
647             (sp->state >= STATE_INDEX0))
648                 cueabort("Badly placed ISRC keyword");
649         sp->state = STATE_FLAGS;
650
651         word = needitem();
652         setisrc(word, &trackp[track]);
653         txp = gettextptr(track, trackp);
654         txp->tc_isrc = strdup(word);
655
656         checkextra();
657 }
658
659 static void 
660 parse_performer(track_t trackp[], state_t *sp)
661 {
662         char    *word;
663         textptr_t *txp;
664
665         word = needitem();
666         txp = gettextptr(sp->track, trackp);
667         txp->tc_performer = strdup(word);
668
669         checkextra();
670 }
671
672 static void 
673 parse_postgap(track_t trackp[], state_t *sp)
674 {
675         long    l;
676
677         if (sp->state < STATE_INDEX1)
678                 cueabort("Badly placed POSTGAP keyword");
679         sp->state = STATE_POSTGAP;
680
681         parse_offset(&l);
682         sp->postgapsize = l;
683
684         checkextra();
685 }
686
687 static void 
688 parse_pregap(track_t trackp[], state_t *sp)
689 {
690         long    l;
691
692         if ((sp->state < STATE_TRACK) ||
693             (sp->state >= STATE_INDEX0))
694                 cueabort("Badly placed PREGAP keyword");
695         sp->state = STATE_FLAGS;
696
697         parse_offset(&l);
698         sp->pregapsize = l;
699
700         checkextra();
701 }
702
703 static void 
704 parse_songwriter(track_t trackp[], state_t *sp)
705 {
706         char    *word;
707         textptr_t *txp;
708
709         word = needitem();
710         txp = gettextptr(sp->track, trackp);
711         txp->tc_songwriter = strdup(word);
712
713         checkextra();
714 }
715
716 static void 
717 parse_title(track_t trackp[], state_t *sp)
718 {
719         char    *word;
720         textptr_t *txp;
721
722         word = needitem();
723         txp = gettextptr(sp->track, trackp);
724         txp->tc_title = strdup(word);
725
726         checkextra();
727 }
728
729 static void 
730 parse_track(track_t trackp[], state_t *sp)
731 {
732         struct keyw *kp;
733         char    *word;
734         long    l;
735         long    secsize = -1;
736
737         if ((sp->state >= STATE_TRACK) &&
738             (sp->state < STATE_INDEX1))
739                 cueabort("Badly placed TRACK keyword");
740         sp->state = STATE_TRACK;
741         sp->index = -1;
742
743         word = needitem();
744         if (*astolb(word, &l, 10) != '\0')
745                 cueabort("Not a number '%s'", word);
746         if (l <= 0 || l > 99)
747                 cueabort("Illegal TRACK number '%s'", word);
748
749         if ((sp->track < l) &&
750             (((sp->track + 1) == l) || sp->track == 0))
751                 sp->track = l;
752         else
753                 cueabort("Badly placed TRACK %ld number", l);
754
755         word = needword();
756         kp = lookup(word, dtypes);
757         if (kp == NULL)
758                 cueabort("Unknown filetype '%s'", word);
759
760         if (wordendc == '/') {
761                 word = needitem();
762                 if (*astol(++word, &secsize) != '\0')
763                         cueabort("Not a number '%s'", word);
764         }
765
766         /*
767          * Reset all flags that may be set in TRACK & FLAGS lines
768          */
769         sp->flags &= ~(TI_AUDIO|TI_COPY|TI_QUADRO|TI_PREEMP|TI_SCMS);
770
771         if (kp->k_type == K_AUDIO)
772                 sp->flags |= TI_AUDIO;
773
774         switch (kp->k_type) {
775
776         case K_CDG:
777                 if (secsize < 0)
778                         secsize = 2448;
779         case K_AUDIO:
780                 if (secsize < 0)
781                         secsize = 2352;
782
783                 sp->tracktype = TOC_DA;
784                 sp->sectype = SECT_AUDIO;
785                 sp->dbtype = DB_RAW;
786                 sp->secsize = secsize;
787                 sp->dataoff = 0;
788                 if (secsize != 2352)
789                         cueabort("Unsupported sector size %ld for audio", secsize);
790                 break;
791
792         case K_MODE1:
793                 if (secsize < 0)
794                         secsize = 2048;
795
796                 sp->tracktype = TOC_ROM;
797                 sp->sectype = SECT_ROM;
798                 sp->dbtype = DB_ROM_MODE1;
799                 sp->secsize = secsize;
800                 sp->dataoff = 16;
801                 /*
802                  * XXX Sector Size == 2352 ???
803                  * XXX It seems that there exist bin/cue pairs with this value
804                  */
805                 if (secsize != 2048)
806                         cueabort("Unsupported sector size %ld for data", secsize);
807                 break;
808
809         case K_MODE2:
810         case K_CDI:
811                 sp->tracktype = TOC_ROM;
812                 sp->sectype = SECT_MODE_2;
813                 sp->dbtype = DB_ROM_MODE2;
814                 sp->secsize = secsize;
815                 sp->dataoff = 16;
816                 if (secsize == 2352) {
817                         sp->tracktype = TOC_XA2;
818                         sp->sectype = SECT_MODE_2_MIX;
819                         sp->sectype |= ST_MODE_RAW;
820                         sp->dbtype = DB_RAW;
821                         sp->dataoff = 0;
822                 } else if (secsize != 2336)
823                         cueabort("Unsupported sector size %ld for mode2", secsize);
824                 if (kp->k_type == K_CDI)
825                         sp->tracktype = TOC_CDI;
826                 break;
827
828         default:        cueabort("Panic: unknown datatype '%s'", word);
829         }
830
831         if (sp->flags & TI_PREEMP)
832                 sp->sectype |= ST_PREEMPMASK;
833         sp->secsize = secsize;
834
835         if (xdebug > 1) {
836                 printf("Track %d Tracktype %s/%d\n",
837                         sp->track, kp->k_name, sp->secsize);
838         }
839
840         checkextra();
841 }
842
843 static void 
844 parse_offset(long *lp)
845 {
846         char    *word;
847         char    *p;
848         long    m = -1;
849         long    s = -1;
850         long    f = -1;
851
852         word = needitem();
853
854         if (strchr(word, ':') == NULL) {
855                 if (*astol(word, lp) != '\0')
856                         cueabort("Not a number '%s'", word);
857                 return;
858         }
859         if (*(p = astolb(word, &m, 10)) != ':')
860                 cueabort("Not a number '%s'", word);
861         if (m < 0 || m >= 160)
862                 cueabort("Illegal minute value in '%s'", word);
863         p++;
864         if (*(p = astolb(p, &s, 10)) != ':')
865                 cueabort("Not a number '%s'", p);
866         if (s < 0 || s >= 60)
867                 cueabort("Illegal second value in '%s'", word);
868         p++;
869         if (*(p = astolb(p, &f, 10)) != '\0')
870                 cueabort("Not a number '%s'", p);
871         if (f < 0 || f >= 75)
872                 cueabort("Illegal frame value in '%s'", word);
873
874         m = m * 60 + s;
875         m = m * 75 + f;
876         *lp = m;
877 }
878
879 /*--------------------------------------------------------------------------*/
880 static void 
881 newtrack(track_t trackp[], state_t *sp)
882 {
883         register int    i;
884         register int    track = sp->track;
885                 Llong   tracksize;
886
887         if (xdebug > 1)
888                 printf("-->Newtrack %d\n", track);
889         if (track > 1) {
890                 tracksize = (sp->index1 - sp->secoff) * trackp[track-1].secsize;
891
892                 if (xdebug > 1)
893                         printf("    trackoff %lld filesize %lld index1 %ld size %ld/%lld\n",
894                                 sp->trackoff, sp->filesize, sp->index1,
895                                 sp->index1 - sp->secoff,
896                                 tracksize);
897
898                 trackp[track-1].itracksize = tracksize;
899                 trackp[track-1].tracksize = tracksize;
900                 trackp[track-1].tracksecs = sp->index1 - sp->secoff;
901
902                 sp->trackoff += tracksize;
903                 sp->secoff = sp->index1;
904         }
905         /*
906          * Make 'tracks' immediately usable in track structure.
907          */
908         for (i = 0; i < MAX_TRACK+2; i++)
909                 trackp[i].tracks = track;
910
911         trackp[track].filename = sp->filename;
912         trackp[track].xfp = xopen(sp->filename, O_RDONLY|O_BINARY, 0);
913         trackp[track].trackstart = 0L;
914 /*
915 SEtzen wenn tracksecs bekannt sind
916 d.h. mit Index0 oder Index 1 vom nächsten track
917
918         trackp[track].itracksize = tracksize;
919         trackp[track].tracksize = tracksize;
920         trackp[track].tracksecs = -1L;
921 */
922         tracksize = sp->filesize - sp->trackoff;
923
924         trackp[track].itracksize = tracksize;
925         trackp[track].tracksize = tracksize;
926         trackp[track].tracksecs = (tracksize + sp->secsize - 1) / sp->secsize;
927
928         if (xdebug > 1)
929                 printf("    Remaining Filesize %lld (%lld secs)\n",
930                         (sp->filesize-sp->trackoff),
931                         (sp->filesize-sp->trackoff +sp->secsize - 1) / sp->secsize);
932
933         if (sp->pregapsize >= 0) {
934 /*              trackp[track].flags &= ~TI_PREGAP;*/
935                 sp->flags &= ~TI_PREGAP;
936                 trackp[track].pregapsize = sp->pregapsize;
937         } else {
938 /*              trackp[track].flags |= TI_PREGAP;*/
939                 if (track > 1)
940                         sp->flags |= TI_PREGAP;
941                 if (track == 1)
942                         trackp[track].pregapsize = sp->index1 + 150;
943                 else if (sp->index0 < 0)
944                         trackp[track].pregapsize = -1;
945                 else
946                         trackp[track].pregapsize = sp->index1 - sp->index0;
947         }
948 /*      trackp[track].padsecs = xxx*/
949
950         trackp[track].isecsize = sp->secsize;
951         trackp[track].secsize = sp->secsize;
952         trackp[track].flags = sp->flags | trackp[0].flags;
953
954         trackp[track].secspt = 0;       /* transfer size is set up in set_trsizes() */
955 /*      trackp[track].pktsize = pktsize; */
956         trackp[track].pktsize = 0;
957         trackp[track].trackno = sp->track;
958         trackp[track].sectype = sp->sectype;
959
960         trackp[track].dataoff = sp->dataoff;
961         trackp[track].tracktype = sp->tracktype;
962         trackp[track].dbtype = sp->dbtype;
963
964         if (track == 1) {
965                 trackp[0].tracktype &= ~TOC_MASK;
966                 trackp[0].tracktype |= sp->tracktype;
967
968                 if (xdebug > 1) {
969                         printf("Track %d Tracktype %X\n",
970                                         0, trackp[0].tracktype);
971                 }
972         }
973         if (xdebug > 1) {
974                 printf("Track %d Tracktype %X\n",
975                                 track, trackp[track].tracktype);
976         }
977         trackp[track].nindex = 1;
978         trackp[track].tindex = 0;
979
980         if (xdebug > 1) {
981                 printf("Track %d flags 0x%08X\n", 0, trackp[0].flags);
982                 printf("Track %d flags 0x%08X\n", track, trackp[track].flags);
983         }
984 }
985
986 /*--------------------------------------------------------------------------*/
987 static keyw_t *
988 lookup(char *word, keyw_t table[])
989 {
990         register keyw_t *kp = table;
991
992         while (kp->k_name) {
993                 if (streql(kp->k_name, word))
994                         return (kp);
995                 kp++;
996         }
997         return (NULL);
998 }
999
1000 /*--------------------------------------------------------------------------*/
1001 /*
1002  * Parser low level functions start here...
1003  */
1004
1005 static void 
1006 wdebug()
1007 {
1008 /*              printf("WORD: '%s' rest '%s'\n", word, peekword());*/
1009                 printf("WORD: '%s' rest '%s'\n", linep, peekword());
1010                 printf("linep %lX peekword %lX end %lX\n",
1011                         (long)linep, (long)peekword(), (long)&linebuf[linelen]);
1012 }
1013
1014 static FILE *
1015 cueopen(char *name)
1016 {
1017         FILE    *f;
1018
1019         f = fileopen(name, "r");
1020         if (f == NULL)
1021                 comerr("Cannot open '%s'.\n", name);
1022
1023         fname = name;
1024         return (f);
1025 }
1026
1027 static char *
1028 cuename()
1029 {
1030         return (fname);
1031 }
1032
1033 static char *
1034 nextline(FILE *f)
1035 {
1036         register int    len;
1037
1038         do {
1039                 fillbytes(linebuf, sizeof (linebuf), '\0');
1040                 len = rols_fgetline(f, linebuf, sizeof (linebuf));
1041                 if (len < 0)
1042                         return (NULL);
1043                 if (len > 0 && linebuf[len-1] == '\r') {
1044                         linebuf[len-1] = '\0';
1045                         len--;
1046                 }
1047                 linelen = len;
1048                 lineno++;
1049         } while (linebuf[0] == '#');
1050
1051         olinelen = linelen;
1052         linep = linebuf;
1053         wordendp = linep;
1054         wordendc = *linep;
1055
1056         return (linep);
1057 }
1058
1059 static void 
1060 ungetline()
1061 {
1062         linelen = olinelen;
1063         linep = linebuf;
1064         *wordendp = wordendc;
1065         wordendp = linep;
1066         wordendc = *linep;
1067 }
1068
1069 static char *
1070 skipwhite(const char *s)
1071 {
1072         register const Uchar    *p = (const Uchar *)s;
1073
1074         while (*p) {
1075                 if (!isspace(*p))
1076                         break;
1077                 p++;
1078         }
1079         return ((char *)p);
1080 }
1081
1082 static char *
1083 peekword()
1084 {
1085         return (&wordendp[1]);
1086 }
1087
1088 static char *
1089 lineend()
1090 {
1091         return (&linebuf[linelen]);
1092 }
1093
1094 static char *
1095 markword(char *delim)
1096 {
1097         register        BOOL    quoted = FALSE;
1098         register        Uchar   c;
1099         register        Uchar   *s;
1100         register        Uchar   *from;
1101         register        Uchar   *to;
1102
1103         for (s = (Uchar *)linep; (c = *s) != '\0'; s++) {
1104                 if (c == '"') {
1105                         quoted = !quoted;
1106 /*                      strcpy((char *)s, (char *)&s[1]);*/
1107                         for (to = s, from = &s[1]; *from; ) {
1108                                 c = *from++;
1109                                 if (c == '\\' && quoted && (*from == '\\' || *from == '"'))
1110                                         c = *from++;
1111                                 *to++ = c;
1112                         }
1113                         *to = '\0';
1114                         c = *s;
1115 linelen--;
1116                 }
1117                 if (!quoted && isspace(c))
1118                         break;
1119                 if (!quoted && strchr(delim, c) && s > (Uchar *)linep)
1120                         break;
1121         }
1122         wordendp = (char *)s;
1123         wordendc = (char)*s;
1124         *s = '\0';
1125
1126         return (linep);
1127 }
1128
1129 static char *
1130 getnextitem(char *delim)
1131 {
1132         *wordendp = wordendc;
1133
1134         linep = skipwhite(wordendp);
1135         return (markword(delim));
1136 }
1137
1138 static char *
1139 neednextitem(char *delim)
1140 {
1141         char    *olinep = linep;
1142         char    *nlinep;
1143
1144         nlinep = getnextitem(delim);
1145
1146         if ((olinep == nlinep) || (*nlinep == '\0'))
1147                 cueabort("Missing text");
1148
1149         return (nlinep);
1150 }
1151
1152 static char *
1153 nextword()
1154 {
1155         return (getnextitem(worddelim));
1156 }
1157
1158 static char *
1159 needword()
1160 {
1161         return (neednextitem(worddelim));
1162 }
1163
1164 static char *
1165 curword()
1166 {
1167         return (linep);
1168 }
1169
1170 static char *
1171 nextitem()
1172 {
1173         return (getnextitem(nulldelim));
1174 }
1175
1176 static char *
1177 needitem()
1178 {
1179         return (neednextitem(nulldelim));
1180 }
1181
1182 static void 
1183 checkextra()
1184 {
1185         if (peekword() < lineend())
1186                 cueabort("Extra text '%s'", peekword());
1187 }
1188
1189 /* VARARGS1 */
1190 static void cueabort(const char *fmt, ...)
1191 {
1192         va_list args;
1193   va_start(args, fmt);
1194   vfprintf(stderr, fmt, args);
1195         va_end(args);
1196   fprintf(stderr, " on line %d in '%s'.\n", lineno, fname);
1197   exit(EXIT_FAILURE);
1198 }