00001 // Filename: multifile.I 00002 // Created by: mike (09Jan97) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 00016 //////////////////////////////////////////////////////////////////// 00017 // Function: Multifile::get_multifile_name 00018 // Access: Published 00019 // Description: Returns the filename of the Multifile, if it is 00020 // available. 00021 //////////////////////////////////////////////////////////////////// 00022 INLINE const Filename &Multifile:: 00023 get_multifile_name() const { 00024 return _multifile_name; 00025 } 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: Multifile::set_multifile_name 00029 // Access: Published 00030 // Description: Replaces the filename of the Multifile. This is 00031 // primarily used for documentation purposes only; 00032 // changing this name does not open the indicated file. 00033 // See open_read() or open_write() for that. 00034 //////////////////////////////////////////////////////////////////// 00035 INLINE void Multifile:: 00036 set_multifile_name(const Filename &multifile_name) { 00037 _multifile_name = multifile_name; 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: Multifile::is_read_valid 00042 // Access: Published 00043 // Description: Returns true if the Multifile has been opened for 00044 // read mode and there have been no errors, and 00045 // individual Subfile contents may be extracted. 00046 //////////////////////////////////////////////////////////////////// 00047 INLINE bool Multifile:: 00048 is_read_valid() const { 00049 return (_read != (IStreamWrapper *)NULL); 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: Multifile::is_write_valid 00054 // Access: Published 00055 // Description: Returns true if the Multifile has been opened for 00056 // write mode and there have been no errors, and 00057 // Subfiles may be added or removed from the Multifile. 00058 //////////////////////////////////////////////////////////////////// 00059 INLINE bool Multifile:: 00060 is_write_valid() const { 00061 return (_write != (ostream *)NULL && !_write->fail()); 00062 } 00063 00064 //////////////////////////////////////////////////////////////////// 00065 // Function: Multifile::needs_repack 00066 // Access: Published 00067 // Description: Returns true if the Multifile index is suboptimal and 00068 // should be repacked. Call repack() to achieve this. 00069 //////////////////////////////////////////////////////////////////// 00070 INLINE bool Multifile:: 00071 needs_repack() const { 00072 return _needs_repack || (_scale_factor != _new_scale_factor); 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: Multifile::get_timestamp 00077 // Access: Published 00078 // Description: Returns the modification timestamp of the overall 00079 // Multifile. This indicates the most recent date at 00080 // which subfiles were added or removed from the 00081 // Multifile. Note that it is logically possible for an 00082 // individual subfile to have a more recent timestamp 00083 // than the overall timestamp. 00084 //////////////////////////////////////////////////////////////////// 00085 INLINE time_t Multifile:: 00086 get_timestamp() const { 00087 return _timestamp; 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Function: Multifile::set_record_timestamp 00092 // Access: Published 00093 // Description: Sets the flag indicating whether timestamps should be 00094 // recorded within the Multifile or not. The default is 00095 // true, indicating the Multifile will record timestamps 00096 // for the overall file and also for each subfile. 00097 // 00098 // If this is false, the Multifile will not record 00099 // timestamps internally. In this case, the return 00100 // value from get_timestamp() or get_subfile_timestamp() 00101 // will be estimations. 00102 // 00103 // You may want to set this false to minimize the 00104 // bitwise difference between independently-generated 00105 // Multifiles. 00106 //////////////////////////////////////////////////////////////////// 00107 INLINE void Multifile:: 00108 set_record_timestamp(bool flag) { 00109 _record_timestamp = flag; 00110 _timestamp_dirty = true; 00111 } 00112 00113 //////////////////////////////////////////////////////////////////// 00114 // Function: Multifile::get_record_timestamp 00115 // Access: Published 00116 // Description: Returns the flag indicating whether timestamps 00117 // should be recorded within the Multifile or not. See 00118 // set_record_timestamp(). 00119 //////////////////////////////////////////////////////////////////// 00120 INLINE bool Multifile:: 00121 get_record_timestamp() const { 00122 return _record_timestamp; 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: Multifile::get_scale_factor 00127 // Access: Published 00128 // Description: Returns the internal scale factor for this Multifile. 00129 // See set_scale_factor(). 00130 //////////////////////////////////////////////////////////////////// 00131 INLINE size_t Multifile:: 00132 get_scale_factor() const { 00133 return _new_scale_factor; 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: Multifile::set_encryption_flag 00138 // Access: Published 00139 // Description: Sets the flag indicating whether subsequently-added 00140 // subfiles should be encrypted before writing them to 00141 // the multifile. If true, subfiles will be encrypted; 00142 // if false (the default), they will be written without 00143 // encryption. 00144 // 00145 // When true, subfiles will be encrypted with the 00146 // password specified by set_encryption_password(). It 00147 // is possible to apply a different password to 00148 // different files, but the resulting file can't be 00149 // mounted via VFS. 00150 //////////////////////////////////////////////////////////////////// 00151 INLINE void Multifile:: 00152 set_encryption_flag(bool flag) { 00153 #ifndef HAVE_OPENSSL 00154 if (flag) { 00155 express_cat.warning() 00156 << "OpenSSL not compiled in; cannot generated encrypted multifiles.\n"; 00157 flag = false; 00158 } 00159 #endif // HAVE_OPENSSL 00160 _encryption_flag = flag; 00161 } 00162 00163 //////////////////////////////////////////////////////////////////// 00164 // Function: Multifile::get_encryption_flag 00165 // Access: Published 00166 // Description: Returns the flag indicating whether 00167 // subsequently-added subfiles should be encrypted 00168 // before writing them to the multifile. See 00169 // set_encryption_flag(). 00170 //////////////////////////////////////////////////////////////////// 00171 INLINE bool Multifile:: 00172 get_encryption_flag() const { 00173 return _encryption_flag; 00174 } 00175 00176 //////////////////////////////////////////////////////////////////// 00177 // Function: Multifile::set_encryption_password 00178 // Access: Published 00179 // Description: Specifies the password that will be used to encrypt 00180 // subfiles subsequently added to the multifile, if the 00181 // encryption flag is also set true (see 00182 // set_encryption_flag()). 00183 // 00184 // It is possible to apply a different password to 00185 // different files, but the resulting file can't be 00186 // mounted via VFS. Changing this value may cause an 00187 // implicit call to flush(). 00188 //////////////////////////////////////////////////////////////////// 00189 INLINE void Multifile:: 00190 set_encryption_password(const string &encryption_password) { 00191 if (_encryption_password != encryption_password) { 00192 if (!_new_subfiles.empty()) { 00193 flush(); 00194 } 00195 _encryption_password = encryption_password; 00196 } 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: Multifile::get_encryption_password 00201 // Access: Published 00202 // Description: Returns the password that will be used to encrypt 00203 // subfiles subsequently added to the multifile. See 00204 // set_encryption_password(). 00205 //////////////////////////////////////////////////////////////////// 00206 INLINE const string &Multifile:: 00207 get_encryption_password() const { 00208 return _encryption_password; 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: Multifile::set_encryption_algorithm 00213 // Access: Public 00214 // Description: Specifies the encryption algorithm that should be 00215 // used for future calls to add_subfile(). The default 00216 // is whatever is specified by the encryption-algorithm 00217 // config variable. The complete set of available 00218 // algorithms is defined by the current version of 00219 // OpenSSL. 00220 // 00221 // If an invalid algorithm is specified, there is no 00222 // immediate error return code, but flush() will fail 00223 // and the file will be invalid. 00224 // 00225 // It is possible to apply a different encryption 00226 // algorithm to different files, and unlike the 00227 // password, this does not interfere with mounting the 00228 // multifile via VFS. Changing this value may cause an 00229 // implicit call to flush(). 00230 //////////////////////////////////////////////////////////////////// 00231 INLINE void Multifile:: 00232 set_encryption_algorithm(const string &encryption_algorithm) { 00233 if (_encryption_algorithm != encryption_algorithm) { 00234 if (!_new_subfiles.empty()) { 00235 flush(); 00236 } 00237 _encryption_algorithm = encryption_algorithm; 00238 } 00239 } 00240 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: Multifile::get_encryption_algorithm 00243 // Access: Public 00244 // Description: Returns the encryption algorithm that was specified 00245 // by set_encryption_algorithm(). 00246 //////////////////////////////////////////////////////////////////// 00247 INLINE const string &Multifile:: 00248 get_encryption_algorithm() const { 00249 return _encryption_algorithm; 00250 } 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: Multifile::set_encryption_key_length 00254 // Access: Public 00255 // Description: Specifies the length of the key, in bits, that should 00256 // be used to encrypt the stream in future calls to 00257 // add_subfile(). The default is whatever is specified 00258 // by the encryption-key-length config variable. 00259 // 00260 // If an invalid key_length for the chosen algorithm is 00261 // specified, there is no immediate error return code, 00262 // but flush() will fail and the file will be invalid. 00263 // 00264 // It is possible to apply a different key length to 00265 // different files, and unlike the password, this does 00266 // not interfere with mounting the multifile via VFS. 00267 // Changing this value may cause an implicit call to 00268 // flush(). 00269 //////////////////////////////////////////////////////////////////// 00270 INLINE void Multifile:: 00271 set_encryption_key_length(int encryption_key_length) { 00272 if (_encryption_key_length != encryption_key_length) { 00273 if (!_new_subfiles.empty()) { 00274 flush(); 00275 } 00276 _encryption_key_length = encryption_key_length; 00277 } 00278 } 00279 00280 //////////////////////////////////////////////////////////////////// 00281 // Function: Multifile::get_encryption_key_length 00282 // Access: Public 00283 // Description: Returns the encryption key length, in bits, that was 00284 // specified by set_encryption_key_length(). 00285 //////////////////////////////////////////////////////////////////// 00286 INLINE int Multifile:: 00287 get_encryption_key_length() const { 00288 return _encryption_key_length; 00289 } 00290 00291 //////////////////////////////////////////////////////////////////// 00292 // Function: Multifile::set_encryption_iteration_count 00293 // Access: Public 00294 // Description: Specifies the number of times to repeatedly hash the 00295 // key before writing it to the stream in future calls 00296 // to add_subfile(). Its purpose is to make it 00297 // computationally more expensive for an attacker to 00298 // search the key space exhaustively. This should be a 00299 // multiple of 1,000 and should not exceed about 65 00300 // million; the value 0 indicates just one application 00301 // of the hashing algorithm. 00302 // 00303 // The default is whatever is specified by the 00304 // multifile-encryption-iteration-count config variable. 00305 // 00306 // It is possible to apply a different iteration count 00307 // to different files, and unlike the password, this 00308 // does not interfere with mounting the multifile via 00309 // VFS. Changing this value causes an implicit call to 00310 // flush(). 00311 //////////////////////////////////////////////////////////////////// 00312 INLINE void Multifile:: 00313 set_encryption_iteration_count(int encryption_iteration_count) { 00314 if (_encryption_iteration_count != encryption_iteration_count) { 00315 flush(); 00316 _encryption_iteration_count = encryption_iteration_count; 00317 } 00318 } 00319 00320 //////////////////////////////////////////////////////////////////// 00321 // Function: Multifile::get_encryption_iteration_count 00322 // Access: Public 00323 // Description: Returns the value that was specified by 00324 // set_encryption_iteration_count(). 00325 //////////////////////////////////////////////////////////////////// 00326 INLINE int Multifile:: 00327 get_encryption_iteration_count() const { 00328 return _encryption_iteration_count; 00329 } 00330 00331 //////////////////////////////////////////////////////////////////// 00332 // Function: Multifile::remove_subfile 00333 // Access: Published 00334 // Description: Removes the named subfile from the Multifile, if it 00335 // exists; returns true if successfully removed, or 00336 // false if it did not exist in the first place. The 00337 // file will not actually be removed from the disk until 00338 // the next call to flush(). 00339 // 00340 // Note that this does not actually remove the data from 00341 // the indicated subfile; it simply removes it from the 00342 // index. The Multifile will not be reduced in size 00343 // after this operation, until the next call to 00344 // repack(). 00345 //////////////////////////////////////////////////////////////////// 00346 INLINE bool Multifile:: 00347 remove_subfile(const string &subfile_name) { 00348 int index = find_subfile(subfile_name); 00349 if (index >= 0) { 00350 remove_subfile(index); 00351 return true; 00352 } 00353 return false; 00354 } 00355 00356 //////////////////////////////////////////////////////////////////// 00357 // Function: Multifile::read_subfile 00358 // Access: Published 00359 // Description: Returns a string that contains the entire contents of 00360 // the indicated subfile. 00361 //////////////////////////////////////////////////////////////////// 00362 INLINE string Multifile:: 00363 read_subfile(int index) { 00364 string result; 00365 read_subfile(index, result); 00366 return result; 00367 } 00368 00369 //////////////////////////////////////////////////////////////////// 00370 // Function: Multifile::get_magic_number 00371 // Access: Published, Static 00372 // Description: Returns a string with the first n bytes written to a 00373 // Multifile, to identify it as a Multifile. 00374 //////////////////////////////////////////////////////////////////// 00375 INLINE string Multifile:: 00376 get_magic_number() { 00377 return string(_header, _header_size); 00378 } 00379 00380 //////////////////////////////////////////////////////////////////// 00381 // Function: Multifile::get_header_prefix 00382 // Access: Published 00383 // Description: Returns the string that preceded the Multifile header 00384 // on the file, if any. See set_header_prefix(). 00385 //////////////////////////////////////////////////////////////////// 00386 INLINE const string &Multifile:: 00387 get_header_prefix() const { 00388 return _header_prefix; 00389 } 00390 00391 //////////////////////////////////////////////////////////////////// 00392 // Function: Multifile::word_to_streampos 00393 // Access: Private 00394 // Description: Converts a size_t address read from the file to 00395 // a streampos byte address within the file. 00396 //////////////////////////////////////////////////////////////////// 00397 INLINE streampos Multifile:: 00398 word_to_streampos(size_t word) const { 00399 return (streampos)word * (streampos)_scale_factor; 00400 } 00401 00402 //////////////////////////////////////////////////////////////////// 00403 // Function: Multifile::streampos_to_word 00404 // Access: Private 00405 // Description: Converts a streampos byte address within the file to 00406 // a size_t value suitable for writing to the file. 00407 //////////////////////////////////////////////////////////////////// 00408 INLINE size_t Multifile:: 00409 streampos_to_word(streampos fpos) const { 00410 return (size_t)((fpos + (streampos)_scale_factor - (streampos)1) / (streampos)_scale_factor); 00411 } 00412 00413 //////////////////////////////////////////////////////////////////// 00414 // Function: Multifile::normalize_streampos 00415 // Access: Private 00416 // Description: Rounds the streampos byte address up to the next 00417 // multiple of _scale_factor. Only multiples of 00418 // _scale_factor may be written to the file. 00419 //////////////////////////////////////////////////////////////////// 00420 INLINE streampos Multifile:: 00421 normalize_streampos(streampos fpos) const { 00422 return word_to_streampos(streampos_to_word(fpos)); 00423 } 00424 00425 //////////////////////////////////////////////////////////////////// 00426 // Function: Multifile::tohex 00427 // Access: Private, Static 00428 // Description: Converts a single nibble to a hex digit. 00429 //////////////////////////////////////////////////////////////////// 00430 INLINE char Multifile:: 00431 tohex(unsigned int nibble) { 00432 nibble &= 0xf; 00433 if (nibble < 10) { 00434 return nibble + '0'; 00435 } 00436 return nibble - 10 + 'a'; 00437 } 00438 00439 //////////////////////////////////////////////////////////////////// 00440 // Function: Multifile::Subfile::Constructor 00441 // Access: Public 00442 // Description: 00443 //////////////////////////////////////////////////////////////////// 00444 INLINE Multifile::Subfile:: 00445 Subfile() { 00446 _index_start = 0; 00447 _data_start = 0; 00448 _data_length = 0; 00449 _timestamp = 0; 00450 _source = (istream *)NULL; 00451 _flags = 0; 00452 _compression_level = 0; 00453 #ifdef HAVE_OPENSSL 00454 _pkey = NULL; 00455 #endif 00456 } 00457 00458 //////////////////////////////////////////////////////////////////// 00459 // Function: Multifile::Subfile::operator < 00460 // Access: Public 00461 // Description: Compares two Subfiles for proper sorting within the 00462 // index. 00463 //////////////////////////////////////////////////////////////////// 00464 INLINE bool Multifile::Subfile:: 00465 operator < (const Multifile::Subfile &other) const { 00466 // This should only be called on normal subfiles, not on certificate 00467 // files or signature files. (We don't attempt to sort these 00468 // special signature files.) 00469 nassertr(!is_cert_special() && !other.is_cert_special(), false); 00470 00471 // Normal subfiles are simply sorted in alphabetical order by 00472 // filename. 00473 return _name < other._name; 00474 } 00475 00476 //////////////////////////////////////////////////////////////////// 00477 // Function: Multifile::Subfile::is_deleted 00478 // Access: Public 00479 // Description: Returns true if the Subfile indicates it has been 00480 // deleted (removed from the index), false otherwise. 00481 // This should never be true of Subfiles that currently 00482 // appear in either the _subfiles or _new_subfiles 00483 // lists. 00484 //////////////////////////////////////////////////////////////////// 00485 INLINE bool Multifile::Subfile:: 00486 is_deleted() const { 00487 return (_flags & SF_deleted) != 0; 00488 } 00489 00490 //////////////////////////////////////////////////////////////////// 00491 // Function: Multifile::Subfile::is_index_invalid 00492 // Access: Public 00493 // Description: Returns true if there was some problem reading the 00494 // index record for this Subfile from the Multifile. 00495 //////////////////////////////////////////////////////////////////// 00496 INLINE bool Multifile::Subfile:: 00497 is_index_invalid() const { 00498 return (_flags & SF_index_invalid) != 0; 00499 } 00500 00501 //////////////////////////////////////////////////////////////////// 00502 // Function: Multifile::Subfile::is_data_invalid 00503 // Access: Public 00504 // Description: Returns true if there was some problem reading the 00505 // data contents of this Subfile, particularly when 00506 // copying into the Multifile. 00507 //////////////////////////////////////////////////////////////////// 00508 INLINE bool Multifile::Subfile:: 00509 is_data_invalid() const { 00510 return (_flags & SF_data_invalid) != 0; 00511 } 00512 00513 //////////////////////////////////////////////////////////////////// 00514 // Function: Multifile::Subfile::is_cert_special 00515 // Access: Public 00516 // Description: Returns true if this Subfile represents a signature 00517 // record, which is treated specially; or false if it is 00518 // an ordinary Subfile. 00519 //////////////////////////////////////////////////////////////////// 00520 INLINE bool Multifile::Subfile:: 00521 is_cert_special() const { 00522 return (_flags & SF_signature) != 0; 00523 } 00524 00525 //////////////////////////////////////////////////////////////////// 00526 // Function: Multifile::Subfile::get_last_byte_pos 00527 // Access: Public 00528 // Description: Returns the byte position within the Multifile of the 00529 // last byte that contributes to this Subfile, either in 00530 // the index record or in the subfile data. 00531 //////////////////////////////////////////////////////////////////// 00532 INLINE streampos Multifile::Subfile:: 00533 get_last_byte_pos() const { 00534 return max(_index_start + (streampos)_index_length, 00535 _data_start + (streampos)_data_length) - (streampos)1; 00536 } 00537 00538 #ifdef HAVE_OPENSSL 00539 //////////////////////////////////////////////////////////////////// 00540 // Function: Multifile::CertRecord::Constructor 00541 // Access: Public 00542 // Description: Ownership of the X509 object is passed into the 00543 // CertRecord; it will be freed when the CertRecord 00544 // destructs. 00545 //////////////////////////////////////////////////////////////////// 00546 INLINE Multifile::CertRecord:: 00547 CertRecord(X509 *cert) : 00548 _cert(cert) 00549 { 00550 } 00551 00552 //////////////////////////////////////////////////////////////////// 00553 // Function: Multifile::CertRecord::Copy Constructor 00554 // Access: Public 00555 // Description: 00556 //////////////////////////////////////////////////////////////////// 00557 INLINE Multifile::CertRecord:: 00558 CertRecord(const Multifile::CertRecord ©) : 00559 _cert(X509_dup(copy._cert)) 00560 { 00561 } 00562 00563 //////////////////////////////////////////////////////////////////// 00564 // Function: Multifile::CertRecord::Destructor 00565 // Access: Public 00566 // Description: 00567 //////////////////////////////////////////////////////////////////// 00568 INLINE Multifile::CertRecord:: 00569 ~CertRecord() { 00570 X509_free(_cert); 00571 } 00572 00573 //////////////////////////////////////////////////////////////////// 00574 // Function: Multifile::CertRecord::Copy Assignment 00575 // Access: Public 00576 // Description: 00577 //////////////////////////////////////////////////////////////////// 00578 INLINE void Multifile::CertRecord:: 00579 operator = (const Multifile::CertRecord &other) { 00580 X509_free(_cert); 00581 _cert = X509_dup(other._cert); 00582 } 00583 #endif 00584