Browse Source

add set_record_timestamp()

David Rose 19 years ago
parent
commit
af2ef4dca8

+ 87 - 6
panda/src/downloadertools/multify.cxx

@@ -51,6 +51,43 @@ pset<string> dont_compress;    // -Z
 // Default extensions not to compress.  May be overridden with -Z.
 // Default extensions not to compress.  May be overridden with -Z.
 string dont_compress_str = "jpg,mp3";
 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 
 void 
 usage() {
 usage() {
   cerr <<
   cerr <<
@@ -159,6 +196,14 @@ help() {
     "      \"" << dont_compress_str << "\".  Specify -Z \"\" (be sure to include the space) to allow\n"
     "      \"" << dont_compress_str << "\".  Specify -Z \"\" (be sure to include the space) to allow\n"
     "      all files to be compressed.\n\n"
     "      all files to be compressed.\n\n"
 
 
+    "  -T <flag>\n"
+    "      Enable or disable the recording of file timestamps within the multifile.\n"
+    "      If <flag> is 1, timestamps will be recorded within the multifile for\n"
+    "      each subfile added; this is the default behavior.  If <flag> 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"
     "  -1 .. -9\n"
     "      Specify the compression level when -z is in effect.  Larger numbers\n"
     "      Specify the compression level when -z is in effect.  Larger numbers\n"
     "      generate slightly smaller files, but compression takes longer.  The\n"
     "      generate slightly smaller files, but compression takes longer.  The\n"
@@ -273,6 +318,10 @@ add_files(int argc, char *argv[]) {
       return false;
       return false;
     }
     }
   }
   }
+  
+  if (got_record_timestamp_flag) {
+    multifile->set_record_timestamp(record_timestamp_flag);
+  }
 
 
   if (encryption_flag) {
   if (encryption_flag) {
     multifile->set_encryption_flag(true);
     multifile->set_encryption_flag(true);
@@ -389,10 +438,15 @@ extract_files(int argc, char *argv[]) {
 }
 }
 
 
 const char *
 const char *
-format_timestamp(time_t timestamp) {
+format_timestamp(bool record_timestamp, time_t timestamp) {
   static const size_t buffer_size = 512;
   static const size_t buffer_size = 512;
   static char buffer[buffer_size];
   static char buffer[buffer_size];
 
 
+  if (!record_timestamp) {
+    // No timestamps.
+    return "";
+  }
+  
   if (timestamp == 0) {
   if (timestamp == 0) {
     // A zero timestamp is a special case.
     // A zero timestamp is a special case.
     return "  (no date) ";
     return "  (no date) ";
@@ -447,26 +501,34 @@ list_files(int argc, char *argv[]) {
             printf("%12d worse %c %s %s\n",
             printf("%12d worse %c %s %s\n",
                    multifile->get_subfile_length(i),
                    multifile->get_subfile_length(i),
                    encrypted_symbol,
                    encrypted_symbol,
-                   format_timestamp(multifile->get_subfile_timestamp(i)),
+                   format_timestamp(multifile->get_record_timestamp(),
+                                    multifile->get_subfile_timestamp(i)),
                    subfile_name.c_str());
                    subfile_name.c_str());
           } else {
           } else {
             printf("%12d  %3.0f%% %c %s %s\n",
             printf("%12d  %3.0f%% %c %s %s\n",
                    multifile->get_subfile_length(i),
                    multifile->get_subfile_length(i),
                    100.0 - ratio * 100.0, encrypted_symbol,
                    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());
                    subfile_name.c_str());
           }
           }
         } else {
         } else {
           printf("%12d       %c %s %s\n", 
           printf("%12d       %c %s %s\n", 
                  multifile->get_subfile_length(i),
                  multifile->get_subfile_length(i),
                  encrypted_symbol,
                  encrypted_symbol,
-                 format_timestamp(multifile->get_subfile_timestamp(i)),
+                 format_timestamp(multifile->get_record_timestamp(),
+                                  multifile->get_subfile_timestamp(i)),
                  subfile_name.c_str());
                  subfile_name.c_str());
         }
         }
       }
       }
     }
     }
-    cout << "Last modification " << format_timestamp(multifile->get_timestamp()) << "\n";
     fflush(stdout);
     fflush(stdout);
+
+    if (multifile->get_record_timestamp()) {
+      cout << "Last modification " 
+           << format_timestamp(true, multifile->get_timestamp()) << "\n";
+    }
+
     if (multifile->get_scale_factor() != 1) {
     if (multifile->get_scale_factor() != 1) {
       cout << "Scale factor is " << multifile->get_scale_factor() << "\n";
       cout << "Scale factor is " << multifile->get_scale_factor() << "\n";
     }
     }
