00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "extractor.h"
00016 #include "config_downloader.h"
00017 #include "trueClock.h"
00018 #include "filename.h"
00019 #include "error_utils.h"
00020
00021
00022
00023
00024
00025
00026
00027 Extractor::
00028 Extractor() {
00029 _initiated = false;
00030 _multifile = new Multifile;
00031 }
00032
00033
00034
00035
00036
00037
00038 Extractor::
00039 ~Extractor() {
00040 reset();
00041 }
00042
00043
00044
00045
00046
00047
00048
00049
00050 bool Extractor::
00051 set_multifile(const Filename &multifile_name) {
00052 reset();
00053 _multifile_name = multifile_name;
00054 return _multifile->open_read(multifile_name);
00055 }
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 void Extractor::
00066 set_extract_dir(const Filename &extract_dir) {
00067 _extract_dir = extract_dir;
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077 void Extractor::
00078 reset() {
00079 if (_initiated) {
00080 if (_read != (istream *)NULL) {
00081 Multifile::close_read_subfile(_read);
00082 _read = (istream *)NULL;
00083 }
00084 _write.close();
00085 _initiated = false;
00086 }
00087
00088 _requests.clear();
00089 _requests_total_length = 0;
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099 bool Extractor::
00100 request_subfile(const Filename &subfile_name) {
00101 int index = _multifile->find_subfile(subfile_name);
00102 if (index < 0) {
00103 return false;
00104 }
00105 _requests.push_back(index);
00106 _requests_total_length += _multifile->get_subfile_length(index);
00107 return true;
00108 }
00109
00110
00111
00112
00113
00114
00115
00116 int Extractor::
00117 request_all_subfiles() {
00118 _requests.clear();
00119 _requests_total_length = 0;
00120 int num_subfiles = _multifile->get_num_subfiles();
00121 for (int i = 0; i < num_subfiles; i++) {
00122 _requests.push_back(i);
00123 _requests_total_length += _multifile->get_subfile_length(i);
00124 }
00125 return num_subfiles;
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 int Extractor::
00143 step() {
00144 if (!_initiated) {
00145 _request_index = 0;
00146 _subfile_index = 0;
00147 _subfile_pos = 0;
00148 _subfile_length = 0;
00149 _total_bytes_extracted = 0;
00150 _read = (istream *)NULL;
00151 _initiated = true;
00152 }
00153
00154 TrueClock *clock = TrueClock::get_global_ptr();
00155 double now = clock->get_short_time();
00156 double finish = now + extractor_step_time;
00157
00158 do {
00159 if (_read == (istream *)NULL) {
00160
00161 if (_request_index >= (int)_requests.size()) {
00162
00163 if (downloader_cat.is_debug()) {
00164 downloader_cat.debug()
00165 << "Finished extracting.\n";
00166 }
00167 reset();
00168 return EU_success;
00169 }
00170
00171 _subfile_index = _requests[_request_index];
00172 _subfile_filename = Filename(_extract_dir,
00173 _multifile->get_subfile_name(_subfile_index));
00174
00175 if (downloader_cat.is_debug()) {
00176 downloader_cat.debug()
00177 << "Extracting " << _subfile_filename << ".\n";
00178 }
00179
00180 _subfile_filename.set_binary();
00181 _subfile_filename.make_dir();
00182 if (!_subfile_filename.open_write(_write, true)) {
00183 downloader_cat.error()
00184 << "Unable to write to " << _subfile_filename << ".\n";
00185 reset();
00186 return EU_error_abort;
00187 }
00188
00189 _subfile_length = _multifile->get_subfile_length(_subfile_index);
00190 _subfile_pos = 0;
00191 _read = _multifile->open_read_subfile(_subfile_index);
00192 if (_read == (istream *)NULL) {
00193 downloader_cat.error()
00194 << "Unable to read subfile "
00195 << _multifile->get_subfile_name(_subfile_index) << ".\n";
00196 reset();
00197 return EU_error_abort;
00198 }
00199
00200 } else if (_subfile_pos >= _subfile_length) {
00201
00202
00203 if (downloader_cat.is_debug()) {
00204 downloader_cat.debug()
00205 << "Finished current subfile.\n";
00206 }
00207 Multifile::close_read_subfile(_read);
00208 _read = (istream *)NULL;
00209 _write.close();
00210 _request_index++;
00211
00212 } else {
00213
00214
00215 static const size_t buffer_size = 1024;
00216 char buffer[buffer_size];
00217
00218 size_t max_bytes = min(buffer_size, _subfile_length - _subfile_pos);
00219 _read->read(buffer, max_bytes);
00220 size_t count = _read->gcount();
00221 while (count != 0) {
00222 if (downloader_cat.is_spam()) {
00223 downloader_cat.spam()
00224 << " . . . read " << count << " bytes.\n";
00225 }
00226 _write.write(buffer, count);
00227 if (!_write) {
00228 downloader_cat.error()
00229 << "Error writing to " << _subfile_filename << ".\n";
00230 reset();
00231 return EU_error_abort;
00232 }
00233
00234 _subfile_pos += count;
00235 _total_bytes_extracted += count;
00236
00237 now = clock->get_short_time();
00238 if (now >= finish) {
00239
00240 return EU_ok;
00241 }
00242
00243 max_bytes = min(buffer_size, _subfile_length - _subfile_pos);
00244 _read->read(buffer, max_bytes);
00245 count = _read->gcount();
00246 }
00247
00248 if (max_bytes != 0) {
00249 downloader_cat.error()
00250 << "Unexpected EOF on multifile " << _multifile_name << ".\n";
00251 reset();
00252 return EU_error_abort;
00253 }
00254 }
00255
00256 now = clock->get_short_time();
00257 } while (now < finish);
00258
00259
00260 return EU_ok;
00261 }
00262
00263
00264
00265
00266
00267
00268
00269 PN_stdfloat Extractor::
00270 get_progress() const {
00271 if (!_initiated) {
00272 return 0.0f;
00273 }
00274 if (_requests_total_length == 0) {
00275 return 1.0f;
00276 }
00277
00278 return (PN_stdfloat)_total_bytes_extracted / (PN_stdfloat)_requests_total_length;
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 bool Extractor::
00295 run() {
00296 while (true) {
00297 int ret = step();
00298 if (ret == EU_success) {
00299 return true;
00300 }
00301 if (ret < 0) {
00302 return false;
00303 }
00304 }
00305 }