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