diff --git a/panda/src/downloadertools/multify.cxx b/panda/src/downloadertools/multify.cxx index a3b77fe0bd..e311b38714 100644 --- a/panda/src/downloadertools/multify.cxx +++ b/panda/src/downloadertools/multify.cxx @@ -51,6 +51,43 @@ pset dont_compress; // -Z // Default extensions not to compress. May be overridden with -Z. string dont_compress_str = "jpg,mp3"; +bool got_record_timestamp_flag = false; +bool record_timestamp_flag = true; + +//////////////////////////////////////////////////////////////////// +// Function: string_to_int +// Description: A string-interface wrapper around the C library +// strtol(). This parses the ASCII representation of an +// integer, and then sets tail to everything that +// follows the first valid integer read. If, on exit, +// str == tail, there was no valid integer in the +// source string; if !tail.empty(), there was garbage +// after the integer. +// +// It is legal if str and tail refer to the same string. +//////////////////////////////////////////////////////////////////// +static int +string_to_int(const string &str, string &tail) { + const char *nptr = str.c_str(); + char *endptr; + int result = strtol(nptr, &endptr, 10); + tail = endptr; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: string_to_int +// Description: Another flavor of string_to_int(), this one returns +// true if the string is a perfectly valid integer (and +// sets result to that value), or false otherwise. +//////////////////////////////////////////////////////////////////// +static bool +string_to_int(const string &str, int &result) { + string tail; + result = string_to_int(str, tail); + return tail.empty(); +} + void usage() { cerr << @@ -159,6 +196,14 @@ help() { " \"" << dont_compress_str << "\". Specify -Z \"\" (be sure to include the space) to allow\n" " all files to be compressed.\n\n" + " -T \n" + " Enable or disable the recording of file timestamps within the multifile.\n" + " If is 1, timestamps will be recorded within the multifile for\n" + " each subfile added; this is the default behavior. If is 0,\n" + " timestamps will not be recorded, which will make it easier to do a\n" + " bitwise comparison between multifiles to determine whether their\n" + " contents are equivalent.\n\n" + " -1 .. -9\n" " Specify the compression level when -z is in effect. Larger numbers\n" " generate slightly smaller files, but compression takes longer. The\n" @@ -273,6 +318,10 @@ add_files(int argc, char *argv[]) { return false; } } + + if (got_record_timestamp_flag) { + multifile->set_record_timestamp(record_timestamp_flag); + } if (encryption_flag) { multifile->set_encryption_flag(true); @@ -389,10 +438,15 @@ extract_files(int argc, char *argv[]) { } const char * -format_timestamp(time_t timestamp) { +format_timestamp(bool record_timestamp, time_t timestamp) { static const size_t buffer_size = 512; static char buffer[buffer_size]; + if (!record_timestamp) { + // No timestamps. + return ""; + } + if (timestamp == 0) { // A zero timestamp is a special case. return " (no date) "; @@ -447,26 +501,34 @@ list_files(int argc, char *argv[]) { printf("%12d worse %c %s %s\n", multifile->get_subfile_length(i), encrypted_symbol, - format_timestamp(multifile->get_subfile_timestamp(i)), + format_timestamp(multifile->get_record_timestamp(), + multifile->get_subfile_timestamp(i)), subfile_name.c_str()); } else { printf("%12d %3.0f%% %c %s %s\n", multifile->get_subfile_length(i), 100.0 - ratio * 100.0, encrypted_symbol, - format_timestamp(multifile->get_subfile_timestamp(i)), + format_timestamp(multifile->get_record_timestamp(), + multifile->get_subfile_timestamp(i)), subfile_name.c_str()); } } else { printf("%12d %c %s %s\n", multifile->get_subfile_length(i), encrypted_symbol, - format_timestamp(multifile->get_subfile_timestamp(i)), + format_timestamp(multifile->get_record_timestamp(), + multifile->get_subfile_timestamp(i)), subfile_name.c_str()); } } } - cout << "Last modification " << format_timestamp(multifile->get_timestamp()) << "\n"; fflush(stdout); + + if (multifile->get_record_timestamp()) { + cout << "Last modification " + << format_timestamp(true, multifile->get_timestamp()) << "\n"; + } + if (multifile->get_scale_factor() != 1) { cout << "Scale factor is " << multifile->get_scale_factor() << "\n"; } @@ -520,7 +582,7 @@ main(int argc, char *argv[]) { extern char *optarg; extern int optind; - static const char *optflags = "crutxvz123456789Z:f:OC:ep:F:h"; + static const char *optflags = "crutxvz123456789Z:T:f:OC:ep:F:h"; int flag = getopt(argc, argv, optflags); Filename rel_path; while (flag != EOF) { @@ -585,6 +647,19 @@ main(int argc, char *argv[]) { case 'Z': dont_compress_str = optarg; break; + case 'T': + { + int flag; + if (!string_to_int(optarg, flag) || + (flag != 0 && flag != 1)) { + cerr << "Invalid timestamp flag: " << optarg << "\n"; + usage(); + return 1; + } + record_timestamp_flag = (flag != 0); + got_record_timestamp_flag = true; + } + break; case 'f': multifile_name = Filename::from_os_specific(optarg); got_multifile_name = true; @@ -655,8 +730,14 @@ main(int argc, char *argv[]) { if (create || append || update) { okflag = add_files(argc, argv); } else if (extract) { + if (got_record_timestamp_flag) { + cerr << "Warning: -T ignored on extract.\n"; + } okflag = extract_files(argc, argv); } else { // list + if (got_record_timestamp_flag) { + cerr << "Warning: -T ignored on list.\n"; + } okflag = list_files(argc, argv); } diff --git a/panda/src/express/multifile.I b/panda/src/express/multifile.I index 4354e1e7a7..2d68d9d455 100644 --- a/panda/src/express/multifile.I +++ b/panda/src/express/multifile.I @@ -78,6 +78,41 @@ get_timestamp() const { return _timestamp; } +//////////////////////////////////////////////////////////////////// +// Function: Multifile::set_record_timestamp +// Access: Published +// Description: 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; +} + +//////////////////////////////////////////////////////////////////// +// Function: Multifile::get_record_timestamp +// Access: Published +// Description: 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; +} + //////////////////////////////////////////////////////////////////// // Function: Multifile::get_scale_factor // Access: Published diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index eeb2a3d3f0..07025dbf7b 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -111,6 +111,7 @@ Multifile() { _needs_repack = false; _timestamp = 0; _timestamp_dirty = false; + _record_timestamp = true; _scale_factor = 1; _new_scale_factor = 1; _encryption_flag = false; @@ -534,7 +535,11 @@ flush() { nassertr(!_write->fail(), false); StreamWriter writer(*_write); - writer.add_uint32(_timestamp); + if (_record_timestamp) { + writer.add_uint32(_timestamp); + } else { + writer.add_uint32(0); + } _timestamp_dirty = false; } @@ -808,14 +813,19 @@ get_subfile_length(int index) const { // Access: Published // Description: Returns the modification time of the nth // subfile. If this is called on an older .mf file, -// which did not store individual timestamps in the -// file, this will return the modification time of the -// overall multifile. +// which did not store individual timestamps in the file +// (or if get_record_timestamp() is false), this will +// return the modification time of the overall +// multifile. //////////////////////////////////////////////////////////////////// time_t Multifile:: get_subfile_timestamp(int index) const { nassertr(index >= 0 && index < (int)_subfiles.size(), 0); - return _subfiles[index]->_timestamp; + if (!get_record_timestamp()) { + return get_timestamp(); + } else { + return _subfiles[index]->_timestamp; + } } //////////////////////////////////////////////////////////////////// @@ -1384,8 +1394,16 @@ read_index() { return false; } + _record_timestamp = true; if (_file_minor_ver >= 1) { - _timestamp = reader.get_uint32(); + time_t read_timestamp = reader.get_uint32(); + if (read_timestamp == 0) { + // If we read a 0 timestamp from the file, that implies that we + // don't want to record a timestamp in this particular file. + _record_timestamp = false; + } else { + _timestamp = read_timestamp; + } _timestamp_dirty = false; } @@ -1456,7 +1474,12 @@ write_header() { writer.add_int16(_current_minor_ver); writer.add_uint32(_scale_factor); - writer.add_uint32(_timestamp); + if (_record_timestamp) { + writer.add_uint32(_timestamp); + } else { + writer.add_uint32(0); + _timestamp_dirty = false; + } _next_index = _write->tellp(); _next_index = pad_to_streampos(_next_index); @@ -1515,6 +1538,9 @@ read_index(istream &read, streampos fpos, Multifile *multifile) { _timestamp = multifile->get_timestamp(); } else { _timestamp = reader.get_uint32(); + if (_timestamp == 0) { + _timestamp = multifile->get_timestamp(); + } } size_t name_length = reader.get_uint16(); @@ -1758,7 +1784,11 @@ rewrite_index_data_start(ostream &write, Multifile *multifile) { if ((_flags & (SF_compressed | SF_encrypted)) != 0) { writer.add_uint32(_uncompressed_length); } - writer.add_uint32(_timestamp); + if (multifile->_record_timestamp) { + writer.add_uint32(_timestamp); + } else { + writer.add_uint32(0); + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/express/multifile.h b/panda/src/express/multifile.h index fde54f0de6..c64d9b4a35 100644 --- a/panda/src/express/multifile.h +++ b/panda/src/express/multifile.h @@ -56,6 +56,9 @@ PUBLISHED: INLINE time_t get_timestamp() const; + INLINE void set_record_timestamp(bool record_timestamp); + INLINE bool get_record_timestamp() const; + void set_scale_factor(size_t scale_factor); INLINE size_t get_scale_factor() const; @@ -168,6 +171,7 @@ private: bool _needs_repack; time_t _timestamp; bool _timestamp_dirty; + bool _record_timestamp; size_t _scale_factor; size_t _new_scale_factor;