diff --git a/src/dvdcopy.cc b/src/dvdcopy.cc index 528c1cf..689f437 100644 --- a/src/dvdcopy.cc +++ b/src/dvdcopy.cc @@ -44,6 +44,33 @@ int debug = 1; +std::string BadSectors::toString() const +{ + char buffer[1024]; + snprintf(buffer, sizeof(buffer), + "%s: %d,%d,%d %d (%d)", + file->fileName().c_str(), + file->title, + file->domain, + file->number, + start, number); + return std::string(buffer); +} + +bool BadSectors::tryMerge(const BadSectors & follower) +{ + if(follower.file != file) + return false; + if(start + number != follower.start) + return false; + number += follower.number; + return true; +} + + +////////////////////////////////////////////////////////////////////// + + DVDCopy::DVDCopy() : badSectors(NULL) { reader = NULL; @@ -219,8 +246,6 @@ void DVDCopy::scanForBadSectors(const char *device, { setup(device, NULL); - badSectors = fopen(badSectorsFile, "w"); - for(std::vector::iterator i = files.begin(); i != files.end(); i++) { DVDFileData * dat = *i; @@ -241,20 +266,35 @@ void DVDCopy::scanForBadSectors(const char *device, if(buffer[2] == 1 && buffer[first_pes_offset + 3] == 1) continue; else - registerBadSectors(dat, blk + i, 1); + registerBadSectors(dat, blk + i, 1, true); } }; auto failure = [this](int blk, int nb, const DVDFileData * dat) { - registerBadSectors(dat, blk, nb); + registerBadSectors(dat, blk, nb, true); }; file->walkFile(0, sz, 128, success, failure); - /// @todo Compact the bad sectors file (this should be done at the - /// very end, rewriting the whole file) } + + // OK, now, we have a list of bad sectors. We simplify it + std::vector simplifiedBad; + for(int i = 0; i < badSectorsList.size(); i++) { + const BadSectors & bs = badSectorsList[i]; + if(!i) + simplifiedBad.push_back(bs); + else { + if(! simplifiedBad.back().tryMerge(bs)) + simplifiedBad.push_back(bs); + } + } + + FILE * bad = fopen(badSectorsFile, "w"); + for(int i = 0; i < simplifiedBad.size(); i++) + fprintf(bad, "%s\n", + simplifiedBad[i].toString().c_str()); } DVDCopy::~DVDCopy() @@ -277,18 +317,15 @@ void DVDCopy::openBadSectorsFile(const char * mode) } void DVDCopy::registerBadSectors(const DVDFileData * dat, - int beg, int size) + int beg, int size, bool dontWrite) { - openBadSectorsFile("a"); - fprintf(badSectors, "%s: %d,%d,%d %d (%d)\n", - dat->fileName().c_str(), - dat->title, - dat->domain, - dat->number, - beg, size); - fflush(badSectors); - badSectorsList.push_back(BadSectors(dat, beg, size)); + if(! dontWrite) { + openBadSectorsFile("a"); + fprintf(badSectors, "%s\n", + badSectorsList.back().toString().c_str()); + fflush(badSectors); + } } int DVDCopy::findFile(int title, dvd_read_domain_t domain, int number) diff --git a/src/dvdcopy.hh b/src/dvdcopy.hh index 691336f..9fead3b 100644 --- a/src/dvdcopy.hh +++ b/src/dvdcopy.hh @@ -22,6 +22,33 @@ #include "dvdreader.hh" +/// Class representing a series of consecutive bad sectors. +/// +/// @todo Write to- and from- string methods. +class BadSectors { +public: + + /// The underlying DVD file (ie something in the files list) + const DVDFileData * file; + + /// The starting sector + int start; + + /// The number of bad sectors; + int number; + + BadSectors(const DVDFileData * f, int s, int n) : + file(f), start(s), number(n) {;} + + /// Transform into a string + std::string toString() const; + + /// If the given bad sector is next to this one, appends it and + /// return true, else return false + bool tryMerge(const BadSectors & follower); +}; + + /// Handles the actual copying job, from a source to a target. class DVDCopy { /// Copies one file. @@ -47,10 +74,12 @@ class DVDCopy { /// In the hope to be read again... FILE * badSectors; - /// Writes a bad sector list to the file, and add them to the - /// badSectors list. + /// Writes a bad sector list to the bad sectors file (unless + /// dontWrite is true), and add them to the badSectors list (in any + /// case). void registerBadSectors(const DVDFileData * dat, - int beg, int size); + int beg, int size, + bool dontWrite = false); /// sets up the reader and gets the list of files, and sets up the @@ -60,25 +89,6 @@ class DVDCopy { /// The underlying files of the source std::vector files; - /// Subclass representing a single line in a bad sectors file. - /// - /// @todo Write to- and from- string methods. - class BadSectors { - public: - - /// The underlying DVD file (ie something in the files list) - const DVDFileData * file; - - /// The starting sector - int start; - - /// The number of bad sectors; - int number; - - BadSectors(const DVDFileData * f, int s, int n) : - file(f), start(s), number(n) {;} - }; - /// The list of bad sectors, either read from the bad sectors file /// or directly populated registerBadSectors std::vector badSectorsList;