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

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: Toc.cc,v $
  21.  * Revision 1.11  1999/04/05 11:03:01  mueller
  22.  * Added CD-TEXT support.
  23.  *
  24.  * Revision 1.10  1999/04/02 20:36:21  mueller
  25.  * Created implementation class that contains all mutual member data.
  26.  *
  27.  * Revision 1.9  1999/03/27 19:52:26  mueller
  28.  * Added data track support.
  29.  *
  30.  * Revision 1.8  1999/01/10 15:10:13  mueller
  31.  * Added functions 'appendTrack()' and 'appendAudioData()'.
  32.  *
  33.  * Revision 1.7  1998/11/15 12:19:13  mueller
  34.  * Added several functions for manipulating track/index marks.
  35.  *
  36.  * Revision 1.6  1998/10/24 14:28:16  mueller
  37.  * Fixed bug in 'readSamples()'.
  38.  *
  39.  * Revision 1.5  1998/10/03 14:32:31  mueller
  40.  * Applied patch from Bjoern Fischer <bfischer@Techfak.Uni-Bielefeld.DE>.
  41.  *
  42.  * Revision 1.4  1998/09/22 19:17:19  mueller
  43.  * Added seeking to and reading of samples for GUI.
  44.  *
  45.  * Revision 1.3  1998/09/06 12:00:26  mueller
  46.  * Used 'message' function for messages.
  47.  *
  48.  */
  49. static char rcsid[] = "$Id: Toc.cc,v 1.11 1999/04/05 11:03:01 mueller Exp mueller $";
  50. #include <config.h>
  51. #include <stdio.h>
  52. #include <assert.h>
  53. #include <errno.h>
  54. #include <string.h>
  55. #include <ctype.h>
  56. #include <fstream.h>
  57. #include "Toc.h"
  58. #include "util.h"
  59. #include "TrackDataList.h"
  60. #include "CdTextItem.h"
  61. extern Toc *parseToc(FILE *fp, const char *filename);
  62. extern Toc *parseCue(FILE *fp, const char *filename);
  63. Toc::Toc() : length_(0)
  64. {
  65.   tocType_ = CD_DA;
  66.   nofTracks_ = 0;
  67.   tracks_ = lastTrack_ = NULL;
  68.   catalogValid_ = 0;
  69. }
  70. Toc::~Toc()
  71. {
  72.   TrackEntry *run = tracks_;
  73.   TrackEntry *next;
  74.   while (run != NULL) {
  75.     next = run->next;
  76.     delete run->track;
  77.     delete run;
  78.     run = next;
  79.   }
  80. }
  81.       
  82. // appends track
  83. // return: 0: OK
  84. //         1: first track contains pregap
  85. int Toc::append(const Track *t)
  86. {
  87.   if (tracks_ == NULL) {
  88.     tracks_ = lastTrack_ = new TrackEntry;
  89.   }
  90.   else {
  91.     lastTrack_->next = new TrackEntry;
  92.     lastTrack_->next->pred = lastTrack_;
  93.     lastTrack_ = lastTrack_->next;
  94.   }
  95.   lastTrack_->track = new Track(*t);
  96.   nofTracks_ += 1;
  97.   update();
  98.   return 0;
  99. }
  100. void Toc::update()
  101. {
  102.   TrackEntry *run;
  103.   long length = 0; // length of disc in blocks
  104.   long tlength; // length of single track in blocks
  105.   int tnum;
  106.   for (run = tracks_, tnum = 1; run != NULL; run = run->next, tnum++) {
  107.     tlength = run->track->length().lba();
  108.     run->absStart = Msf(length);
  109.     run->start = Msf(length + run->track->start().lba());
  110.     run->end = Msf(length + tlength);
  111.     run->trackNr = tnum;
  112.     length += tlength;
  113.   }
  114.   length_ = Msf(length);
  115. }
  116. Toc *Toc::read(const char *filename)
  117. {
  118.   FILE *fp;
  119.   Toc *ret;
  120.   const char *p;
  121.   if ((fp = fopen(filename, "r")) == NULL) {
  122.     message(-2, "Cannot open toc file '%s' for reading: %s",
  123.     filename, strerror(errno));
  124.     return NULL;
  125.   }
  126.   if ((p = strrchr(filename, '.')) != NULL && strcasecmp(p, ".cue") == 0)
  127.     ret = parseCue(fp, filename);
  128.   else
  129.     ret = parseToc(fp, filename);
  130.   fclose(fp);
  131.   /*
  132.   if (ret != NULL)
  133.     ret->print(cout);
  134.     */
  135.   return ret;
  136. }
  137. // Writes toc to file with given name.
  138. // Return: 0: OK
  139. //         1: error occured
  140. int Toc::write(const char *filename) const
  141. {
  142.   assert(filename != NULL);
  143.   assert(*filename != 0);
  144.   ofstream out(filename);
  145.   if (!out) {
  146.     message(-2, "Cannot open file "%s" for writing: %s", filename,
  147.     strerror(errno));
  148.     return 1;
  149.   }
  150.   print(out);
  151.   return 0;
  152. }
  153. int Toc::check() const
  154. {
  155.   TrackEntry *t;
  156.   int ret;
  157.   for (t = tracks_; t != NULL; t = t->next) {
  158.     if ((ret = t->track->check()) != 0) {
  159.       return ret;
  160.     }
  161.   }
  162.   return 0;
  163. }
  164. // Sets catalog number. 's' must be a string of 13 digits.
  165. // return: 0: OK
  166. //         1: illegal catalog string
  167. int Toc::catalog(const char *s)
  168. {
  169.   int i;
  170.   if (s == NULL) {
  171.     catalogValid_ = 0;
  172.     return 0;
  173.   }
  174.   if (strlen(s) != 13) {
  175.     return 1;
  176.   }
  177.   for (i = 0; i < 13; i++) {
  178.     if (!isdigit(s[i]))
  179.       return 1;
  180.   }
  181.   for (i = 0; i < 13; i++)
  182.     catalog_[i] = s[i] - '0';
  183.   catalogValid_ = 1;
  184.   return 0;
  185. }
  186. const char *Toc::catalog() const
  187. {
  188.   static char buf[14];
  189.   int i;
  190.   if (!catalogValid_)
  191.     return NULL;
  192.   for (i = 0; i < 13; i++)
  193.     buf[i] = catalog_[i] + '0';
  194.   buf[13] = 0;
  195.   return buf;
  196. }
  197. // writes contents in TOC file syntax
  198. void Toc::print(ostream &out) const
  199. {
  200.   int i;
  201.   TrackEntry *t;
  202.   out << tocType2String(tocType()) << "nn";
  203.   if (catalogValid()) {
  204.     out << "CATALOG "";
  205.     for (i = 0; i < 13; i++) {
  206.       out << (char)(catalog(i) + '0');
  207.     }
  208.     out << """ << endl;
  209.   }
  210.   cdtext_.print(0, out);
  211.   for (t = tracks_, i = 1; t != NULL; t = t->next, i++) {
  212.     out << "n// Track " << i << "n";
  213.     t->track->print(out);
  214.     out << endl;
  215.   }
  216. }
  217. // find track entry that contains given sample number
  218. // return: found track entry or 'NULL' if sample is out of range
  219. Toc::TrackEntry *Toc::findTrack(unsigned long sample) const
  220. {
  221.   TrackEntry *run;
  222.   for (run = tracks_; run != NULL; run = run->next) {
  223.     if (sample < run->end.samples())
  224.       return run;
  225.   }
  226.   return NULL;
  227. }
  228. // find track with given number
  229. // return: found track entry or 'NULL' if 'trackNr' is out of range
  230. Toc::TrackEntry *Toc::findTrackByNumber(int trackNr) const
  231. {
  232.   TrackEntry *run;
  233.   for (run = tracks_; run != NULL; run = run->next) {
  234.     if (run->trackNr == trackNr)
  235.       return run;
  236.   }
  237.   return NULL;
  238. }
  239. Track *Toc::getTrack(int trackNr)
  240. {
  241.   TrackEntry *ent = findTrackByNumber(trackNr);
  242.   if (ent != NULL)
  243.     return ent->track;
  244.   else
  245.     return NULL;
  246. }
  247. // Moves specified track/index position to given LBA if possible.
  248. // return: 0: OK
  249. //         1: Cannot move pre-gap of first track
  250. //         2: specified track/index position not found in toc
  251. //         3: 'lba' is an illegal position for track/index mark
  252. //         4: resulting track length would be short than 4 seconds
  253. //         5: cannot cross track/index boundaries
  254. //         6: cannot modify data track
  255. int Toc::moveTrackMarker(int trackNr, int indexNr, long lba)
  256. {
  257.   TrackEntry *act;
  258.   if (trackNr == 1 && indexNr == 0)
  259.     return 1;
  260.   if ((act = findTrackByNumber(trackNr)) == NULL) {
  261.     return 2;
  262.   }
  263.   if (indexNr <= 1 && act->track->type() != TrackData::AUDIO)
  264.     return 6;
  265.   if ((indexNr == 0 || (indexNr == 1 && act->track->start().lba() == 0)) &&
  266.       act->pred != NULL && act->pred->track->type() != TrackData::AUDIO)
  267.     return 6;
  268.   
  269.   if (indexNr == 0 && act->track->start().lba() == 0)
  270.     return 2;
  271.   if (indexNr > 1 && indexNr - 2 >= act->track->nofIndices())
  272.     return 2;
  273.   if (lba < 0 || lba >= length().lba())
  274.     return 3;
  275.   if ((indexNr == 1 && (act->track->start().lba() > 0 || trackNr == 1)) ||
  276.       indexNr > 1) {
  277.     // change track/index position within track
  278.     if (indexNr == 1) {
  279.       if (lba > act->end.lba() - 4 * 75)
  280. return 4;
  281.       if (lba <= act->absStart.lba() && trackNr > 1)
  282. return 3;
  283.     }
  284.     else {
  285.       if (lba - act->absStart.lba() <= 0)
  286. return 3;
  287.     }
  288.     switch (act->track->moveIndex(indexNr, lba - act->absStart.lba())) {
  289.     case 1:
  290.       return 4;
  291.     case 2:
  292.       return 5;
  293.     }
  294.   }
  295.   else {
  296.     // move track start position, we need to shift audio data from
  297.     // on track to the other
  298.     // 'act->pred' is always non NULL in this case because track 1 is 
  299.     // exhaustively handled above
  300.     TrackDataList *dataList; // audio data that is removed from one track
  301.     if (lba < act->absStart.lba()) {
  302.       // move to the left
  303.       if (lba < act->pred->start.lba() + 4 * 75)
  304. return 4;
  305.       
  306.       dataList =
  307. act->pred->track->removeToEnd(Msf(lba - act->pred->absStart.lba()).samples());
  308.       act->track->prependTrackData(dataList);
  309.       delete dataList;
  310.       // adjust start of track
  311.       act->track->start(Msf(act->start.lba() - lba));
  312.       if (indexNr == 1)
  313. act->track->moveIndex(1, 0); // remove intermediate pre-gap
  314.     }
  315.     else if (lba > act->absStart.lba()) {
  316.       // move to the right
  317.       
  318.       if (indexNr == 1) {
  319. // introduce an intermediate pre-gap that adjusts the index 
  320. // increments
  321. switch (act->track->moveIndex(1, lba - act->absStart.lba())) {
  322. case 1:
  323.   return 4;
  324. case 2:
  325.   return 5;
  326. }
  327. // remove intermediate pre-gap
  328. act->track->start(Msf(0));
  329.       }
  330.       else {
  331. // adjust pre-gap
  332. if (lba >= act->start.lba())
  333.   return 5;
  334. act->track->start(Msf(act->start.lba() - lba));
  335.       }
  336.       dataList =
  337. act->track->removeFromStart(Msf(lba - act->absStart.lba()).samples());
  338.       act->pred->track->appendTrackData(dataList);
  339.       delete dataList;
  340.     }
  341.   }
  342.   update();
  343.   checkConsistency();
  344.   return 0;
  345. }
  346. void Toc::remove(TrackEntry *ent)
  347. {
  348.   if (ent->pred != NULL)
  349.     ent->pred->next = ent->next;
  350.   else
  351.     tracks_ = ent->next;
  352.   if (ent->next != NULL)
  353.     ent->next->pred = ent->pred;
  354.   else
  355.     lastTrack_ = ent->pred;
  356.   ent->pred = ent->next = NULL;
  357.   ent->track = NULL;
  358.   delete ent;
  359. }
  360. // Removes specified track marker.
  361. // return: 0: OK
  362. //         1: cannot remove first track
  363. //         2: specified track/index position not found in toc
  364. //         3: cannot modify a data track
  365. int Toc::removeTrackMarker(int trackNr, int indexNr)
  366. {
  367.   TrackEntry *act;
  368.   if (trackNr == 1 && indexNr == 1)
  369.     return 1;
  370.   if ((act = findTrackByNumber(trackNr)) == NULL) {
  371.     return 2;
  372.   }
  373.   if (act->track->type() != TrackData::AUDIO && indexNr <= 1)
  374.     return 3;
  375.   if (act->pred != NULL && act->pred->track->type() != TrackData::AUDIO &&
  376.       indexNr <= 1)
  377.     return 3;
  378.   if (trackNr == 1 && indexNr == 0) {
  379.     // pre-gap of first track
  380.     if (act->start.lba() == 0)
  381.       return 2; // no pre-gap
  382.     act->track->start(Msf(0));
  383.   }
  384.   else if (indexNr > 1) {
  385.     // index increment
  386.     if (act->track->removeIndex(indexNr - 2) != 0)
  387.       return 2;
  388.   }
  389.   else if (indexNr == 0) {
  390.     // remove pre-gap, audio data of pre-gap is appended to previous track
  391.     unsigned long len = act->track->start().samples();
  392.     if (len == 0)
  393.       return 2; // track has no pre-gap
  394.     act->track->start(Msf(0));
  395.     TrackDataList *dataList =  act->track->removeFromStart(len);
  396.     act->pred->track->appendTrackData(dataList);
  397.     delete dataList;
  398.   }
  399.   else {
  400.     // index == 1, remove track completely
  401.     
  402.     act->pred->track->appendTrackData(act->track);
  403.     Track *store = act->track;
  404.     remove(act);
  405.     delete store;
  406.     nofTracks_--;
  407.   }
  408.   update();
  409.   checkConsistency();
  410.   return 0;
  411. }
  412. // Adds index increment at given LBA.
  413. // return: 0: OK
  414. //         1: LBA out of range
  415. //         2: cannot add index at this position
  416. //         3: more than 98 index increments
  417. int Toc::addIndexMarker(long lba)
  418. {
  419.   TrackEntry *act = findTrack(Msf(lba).samples());
  420.   if (act == NULL)
  421.     return 1;
  422.   if (lba <= act->start.lba())
  423.     return 2;
  424.   switch (act->track->addIndex(Msf(lba - act->start.lba()))) {
  425.   case 1:
  426.     return 3;
  427.   case 2:
  428.     return 2;
  429.   }
  430.   return 0;
  431. }
  432. // Adds a track marker at given LBA.
  433. // return: 0: OK
  434. //         1: LBA out of range
  435. //         2: cannot add track at this position
  436. //         3: resulting track would be shorter than 4 seconds
  437. //         4: previous track would be short than 4 seconds
  438. //         5: cannot modify a data track
  439. int Toc::addTrackMarker(long lba)
  440. {
  441.   TrackEntry *act = findTrack(Msf(lba).samples());
  442.   if (act == NULL)
  443.     return 1;
  444.   if (act->track->type() != TrackData::AUDIO)
  445.     return 5;
  446.   if (lba <= act->start.lba())
  447.     return 2;
  448.   
  449.   if (lba - act->start.lba() < 4 * 75)
  450.     return 4;
  451.   if (act->end.lba() - lba < 4 * 75)
  452.     return 3;
  453.   TrackDataList *dataList =
  454.     act->track->removeToEnd(Msf(lba - act->absStart.lba()).samples());
  455.   Track *t = new Track(act->track->type());
  456.   t->appendTrackData(dataList);
  457.   delete dataList;
  458.   TrackEntry *ent = new TrackEntry;
  459.   ent->track = t;
  460.   ent->next = act->next;
  461.   if (ent->next != NULL)
  462.     ent->next->pred = ent;
  463.   ent->pred = act;
  464.   act->next = ent;
  465.   
  466.   if (act == lastTrack_)
  467.     lastTrack_ = ent;
  468.   nofTracks_++;
  469.   update();
  470.   checkConsistency();
  471.   return 0;
  472. }
  473. // Adds pre-gap add given LBA.
  474. // return: 0: OK
  475. //         1: LBA out of range
  476. //         2: cannot add pre-gap at this point
  477. //         3: actual track would be shorter than 4 seconds
  478. //         4: cannot modify a data track
  479. int Toc::addPregap(long lba)
  480. {
  481.   TrackEntry *act = findTrack(Msf(lba).samples());
  482.   if (act == NULL)
  483.     return 1;
  484.   if (act->track->type() != TrackData::AUDIO) 
  485.     return 4;
  486.   
  487.   if (act->next == NULL)
  488.     return 2; // no next track where we could add pre-gap
  489.   if (act->next->track->type() != TrackData::AUDIO) 
  490.     return 4;
  491.   
  492.   if (lba <= act->start.lba())
  493.     return 2;
  494.   if (act->next->track->start().lba() != 0)
  495.     return 2; // track has already a pre-gap
  496.   if (lba - act->start.lba() < 4 * 75)
  497.     return 3;
  498.   TrackDataList *dataList =
  499.     act->track->removeToEnd(Msf(lba - act->absStart.lba()).samples());
  500.   act->next->track->prependTrackData(dataList);
  501.   delete dataList;
  502.   act->next->track->start(Msf(act->next->start.lba() - lba));
  503.   update();
  504.   checkConsistency();
  505.   return 0;
  506. }
  507. void Toc::checkConsistency()
  508. {
  509.   TrackEntry *run, *last = NULL;
  510.   long cnt = 0;
  511.   for (run = tracks_; run != NULL; last = run, run = run->next) {
  512.     cnt++;
  513.     if (run->pred != last) 
  514.       message(-3, "Toc::checkConsistency: wrong pred pointer.");
  515.     run->track->checkConsistency();
  516.   }
  517.   if (last != lastTrack_)
  518.     message(-3, "Toc::checkConsistency: wrong last pointer.");
  519.   if (cnt != nofTracks_)
  520.     message(-3, "Toc::checkConsistency: wrong sub track counter.");
  521. }
  522. // Appends a track with given audio data. 'start' is filled with
  523. // first LBA of new track, 'end' is filled with last LBA + 1 of new track.
  524. void Toc::appendTrack(const TrackDataList *list, long *start, long *end)
  525. {
  526.   Track t(TrackData::AUDIO);
  527.   const TrackData *run;
  528.   for (run = list->first(); run != NULL; run = list->next())
  529.     t.append(SubTrack(SubTrack::DATA, *run));
  530.   // ensure that track lasts at least 4 seconds
  531.   unsigned long minTime = 4 * 75 * SAMPLES_PER_BLOCK; // 4 seconds
  532.   unsigned long len = list->length();
  533.   if (len < minTime)
  534.     t.append(SubTrack(SubTrack::DATA,
  535.       TrackData(TrackData::AUDIO, minTime - len)));
  536.   *start = length().lba();
  537.   append(&t);
  538.   checkConsistency();
  539.   *end = length().lba();
  540. }
  541. // Appends given audio data to last track. If no track exists 'appendTrack'
  542. // will be called. 'start' and 'end' is filled with position of modified
  543. // region.
  544. // Return: 0: OK
  545. //         1: cannot modify a data track
  546. int Toc::appendTrackData(const TrackDataList *list, long *start, long *end)
  547. {
  548.   const TrackData *run;
  549.   if (lastTrack_ == NULL) {
  550.     appendTrack(list, start, end);
  551.     return 0;
  552.   }
  553.   if (lastTrack_->track->type() != TrackData::AUDIO)
  554.     return 1;
  555.   *start = length().lba();
  556.   for (run = list->first(); run != NULL; run = list->next())
  557.     lastTrack_->track->append(SubTrack(SubTrack::DATA, *run));
  558.   
  559.   update();
  560.   checkConsistency();
  561.   *end = length().lba();
  562.   return 0;
  563. }
  564. // Removes specified range of samples from a single track.
  565. // Return: 0: OK
  566. //         1: samples range covers more than one track
  567. //         2: cannot modify a data track
  568. //         3: illegal 'start' position
  569. int Toc::removeTrackData(unsigned long start, unsigned long end,
  570.  TrackDataList **list)
  571. {
  572.   TrackEntry *tent = findTrack(start);
  573.   if (tent == NULL)
  574.     return 3;
  575.   if (tent->track->type() != TrackData::AUDIO)
  576.     return 2;
  577.   if (tent != findTrack(end))
  578.     return 1;
  579.   *list = tent->track->removeTrackData(start - tent->absStart.samples(),
  580.        end - tent->absStart.samples());
  581.   update();
  582.   checkConsistency();
  583.   
  584.   return 0;
  585. }
  586. // Inserts given track data at specified postion.
  587. // Return: 0: OK
  588. //         1: cannot modify a data track
  589. int Toc::insertTrackData(unsigned long pos, const TrackDataList *list)
  590. {
  591.   TrackEntry *tent = findTrack(pos);
  592.   if (tent != NULL && tent->track->type() != TrackData::AUDIO)
  593.     return 1;
  594.   
  595.   if (tent != NULL) {
  596.     tent->track->insertTrackData(pos - tent->absStart.samples(), list);
  597.     update();
  598.     checkConsistency();
  599.     return 0;
  600.   }
  601.   else {
  602.     long start, end;
  603.     return appendTrackData(list, &start, &end);
  604.   }
  605. }
  606. // Returns mode that should be used for lead-in. The mode of first track's
  607. // first sub-track is used.
  608. TrackData::Mode Toc::leadInMode() const
  609. {
  610.   const SubTrack *t;
  611.   if (tracks_ == NULL || (t = tracks_->track->firstSubTrack()) == NULL) {
  612.     // no track or track data available - return AUDIO in this case
  613.     return TrackData::AUDIO;
  614.   }
  615.   return t->mode();
  616. }
  617. // Returns mode that should be used for lead-out. The mode of last track's
  618. // last sub-track is used
  619. TrackData::Mode Toc::leadOutMode() const
  620. {
  621.   const SubTrack *t;
  622.   if (lastTrack_ == NULL || (t = lastTrack_->track->lastSubTrack()) == NULL) {
  623.     // no track or track data available - return AUDIO in this case
  624.     return TrackData::AUDIO;
  625.   }
  626.   return t->mode();
  627. }
  628. const char *Toc::tocType2String(TocType t)
  629. {
  630.   const char *ret = NULL;
  631.   switch (t) {
  632.   case CD_DA:
  633.     ret = "CD_DA";
  634.     break;
  635.   case CD_ROM:
  636.     ret = "CD_ROM";
  637.     break;
  638.   case CD_I:
  639.     ret = "CD_I";
  640.     break;
  641.   case CD_ROM_XA:
  642.     ret = "CD_ROM_XA";
  643.     break;
  644.   }
  645.   return ret;
  646. }
  647. void Toc::addCdTextItem(int trackNr, CdTextItem *item)
  648. {
  649.   assert(trackNr >= 0 && trackNr <= 99);
  650.   if (trackNr == 0) {
  651.     cdtext_.add(item);
  652.   }
  653.   else {
  654.     TrackEntry *track = findTrackByNumber(trackNr);
  655.     if (track == NULL) {
  656.       message(-3, "addCdTextItem: Track %d is not available.", trackNr);
  657.       return;
  658.     }
  659.     track->track->addCdTextItem(item);
  660.   }
  661. }
  662. void Toc::removeCdTextItem(int trackNr, CdTextItem::PackType type, int blockNr)
  663. {
  664.   assert(trackNr >= 0 && trackNr <= 99);
  665.   if (trackNr == 0) {
  666.     cdtext_.remove(type, blockNr);
  667.   }
  668.   else {
  669.     TrackEntry *track = findTrackByNumber(trackNr);
  670.     if (track == NULL) {
  671.       message(-3, "addCdTextItem: Track %d is not available.", trackNr);
  672.       return;
  673.     }
  674.     track->track->removeCdTextItem(type, blockNr);
  675.   }
  676. }
  677. int Toc::existCdTextBlock(int blockNr) const
  678. {
  679.   if (cdtext_.existBlock(blockNr))
  680.     return 1;
  681.   TrackEntry *run;
  682.   for (run = tracks_; run != NULL; run = run->next) {
  683.     if (run->track->existCdTextBlock(blockNr))
  684.       return 1;
  685.   }
  686.   return 0;
  687. }
  688. const CdTextItem *Toc::getCdTextItem(int trackNr, int blockNr,
  689.      CdTextItem::PackType type) const
  690. {
  691.   if (trackNr == 0) {
  692.     return cdtext_.getPack(blockNr, type);
  693.   }
  694.   TrackEntry *track = findTrackByNumber(trackNr);
  695.   if (track == NULL)
  696.     return NULL;
  697.   return track->track->getCdTextItem(blockNr, type);
  698. }
  699. void Toc::cdTextLanguage(int blockNr, int lang)
  700. {
  701.   cdtext_.language(blockNr, lang);
  702. }
  703. int Toc::cdTextLanguage(int blockNr) const
  704. {
  705.   return cdtext_.language(blockNr);
  706. }
  707. // Check the consistency of the CD-TEXT data.
  708. // Return: 0: OK
  709. //         1: at least one warning occured
  710. //         2: at least one error occured
  711. int Toc::checkCdTextData() const
  712. {
  713.   TrackEntry *trun;
  714.   int err = 0;
  715.   int l;
  716.   int last;
  717.   int titleCnt, performerCnt, songwriterCnt, composerCnt, arrangerCnt;
  718.   int messageCnt, isrcCnt, genreCnt;
  719.   int languageCnt = 0;
  720.   genreCnt = 0;
  721.   // Check if language numbers are continuously used starting at 0
  722.   for (l = 0, last = -1; l <= 7; l++) {
  723.     if (cdTextLanguage(l) >= 0) {
  724.       languageCnt++;
  725.       if (cdtext_.getPack(l, CdTextItem::CDTEXT_GENRE) != NULL)
  726. genreCnt++;
  727.       if (l - 1 != last) {
  728. if (last == -1)
  729.   message(-2, "CD-TEXT: Language number %d: Language numbers must start at 0.", l);
  730. else
  731.   message(-2, "CD-TEXT: Language number %d: Language numbers are not continuously used.", l);
  732. if (err < 2)
  733.   err = 2;
  734.       }
  735.       
  736.       last = l;
  737.     }
  738.   }
  739.   if (genreCnt > 0 && genreCnt != languageCnt) {
  740.     message(-1, "CD-TEXT: %s field not defined for all languages.",
  741.     CdTextItem::packType2String(1, CdTextItem::CDTEXT_GENRE));
  742.     if (err < 1)
  743.       err = 1;
  744.   }
  745.   for (l = 0, last = -1; l <= 7; l++) {
  746.     if (cdTextLanguage(l) < 0)
  747.       continue;
  748.     titleCnt = (cdtext_.getPack(l, CdTextItem::CDTEXT_TITLE) != NULL) ? 1 : 0;
  749.     performerCnt = (cdtext_.getPack(l, CdTextItem::CDTEXT_PERFORMER) != NULL) ? 1 : 0;
  750.     songwriterCnt = (cdtext_.getPack(l, CdTextItem::CDTEXT_SONGWRITER) != NULL) ? 1 : 0;
  751.     composerCnt = (cdtext_.getPack(l, CdTextItem::CDTEXT_COMPOSER) != NULL) ? 1 : 0;
  752.     arrangerCnt = (cdtext_.getPack(l, CdTextItem::CDTEXT_ARRANGER) != NULL) ? 1 : 0;
  753.     messageCnt = (cdtext_.getPack(l, CdTextItem::CDTEXT_MESSAGE) != NULL) ? 1 : 0;
  754.     isrcCnt = 0;
  755.     
  756.     for (trun = tracks_; trun != NULL; trun = trun->next) {
  757.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_TITLE) != NULL)
  758. titleCnt++;
  759.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_PERFORMER) != NULL)
  760. performerCnt++;
  761.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_SONGWRITER) != NULL)
  762. songwriterCnt++;
  763.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_COMPOSER) != NULL)
  764. composerCnt++;
  765.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_ARRANGER) != NULL)
  766. arrangerCnt++;
  767.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_MESSAGE) != NULL)
  768. messageCnt++;
  769.       if (trun->track->getCdTextItem(l, CdTextItem::CDTEXT_UPCEAN_ISRC) != NULL)
  770. isrcCnt++;
  771.     }
  772.     if (titleCnt > 0 && titleCnt != nofTracks_ + 1) {
  773.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.",
  774.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_TITLE));
  775.       if (err < 2)
  776. err = 2;
  777.     }
  778.     else if (titleCnt == 0) {
  779.       message(-1, "CD-TEXT: Language %d: %s field is not defined.",
  780.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_TITLE));
  781.       if (err < 1)
  782. err = 1;
  783.     }
  784.     if (performerCnt > 0 && performerCnt != nofTracks_ + 1) {
  785.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.",
  786.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_PERFORMER));
  787.       if (err < 2)
  788. err = 2;
  789.     }
  790.     else if (performerCnt == 0) {
  791.       message(-1, "CD-TEXT: Language %d: %s field is not defined.",
  792.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_PERFORMER));
  793.       if (err < 1)
  794. err = 1;
  795.     }
  796.     if (songwriterCnt > 0 && songwriterCnt != nofTracks_ + 1) {
  797.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.",
  798.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_SONGWRITER));
  799.       if (err < 2)
  800. err = 2;
  801.     }
  802.     if (composerCnt > 0 && composerCnt != nofTracks_ + 1) {
  803.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.",
  804.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_COMPOSER));
  805.       if (err < 2)
  806. err = 2;
  807.     }
  808.     if (arrangerCnt > 0 && arrangerCnt != nofTracks_ + 1) {
  809.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.",
  810.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_ARRANGER));
  811.       if (err < 2)
  812. err = 2;
  813.     }
  814.     if (messageCnt > 0 && messageCnt != nofTracks_ + 1) {
  815.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.",
  816.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_MESSAGE));
  817.       if (err < 2)
  818. err = 2;
  819.     }
  820.     if ((isrcCnt > 0 && isrcCnt != nofTracks_) ||
  821. (isrcCnt == 0 &&
  822.  cdtext_.getPack(l, CdTextItem::CDTEXT_UPCEAN_ISRC) != NULL)) {
  823.       message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks.",
  824.       l, CdTextItem::packType2String(1, CdTextItem::CDTEXT_UPCEAN_ISRC));
  825.       if (err < 2)
  826. err = 2;
  827.     }
  828.   }
  829.   return err;
  830. }
  831. // Class TrackIterator
  832. TrackIterator::TrackIterator(const Toc *t)
  833. {
  834.   toc_ = t;
  835.   iterator_ = NULL;
  836. }
  837. TrackIterator::~TrackIterator()
  838. {
  839.   toc_ = NULL;
  840.   iterator_ = NULL;
  841. }
  842. const Track *TrackIterator::find(int trackNr, Msf &start, Msf &end)
  843. {
  844.   Track *t;
  845.   iterator_ = toc_->findTrackByNumber(trackNr);
  846.   if (iterator_ != NULL) {
  847.     start = iterator_->start;
  848.     end = iterator_->end;
  849.     t = iterator_->track;
  850.     iterator_ = iterator_->next;
  851.     return t;
  852.   }
  853.    
  854.   return NULL;
  855. }
  856.   
  857. const Track *TrackIterator::find(unsigned long sample, Msf &start, Msf &end,
  858.  int *trackNr)
  859. {
  860.   Track *t;
  861.   iterator_ = toc_->findTrack(sample);
  862.   if (iterator_ != NULL) {
  863.     start = iterator_->start;
  864.     end = iterator_->end;
  865.     *trackNr = iterator_->trackNr;
  866.     t = iterator_->track;
  867.     iterator_ = iterator_->next;
  868.     return t;
  869.   }
  870.    
  871.   return NULL;
  872. }
  873. const Track *TrackIterator::first(Msf &start, Msf &end)
  874. {
  875.   iterator_ = toc_->tracks_;
  876.   return next(start, end);
  877. }
  878. const Track *TrackIterator::next(Msf &start, Msf &end)
  879. {
  880.   Track *t;
  881.   if (iterator_ != NULL) {
  882.     start = iterator_->start;
  883.     end = iterator_->end;
  884.     t = iterator_->track;
  885.     iterator_ = iterator_->next;
  886.     return t;
  887.   }
  888.   else {
  889.     return NULL;
  890.   }
  891. }
  892. // Class TocReader
  893. TocReader::TocReader(const Toc *t) : reader(NULL)
  894. {
  895.   toc_ = t;
  896.   
  897.   readTrack_ = NULL;
  898.   readPos_ = 0;
  899.   readPosSample_ = 0;
  900.   open_ = 0;
  901. }
  902. TocReader::~TocReader ()
  903. {
  904.   if (open_) {
  905.     closeData();
  906.   }
  907.   toc_ = NULL;
  908.   readTrack_ = NULL;
  909. }
  910. void TocReader::init(const Toc *t)
  911. {
  912.   if (open_) {
  913.     closeData();
  914.   }
  915.   reader.init(NULL);
  916.   toc_ = t;
  917.   readTrack_ = NULL;
  918. }
  919. int TocReader::openData()
  920. {
  921.   int ret = 0;
  922.   assert(open_ == 0);
  923.   assert(toc_ != NULL);
  924.   readTrack_ = toc_->tracks_;
  925.   readPos_ = 0;
  926.   readPosSample_ = 0;
  927.   reader.init(readTrack_->track);
  928.   if (readTrack_ != NULL) {
  929.     ret = reader.openData();
  930.   }
  931.   open_ = 1;
  932.   return ret;
  933. }
  934. void TocReader::closeData()
  935. {
  936.   if (open_ != 0) {
  937.     reader.closeData();
  938.     readTrack_ = NULL;
  939.     readPos_ = 0;
  940.     open_ = 0;
  941.     readPosSample_ = 0;
  942.   }
  943. }
  944. long TocReader::readData(long lba, char *buf, long len)
  945. {
  946.   long n;
  947.   long nread = 0;
  948.   assert(open_ != 0);
  949.   
  950.   if (readPos_ + len > toc_->length_.lba()) {
  951.     if ((len = toc_->length_.lba() - readPos_) <= 0) {
  952.       return 0;
  953.     }
  954.   }
  955.   do {
  956.     n = reader.readData(0, lba, buf + (nread * AUDIO_BLOCK_LEN), len);
  957.     if (n < 0) {
  958.       return -1;
  959.     }
  960.     lba += n;
  961.     if (n != len) {
  962.       // skip to next track
  963.       readTrack_ = readTrack_->next;
  964.       assert(readTrack_ != NULL);
  965.       reader.init(readTrack_->track);
  966.       if (reader.openData() != 0) {
  967. return -1;
  968.       }
  969.     }
  970.     
  971.     nread += n;
  972.     len -= n;
  973.   } while (len > 0);
  974.   
  975.   readPos_ += nread;
  976.  
  977.   return nread;
  978. }
  979. // seeks to specified sample (absolute position)
  980. // return: 0: OK
  981. //         10: sample position out of range
  982. //         return codes from 'Track::openData()'
  983. int TocReader::seekSample(unsigned long sample)
  984. {
  985.   int ret;
  986.   assert(open_ != 0);
  987.   // find track that contains 'sample'
  988.   Toc::TrackEntry *tr = toc_->findTrack(sample);
  989.   if (tr == NULL)
  990.     return 10;
  991.   // open track if necessary
  992.   if (tr != readTrack_) {
  993.     readTrack_ = tr;
  994.     reader.init(readTrack_->track);
  995.     if ((ret = reader.openData() != 0))
  996.       return ret;
  997.   }
  998.   assert(sample >= readTrack_->absStart.samples());
  999.   unsigned long offset = sample - readTrack_->absStart.samples();
  1000.   // seek in track
  1001.   if ((ret = reader.seekSample(offset)) != 0)
  1002.     return ret;
  1003.   readPosSample_ = sample;
  1004.   return 0;
  1005. }
  1006. long TocReader::readSamples(Sample *buf, long len)
  1007. {
  1008.   long n;
  1009.   long nread = 0;
  1010.   assert(open_ != 0);
  1011.   
  1012.   if (readPosSample_ + (unsigned long)len > toc_->length_.samples()) {
  1013.     if ((len = toc_->length_.samples() - readPosSample_) <= 0)
  1014.       return 0;
  1015.   }
  1016.   do {
  1017.     n = reader.readSamples(buf + nread , len);
  1018.     if (n < 0)
  1019.       return -1;
  1020.     if (n != len) {
  1021.       // skip to next track
  1022.       readTrack_ = readTrack_->next;
  1023.       reader.init(readTrack_->track);
  1024.       assert(readTrack_ != NULL);
  1025.       if (reader.openData() != 0) {
  1026. return -1;
  1027.       }
  1028.     }
  1029.     
  1030.     nread += n;
  1031.     len -= n;
  1032.   } while (len > 0);
  1033.   
  1034.   readPosSample_ += nread;
  1035.  
  1036.   return nread;
  1037. }