Panda3D
 All Classes Functions Variables Enumerations
multifile.I
1 // Filename: multifile.I
2 // Created by: mike (09Jan97)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 
16 ////////////////////////////////////////////////////////////////////
17 // Function: Multifile::get_multifile_name
18 // Access: Published
19 // Description: Returns the filename of the Multifile, if it is
20 // available.
21 ////////////////////////////////////////////////////////////////////
22 INLINE const Filename &Multifile::
24  return _multifile_name;
25 }
26 
27 ////////////////////////////////////////////////////////////////////
28 // Function: Multifile::set_multifile_name
29 // Access: Published
30 // Description: Replaces the filename of the Multifile. This is
31 // primarily used for documentation purposes only;
32 // changing this name does not open the indicated file.
33 // See open_read() or open_write() for that.
34 ////////////////////////////////////////////////////////////////////
35 INLINE void Multifile::
36 set_multifile_name(const Filename &multifile_name) {
37  _multifile_name = multifile_name;
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: Multifile::is_read_valid
42 // Access: Published
43 // Description: Returns true if the Multifile has been opened for
44 // read mode and there have been no errors, and
45 // individual Subfile contents may be extracted.
46 ////////////////////////////////////////////////////////////////////
47 INLINE bool Multifile::
48 is_read_valid() const {
49  return (_read != (IStreamWrapper *)NULL);
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: Multifile::is_write_valid
54 // Access: Published
55 // Description: Returns true if the Multifile has been opened for
56 // write mode and there have been no errors, and
57 // Subfiles may be added or removed from the Multifile.
58 ////////////////////////////////////////////////////////////////////
59 INLINE bool Multifile::
60 is_write_valid() const {
61  return (_write != (ostream *)NULL && !_write->fail());
62 }
63 
64 ////////////////////////////////////////////////////////////////////
65 // Function: Multifile::needs_repack
66 // Access: Published
67 // Description: Returns true if the Multifile index is suboptimal and
68 // should be repacked. Call repack() to achieve this.
69 ////////////////////////////////////////////////////////////////////
70 INLINE bool Multifile::
71 needs_repack() const {
72  return _needs_repack || (_scale_factor != _new_scale_factor);
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: Multifile::get_timestamp
77 // Access: Published
78 // Description: Returns the modification timestamp of the overall
79 // Multifile. This indicates the most recent date at
80 // which subfiles were added or removed from the
81 // Multifile. Note that it is logically possible for an
82 // individual subfile to have a more recent timestamp
83 // than the overall timestamp.
84 ////////////////////////////////////////////////////////////////////
85 INLINE time_t Multifile::
86 get_timestamp() const {
87  return _timestamp;
88 }
89 
90 ////////////////////////////////////////////////////////////////////
91 // Function: Multifile::set_record_timestamp
92 // Access: Published
93 // Description: Sets the flag indicating whether timestamps should be
94 // recorded within the Multifile or not. The default is
95 // true, indicating the Multifile will record timestamps
96 // for the overall file and also for each subfile.
97 //
98 // If this is false, the Multifile will not record
99 // timestamps internally. In this case, the return
100 // value from get_timestamp() or get_subfile_timestamp()
101 // will be estimations.
102 //
103 // You may want to set this false to minimize the
104 // bitwise difference between independently-generated
105 // Multifiles.
106 ////////////////////////////////////////////////////////////////////
107 INLINE void Multifile::
109  _record_timestamp = flag;
110  _timestamp_dirty = true;
111 }
112 
113 ////////////////////////////////////////////////////////////////////
114 // Function: Multifile::get_record_timestamp
115 // Access: Published
116 // Description: Returns the flag indicating whether timestamps
117 // should be recorded within the Multifile or not. See
118 // set_record_timestamp().
119 ////////////////////////////////////////////////////////////////////
120 INLINE bool Multifile::
122  return _record_timestamp;
123 }
124 
125 ////////////////////////////////////////////////////////////////////
126 // Function: Multifile::get_scale_factor
127 // Access: Published
128 // Description: Returns the internal scale factor for this Multifile.
129 // See set_scale_factor().
130 ////////////////////////////////////////////////////////////////////
131 INLINE size_t Multifile::
133  return _new_scale_factor;
134 }
135 
136 ////////////////////////////////////////////////////////////////////
137 // Function: Multifile::set_encryption_flag
138 // Access: Published
139 // Description: Sets the flag indicating whether subsequently-added
140 // subfiles should be encrypted before writing them to
141 // the multifile. If true, subfiles will be encrypted;
142 // if false (the default), they will be written without
143 // encryption.
144 //
145 // When true, subfiles will be encrypted with the
146 // password specified by set_encryption_password(). It
147 // is possible to apply a different password to
148 // different files, but the resulting file can't be
149 // mounted via VFS.
150 ////////////////////////////////////////////////////////////////////
151 INLINE void Multifile::
153 #ifndef HAVE_OPENSSL
154  if (flag) {
155  express_cat.warning()
156  << "OpenSSL not compiled in; cannot generated encrypted multifiles.\n";
157  flag = false;
158  }
159 #endif // HAVE_OPENSSL
160  _encryption_flag = flag;
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: Multifile::get_encryption_flag
165 // Access: Published
166 // Description: Returns the flag indicating whether
167 // subsequently-added subfiles should be encrypted
168 // before writing them to the multifile. See
169 // set_encryption_flag().
170 ////////////////////////////////////////////////////////////////////
171 INLINE bool Multifile::
173  return _encryption_flag;
174 }
175 
176 ////////////////////////////////////////////////////////////////////
177 // Function: Multifile::set_encryption_password
178 // Access: Published
179 // Description: Specifies the password that will be used to encrypt
180 // subfiles subsequently added to the multifile, if the
181 // encryption flag is also set true (see
182 // set_encryption_flag()).
183 //
184 // It is possible to apply a different password to
185 // different files, but the resulting file can't be
186 // mounted via VFS. Changing this value may cause an
187 // implicit call to flush().
188 ////////////////////////////////////////////////////////////////////
189 INLINE void Multifile::
190 set_encryption_password(const string &encryption_password) {
191  if (_encryption_password != encryption_password) {
192  if (!_new_subfiles.empty()) {
193  flush();
194  }
195  _encryption_password = encryption_password;
196  }
197 }
198 
199 ////////////////////////////////////////////////////////////////////
200 // Function: Multifile::get_encryption_password
201 // Access: Published
202 // Description: Returns the password that will be used to encrypt
203 // subfiles subsequently added to the multifile. See
204 // set_encryption_password().
205 ////////////////////////////////////////////////////////////////////
206 INLINE const string &Multifile::
208  return _encryption_password;
209 }
210 
211 ////////////////////////////////////////////////////////////////////
212 // Function: Multifile::set_encryption_algorithm
213 // Access: Public
214 // Description: Specifies the encryption algorithm that should be
215 // used for future calls to add_subfile(). The default
216 // is whatever is specified by the encryption-algorithm
217 // config variable. The complete set of available
218 // algorithms is defined by the current version of
219 // OpenSSL.
220 //
221 // If an invalid algorithm is specified, there is no
222 // immediate error return code, but flush() will fail
223 // and the file will be invalid.
224 //
225 // It is possible to apply a different encryption
226 // algorithm to different files, and unlike the
227 // password, this does not interfere with mounting the
228 // multifile via VFS. Changing this value may cause an
229 // implicit call to flush().
230 ////////////////////////////////////////////////////////////////////
231 INLINE void Multifile::
232 set_encryption_algorithm(const string &encryption_algorithm) {
233  if (_encryption_algorithm != encryption_algorithm) {
234  if (!_new_subfiles.empty()) {
235  flush();
236  }
237  _encryption_algorithm = encryption_algorithm;
238  }
239 }
240 
241 ////////////////////////////////////////////////////////////////////
242 // Function: Multifile::get_encryption_algorithm
243 // Access: Public
244 // Description: Returns the encryption algorithm that was specified
245 // by set_encryption_algorithm().
246 ////////////////////////////////////////////////////////////////////
247 INLINE const string &Multifile::
249  return _encryption_algorithm;
250 }
251 
252 ////////////////////////////////////////////////////////////////////
253 // Function: Multifile::set_encryption_key_length
254 // Access: Public
255 // Description: Specifies the length of the key, in bits, that should
256 // be used to encrypt the stream in future calls to
257 // add_subfile(). The default is whatever is specified
258 // by the encryption-key-length config variable.
259 //
260 // If an invalid key_length for the chosen algorithm is
261 // specified, there is no immediate error return code,
262 // but flush() will fail and the file will be invalid.
263 //
264 // It is possible to apply a different key length to
265 // different files, and unlike the password, this does
266 // not interfere with mounting the multifile via VFS.
267 // Changing this value may cause an implicit call to
268 // flush().
269 ////////////////////////////////////////////////////////////////////
270 INLINE void Multifile::
271 set_encryption_key_length(int encryption_key_length) {
272  if (_encryption_key_length != encryption_key_length) {
273  if (!_new_subfiles.empty()) {
274  flush();
275  }
276  _encryption_key_length = encryption_key_length;
277  }
278 }
279 
280 ////////////////////////////////////////////////////////////////////
281 // Function: Multifile::get_encryption_key_length
282 // Access: Public
283 // Description: Returns the encryption key length, in bits, that was
284 // specified by set_encryption_key_length().
285 ////////////////////////////////////////////////////////////////////
286 INLINE int Multifile::
288  return _encryption_key_length;
289 }
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: Multifile::set_encryption_iteration_count
293 // Access: Public
294 // Description: Specifies the number of times to repeatedly hash the
295 // key before writing it to the stream in future calls
296 // to add_subfile(). Its purpose is to make it
297 // computationally more expensive for an attacker to
298 // search the key space exhaustively. This should be a
299 // multiple of 1,000 and should not exceed about 65
300 // million; the value 0 indicates just one application
301 // of the hashing algorithm.
302 //
303 // The default is whatever is specified by the
304 // multifile-encryption-iteration-count config variable.
305 //
306 // It is possible to apply a different iteration count
307 // to different files, and unlike the password, this
308 // does not interfere with mounting the multifile via
309 // VFS. Changing this value causes an implicit call to
310 // flush().
311 ////////////////////////////////////////////////////////////////////
312 INLINE void Multifile::
313 set_encryption_iteration_count(int encryption_iteration_count) {
314  if (_encryption_iteration_count != encryption_iteration_count) {
315  flush();
316  _encryption_iteration_count = encryption_iteration_count;
317  }
318 }
319 
320 ////////////////////////////////////////////////////////////////////
321 // Function: Multifile::get_encryption_iteration_count
322 // Access: Public
323 // Description: Returns the value that was specified by
324 // set_encryption_iteration_count().
325 ////////////////////////////////////////////////////////////////////
326 INLINE int Multifile::
328  return _encryption_iteration_count;
329 }
330 
331 ////////////////////////////////////////////////////////////////////
332 // Function: Multifile::remove_subfile
333 // Access: Published
334 // Description: Removes the named subfile from the Multifile, if it
335 // exists; returns true if successfully removed, or
336 // false if it did not exist in the first place. The
337 // file will not actually be removed from the disk until
338 // the next call to flush().
339 //
340 // Note that this does not actually remove the data from
341 // the indicated subfile; it simply removes it from the
342 // index. The Multifile will not be reduced in size
343 // after this operation, until the next call to
344 // repack().
345 ////////////////////////////////////////////////////////////////////
346 INLINE bool Multifile::
347 remove_subfile(const string &subfile_name) {
348  int index = find_subfile(subfile_name);
349  if (index >= 0) {
350  remove_subfile(index);
351  return true;
352  }
353  return false;
354 }
355 
356 ////////////////////////////////////////////////////////////////////
357 // Function: Multifile::read_subfile
358 // Access: Published
359 // Description: Returns a string that contains the entire contents of
360 // the indicated subfile.
361 ////////////////////////////////////////////////////////////////////
362 INLINE string Multifile::
363 read_subfile(int index) {
364  string result;
365  read_subfile(index, result);
366  return result;
367 }
368 
369 ////////////////////////////////////////////////////////////////////
370 // Function: Multifile::get_magic_number
371 // Access: Published, Static
372 // Description: Returns a string with the first n bytes written to a
373 // Multifile, to identify it as a Multifile.
374 ////////////////////////////////////////////////////////////////////
375 INLINE string Multifile::
377  return string(_header, _header_size);
378 }
379 
380 ////////////////////////////////////////////////////////////////////
381 // Function: Multifile::get_header_prefix
382 // Access: Published
383 // Description: Returns the string that preceded the Multifile header
384 // on the file, if any. See set_header_prefix().
385 ////////////////////////////////////////////////////////////////////
386 INLINE const string &Multifile::
388  return _header_prefix;
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: Multifile::word_to_streampos
393 // Access: Private
394 // Description: Converts a size_t address read from the file to
395 // a streampos byte address within the file.
396 ////////////////////////////////////////////////////////////////////
397 INLINE streampos Multifile::
398 word_to_streampos(size_t word) const {
399  return (streampos)word * (streampos)_scale_factor;
400 }
401 
402 ////////////////////////////////////////////////////////////////////
403 // Function: Multifile::streampos_to_word
404 // Access: Private
405 // Description: Converts a streampos byte address within the file to
406 // a size_t value suitable for writing to the file.
407 ////////////////////////////////////////////////////////////////////
408 INLINE size_t Multifile::
409 streampos_to_word(streampos fpos) const {
410  return (size_t)((fpos + (streampos)_scale_factor - (streampos)1) / (streampos)_scale_factor);
411 }
412 
413 ////////////////////////////////////////////////////////////////////
414 // Function: Multifile::normalize_streampos
415 // Access: Private
416 // Description: Rounds the streampos byte address up to the next
417 // multiple of _scale_factor. Only multiples of
418 // _scale_factor may be written to the file.
419 ////////////////////////////////////////////////////////////////////
420 INLINE streampos Multifile::
421 normalize_streampos(streampos fpos) const {
422  return word_to_streampos(streampos_to_word(fpos));
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: Multifile::tohex
427 // Access: Private, Static
428 // Description: Converts a single nibble to a hex digit.
429 ////////////////////////////////////////////////////////////////////
430 INLINE char Multifile::
431 tohex(unsigned int nibble) {
432  nibble &= 0xf;
433  if (nibble < 10) {
434  return nibble + '0';
435  }
436  return nibble - 10 + 'a';
437 }
438 
439 ////////////////////////////////////////////////////////////////////
440 // Function: Multifile::Subfile::Constructor
441 // Access: Public
442 // Description:
443 ////////////////////////////////////////////////////////////////////
444 INLINE Multifile::Subfile::
445 Subfile() {
446  _index_start = 0;
447  _data_start = 0;
448  _data_length = 0;
449  _timestamp = 0;
450  _source = (istream *)NULL;
451  _flags = 0;
452  _compression_level = 0;
453 #ifdef HAVE_OPENSSL
454  _pkey = NULL;
455 #endif
456 }
457 
458 ////////////////////////////////////////////////////////////////////
459 // Function: Multifile::Subfile::operator <
460 // Access: Public
461 // Description: Compares two Subfiles for proper sorting within the
462 // index.
463 ////////////////////////////////////////////////////////////////////
464 INLINE bool Multifile::Subfile::
465 operator < (const Multifile::Subfile &other) const {
466  // This should only be called on normal subfiles, not on certificate
467  // files or signature files. (We don't attempt to sort these
468  // special signature files.)
469  nassertr(!is_cert_special() && !other.is_cert_special(), false);
470 
471  // Normal subfiles are simply sorted in alphabetical order by
472  // filename.
473  return _name < other._name;
474 }
475 
476 ////////////////////////////////////////////////////////////////////
477 // Function: Multifile::Subfile::is_deleted
478 // Access: Public
479 // Description: Returns true if the Subfile indicates it has been
480 // deleted (removed from the index), false otherwise.
481 // This should never be true of Subfiles that currently
482 // appear in either the _subfiles or _new_subfiles
483 // lists.
484 ////////////////////////////////////////////////////////////////////
485 INLINE bool Multifile::Subfile::
486 is_deleted() const {
487  return (_flags & SF_deleted) != 0;
488 }
489 
490 ////////////////////////////////////////////////////////////////////
491 // Function: Multifile::Subfile::is_index_invalid
492 // Access: Public
493 // Description: Returns true if there was some problem reading the
494 // index record for this Subfile from the Multifile.
495 ////////////////////////////////////////////////////////////////////
496 INLINE bool Multifile::Subfile::
497 is_index_invalid() const {
498  return (_flags & SF_index_invalid) != 0;
499 }
500 
501 ////////////////////////////////////////////////////////////////////
502 // Function: Multifile::Subfile::is_data_invalid
503 // Access: Public
504 // Description: Returns true if there was some problem reading the
505 // data contents of this Subfile, particularly when
506 // copying into the Multifile.
507 ////////////////////////////////////////////////////////////////////
508 INLINE bool Multifile::Subfile::
509 is_data_invalid() const {
510  return (_flags & SF_data_invalid) != 0;
511 }
512 
513 ////////////////////////////////////////////////////////////////////
514 // Function: Multifile::Subfile::is_cert_special
515 // Access: Public
516 // Description: Returns true if this Subfile represents a signature
517 // record, which is treated specially; or false if it is
518 // an ordinary Subfile.
519 ////////////////////////////////////////////////////////////////////
520 INLINE bool Multifile::Subfile::
521 is_cert_special() const {
522  return (_flags & SF_signature) != 0;
523 }
524 
525 ////////////////////////////////////////////////////////////////////
526 // Function: Multifile::Subfile::get_last_byte_pos
527 // Access: Public
528 // Description: Returns the byte position within the Multifile of the
529 // last byte that contributes to this Subfile, either in
530 // the index record or in the subfile data.
531 ////////////////////////////////////////////////////////////////////
532 INLINE streampos Multifile::Subfile::
533 get_last_byte_pos() const {
534  return max(_index_start + (streampos)_index_length,
535  _data_start + (streampos)_data_length) - (streampos)1;
536 }
int find_subfile(const string &subfile_name) const
Returns the index of the subfile with the indicated name, or -1 if the named subfile is not within th...
Definition: multifile.cxx:1561
void set_encryption_password(const string &encryption_password)
Specifies the password that will be used to encrypt subfiles subsequently added to the multifile...
Definition: multifile.I:190
void set_encryption_key_length(int encryption_key_length)
Specifies the length of the key, in bits, that should be used to encrypt the stream in future calls t...
Definition: multifile.I:271
int get_encryption_iteration_count() const
Returns the value that was specified by set_encryption_iteration_count().
Definition: multifile.I:327
const string & get_encryption_password() const
Returns the password that will be used to encrypt subfiles subsequently added to the multifile...
Definition: multifile.I:207
string read_subfile(int index)
Returns a string that contains the entire contents of the indicated subfile.
Definition: multifile.I:363
void set_encryption_flag(bool flag)
Sets the flag indicating whether subsequently-added subfiles should be encrypted before writing them ...
Definition: multifile.I:152
void set_encryption_algorithm(const string &encryption_algorithm)
Specifies the encryption algorithm that should be used for future calls to add_subfile().
Definition: multifile.I:232
bool get_record_timestamp() const
Returns the flag indicating whether timestamps should be recorded within the Multifile or not...
Definition: multifile.I:121
size_t get_scale_factor() const
Returns the internal scale factor for this Multifile.
Definition: multifile.I:132
bool is_read_valid() const
Returns true if the Multifile has been opened for read mode and there have been no errors...
Definition: multifile.I:48
bool is_write_valid() const
Returns true if the Multifile has been opened for write mode and there have been no errors...
Definition: multifile.I:60
const string & get_header_prefix() const
Returns the string that preceded the Multifile header on the file, if any.
Definition: multifile.I:387
void set_multifile_name(const Filename &multifile_name)
Replaces the filename of the Multifile.
Definition: multifile.I:36
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
static string get_magic_number()
Returns a string with the first n bytes written to a Multifile, to identify it as a Multifile...
Definition: multifile.I:376
This class provides a locking wrapper around an arbitrary istream pointer.
Definition: streamWrapper.h:53
void set_encryption_iteration_count(int encryption_iteration_count)
Specifies the number of times to repeatedly hash the key before writing it to the stream in future ca...
Definition: multifile.I:313
bool flush()
Writes all contents of the Multifile to disk.
Definition: multifile.cxx:1309
void set_record_timestamp(bool record_timestamp)
Sets the flag indicating whether timestamps should be recorded within the Multifile or not...
Definition: multifile.I:108
void remove_subfile(int index)
Removes the nth subfile from the Multifile.
Definition: multifile.cxx:1666
const string & get_encryption_algorithm() const
Returns the encryption algorithm that was specified by set_encryption_algorithm().
Definition: multifile.I:248
int get_encryption_key_length() const
Returns the encryption key length, in bits, that was specified by set_encryption_key_length().
Definition: multifile.I:287
bool get_encryption_flag() const
Returns the flag indicating whether subsequently-added subfiles should be encrypted before writing th...
Definition: multifile.I:172
time_t get_timestamp() const
Returns the modification timestamp of the overall Multifile.
Definition: multifile.I:86
bool needs_repack() const
Returns true if the Multifile index is suboptimal and should be repacked.
Definition: multifile.I:71
const Filename & get_multifile_name() const
Returns the filename of the Multifile, if it is available.
Definition: multifile.I:23