Switch to a more object-oriented way to read DVD files, though it admittedly could be more OOed still
This commit is contained in:
parent
e7f5d26c94
commit
01e56bc301
5 changed files with 161 additions and 123 deletions
|
|
@ -3,7 +3,8 @@ bin_PROGRAMS = dvdcopy secdump
|
|||
dvdcopy_SOURCES = src/main.cc src/headers.hh \
|
||||
src/dvdcopy.hh src/dvdcopy.cc \
|
||||
src/dvdoutfile.hh src/dvdoutfile.cc \
|
||||
src/dvdreader.hh src/dvdreader.cc
|
||||
src/dvdreader.hh src/dvdreader.cc \
|
||||
src/dvdfile.hh src/dvdfile.cc
|
||||
|
||||
secdump_SOURCES = src/secdump.cc
|
||||
|
||||
|
|
|
|||
197
src/dvdcopy.cc
197
src/dvdcopy.cc
|
|
@ -20,6 +20,7 @@
|
|||
#include "headers.hh"
|
||||
#include "dvdcopy.hh"
|
||||
|
||||
#include "dvdfile.hh"
|
||||
#include "dvdoutfile.hh"
|
||||
|
||||
#include <stdio.h>
|
||||
|
|
@ -101,9 +102,16 @@ int DVDCopy::copyFile(const DVDFileData * dat, int firstBlock,
|
|||
if(dat->number > 1)
|
||||
return 0;
|
||||
|
||||
dvd_file_t * file = DVDOpenFile(reader, dat->title, dat->domain);
|
||||
DVDOutFile outfile(targetDirectory.c_str(), dat->title, dat->domain);
|
||||
|
||||
DVDFile * f = DVDFile::openFile(reader, dat);
|
||||
if(! f) {
|
||||
std::string fileName = outfile.currentOutputName();
|
||||
printf("\nSkipping file %s (not found)\n", fileName.c_str());
|
||||
return 0;
|
||||
}
|
||||
std::unique_ptr<DVDFile> file(f);
|
||||
|
||||
/* Data structures necessary for progress report */
|
||||
struct timeval init;
|
||||
struct timeval current;
|
||||
|
|
@ -112,125 +120,80 @@ int DVDCopy::copyFile(const DVDFileData * dat, int firstBlock,
|
|||
double estimated_seconds;
|
||||
double rate;
|
||||
const char * rate_suffix;
|
||||
if(file) {
|
||||
int size = DVDFileSize(file);
|
||||
int current_size = outfile.fileSize();
|
||||
if(firstBlock > 0)
|
||||
current_size = firstBlock; // Seek to the beginning of the
|
||||
|
||||
int size = file->fileSize();
|
||||
int current_size = outfile.fileSize();
|
||||
if(firstBlock > 0)
|
||||
current_size = firstBlock; // Seek to the beginning of the
|
||||
// region to be read
|
||||
int read;
|
||||
int blk = 0;
|
||||
unsigned nb; /* The number of blocks we're about to read */
|
||||
int skipped = 0;
|
||||
if(current_size == size) {
|
||||
printf("File already fully read: not reading again\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now, if current_size > 0:
|
||||
- seek the input file, if necessary
|
||||
- seek the output file...
|
||||
*/
|
||||
if(current_size > 0) {
|
||||
if(dat->domain == DVD_READ_INFO_FILE ||
|
||||
dat->domain == DVD_READ_INFO_BACKUP_FILE)
|
||||
DVDFileSeek(file, current_size * 2048);
|
||||
else
|
||||
blk = current_size;
|
||||
|
||||
outfile.seek(current_size);
|
||||
size -= current_size;
|
||||
const char * fmt =
|
||||
(firstBlock > 0 ?
|
||||
"Partial read starting at sector %d\n":
|
||||
"File already partially read: using %d sectors\n");
|
||||
|
||||
printf(fmt, current_size);
|
||||
}
|
||||
if(blockNumber > 0)
|
||||
size = blockNumber; // we read only the relevant portion
|
||||
switch(dat->domain) {
|
||||
case DVD_READ_INFO_FILE:
|
||||
case DVD_READ_INFO_BACKUP_FILE:
|
||||
size *= 2048; /* The number of bytes to read ! */
|
||||
while(size > 0) {
|
||||
read = DVDReadBytes(file, readBuffer,
|
||||
(size > BUF_SIZE) ? BUF_SIZE : size);
|
||||
if(read < 0) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
outfile.writeSectors(readBuffer, read/2048);
|
||||
size -= read;
|
||||
}
|
||||
break;
|
||||
case DVD_READ_MENU_VOBS:
|
||||
case DVD_READ_TITLE_VOBS:
|
||||
/* TODO: error handling */
|
||||
gettimeofday(&init, NULL);
|
||||
printf("Reading %d sectors at a time\n", readNumber);
|
||||
while(size > 0) {
|
||||
/* First, we determine the number of blocks to be read */
|
||||
if(size > readNumber)
|
||||
nb = readNumber;
|
||||
else
|
||||
nb = size;
|
||||
|
||||
std::string fileName = outfile.currentOutputName();
|
||||
printf("\rReading block %7d/%d (%s)",
|
||||
blk, blk + size, fileName.c_str());
|
||||
read = DVDReadBlocks(file, blk, nb, (unsigned char*) readBuffer);
|
||||
|
||||
if(read < 0) {
|
||||
/* There was an error reading the file. */
|
||||
printf("\rError while reading block %d of file %s, skipping\n",
|
||||
blk, fileName.c_str());
|
||||
outfile.skipSectors(nb);
|
||||
registerBadSectors(dat, blk, nb);
|
||||
read = nb;
|
||||
skipped += nb;
|
||||
}
|
||||
else {
|
||||
outfile.writeSectors(readBuffer, read);
|
||||
}
|
||||
size -= read;
|
||||
blk += read;
|
||||
gettimeofday(¤t, NULL);
|
||||
elapsed_seconds = current.tv_sec - init.tv_sec +
|
||||
1e-6 * (current.tv_usec - init.tv_usec);
|
||||
estimated_seconds = elapsed_seconds * (blk + size)/(blk);
|
||||
rate = (blk * 2048.)/(elapsed_seconds);
|
||||
if(rate >= 1e6) {
|
||||
rate_suffix = "MB/s";
|
||||
rate /= 1e6;
|
||||
}
|
||||
else if(rate >= 1e3) {
|
||||
rate_suffix = "kB/s";
|
||||
rate /= 1e3;
|
||||
}
|
||||
else
|
||||
rate_suffix = "B/s";
|
||||
printf(" (%02d:%02d out of %02d:%02d, %5.1f%s)",
|
||||
((int) elapsed_seconds) / 60, ((int) elapsed_seconds) % 60,
|
||||
((int) estimated_seconds) / 60, ((int) estimated_seconds) % 60,
|
||||
rate, rate_suffix);
|
||||
fflush(stdout);
|
||||
}
|
||||
outfile.closeFile();
|
||||
DVDCloseFile(file);
|
||||
if(skipped) {
|
||||
printf("\nThere were %d sectors skipped in this title set\n",
|
||||
skipped);
|
||||
}
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
else {
|
||||
std::string fileName = outfile.currentOutputName();
|
||||
printf("\nSkipping file %s (not found)\n", fileName.c_str());
|
||||
int read;
|
||||
int blk = 0;
|
||||
unsigned nb; /* The number of blocks we're about to read */
|
||||
int skipped = 0;
|
||||
if(current_size == size) {
|
||||
printf("File already fully read: not reading again\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: error handling */
|
||||
gettimeofday(&init, NULL);
|
||||
printf("Reading %d sectors at a time\n", readNumber);
|
||||
while(size > 0) {
|
||||
/* First, we determine the number of blocks to be read */
|
||||
if(size > readNumber)
|
||||
nb = readNumber;
|
||||
else
|
||||
nb = size;
|
||||
|
||||
std::string fileName = outfile.currentOutputName();
|
||||
printf("\rReading block %7d/%d (%s)",
|
||||
blk, blk + size, fileName.c_str());
|
||||
read = file->readBlocks(blk, nb, (unsigned char*) readBuffer);
|
||||
|
||||
if(read < 0) {
|
||||
/* There was an error reading the file. */
|
||||
printf("\nError while reading block %d of file %s, skipping\n",
|
||||
blk, fileName.c_str());
|
||||
outfile.skipSectors(nb);
|
||||
registerBadSectors(dat, blk, nb);
|
||||
read = nb;
|
||||
skipped += nb;
|
||||
}
|
||||
else {
|
||||
outfile.writeSectors(readBuffer, read);
|
||||
}
|
||||
size -= read;
|
||||
blk += read;
|
||||
|
||||
// Progress report
|
||||
gettimeofday(¤t, NULL);
|
||||
|
||||
elapsed_seconds = current.tv_sec - init.tv_sec +
|
||||
1e-6 * (current.tv_usec - init.tv_usec);
|
||||
estimated_seconds = elapsed_seconds * (blk + size)/(blk);
|
||||
rate = (blk * 2048.)/(elapsed_seconds);
|
||||
if(rate >= 1e6) {
|
||||
rate_suffix = "MB/s";
|
||||
rate /= 1e6;
|
||||
}
|
||||
else if(rate >= 1e3) {
|
||||
rate_suffix = "kB/s";
|
||||
rate /= 1e3;
|
||||
}
|
||||
else
|
||||
rate_suffix = "B/s";
|
||||
printf(" (%02d:%02d out of %02d:%02d, %5.1f%s)",
|
||||
((int) elapsed_seconds) / 60, ((int) elapsed_seconds) % 60,
|
||||
((int) estimated_seconds) / 60, ((int) estimated_seconds) % 60,
|
||||
rate, rate_suffix);
|
||||
fflush(stdout);
|
||||
}
|
||||
outfile.closeFile();
|
||||
if(skipped) {
|
||||
printf("\nThere were %d sectors skipped in this title set\n",
|
||||
skipped);
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
void DVDCopy::setup(const char *device, const char * target)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@
|
|||
*/
|
||||
|
||||
#include "headers.hh"
|
||||
#include "dvdoutfile.hh"
|
||||
#include "dvdfile.hh"
|
||||
#include "dvdreader.hh"
|
||||
|
||||
/* For stat(2), open(2) and comrades... */
|
||||
#include <sys/types.h>
|
||||
|
|
@ -32,12 +33,26 @@
|
|||
|
||||
#define SECTOR_SIZE 2048
|
||||
|
||||
|
||||
|
||||
/// Files that work byte-by-byte
|
||||
class DVDByteFile : public DVDFile {
|
||||
int blockOffset;
|
||||
public:
|
||||
virtual int readBlocks(int blocks, int offset, unsigned char * dest) {
|
||||
|
||||
virtual int readBlocks(int offset, int blocks, unsigned char * dest) {
|
||||
if(offset != blockOffset) {
|
||||
/// @todo error handling here.
|
||||
DVDFileSeek(file, offset * SECTOR_SIZE);
|
||||
}
|
||||
|
||||
/// @todo By construction, this function doesn't work with
|
||||
/// sub-sector granularity.
|
||||
int nbread = DVDReadBytes(file, dest, blocks * SECTOR_SIZE);
|
||||
if(nbread < 0)
|
||||
return -1;
|
||||
nbread /= SECTOR_SIZE;
|
||||
blockOffset = offset + nbread;
|
||||
return nbread; // Great !
|
||||
}
|
||||
|
||||
DVDByteFile(dvd_file_t * f) :
|
||||
|
|
@ -47,3 +62,58 @@ public:
|
|||
}
|
||||
|
||||
};
|
||||
|
||||
/// Files that work sectors by sectors
|
||||
class DVDBlockFile : public DVDFile {
|
||||
public:
|
||||
virtual int readBlocks(int offset, int blocks, unsigned char * dest) {
|
||||
return DVDReadBlocks(file, offset, blocks, dest);
|
||||
}
|
||||
|
||||
DVDBlockFile(dvd_file_t * f) :
|
||||
DVDFile(f)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
DVDFile::DVDFile(dvd_file_t * f) :
|
||||
file(f)
|
||||
{
|
||||
// file shouldn't be 0 !
|
||||
}
|
||||
|
||||
DVDFile::~DVDFile()
|
||||
{
|
||||
DVDCloseFile(file);
|
||||
}
|
||||
|
||||
|
||||
int DVDFile::fileSize()
|
||||
{
|
||||
return DVDFileSize(file);
|
||||
}
|
||||
|
||||
DVDFile * DVDFile::openFile(dvd_reader_t * reader, const DVDFileData * dat)
|
||||
{
|
||||
dvd_file_t * file = DVDOpenFile(reader, dat->title, dat->domain);
|
||||
if(! file)
|
||||
return NULL;
|
||||
|
||||
switch(dat->domain) {
|
||||
case DVD_READ_INFO_FILE:
|
||||
case DVD_READ_INFO_BACKUP_FILE:
|
||||
return new DVDByteFile(file);
|
||||
case DVD_READ_MENU_VOBS:
|
||||
case DVD_READ_TITLE_VOBS:
|
||||
return new DVDBlockFile(file);
|
||||
default:
|
||||
;
|
||||
}
|
||||
DVDCloseFile(file); // Because it has been opened !
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public:
|
|||
|
||||
/// Reads a given number of blocks at the given offset, and returns
|
||||
/// the number of blocks read, or -1 if an error occurred.
|
||||
virtual int readBlocks(int blocks, int offset, unsigned char * dest);
|
||||
virtual int readBlocks(int offset, int blocks, unsigned char * dest) = 0;
|
||||
|
||||
/// Returns the size of the file in blocks
|
||||
int fileSize();
|
||||
|
|
@ -46,7 +46,10 @@ public:
|
|||
/// went wrong.
|
||||
///
|
||||
/// It actually returns a subclass of DVDFile, depending on the domain.
|
||||
static DVDFile * openFile(DVDFileData * dat);
|
||||
///
|
||||
/// @todo It still needs a reader argument, while it would be much
|
||||
/// nicer to make it part of DVDFileData ?
|
||||
static DVDFile * openFile(dvd_reader_t * reader, const DVDFileData * dat);
|
||||
|
||||
virtual ~DVDFile();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// DVDRead
|
||||
#include <dvdread/dvd_reader.h>
|
||||
|
|
|
|||
Loading…
Reference in a new issue