|
@@ -25,7 +25,7 @@
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: Extractor::Constructor
|
|
// Function: Extractor::Constructor
|
|
|
-// Access: Public
|
|
|
|
|
|
|
+// Access: Published
|
|
|
// Description:
|
|
// Description:
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
Extractor::
|
|
Extractor::
|
|
@@ -35,89 +35,137 @@ Extractor() {
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: Extractor::Destructor
|
|
// Function: Extractor::Destructor
|
|
|
-// Access: Public
|
|
|
|
|
|
|
+// Access: Published
|
|
|
// Description:
|
|
// Description:
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
Extractor::
|
|
Extractor::
|
|
|
~Extractor() {
|
|
~Extractor() {
|
|
|
- if (downloader_cat.is_debug())
|
|
|
|
|
- downloader_cat.debug()
|
|
|
|
|
- << "Extractor destructor called" << endl;
|
|
|
|
|
- if (_initiated) {
|
|
|
|
|
- cleanup();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ reset();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Extractor::initiate
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Begins the extraction process. Returns EU_success if
|
|
|
|
|
-// successful, EU_error_abort otherwise.
|
|
|
|
|
-//
|
|
|
|
|
-// After calling initiate(), you should repeatedly call
|
|
|
|
|
-// run() as a background task until the file is
|
|
|
|
|
-// completely extracted.
|
|
|
|
|
|
|
+// Function: Extractor::set_multifile
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Specifies the filename of the Multifile that the
|
|
|
|
|
+// Extractor will read. Returns true on success, false
|
|
|
|
|
+// if the mulifile name is invalid.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-int Extractor::
|
|
|
|
|
-initiate(const Filename &multifile_name, const Filename &extract_to) {
|
|
|
|
|
|
|
+bool Extractor::
|
|
|
|
|
+set_multifile(const Filename &multifile_name) {
|
|
|
|
|
+ reset();
|
|
|
|
|
+ _multifile_name = multifile_name;
|
|
|
|
|
+ return _multifile.open_read(multifile_name);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: Extractor::set_extract_dir
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Specifies the directory into which all extracted
|
|
|
|
|
+// subfiles will be written. Relative paths of subfiles
|
|
|
|
|
+// within the Multifile will be written as relative
|
|
|
|
|
+// paths to this directory.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void Extractor::
|
|
|
|
|
+set_extract_dir(const Filename &extract_dir) {
|
|
|
|
|
+ _extract_dir = extract_dir;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: Extractor::reset
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Interrupts the Extractor in the middle of its
|
|
|
|
|
+// business and makes it ready to accept a new list of
|
|
|
|
|
+// subfiles to extract.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void Extractor::
|
|
|
|
|
+reset() {
|
|
|
if (_initiated) {
|
|
if (_initiated) {
|
|
|
- downloader_cat.error()
|
|
|
|
|
- << "Extractor::initiate() - Extraction has already been initiated"
|
|
|
|
|
- << endl;
|
|
|
|
|
- return EU_error_abort;
|
|
|
|
|
|
|
+ if (_read != (istream *)NULL) {
|
|
|
|
|
+ delete _read;
|
|
|
|
|
+ _read = (istream *)NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ _write.close();
|
|
|
|
|
+ _initiated = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _multifile_name = multifile_name;
|
|
|
|
|
- _extract_to = extract_to;
|
|
|
|
|
|
|
+ _requests.clear();
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if (!_multifile.open_read(_multifile_name)) {
|
|
|
|
|
- downloader_cat.error()
|
|
|
|
|
- << "Error opening Multifile " << _multifile_name << ".\n";
|
|
|
|
|
- return EU_error_abort;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: Extractor::request_subfile
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Requests a particular subfile to be extracted when
|
|
|
|
|
+// step() or run() is called. Returns true if the
|
|
|
|
|
+// subfile exists, false otherwise.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+bool Extractor::
|
|
|
|
|
+request_subfile(const Filename &subfile_name) {
|
|
|
|
|
+ int index = _multifile.find_subfile(subfile_name);
|
|
|
|
|
+ if (index < 0) {
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
+ _requests.push_back(index);
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- _subfile_index = 0;
|
|
|
|
|
- _subfile_pos = 0;
|
|
|
|
|
- _subfile_length = 0;
|
|
|
|
|
- _read = (istream *)NULL;
|
|
|
|
|
- _initiated = true;
|
|
|
|
|
-
|
|
|
|
|
- return EU_success;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: Extractor::request_all_subfiles
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: Requests all subfiles in the Multifile to be
|
|
|
|
|
+// extracted. Returns the number requested.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+int Extractor::
|
|
|
|
|
+request_all_subfiles() {
|
|
|
|
|
+ _requests.clear();
|
|
|
|
|
+ int num_subfiles = _multifile.get_num_subfiles();
|
|
|
|
|
+ for (int i = 0; i < num_subfiles; i++) {
|
|
|
|
|
+ _requests.push_back(i);
|
|
|
|
|
+ }
|
|
|
|
|
+ return num_subfiles;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Extractor::run
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Extracts the next small unit of data from the
|
|
|
|
|
|
|
+// Function: Extractor::step
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description: After all of the requests have been made via
|
|
|
|
|
+// request_file() or request_all_subfiles(), call step()
|
|
|
|
|
+// repeatedly until it stops returning EU_ok.
|
|
|
|
|
+//
|
|
|
|
|
+// step() extracts the next small unit of data from the
|
|
|
// Multifile. Returns EU_ok if progress is continuing,
|
|
// Multifile. Returns EU_ok if progress is continuing,
|
|
|
// EU_error_abort if there is a problem, or EU_success
|
|
// EU_error_abort if there is a problem, or EU_success
|
|
|
// when the last piece has been extracted.
|
|
// when the last piece has been extracted.
|
|
|
|
|
+//
|
|
|
|
|
+// Also see run().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
int Extractor::
|
|
int Extractor::
|
|
|
-run() {
|
|
|
|
|
|
|
+step() {
|
|
|
if (!_initiated) {
|
|
if (!_initiated) {
|
|
|
- downloader_cat.error()
|
|
|
|
|
- << "Extractor::run() - Extraction has not been initiated"
|
|
|
|
|
- << endl;
|
|
|
|
|
- return EU_error_abort;
|
|
|
|
|
|
|
+ _request_index = 0;
|
|
|
|
|
+ _subfile_index = 0;
|
|
|
|
|
+ _subfile_pos = 0;
|
|
|
|
|
+ _subfile_length = 0;
|
|
|
|
|
+ _read = (istream *)NULL;
|
|
|
|
|
+ _initiated = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (_read == (istream *)NULL) {
|
|
if (_read == (istream *)NULL) {
|
|
|
// Time to open the next subfile.
|
|
// Time to open the next subfile.
|
|
|
- if (_subfile_index >= _multifile.get_num_subfiles()) {
|
|
|
|
|
|
|
+ if (_request_index >= (int)_requests.size()) {
|
|
|
// All done!
|
|
// All done!
|
|
|
- cleanup();
|
|
|
|
|
|
|
+ reset();
|
|
|
return EU_success;
|
|
return EU_success;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Filename subfile_filename(_extract_to,
|
|
|
|
|
|
|
+ _subfile_index = _requests[_request_index];
|
|
|
|
|
+ Filename subfile_filename(_extract_dir,
|
|
|
_multifile.get_subfile_name(_subfile_index));
|
|
_multifile.get_subfile_name(_subfile_index));
|
|
|
subfile_filename.set_binary();
|
|
subfile_filename.set_binary();
|
|
|
subfile_filename.make_dir();
|
|
subfile_filename.make_dir();
|
|
|
if (!subfile_filename.open_write(_write)) {
|
|
if (!subfile_filename.open_write(_write)) {
|
|
|
downloader_cat.error()
|
|
downloader_cat.error()
|
|
|
<< "Unable to write to " << subfile_filename << ".\n";
|
|
<< "Unable to write to " << subfile_filename << ".\n";
|
|
|
- cleanup();
|
|
|
|
|
|
|
+ reset();
|
|
|
return EU_error_abort;
|
|
return EU_error_abort;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -130,7 +178,7 @@ run() {
|
|
|
delete _read;
|
|
delete _read;
|
|
|
_read = (istream *)NULL;
|
|
_read = (istream *)NULL;
|
|
|
_write.close();
|
|
_write.close();
|
|
|
- _subfile_index++;
|
|
|
|
|
|
|
+ _request_index++;
|
|
|
|
|
|
|
|
} else {
|
|
} else {
|
|
|
// Read a number of bytes from the subfile and write them to the
|
|
// Read a number of bytes from the subfile and write them to the
|
|
@@ -142,7 +190,7 @@ run() {
|
|
|
if (_read->eof() || _read->fail()) {
|
|
if (_read->eof() || _read->fail()) {
|
|
|
downloader_cat.error()
|
|
downloader_cat.error()
|
|
|
<< "Unexpected EOF on multifile " << _multifile_name << ".\n";
|
|
<< "Unexpected EOF on multifile " << _multifile_name << ".\n";
|
|
|
- cleanup();
|
|
|
|
|
|
|
+ reset();
|
|
|
return EU_error_abort;
|
|
return EU_error_abort;
|
|
|
}
|
|
}
|
|
|
_write.put(byte);
|
|
_write.put(byte);
|
|
@@ -154,20 +202,22 @@ run() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: Extractor::extract
|
|
|
|
|
-// Access: Public
|
|
|
|
|
|
|
+// Function: Extractor::run
|
|
|
|
|
+// Access: Published
|
|
|
// Description: A convenience function to extract the Multifile all
|
|
// Description: A convenience function to extract the Multifile all
|
|
|
// at once, when you don't care about doing it in the
|
|
// at once, when you don't care about doing it in the
|
|
|
// background.
|
|
// background.
|
|
|
|
|
+//
|
|
|
|
|
+// First, call request_file() or request_all_files() to
|
|
|
|
|
+// specify the files you would like to extract, then
|
|
|
|
|
+// call run() to do the extraction. Also see step() for
|
|
|
|
|
+// when you would like the extraction to happen as a
|
|
|
|
|
+// background task.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
bool Extractor::
|
|
bool Extractor::
|
|
|
-extract(const Filename &source_file, const Filename &rel_path) {
|
|
|
|
|
- int ret = initiate(source_file, rel_path);
|
|
|
|
|
- if (ret < 0) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- for (;;) {
|
|
|
|
|
- ret = run();
|
|
|
|
|
|
|
+run() {
|
|
|
|
|
+ while (true) {
|
|
|
|
|
+ int ret = step();
|
|
|
if (ret == EU_success) {
|
|
if (ret == EU_success) {
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -177,28 +227,3 @@ extract(const Filename &source_file, const Filename &rel_path) {
|
|
|
}
|
|
}
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: Extractor::cleanup
|
|
|
|
|
-// Access: Private
|
|
|
|
|
-// Description:
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void Extractor::
|
|
|
|
|
-cleanup() {
|
|
|
|
|
- if (downloader_cat.is_debug())
|
|
|
|
|
- downloader_cat.debug()
|
|
|
|
|
- << "Extractor cleanup called" << endl;
|
|
|
|
|
- if (!_initiated) {
|
|
|
|
|
- downloader_cat.error()
|
|
|
|
|
- << "Extractor::cleanup() - Extraction has not been initiated"
|
|
|
|
|
- << endl;
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (_read != (istream *)NULL) {
|
|
|
|
|
- delete _read;
|
|
|
|
|
- _read = (istream *)NULL;
|
|
|
|
|
- }
|
|
|
|
|
- _multifile.close();
|
|
|
|
|
- _write.close();
|
|
|
|
|
-}
|
|
|