@@ -520,7 +582,7 @@ main(int argc, char *argv[]) {
 
 
   extern char *optarg;
   extern char *optarg;
   extern int optind;
   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);
   int flag = getopt(argc, argv, optflags);
   Filename rel_path;
   Filename rel_path;
   while (flag != EOF) {
   while (flag != EOF) {
@@ -585,6 +647,19 @@ main(int argc, char *argv[]) {
     case 'Z':
     case 'Z':
       dont_compress_str = optarg;
       dont_compress_str = optarg;
       break;
       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':
     case 'f':
       multifile_name = Filename::from_os_specific(optarg);
       multifile_name = Filename::from_os_specific(optarg);
       got_multifile_name = true;
       got_multifile_name = true;
@@ -655,8 +730,14 @@ main(int argc, char *argv[]) {
   if (create || append || update) {
   if (create || append || update) {
     okflag = add_files(argc, argv);
     okflag = add_files(argc, argv);
   } else if (extract) {
   } else if (extract) {
+    if (got_record_timestamp_flag) {
+      cerr << "Warning: -T ignored on extract.\n";
+    }
     okflag = extract_files(argc, argv);
     okflag = extract_files(argc, argv);
   } else { // list
   } else { // list
+    if (got_record_timestamp_flag) {
+      cerr << "Warning: -T ignored on list.\n";
+    }
     okflag = list_files(argc, argv);
     okflag = list_files(argc, argv);
   }
   }
 
 

+ 35 - 0
panda/src/express/multifile.I

@@ -78,6 +78,41 @@ get_timestamp() const {
   return _timestamp;
   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
 //     Function: Multifile::get_scale_factor
 //       Access: Published
 //       Access: Published

+ 38 - 8
panda/src/express/multifile.cxx

@@ -111,6 +111,7 @@ Multifile() {
   _needs_repack = false;
   _needs_repack = false;
   _timestamp = 0;
   _timestamp = 0;
   _timestamp_dirty = false;
   _timestamp_dirty = false;
+  _record_timestamp = true;
   _scale_factor = 1;
   _scale_factor = 1;
   _new_scale_factor = 1;
   _new_scale_factor = 1;
   _encryption_flag = false;
   _encryption_flag = false;
@@ -534,7 +535,11 @@ flush() {
     nassertr(!_write->fail(), false);
     nassertr(!_write->fail(), false);
     
     
     StreamWriter writer(*_write);
     StreamWriter writer(*_write);
-    writer.add_uint32(_timestamp);
+    if (_record_timestamp) {
+      writer.add_uint32(_timestamp);
+    } else {
+      writer.add_uint32(0);
+    }
     _timestamp_dirty = false;
     _timestamp_dirty = false;
   }
   }
 
 
@@ -808,14 +813,19 @@ get_subfile_length(int index) const {
 //       Access: Published
 //       Access: Published
 //  Description: Returns the modification time of the nth
 //  Description: Returns the modification time of the nth
 //               subfile.  If this is called on an older .mf file,
 //               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::
 time_t Multifile::
 get_subfile_timestamp(int index) const {
 get_subfile_timestamp(int index) const {
   nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
   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;
     return false;
   }
   }
 
 
+  _record_timestamp = true;
   if (_file_minor_ver >= 1) {
   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;
     _timestamp_dirty = false;
   }
   }
 
 
@@ -1456,7 +1474,12 @@ write_header() {
   writer.add_int16(_current_minor_ver);
   writer.add_int16(_current_minor_ver);
   writer.add_uint32(_scale_factor);
   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 = _write->tellp();
   _next_index = pad_to_streampos(_next_index);
   _next_index = pad_to_streampos(_next_index);
@@ -1515,6 +1538,9 @@ read_index(istream &read, streampos fpos, Multifile *multifile) {
     _timestamp = multifile->get_timestamp();
     _timestamp = multifile->get_timestamp();
   } else {
   } else {
     _timestamp = reader.get_uint32();
     _timestamp = reader.get_uint32();
+    if (_timestamp == 0) {
+      _timestamp = multifile->get_timestamp();
+    }
   }
   }
 
 
   size_t name_length = reader.get_uint16();
   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) {
   if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
     writer.add_uint32(_uncompressed_length);
     writer.add_uint32(_uncompressed_length);
   }
   }
-  writer.add_uint32(_timestamp);
+  if (multifile->_record_timestamp) {
+    writer.add_uint32(_timestamp);
+  } else {
+    writer.add_uint32(0);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 4 - 0
panda/src/express/multifile.h

@@ -56,6 +56,9 @@ PUBLISHED:
 
 
   INLINE time_t get_timestamp() const;
   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);
   void set_scale_factor(size_t scale_factor);
   INLINE size_t get_scale_factor() const;
   INLINE size_t get_scale_factor() const;
 
 
@@ -168,6 +171,7 @@ private:
   bool _needs_repack;
   bool _needs_repack;
   time_t _timestamp;
   time_t _timestamp;
   bool _timestamp_dirty;
   bool _timestamp_dirty;
+  bool _record_timestamp;
   size_t _scale_factor;
   size_t _scale_factor;
   size_t _new_scale_factor;
   size_t _new_scale_factor;