Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/downloader/extractor.cxx

Go to the documentation of this file.
00001 // Filename: extractor.cxx
00002 // Created by:  mike (09Jan97)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "extractor.h"
00020 #include "config_downloader.h"
00021 
00022 #include "filename.h"
00023 #include "error_utils.h"
00024 
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: Extractor::Constructor
00028 //       Access: Published
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 Extractor::
00032 Extractor() {
00033   _initiated = false;
00034 }
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: Extractor::Destructor
00038 //       Access: Published
00039 //  Description:
00040 ////////////////////////////////////////////////////////////////////
00041 Extractor::
00042 ~Extractor() {
00043   reset();
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: Extractor::set_multifile
00048 //       Access: Published
00049 //  Description: Specifies the filename of the Multifile that the
00050 //               Extractor will read.  Returns true on success, false
00051 //               if the mulifile name is invalid.
00052 ////////////////////////////////////////////////////////////////////
00053 bool Extractor::
00054 set_multifile(const Filename &multifile_name) {
00055   reset();
00056   _multifile_name = multifile_name;
00057   return _multifile.open_read(multifile_name);
00058 }
00059 
00060 ////////////////////////////////////////////////////////////////////
00061 //     Function: Extractor::set_extract_dir
00062 //       Access: Published
00063 //  Description: Specifies the directory into which all extracted
00064 //               subfiles will be written.  Relative paths of subfiles
00065 //               within the Multifile will be written as relative
00066 //               paths to this directory.
00067 ////////////////////////////////////////////////////////////////////
00068 void Extractor::
00069 set_extract_dir(const Filename &extract_dir) {
00070   _extract_dir = extract_dir;
00071 }
00072 
00073 ////////////////////////////////////////////////////////////////////
00074 //     Function: Extractor::reset
00075 //       Access: Published
00076 //  Description: Interrupts the Extractor in the middle of its
00077 //               business and makes it ready to accept a new list of
00078 //               subfiles to extract.
00079 ////////////////////////////////////////////////////////////////////
00080 void Extractor::
00081 reset() {
00082   if (_initiated) {
00083     if (_read != (istream *)NULL) {
00084       delete _read;
00085       _read = (istream *)NULL;
00086     }
00087     _write.close();
00088     _initiated = false;
00089   }
00090 
00091   _requests.clear();
00092   _requests_total_length = 0;
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: Extractor::request_subfile
00097 //       Access: Published
00098 //  Description: Requests a particular subfile to be extracted when
00099 //               step() or run() is called.  Returns true if the
00100 //               subfile exists, false otherwise.
00101 ////////////////////////////////////////////////////////////////////
00102 bool Extractor::
00103 request_subfile(const Filename &subfile_name) {
00104   int index = _multifile.find_subfile(subfile_name);
00105   if (index < 0) {
00106     return false;
00107   }
00108   _requests.push_back(index);
00109   _requests_total_length += _multifile.get_subfile_length(index);
00110   return true;
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: Extractor::request_all_subfiles
00115 //       Access: Published
00116 //  Description: Requests all subfiles in the Multifile to be
00117 //               extracted.  Returns the number requested.
00118 ////////////////////////////////////////////////////////////////////
00119 int Extractor::
00120 request_all_subfiles() {
00121   _requests.clear();
00122   _requests_total_length = 0;
00123   int num_subfiles = _multifile.get_num_subfiles();
00124   for (int i = 0; i < num_subfiles; i++) {
00125     _requests.push_back(i);
00126     _requests_total_length += _multifile.get_subfile_length(i);
00127   }
00128   return num_subfiles;
00129 }
00130 
00131 ////////////////////////////////////////////////////////////////////
00132 //     Function: Extractor::step
00133 //       Access: Published
00134 //  Description: After all of the requests have been made via
00135 //               request_file() or request_all_subfiles(), call step()
00136 //               repeatedly until it stops returning EU_ok.
00137 //
00138 //               step() extracts the next small unit of data from the
00139 //               Multifile.  Returns EU_ok if progress is continuing,
00140 //               EU_error_abort if there is a problem, or EU_success
00141 //               when the last piece has been extracted.
00142 //
00143 //               Also see run().
00144 ////////////////////////////////////////////////////////////////////
00145 int Extractor::
00146 step() {
00147   if (!_initiated) {
00148     _request_index = 0;
00149     _subfile_index = 0;
00150     _subfile_pos = 0;
00151     _subfile_length = 0;
00152     _total_bytes_extracted = 0;
00153     _read = (istream *)NULL;
00154     _initiated = true;
00155   }
00156 
00157   if (_read == (istream *)NULL) {
00158     // Time to open the next subfile.
00159     if (_request_index >= (int)_requests.size()) {
00160       // All done!
00161       reset();
00162       return EU_success;
00163     }
00164 
00165     _subfile_index = _requests[_request_index];
00166     _subfile_filename = Filename(_extract_dir, 
00167                                  _multifile.get_subfile_name(_subfile_index));
00168     _subfile_filename.set_binary();
00169     _subfile_filename.make_dir();
00170     if (!_subfile_filename.open_write(_write, true)) {
00171       downloader_cat.error()
00172         << "Unable to write to " << _subfile_filename << ".\n";
00173       reset();
00174       return EU_error_abort;
00175     }
00176 
00177     _subfile_length = _multifile.get_subfile_length(_subfile_index);
00178     _subfile_pos = 0;
00179     _read = _multifile.open_read_subfile(_subfile_index);
00180     if (_read == (istream *)NULL) {
00181       downloader_cat.error()
00182         << "Unable to read subfile "
00183         << _multifile.get_subfile_name(_subfile_index) << ".\n";
00184       reset();
00185       return EU_error_abort;
00186     }
00187 
00188   } else if (_subfile_pos >= _subfile_length) {
00189     // Time to close this subfile.
00190     delete _read;
00191     _read = (istream *)NULL;
00192     _write.close();
00193     _request_index++;
00194 
00195   } else {
00196     // Read a number of bytes from the subfile and write them to the
00197     // output.
00198     size_t max_bytes = min((size_t)extractor_buffer_size, 
00199                            _subfile_length - _subfile_pos);
00200     for (size_t p = 0; p < max_bytes; p++) {
00201       int byte = _read->get();
00202       if (_read->eof() || _read->fail()) {
00203         downloader_cat.error()
00204           << "Unexpected EOF on multifile " << _multifile_name << ".\n";
00205         reset();
00206         return EU_error_abort;
00207       }
00208       _write.put(byte);
00209     }
00210     if (!_write) {
00211       downloader_cat.error()
00212         << "Error writing to " << _subfile_filename << ".\n";
00213       reset();
00214       return EU_error_abort;
00215     }
00216     _subfile_pos += max_bytes;
00217     _total_bytes_extracted += max_bytes;
00218   }
00219 
00220   return EU_ok;
00221 }
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //     Function: Extractor::get_progress
00225 //       Access: Public
00226 //  Description: Returns the fraction of the Multifile extracted so
00227 //               far.
00228 ////////////////////////////////////////////////////////////////////
00229 float Extractor::
00230 get_progress() const {
00231   if (!_initiated) {
00232     return 0.0f;
00233   }
00234   if (_requests_total_length == 0) {
00235     return 1.0f;
00236   }
00237 
00238   return (float)_total_bytes_extracted / (float)_requests_total_length;
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: Extractor::run
00243 //       Access: Published
00244 //  Description: A convenience function to extract the Multifile all
00245 //               at once, when you don't care about doing it in the
00246 //               background.
00247 //
00248 //               First, call request_file() or request_all_files() to
00249 //               specify the files you would like to extract, then
00250 //               call run() to do the extraction.  Also see step() for
00251 //               when you would like the extraction to happen as a
00252 //               background task.
00253 ////////////////////////////////////////////////////////////////////
00254 bool Extractor::
00255 run() {
00256   while (true) {
00257     int ret = step();
00258     if (ret == EU_success) {
00259       return true;
00260     }
00261     if (ret < 0) {
00262       return false;
00263     }
00264   }
00265 }

Generated on Fri May 2 00:36:46 2003 for Panda by doxygen1.3