Panda3D
Loading...
Searching...
No Matches
extractor.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file extractor.cxx
10 * @author mike
11 * @date 1997-01-09
12 */
13
14#include "extractor.h"
15#include "config_downloader.h"
16#include "trueClock.h"
17#include "filename.h"
18#include "error_utils.h"
19
20
21/**
22 *
23 */
24Extractor::
25Extractor() {
26 _initiated = false;
27 _multifile = new Multifile;
28}
29
30/**
31 *
32 */
33Extractor::
34~Extractor() {
35 reset();
36}
37
38/**
39 * Specifies the filename of the Multifile that the Extractor will read.
40 * Returns true on success, false if the mulifile name is invalid.
41 */
43set_multifile(const Filename &multifile_name) {
44 reset();
45 _multifile_name = multifile_name;
46 return _multifile->open_read(multifile_name);
47}
48
49/**
50 * Specifies the directory into which all extracted subfiles will be written.
51 * Relative paths of subfiles within the Multifile will be written as relative
52 * paths to this directory.
53 */
55set_extract_dir(const Filename &extract_dir) {
56 _extract_dir = extract_dir;
57}
58
59/**
60 * Interrupts the Extractor in the middle of its business and makes it ready
61 * to accept a new list of subfiles to extract.
62 */
64reset() {
65 if (_initiated) {
66 if (_read != nullptr) {
68 _read = nullptr;
69 }
70 _write.close();
71 _initiated = false;
72 }
73
74 _requests.clear();
75 _requests_total_length = 0;
76}
77
78/**
79 * Requests a particular subfile to be extracted when step() or run() is
80 * called. Returns true if the subfile exists, false otherwise.
81 */
83request_subfile(const Filename &subfile_name) {
84 int index = _multifile->find_subfile(subfile_name);
85 if (index < 0) {
86 return false;
87 }
88 _requests.push_back(index);
89 _requests_total_length += _multifile->get_subfile_length(index);
90 return true;
91}
92
93/**
94 * Requests all subfiles in the Multifile to be extracted. Returns the number
95 * requested.
96 */
99 _requests.clear();
100 _requests_total_length = 0;
101 int num_subfiles = _multifile->get_num_subfiles();
102 for (int i = 0; i < num_subfiles; i++) {
103 _requests.push_back(i);
104 _requests_total_length += _multifile->get_subfile_length(i);
105 }
106 return num_subfiles;
107}
108
109/**
110 * After all of the requests have been made via request_file() or
111 * request_all_subfiles(), call step() repeatedly until it stops returning
112 * EU_ok.
113 *
114 * step() extracts the next small unit of data from the Multifile. Returns
115 * EU_ok if progress is continuing, EU_error_abort if there is a problem, or
116 * EU_success when the last piece has been extracted.
117 *
118 * Also see run().
119 */
121step() {
122 if (!_initiated) {
123 _request_index = 0;
124 _subfile_index = 0;
125 _subfile_pos = 0;
126 _subfile_length = 0;
127 _total_bytes_extracted = 0;
128 _read = nullptr;
129 _initiated = true;
130 }
131
133 double now = clock->get_short_time();
134 double finish = now + extractor_step_time;
135
136 do {
137 if (_read == nullptr) {
138 // Time to open the next subfile.
139 if (_request_index >= (int)_requests.size()) {
140 // All done!
141 if (downloader_cat.is_debug()) {
142 downloader_cat.debug()
143 << "Finished extracting.\n";
144 }
145 reset();
146 return EU_success;
147 }
148
149 _subfile_index = _requests[_request_index];
150 _subfile_filename = Filename(_extract_dir,
151 _multifile->get_subfile_name(_subfile_index));
152
153 if (downloader_cat.is_debug()) {
154 downloader_cat.debug()
155 << "Extracting " << _subfile_filename << ".\n";
156 }
157
158 _subfile_filename.set_binary();
159 _subfile_filename.make_dir();
160 if (!_subfile_filename.open_write(_write, true)) {
161 downloader_cat.error()
162 << "Unable to write to " << _subfile_filename << ".\n";
163 reset();
164 return EU_error_abort;
165 }
166
167 _subfile_length = _multifile->get_subfile_length(_subfile_index);
168 _subfile_pos = 0;
169 _read = _multifile->open_read_subfile(_subfile_index);
170 if (_read == nullptr) {
171 downloader_cat.error()
172 << "Unable to read subfile "
173 << _multifile->get_subfile_name(_subfile_index) << ".\n";
174 reset();
175 return EU_error_abort;
176 }
177
178 } else if (_subfile_pos >= _subfile_length) {
179 // Time to close this subfile.
180
181 if (downloader_cat.is_debug()) {
182 downloader_cat.debug()
183 << "Finished current subfile.\n";
184 }
186 _read = nullptr;
187 _write.close();
188 _request_index++;
189
190 } else {
191 // Read a number of bytes from the subfile and write them to the output.
192 static const size_t buffer_size = 1024;
193 char buffer[buffer_size];
194
195 size_t max_bytes = std::min(buffer_size, _subfile_length - _subfile_pos);
196 _read->read(buffer, max_bytes);
197 size_t count = _read->gcount();
198 while (count != 0) {
199 if (downloader_cat.is_spam()) {
200 downloader_cat.spam()
201 << " . . . read " << count << " bytes.\n";
202 }
203 _write.write(buffer, count);
204 if (!_write) {
205 downloader_cat.error()
206 << "Error writing to " << _subfile_filename << ".\n";
207 reset();
208 return EU_error_abort;
209 }
210
211 _subfile_pos += count;
212 _total_bytes_extracted += count;
213
214 now = clock->get_short_time();
215 if (now >= finish) {
216 // That's enough for now.
217 return EU_ok;
218 }
219
220 max_bytes = std::min(buffer_size, _subfile_length - _subfile_pos);
221 _read->read(buffer, max_bytes);
222 count = _read->gcount();
223 }
224
225 if (max_bytes != 0) {
226 downloader_cat.error()
227 << "Unexpected EOF on multifile " << _multifile_name << ".\n";
228 reset();
229 return EU_error_abort;
230 }
231 }
232
233 now = clock->get_short_time();
234 } while (now < finish);
235
236 // That's enough for now.
237 return EU_ok;
238}
239
240/**
241 * Returns the fraction of the Multifile extracted so far.
242 */
243PN_stdfloat Extractor::
244get_progress() const {
245 if (!_initiated) {
246 return 0.0f;
247 }
248 if (_requests_total_length == 0) {
249 return 1.0f;
250 }
251
252 return (PN_stdfloat)_total_bytes_extracted / (PN_stdfloat)_requests_total_length;
253}
254
255/**
256 * A convenience function to extract the Multifile all at once, when you don't
257 * care about doing it in the background.
258 *
259 * First, call request_file() or request_all_files() to specify the files you
260 * would like to extract, then call run() to do the extraction. Also see
261 * step() for when you would like the extraction to happen as a background
262 * task.
263 */
265run() {
266 while (true) {
267 int ret = step();
268 if (ret == EU_success) {
269 return true;
270 }
271 if (ret < 0) {
272 return false;
273 }
274 }
275}
void reset()
Interrupts the Extractor in the middle of its business and makes it ready to accept a new list of sub...
Definition extractor.cxx:64
bool run()
A convenience function to extract the Multifile all at once, when you don't care about doing it in th...
void set_extract_dir(const Filename &extract_dir)
Specifies the directory into which all extracted subfiles will be written.
Definition extractor.cxx:55
bool set_multifile(const Filename &multifile_name)
Specifies the filename of the Multifile that the Extractor will read.
Definition extractor.cxx:43
bool request_subfile(const Filename &subfile_name)
Requests a particular subfile to be extracted when step() or run() is called.
Definition extractor.cxx:83
get_progress
Returns the fraction of the Multifile extracted so far.
Definition extractor.h:54
int request_all_subfiles()
Requests all subfiles in the Multifile to be extracted.
Definition extractor.cxx:98
int step()
After all of the requests have been made via request_file() or request_all_subfiles(),...
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
void set_binary()
Indicates that the filename represents a binary file.
Definition filename.I:414
bool make_dir() const
Creates all the directories in the path to the file specified in the filename, except for the basenam...
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
A file that contains a set of files.
Definition multifile.h:37
static void close_read_subfile(std::istream *stream)
Closes a file opened by a previous call to open_read_subfile().
An interface to whatever real-time clock we might have available in the current environment.
Definition trueClock.h:33
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition trueClock.I:68
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.