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