CueParser.g
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:14k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.de>
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19. /*
  20.  * $Log: CueParser.g,v $
  21.  * Revision 1.1  1999/07/10 18:18:17  mueller
  22.  * Initial revision
  23.  *
  24.  */
  25. #header <<
  26. #include <config.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include "Toc.h"
  30. #include "TrackData.h"
  31. #include "util.h"
  32. struct CueTrackData;
  33. >>
  34. <<
  35. #include <sys/types.h>
  36. #include <sys/stat.h>
  37. #include <unistd.h>
  38. #include <fcntl.h>
  39. #include <errno.h>
  40. #include "CueLexerBase.h"
  41. /* Use 'ANTLRCommonToken' as 'ANTLRToken' to be compatible with some bug
  42.  * fix releases of PCCTS-1.33. The drawback is that the token length is
  43.  * limited to 100 characters. This might be a problem for long file names.
  44.  * Define 'USE_ANTLRCommonToken' to 0 if you want to use the dynamic token
  45.  * which handles arbitrary token lengths (there'll be still a limitation in
  46.  * the lexer code but that's more than 100 characters). In this case it might
  47.  * be necessary to adjust the types of the member functions to the types in
  48.  * 'ANTLRAbstractToken' defined in PCCTSDIR/h/AToken.h'.
  49.  */
  50. #define USE_ANTLRCommonToken 1
  51. #if USE_ANTLRCommonToken
  52. typedef ANTLRCommonToken ANTLRToken;
  53. #else
  54. class ANTLRToken : public ANTLRRefCountToken {
  55. private:
  56.   ANTLRTokenType type_;
  57.   int line_;
  58.   ANTLRChar *text_;
  59. public:
  60.   ANTLRToken(ANTLRTokenType t, ANTLRChar *s) 
  61.     : ANTLRRefCountToken(t, s)
  62.   { 
  63.     setType(t); 
  64.     line_ = 0; 
  65.     setText(s); 
  66.   }
  67.   ANTLRToken()
  68.   { 
  69.     setType((ANTLRTokenType)0); 
  70.     line_ = 0; 
  71.     setText("");
  72.   }
  73.   virtual ~ANTLRToken() { delete[] text_; }
  74. #if 1
  75.   // use this for basic PCCTS-1.33 release
  76.   ANTLRTokenType getType()  { return type_; }
  77.   virtual int getLine()  { return line_; }
  78.   ANTLRChar *getText()  { return text_; }
  79. #else
  80.   // use this for PCCTS-1.33 bug fix releases
  81.   ANTLRTokenType getType() const { return type_; }
  82.   virtual int getLine()    const { return line_; }
  83.   ANTLRChar *getText()    const { return text_; }
  84. #endif
  85.   void setType(ANTLRTokenType t) { type_ = t; }
  86.   void setLine(int line)  { line_ = line; }
  87.   void setText(ANTLRChar *s)     { text_ = strdupCC(s); }
  88.   virtual ANTLRAbstractToken *makeToken(ANTLRTokenType tt, ANTLRChar *txt,
  89. int line)
  90.   {
  91.     ANTLRAbstractToken *t = new ANTLRToken(tt,txt);
  92.     t->setLine(line);
  93.     return t;
  94.   }
  95. };
  96. #endif
  97.  >>
  98. <<
  99. class CueLexer : public CueLexerBase {
  100. public:
  101.   CueLexer(DLGInputStream *in, unsigned bufsize=2000)
  102.     : CueLexerBase(in, bufsize) { parser_ = NULL; }
  103.   virtual ANTLRTokenType erraction();
  104.   CueParserGram *parser_;   
  105. };
  106. >>
  107. <<
  108. struct CueTrackData {
  109.   TrackData::Mode mode;
  110.   long offset;
  111.   long pregap;
  112.   long indexCnt;
  113.   long index[99];
  114.   unsigned int swap : 1;
  115.   unsigned int copy : 1;
  116.   unsigned int fourChannelAudio : 1;
  117.   unsigned int preemphasis : 1;
  118. };
  119. >>
  120. #lexclass START
  121. #token Eof "@"
  122. #token                  "[tr ]+"    << skip(); >>
  123. #token                  "n"         << newline(); skip(); >>
  124. #token BeginString      """         << mode(STRING); >>
  125. #token TrackDef         "TRACK"
  126. #token Audio            "AUDIO"
  127. #token Mode1_2048       "MODE1/2048"
  128. #token Mode1_2352       "MODE1/2352"
  129. #token Mode2_2336       "MODE2/2336"
  130. #token Mode2_2352       "MODE2/2352"
  131. #token Index            "INDEX"
  132. #token File             "FILE"       << mode(FILE); >>
  133. #token Pregap           "PREGAP"
  134. #token Postgap          "POSTGAP"
  135. #token Binary           "BINARY"
  136. #token Motorola         "MOTOROLA"
  137. #token Flags            "FLAGS"
  138. #token Catalog          "CATALOG"   << mode(CATALOG); >>
  139. #token Isrc             "ISRC"      << mode(ISRC); >>
  140. #token                  "4CH"
  141. #token Integer          "[0-9]+"
  142. #lexclass STRING
  143. #token EndString        """         << mode(START); >>
  144. #token StringQuote      "\""
  145. #token StringOctal      "\[0-9][0-9][0-9]"
  146. #token String           "[ ]+"
  147. #token String           "~[\n"t ]*"
  148. #lexclass FILE
  149. #token                  "n"           << newline(); skip(); >>
  150. #token                  "[tr ]*"    << skip(); >>
  151. #token FileName         "~[trn ]*" << mode(START); >>
  152. #lexclass CATALOG
  153. #token                  "n"          << newline(); skip(); >>
  154. #token                  "[tr ]*"   << skip(); >>
  155. #token CatalogNr        "[0-9]+"      << mode(START); >>
  156. #lexclass ISRC
  157. #token                  "n"          << newline(); skip(); >>
  158. #token                  "[tr ]*"   << skip(); >>
  159. #token IsrcCode         "[0-9A-Z]+"   << mode(START); >>
  160. #lexclass START
  161. class CueParserGram {
  162. <<
  163. public:
  164.   const char *filename_;
  165.   int error_;
  166.   void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset,
  167.    ANTLRTokenType etok, int k);
  168. >>
  169. cue [ CueTrackData *trackData ] > [ int nofTracks ]
  170.   : << $nofTracks = 0;
  171.        int lineNr = 0;
  172.        int i;
  173.        TrackData::Mode mode;
  174.        int index;
  175.        Msf m;
  176.        int swapSamples = 0;
  177.     >>
  178.     (  File FileName (  Binary << swapSamples = 1; >>
  179.                       | Motorola << swapSamples = 0; >>
  180.                      )
  181.      | Catalog CatalogNr
  182.     )*
  183.     ( TrackDef integer > [ i, lineNr ] 
  184.       << if ($nofTracks >= 99) {
  185.            message(-2, "%s:%d: Too many tracks.", filename_, $1->getLine());
  186.            error_ = 1;
  187.          }
  188.          else {
  189.    trackData[$nofTracks].pregap = 0;
  190.    trackData[$nofTracks].swap = (swapSamples ? 1 : 0);
  191.    trackData[$nofTracks].copy = 0;
  192.    trackData[$nofTracks].fourChannelAudio = 0;
  193.    trackData[$nofTracks].preemphasis = 0;
  194.    index = 0;
  195.  }
  196.       >>
  197.       trackMode > [ mode ]
  198.       << if ($nofTracks < 99) {
  199.            trackData[$nofTracks].mode = mode;
  200.          }
  201.       >>
  202.       (  Flags (  "DCP" << trackData[$nofTracks].copy = 1; >>
  203.                 | "4CH" << trackData[$nofTracks].fourChannelAudio = 1; >>
  204.                 | "PRE" << trackData[$nofTracks].preemphasis = 1; >>
  205.                )+
  206.         | Isrc IsrcCode << message(0, "%s", $2->getText()); >>
  207.       )*
  208.       { Pregap msf > [ m ] 
  209.         << if ($nofTracks < 99) {
  210.              trackData[$nofTracks].pregap = m.lba();
  211.    }
  212.         >>
  213.       }
  214.       Index integer > [ i, lineNr ] msf > [ m ]
  215.       << if ($nofTracks < 99) {
  216.            trackData[$nofTracks].offset = m.lba();
  217.    if (i == 1) {
  218.      trackData[$nofTracks].index[index] = m.lba();
  219.      index++;
  220.    }
  221.          }
  222.       >>
  223.       ( Index integer > [ i, lineNr ] msf > [ m ]
  224.         << if ($nofTracks < 99) {
  225.              if (index < 99) {
  226.                trackData[$nofTracks].index[index] = m.lba();
  227.                index++;
  228.      }
  229.      else {
  230.        message(-2, "%s:%d: Too many index marks.",
  231.        filename_, $1->getLine());
  232.        error_ = 1;
  233.      }
  234.    }
  235.         >>
  236.       )*
  237.       { Postgap msf > [ m ] }
  238.       << if ($nofTracks < 99) {
  239.            if (index == 0) {
  240.      message(-2, "%s:%d: Track %d: Missing Index 1.",
  241.      filename_, $1->getLine(), $nofTracks + 1);
  242.      error_ = 1;
  243.    }
  244.    trackData[$nofTracks].indexCnt = index;
  245.    $nofTracks += 1;
  246.          }
  247.       >>
  248.     )+
  249.     Eof
  250.     ;
  251.     // fail action
  252.     << $nofTracks = 0;
  253.     >>
  254. string > [ char *ret ]
  255.  :  << $ret = strdupCC("");
  256.        char *s;
  257.        char buf[2];
  258.     >>
  259.     << buf[1] = 0; >>
  260.     BeginString 
  261.     ( (  String      << s = strdup3CC($ret, $1->getText(), NULL); >>
  262.        | StringQuote << s = strdup3CC($ret, """, NULL); >>
  263.        | StringOctal << buf[0] = strtol($1->getText() + 1, NULL, 8);
  264.                         s = strdup3CC($ret, buf, NULL);
  265.                      >>
  266.       )
  267.       << delete[] $ret;
  268.          $ret = s;
  269.       >>
  270.     )+
  271.  
  272.     EndString
  273.     ;
  274. integer > [ int i, int lineNr ]
  275.   : << $i = 0; >>
  276.     Integer << $i = atol($1->getText()); $lineNr = $1->getLine(); >>
  277.     ;
  278.     
  279. msf > [ Msf m ]
  280.   : << int min = 0;
  281.        int sec = 0;
  282.        int frac = 0;
  283.        int err = 0;
  284.        int minLine;
  285.        int secLine;
  286.        int fracLine;
  287.     >>
  288.     integer > [min, minLine] ":" integer > [sec, secLine] 
  289.     ":" integer > [frac, fracLine]
  290.     << if (min < 0) {
  291.  fprintf(stderr, "%s:%d: Illegal minute field: %dn", filename_,
  292.          minLine, min);
  293.          err = error_ = 1;
  294.        }
  295.        if (sec < 0 || sec > 59) {
  296.  fprintf(stderr, "%s:%d: Illegal second field: %dn", filename_,
  297.          secLine, sec);
  298.  err = error_ = 1;
  299.        }
  300.        if (frac < 0 || frac > 74) {
  301.  fprintf(stderr, "%s:%d: Illegal fraction field: %dn", filename_,
  302.  fracLine, frac);
  303.  err = error_ = 1;
  304.        }
  305.   
  306.        if (err != 0) {
  307.  $m = Msf(0);
  308.        }
  309.        else {
  310.  $m = Msf(min, sec, frac);
  311.        }
  312.     >>
  313.     ;
  314. trackMode > [ TrackData::Mode m ]
  315.   :
  316.     (  Audio <<  $m = TrackData::AUDIO; >>
  317.      | Mode1_2048 << $m = TrackData::MODE1; >>
  318.      | Mode1_2352 << $m = TrackData::MODE1_RAW; >>
  319.      | Mode2_2336 << $m = TrackData::MODE2_FORM_MIX; >>
  320.      | Mode2_2352 << $m = TrackData::MODE2_RAW; >>
  321.     )
  322.     ;
  323. }
  324. <<
  325. ANTLRTokenType CueLexer::erraction()
  326. {
  327.   message(-2, "%s:%d: Illegal token: %s", parser_->filename_,
  328.   _line, _lextext);
  329.   parser_->error_ = 1;
  330.   return Eof;
  331. }
  332. >>
  333. <<
  334. void CueParserGram::syn(_ANTLRTokenPtr tok, ANTLRChar *egroup,
  335. SetWordType *eset, ANTLRTokenType etok, int k)
  336. {
  337.   int line;
  338.   error_ = 1;
  339.   line = LT(1)->getLine();
  340.   fprintf(stderr, "%s:%d: syntax error at "%s"", filename_, line,
  341.           LT(1)->getType() == Eof ? "EOF" : LT(1)->getText());
  342.   if ( !etok && !eset ) {
  343.     fprintf(stderr, "n");
  344.     return;
  345.   }
  346.   if ( k==1 ) {
  347.     fprintf(stderr, " missing");
  348.   }
  349.   else {
  350.     fprintf(stderr, "; "%s" not", LT(1)->getText());
  351.     if ( set_deg(eset)>1 ) fprintf(stderr, " in");
  352.   }
  353.   if ( set_deg(eset)>0 )
  354.     edecode(eset);
  355.   else fprintf(stderr, " %s", token_tbl[etok]);
  356.   if ( strlen(egroup) > 0 )
  357.     fprintf(stderr, " in %s", egroup);
  358.   fprintf(stderr, "n");
  359. }
  360. >>
  361. <<
  362. static Toc *createToc(const char *cueFileName, const char *binFileName,
  363.       CueTrackData *trackData, int nofTracks)
  364. {
  365.   int t, i;
  366.   int fd, ret;
  367.   struct stat sbuf;
  368.   long binFileLength;
  369.   long byteOffset = 0;
  370.   long blockLen;
  371.   if ((fd = open(binFileName, O_RDONLY)) < 0) {
  372.     message(-2, "Cannot open bin file '%s': %s", binFileName, strerror(errno));
  373.     return NULL;
  374.   }
  375.   ret = fstat(fd, &sbuf);
  376.   close(fd);
  377.   if (ret != 0) {
  378.     message(-2, "Cannot access bin file '%s': %s", binFileName,
  379.     strerror(errno));
  380.     return NULL;
  381.   }
  382.   binFileLength = sbuf.st_size;
  383.   Toc *toc = new Toc; 
  384.   Msf trackLength;
  385.   
  386.   toc->tocType(Toc::CD_DA);
  387.   
  388.   for (t = 0; t < nofTracks; t++) {
  389.     Track track(trackData[t].mode);
  390.     blockLen = TrackData::dataBlockSize(trackData[t].mode);
  391.     
  392.     // very simplified guessing of toc type
  393.     switch (trackData[t].mode) {
  394.     case TrackData::MODE1:
  395.     case TrackData::MODE1_RAW:
  396.     case TrackData::MODE2:
  397.       toc->tocType(Toc::CD_ROM);
  398.       break;
  399.     case TrackData::MODE2_RAW:
  400.     case TrackData::MODE2_FORM_MIX:
  401.       toc->tocType(Toc::CD_ROM_XA);
  402.       break;
  403.     default:
  404.       break;
  405.     }
  406.     track.preEmphasis(trackData[t].preemphasis);
  407.     track.copyPermitted(trackData[t].copy);
  408.     track.audioType(trackData[t].fourChannelAudio);
  409.     if (t < nofTracks - 1) {
  410.       if (trackData[t + 1].offset <= trackData[t].offset) {
  411. message(-2, "%s: Invalid start offset for track %d.", 
  412. cueFileName, t + 2);
  413. delete toc;
  414. return NULL;
  415.       }
  416.       trackLength = Msf(trackData[t + 1].offset - trackData[t].offset);
  417.     }
  418.     else {
  419.       if (byteOffset >= sbuf.st_size) {
  420. message(-2, "Length of bin file "%s" does not match cue file.",
  421. binFileName);
  422. delete toc;
  423. return NULL;
  424.       }
  425.       if (((sbuf.st_size - byteOffset) % blockLen) != 0) {
  426. message(-1,
  427. "Length of bin file "%s" is not a multiple of block size.",
  428. binFileName);
  429.       }
  430.       trackLength = Msf((sbuf.st_size - byteOffset) / blockLen);
  431.     }
  432.     if (trackLength.lba() < 4 * 75) {
  433.       message(-2, "%s: Track %d is shorter than 4 seconds.", cueFileName,
  434.       t + 1);
  435.       delete toc;
  436.       return NULL;
  437.     }
  438.     if (trackData[t].mode == TrackData::AUDIO) {
  439.       if (trackData[t].pregap > 0) {
  440. track.append(SubTrack(SubTrack::DATA,
  441.       TrackData(trackData[t].mode,
  442. Msf(trackData[t].pregap).samples())));
  443.       }
  444.       SubTrack st(SubTrack::DATA, TrackData(binFileName, byteOffset, 0,
  445.     trackLength.samples()));
  446.       st.swapSamples(trackData[t].swap);
  447.       track.append(st);
  448.     }
  449.     else {
  450.       if (trackData[t].pregap > 0) {
  451. track.append(SubTrack(SubTrack::DATA, 
  452.       TrackData(trackData[t].mode,
  453. trackData[t].pregap * blockLen)));
  454.       }
  455.       
  456.       track.append(SubTrack(SubTrack::DATA,
  457.     TrackData(trackData[t].mode,
  458.       binFileName, byteOffset,
  459.       trackLength.lba() * blockLen)));
  460.     }
  461.     if (trackData[t].index[0] < trackData[t].offset) {
  462.       message(-2, "%s: Invalid offset for Index 1 of track %d.",
  463.       cueFileName, t + 1);
  464.       delete toc;
  465.       return NULL;
  466.     }
  467.     
  468.     track.start(Msf(trackData[t].pregap +
  469.     trackData[t].index[0] - trackData[t].offset));
  470.     for (i = 1; i < trackData[t].indexCnt; i++) {
  471.       if (trackData[t].index[i] <= trackData[t].index[i - 1]) {
  472. message(-2, "%s: Invalid offset for index %d of track %d.",
  473. cueFileName, i + 1, t + 1);
  474. delete toc;
  475. return NULL;
  476.       }
  477.       track.appendIndex(Msf(trackData[t].index[i] - trackData[t].index[0]));
  478.     }
  479.     toc->append(&track);
  480.     byteOffset += trackLength.lba() * blockLen;
  481.   }
  482.   return toc;
  483. }
  484. >>
  485. <<
  486. Toc *parseCue(FILE *fp, const char *filename)
  487. {
  488.   char *s, *p;
  489.   char *binFileName;
  490.   DLGFileInput in(fp);
  491.   CueLexer scan(&in);
  492.   ANTLRTokenBuffer pipe(&scan);
  493.   ANTLRToken aToken;
  494.   scan.setToken(&aToken);
  495.   CueParserGram parser(&pipe);
  496.   parser.filename_ = filename;
  497.   scan.parser_ = &parser;
  498.   parser.error_ = 0;
  499.   parser.init();
  500.   CueTrackData *trackData = new CueTrackData[99];
  501.   int nofTracks = parser.cue(trackData);
  502.   if (parser.error_ != 0 || nofTracks <= 0) {
  503.     delete[] trackData;
  504.     return NULL;
  505.   }
  506.   s = strdupCC(filename);
  507.   if ((p = strrchr(s, '.')) != NULL)
  508.     *p  = 0;
  509.   binFileName = strdup3CC(s, ".bin", NULL);
  510.   delete[] s;
  511.   Toc *toc = createToc(filename, binFileName, trackData, nofTracks);
  512.   delete[] binFileName;
  513.   delete[] trackData;
  514.   return toc;
  515. }
  516. >>