historical/toontown-classic.git/panda/include/multifile.I

426 lines
12 KiB
Text
Raw Normal View History

2024-01-16 11:20:27 -06:00
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file multifile.I
* @author mike
* @date 1997-01-09
*/
/**
* Returns the filename of the Multifile, if it is available.
*/
INLINE const Filename &Multifile::
get_multifile_name() const {
return _multifile_name;
}
/**
* Replaces the filename of the Multifile. This is primarily used for
* documentation purposes only; changing this name does not open the indicated
* file. See open_read() or open_write() for that.
*/
INLINE void Multifile::
set_multifile_name(const Filename &multifile_name) {
_multifile_name = multifile_name;
}
/**
* Returns true if the Multifile has been opened for read mode and there have
* been no errors, and individual Subfile contents may be extracted.
*/
INLINE bool Multifile::
is_read_valid() const {
return (_read != nullptr);
}
/**
* Returns true if the Multifile has been opened for write mode and there have
* been no errors, and Subfiles may be added or removed from the Multifile.
*/
INLINE bool Multifile::
is_write_valid() const {
return (_write != nullptr && !_write->fail());
}
/**
* Returns true if the Multifile index is suboptimal and should be repacked.
* Call repack() to achieve this.
*/
INLINE bool Multifile::
needs_repack() const {
return _needs_repack || (_scale_factor != _new_scale_factor);
}
/**
* Returns the modification timestamp of the overall Multifile. This
* indicates the most recent date at which subfiles were added or removed from
* the Multifile. Note that it is logically possible for an individual
* subfile to have a more recent timestamp than the overall timestamp.
*/
INLINE time_t Multifile::
get_timestamp() const {
return _timestamp;
}
/**
* Sets the flag indicating whether timestamps should be recorded within the
* Multifile or not. The default is true, indicating the Multifile will
* record timestamps for the overall file and also for each subfile.
*
* If this is false, the Multifile will not record timestamps internally. In
* this case, the return value from get_timestamp() or get_subfile_timestamp()
* will be estimations.
*
* You may want to set this false to minimize the bitwise difference between
* independently-generated Multifiles.
*/
INLINE void Multifile::
set_record_timestamp(bool flag) {
_record_timestamp = flag;
_timestamp_dirty = true;
}
/**
* Returns the flag indicating whether timestamps should be recorded within
* the Multifile or not. See set_record_timestamp().
*/
INLINE bool Multifile::
get_record_timestamp() const {
return _record_timestamp;
}
/**
* Returns the internal scale factor for this Multifile. See
* set_scale_factor().
*/
INLINE size_t Multifile::
get_scale_factor() const {
return _new_scale_factor;
}
/**
* Sets the flag indicating whether subsequently-added subfiles should be
* encrypted before writing them to the multifile. If true, subfiles will be
* encrypted; if false (the default), they will be written without encryption.
*
* When true, subfiles will be encrypted with the password specified by
* set_encryption_password(). It is possible to apply a different password to
* different files, but the resulting file can't be mounted via VFS.
*/
INLINE void Multifile::
set_encryption_flag(bool flag) {
#ifndef HAVE_OPENSSL
if (flag) {
express_cat.warning()
<< "OpenSSL not compiled in; cannot generated encrypted multifiles.\n";
flag = false;
}
#endif // HAVE_OPENSSL
_encryption_flag = flag;
}
/**
* Returns the flag indicating whether subsequently-added subfiles should be
* encrypted before writing them to the multifile. See set_encryption_flag().
*/
INLINE bool Multifile::
get_encryption_flag() const {
return _encryption_flag;
}
/**
* Specifies the password that will be used to encrypt subfiles subsequently
* added to the multifile, if the encryption flag is also set true (see
* set_encryption_flag()).
*
* It is possible to apply a different password to different files, but the
* resulting file can't be mounted via VFS. Changing this value may cause an
* implicit call to flush().
*/
INLINE void Multifile::
set_encryption_password(const std::string &encryption_password) {
if (_encryption_password != encryption_password) {
if (!_new_subfiles.empty()) {
flush();
}
_encryption_password = encryption_password;
}
}
/**
* Returns the password that will be used to encrypt subfiles subsequently
* added to the multifile. See set_encryption_password().
*/
INLINE const std::string &Multifile::
get_encryption_password() const {
return _encryption_password;
}
/**
* Specifies the encryption algorithm that should be used for future calls to
* add_subfile(). The default is whatever is specified by the encryption-
* algorithm config variable. The complete set of available algorithms is
* defined by the current version of OpenSSL.
*
* If an invalid algorithm is specified, there is no immediate error return
* code, but flush() will fail and the file will be invalid.
*
* It is possible to apply a different encryption algorithm to different
* files, and unlike the password, this does not interfere with mounting the
* multifile via VFS. Changing this value may cause an implicit call to
* flush().
*/
INLINE void Multifile::
set_encryption_algorithm(const std::string &encryption_algorithm) {
if (_encryption_algorithm != encryption_algorithm) {
if (!_new_subfiles.empty()) {
flush();
}
_encryption_algorithm = encryption_algorithm;
}
}
/**
* Returns the encryption algorithm that was specified by
* set_encryption_algorithm().
*/
INLINE const std::string &Multifile::
get_encryption_algorithm() const {
return _encryption_algorithm;
}
/**
* Specifies the length of the key, in bits, that should be used to encrypt
* the stream in future calls to add_subfile(). The default is whatever is
* specified by the encryption-key-length config variable.
*
* If an invalid key_length for the chosen algorithm is specified, there is no
* immediate error return code, but flush() will fail and the file will be
* invalid.
*
* It is possible to apply a different key length to different files, and
* unlike the password, this does not interfere with mounting the multifile
* via VFS. Changing this value may cause an implicit call to flush().
*/
INLINE void Multifile::
set_encryption_key_length(int encryption_key_length) {
if (_encryption_key_length != encryption_key_length) {
if (!_new_subfiles.empty()) {
flush();
}
_encryption_key_length = encryption_key_length;
}
}
/**
* Returns the encryption key length, in bits, that was specified by
* set_encryption_key_length().
*/
INLINE int Multifile::
get_encryption_key_length() const {
return _encryption_key_length;
}
/**
* Specifies the number of times to repeatedly hash the key before writing it
* to the stream in future calls to add_subfile(). Its purpose is to make it
* computationally more expensive for an attacker to search the key space
* exhaustively. This should be a multiple of 1,000 and should not exceed
* about 65 million; the value 0 indicates just one application of the hashing
* algorithm.
*
* The default is whatever is specified by the multifile-encryption-iteration-
* count config variable.
*
* It is possible to apply a different iteration count to different files, and
* unlike the password, this does not interfere with mounting the multifile
* via VFS. Changing this value causes an implicit call to flush().
*/
INLINE void Multifile::
set_encryption_iteration_count(int encryption_iteration_count) {
if (_encryption_iteration_count != encryption_iteration_count) {
flush();
_encryption_iteration_count = encryption_iteration_count;
}
}
/**
* Returns the value that was specified by set_encryption_iteration_count().
*/
INLINE int Multifile::
get_encryption_iteration_count() const {
return _encryption_iteration_count;
}
/**
* Removes the named subfile from the Multifile, if it exists; returns true if
* successfully removed, or false if it did not exist in the first place. The
* file will not actually be removed from the disk until the next call to
* flush().
*
* Note that this does not actually remove the data from the indicated
* subfile; it simply removes it from the index. The Multifile will not be
* reduced in size after this operation, until the next call to repack().
*/
INLINE bool Multifile::
remove_subfile(const std::string &subfile_name) {
int index = find_subfile(subfile_name);
if (index >= 0) {
remove_subfile(index);
return true;
}
return false;
}
/**
* Returns a vector_uchar that contains the entire contents of the indicated
* subfile.
*/
INLINE vector_uchar Multifile::
read_subfile(int index) {
vector_uchar result;
read_subfile(index, result);
return result;
}
/**
* Returns a string with the first n bytes written to a Multifile, to identify
* it as a Multifile.
*/
INLINE std::string Multifile::
get_magic_number() {
return std::string(_header, _header_size);
}
/**
* Returns the string that preceded the Multifile header on the file, if any.
* See set_header_prefix().
*/
INLINE const std::string &Multifile::
get_header_prefix() const {
return _header_prefix;
}
/**
* Converts a size_t address read from the file to a streampos byte address
* within the file.
*/
INLINE std::streampos Multifile::
word_to_streampos(size_t word) const {
return (std::streampos)word * (std::streampos)_scale_factor;
}
/**
* Converts a streampos byte address within the file to a size_t value
* suitable for writing to the file.
*/
INLINE size_t Multifile::
streampos_to_word(std::streampos fpos) const {
return (size_t)((fpos + (std::streampos)_scale_factor - (std::streampos)1) / (std::streampos)_scale_factor);
}
/**
* Rounds the streampos byte address up to the next multiple of _scale_factor.
* Only multiples of _scale_factor may be written to the file.
*/
INLINE std::streampos Multifile::
normalize_streampos(std::streampos fpos) const {
return word_to_streampos(streampos_to_word(fpos));
}
/**
* Converts a single nibble to a hex digit.
*/
INLINE char Multifile::
tohex(unsigned int nibble) {
nibble &= 0xf;
if (nibble < 10) {
return nibble + '0';
}
return nibble - 10 + 'a';
}
/**
*
*/
INLINE Multifile::Subfile::
Subfile() {
_index_start = 0;
_data_start = 0;
_data_length = 0;
_timestamp = 0;
_source = nullptr;
_flags = 0;
_compression_level = 0;
#ifdef HAVE_OPENSSL
_pkey = nullptr;
#endif
}
/**
* Compares two Subfiles for proper sorting within the index.
*/
INLINE bool Multifile::Subfile::
operator < (const Multifile::Subfile &other) const {
// This should only be called on normal subfiles, not on certificate files
// or signature files. (We don't attempt to sort these special signature
// files.)
nassertr(!is_cert_special() && !other.is_cert_special(), false);
// Normal subfiles are simply sorted in alphabetical order by filename.
return _name < other._name;
}
/**
* Returns true if the Subfile indicates it has been deleted (removed from the
* index), false otherwise. This should never be true of Subfiles that
* currently appear in either the _subfiles or _new_subfiles lists.
*/
INLINE bool Multifile::Subfile::
is_deleted() const {
return (_flags & SF_deleted) != 0;
}
/**
* Returns true if there was some problem reading the index record for this
* Subfile from the Multifile.
*/
INLINE bool Multifile::Subfile::
is_index_invalid() const {
return (_flags & SF_index_invalid) != 0;
}
/**
* Returns true if there was some problem reading the data contents of this
* Subfile, particularly when copying into the Multifile.
*/
INLINE bool Multifile::Subfile::
is_data_invalid() const {
return (_flags & SF_data_invalid) != 0;
}
/**
* Returns true if this Subfile represents a signature record, which is
* treated specially; or false if it is an ordinary Subfile.
*/
INLINE bool Multifile::Subfile::
is_cert_special() const {
return (_flags & SF_signature) != 0;
}
/**
* Returns the byte position within the Multifile of the last byte that
* contributes to this Subfile, either in the index record or in the subfile
* data.
*/
INLINE std::streampos Multifile::Subfile::
get_last_byte_pos() const {
return std::max(_index_start + (std::streampos)_index_length,
_data_start + (std::streampos)_data_length) - (std::streampos)1;
}