Panda3D

multifile.I

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 &copy) :
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 
 All Classes Functions Variables Enumerations