Browse Source

convert express to new config system; add more options to pencrypt and OEncryptStream

David Rose 21 years ago
parent
commit
18ced11d6c

+ 1 - 1
panda/src/downloadertools/multify.cxx

@@ -131,7 +131,7 @@ help() {
     "      encrypted using different passwords (although this requires running\n"
     "      encrypted using different passwords (although this requires running\n"
     "      multify multiple times).  It is not possible to encrypt the multifile's\n"
     "      multify multiple times).  It is not possible to encrypt the multifile's\n"
     "      table of contents using this interface, but see the pencrypt program to\n"
     "      table of contents using this interface, but see the pencrypt program to\n"
-    "      encrypt the entire multifile after it has been generated).\n\n"
+    "      encrypt the entire multifile after it has been generated.\n\n"
 
 
 
 
     "  -p \"password\"\n"
     "  -p \"password\"\n"

+ 55 - 3
panda/src/downloadertools/pencrypt.cxx

@@ -46,17 +46,44 @@ usage() {
     << "      Specifies the password to use for encryption.  There are no\n"
     << "      Specifies the password to use for encryption.  There are no\n"
     << "      restrictions on the password length or contents, but longer passwords\n"
     << "      restrictions on the password length or contents, but longer passwords\n"
     << "      are more secure.  If this is not specified, the user is prompted from\n"
     << "      are more secure.  If this is not specified, the user is prompted from\n"
-    << "      standard input.\n\n";
+    << "      standard input.\n\n"
+
+    << "  -a \"algorithm\"\n"
+    << "      Specifies the particular encryption algorithm to use.  The complete\n"
+    << "      set of available algorithms is defined by the current version of\n"
+    << "      OpenSSL.  The default algorithm is taken from the encryption-\n"
+    << "      algorithm config variable.\n\n"
+
+    << "  -k key_length\n"
+    << "      Specifies the key length, in bits, for the selected encryption\n"
+    << "      algorithm.  This only makes sense for those algorithms that support\n"
+    << "      a variable key length.  The default value is taken from the\n"
+    << "      encryption-key-length config variable.\n\n"
+
+    << "  -i iteration_count\n"
+    << "      Specifies the number of times the password is hashed to generate\n"
+    << "      a key.  The only purpose of this is to make it computationally\n"
+    << "      more expensive for an attacker to search the key space exhaustively.\n"
+    << "      This should be a multiple of 1,000 and should not exceed about 65\n"
+    << "      million; the value 0 indicates just one application of the hashing\n"
+    << "      algorithm.  The default value is taken from the encryption-iteration-\n"
+    << "      count config variable.\n\n";
 }
 }
 
 
 int
 int
 main(int argc, char *argv[]) {
 main(int argc, char *argv[]) {
   extern char *optarg;
   extern char *optarg;
   extern int optind;
   extern int optind;
-  const char *optstr = "p:h";
+  const char *optstr = "p:a:k:i:h";
 
 
   string password;
   string password;
   bool got_password = false;
   bool got_password = false;
+  string algorithm;
+  bool got_algorithm = false;
+  int key_length = 0;
+  bool got_key_length = false;
+  int iteration_count = 0;
+  bool got_iteration_count = false;
 
 
   int flag = getopt(argc, argv, optstr);
   int flag = getopt(argc, argv, optstr);
 
 
@@ -67,6 +94,21 @@ main(int argc, char *argv[]) {
       got_password = true;
       got_password = true;
       break;
       break;
 
 
+    case 'a':
+      algorithm = optarg;
+      got_algorithm = true;
+      break;
+
+    case 'k':
+      key_length = atoi(optarg);
+      got_key_length = true;
+      break;
+
+    case 'i':
+      iteration_count = atoi(optarg);
+      got_iteration_count = true;
+      break;
+
     case 'h':
     case 'h':
     case '?':
     case '?':
     default:
     default:
@@ -119,7 +161,17 @@ main(int argc, char *argv[]) {
     
     
   bool fail = false;
   bool fail = false;
   {
   {
-    OEncryptStream encrypt(&write_stream, false, password);
+    OEncryptStream encrypt;
+    if (got_algorithm) {
+      encrypt.set_algorithm(algorithm);
+    }
+    if (got_key_length) {
+      encrypt.set_key_length(key_length);
+    }
+    if (got_iteration_count) {
+      encrypt.set_iteration_count(iteration_count);
+    }
+    encrypt.open(&write_stream, false, password);
     
     
     int ch = read_stream.get();
     int ch = read_stream.get();
     while (!read_stream.eof() && !read_stream.fail()) {
     while (!read_stream.eof() && !read_stream.fail()) {

+ 2 - 2
panda/src/express/Sources.pp

@@ -23,7 +23,7 @@
     datagramGenerator.h \
     datagramGenerator.h \
     datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \
     datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \
     dcast.T dcast.h \
     dcast.T dcast.h \
-    encryptStreamBuf.h encryptStream.h encryptStream.I \
+    encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I \
     error_utils.h \
     error_utils.h \
     get_config_path.h \
     get_config_path.h \
     hashGeneratorBase.I hashGeneratorBase.h \
     hashGeneratorBase.I hashGeneratorBase.h \
@@ -144,7 +144,7 @@
     datagramGenerator.I datagramGenerator.h \
     datagramGenerator.I datagramGenerator.h \
     datagramIterator.I datagramIterator.h \
     datagramIterator.I datagramIterator.h \
     datagramSink.I datagramSink.h dcast.T dcast.h \
     datagramSink.I datagramSink.h dcast.T dcast.h \
-    encryptStreamBuf.h encryptStream.h encryptStream.I \
+    encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I \
     error_utils.h get_config_path.h \
     error_utils.h get_config_path.h \
     hashGeneratorBase.I \
     hashGeneratorBase.I \
     hashGeneratorBase.h hashVal.I hashVal.h \
     hashGeneratorBase.h hashVal.I hashVal.h \

+ 56 - 4
panda/src/express/clockObject.cxx

@@ -19,6 +19,7 @@
 
 
 #include "clockObject.h"
 #include "clockObject.h"
 #include "config_express.h"
 #include "config_express.h"
+#include "configVariableEnum.h"
 
 
 #if defined(WIN32)
 #if defined(WIN32)
   #define WINDOWS_LEAN_AND_MEAN
   #define WINDOWS_LEAN_AND_MEAN
@@ -243,10 +244,12 @@ void ClockObject::
 make_global_clock() {
 make_global_clock() {
   nassertv(_global_clock == (ClockObject *)NULL);
   nassertv(_global_clock == (ClockObject *)NULL);
 
 
-  // Make sure we have run init_libexpress() by this time.  This
-  // function is responsible for initializing the clock_mode Configrc
-  // variable.
-  init_libexpress();
+  ConfigVariableEnum<ClockObject::Mode> clock_mode
+    ("clock-mode", ClockObject::M_normal,
+     "Specifies the mode of the global clock.  The default mode, normal, "
+     "is a real-time clock; other modes allow non-real-time special "
+     "effects like simulated reduced frame rate.  See "
+     "ClockObject::set_mode().");
 
 
   _global_clock = new ClockObject;
   _global_clock = new ClockObject;
   _global_clock->set_mode(clock_mode);
   _global_clock->set_mode(clock_mode);
@@ -259,3 +262,52 @@ make_global_clock() {
 void get_time_of_day(TimeVal &tv) {
 void get_time_of_day(TimeVal &tv) {
   get_true_time_of_day(tv.tv[0], tv.tv[1]);
   get_true_time_of_day(tv.tv[0], tv.tv[1]);
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClockObject::Mode ostream operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, ClockObject::Mode mode) {
+  switch (mode) {
+  case ClockObject::M_normal:
+    return out << "normal";
+
+  case ClockObject::M_non_real_time:
+    return out << "non-real-time";
+
+  case ClockObject::M_forced:
+    return out << "forced";
+
+  case ClockObject::M_degrade:
+    return out << "degrade";
+  };
+
+  return out << "**invalid ClockObject::Mode(" << (int)mode << ")**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClockObject::Mode istream operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+istream &
+operator >> (istream &in, ClockObject::Mode &mode) {
+  string word;
+  in >> word;
+
+  if (word == "normal") {
+    mode = ClockObject::M_normal;
+  } else if (word == "non-real-time") {
+    mode = ClockObject::M_non_real_time;
+  } else if (word == "forced") {
+    mode = ClockObject::M_forced;
+  } else if (word == "degrade") {
+    mode = ClockObject::M_degrade;
+  } else {
+    express_cat.error()
+      << "Invalid ClockObject::Mode: " << word << "\n";
+    mode = ClockObject::M_normal;
+  }
+
+  return in;
+}

+ 3 - 0
panda/src/express/clockObject.h

@@ -132,6 +132,9 @@ private:
   static ClockObject *_global_clock;
   static ClockObject *_global_clock;
 };
 };
 
 
+ostream &operator << (ostream &out, ClockObject::Mode mode);
+istream &operator >> (istream &in, ClockObject::Mode &mode);
+
 #include "clockObject.I"
 #include "clockObject.I"
 
 
 #endif
 #endif

+ 155 - 155
panda/src/express/config_express.cxx

@@ -43,83 +43,94 @@ ConfigureFn(config_express) {
   init_libexpress();
   init_libexpress();
 }
 }
 
 
-const int patchfile_window_size =
-        config_express.GetInt("patchfile-window-size", 16);
-
-const int patchfile_increment_size =
-        config_express.GetInt("patchfile-increment-size", 8);
-
-const int patchfile_buffer_size =
-        config_express.GetInt("patchfile-buffer-size", 4096);
-
-const int patchfile_zone_size =
-        config_express.GetInt("patchfile-zone-size", 10000);
-
-// Set this true to keep around the temporary files from downloading,
-// decompressing, and patching, or false (the default) to delete
-// these.  Mainly useful for debugging when the process goes wrong.
-const bool keep_temporary_files =
-config_express.GetBool("keep-temporary-files", false);
-
-const double average_frame_rate_interval = 
-config_express.GetDouble("average-frame-rate-interval", 1.0);
-
-ClockObject::Mode clock_mode = ClockObject::M_normal;
-const double clock_frame_rate = 
-config_express.GetDouble("clock-frame-rate", 1.0);
-const double clock_degrade_factor = 
-config_express.GetDouble("clock-degrade-factor", 1.0);
-const double max_dt = 
-config_express.GetDouble("max-dt", -1.0);
-
-// This is the accuracy within which we can expect select() to return
-// precisely.  That is, if we use select() to request a timeout of 1.0
-// seconds, we can expect to actually sleep for somewhere between 1.0
-// and 1.0 + sleep-precision seconds.
-const double sleep_precision =
-config_express.GetDouble("sleep-precision", 0.01);
-
-// This defines the OpenSSL encryption algorithm which is used to
-// encrypt any streams created by the current runtime.  The default is
-// Blowfish; the complete set of available algorithms is defined by
-// the current version of OpenSSL.  This value is used only to control
-// encryption; the correct algorithm will automatically be selected on
-// decryption.
-const string encryption_algorithm =
-config_express.GetString("encryption-algorithm", "bf-cbc");
-
-// This defines the key length, in bits, for the selected encryption
-// algorithm.  Some algorithms have a variable key length.  Specifying
-// a value of 0 here means to use the default key length for the
-// algorithm as defined by OpenSSL.  This value is used only to
-// control encryption; the correct key length will automatically be
-// selected on decryption.
-const int encryption_key_length =
-config_express.GetInt("encryption-key-length", 0);
-
-// This defines the number of times a password is hashed to generate a
-// key when encrypting.  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.  This value is used only to control
-// encryption; the correct count will automatically be selected on
-// decryption.
-const int encryption_iteration_count =
-config_express.GetInt("encryption-iteration-count", 100000);
-
-// Set this true to use the VirtualFileSystem mechanism for loading
-// models, etc.  Since the VirtualFileSystem maps to the same as the
-// actual file system by default, there is probably no reason to set
-// this false, except for testing or if you mistrust the new code.
-const bool use_vfs = config_express.GetBool("use-vfs", true);
-
-// Set this true to enable accumulation of several small consecutive
-// TCP datagrams into one large datagram before sending it, to reduce
-// overhead from the TCP/IP protocol.  See
-// Connection::set_collect_tcp() or SocketStream::set_collect_tcp().
-const bool collect_tcp = config_express.GetBool("collect-tcp", false);
-const double collect_tcp_interval = config_express.GetDouble("collect-tcp-interval", 0.2);
+ConfigVariableInt patchfile_window_size
+("patchfile-window-size", 16);
+
+ConfigVariableInt patchfile_increment_size
+("patchfile-increment-size", 8);
+
+ConfigVariableInt patchfile_buffer_size
+("patchfile-buffer-size", 4096);
+
+ConfigVariableInt patchfile_zone_size
+("patchfile-zone-size", 10000);
+
+ConfigVariableBool keep_temporary_files
+("keep-temporary-files", false,
+ "Set this true to keep around the temporary files from downloading, "
+ "decompressing, and patching, or false (the default) to delete "
+ "these.  Mainly useful for debugging when the process goes wrong.");
+
+ConfigVariableDouble average_frame_rate_interval
+("average-frame-rate-interval", 1.0);
+
+ConfigVariableDouble clock_frame_rate
+("clock-frame-rate", 1.0);
+ConfigVariableDouble clock_degrade_factor
+("clock-degrade-factor", 1.0);
+ConfigVariableDouble max_dt
+("max-dt", -1.0);
+
+ConfigVariableDouble sleep_precision
+("sleep-precision", 0.01,
+ "This is the accuracy within which we can expect select() to return "
+ "precisely.  That is, if we use select() to request a timeout of 1.0 "
+ "seconds, we can expect to actually sleep for somewhere between 1.0 "
+ "and 1.0 + sleep-precision seconds.");
+
+ConfigVariableString encryption_algorithm
+("encryption-algorithm", "bf-cbc",
+ "This defines the OpenSSL encryption algorithm which is used to "
+ "encrypt any streams created by the current runtime.  The default is "
+ "Blowfish; the complete set of available algorithms is defined by "
+ "the current version of OpenSSL.  This value is used only to control "
+ "encryption; the correct algorithm will automatically be selected on "
+ "decryption.");
+
+ConfigVariableInt encryption_key_length
+("encryption-key-length", 0,
+ "This defines the key length, in bits, for the selected encryption "
+ "algorithm.  Some algorithms have a variable key length.  Specifying "
+ "a value of 0 here means to use the default key length for the "
+ "algorithm as defined by OpenSSL.  This value is used only to "
+ "control encryption; the correct key length will automatically be "
+ "selected on decryption.");
+
+ConfigVariableInt encryption_iteration_count
+("encryption-iteration-count", 100000,
+ "This defines the number of times a password is hashed to generate a "
+ "key when encrypting.  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.  This value is used only to control "
+ "encryption; the correct count will automatically be selected on "
+ "decryption.");
+
+ConfigVariableInt multifile_encryption_iteration_count
+("multifile-encryption-iteration-count", 0,
+ "This is a special value of encryption-iteration-count used to encrypt "
+ "subfiles within a multifile.  It has a default value of 0 (just one "
+ "application), on the assumption that the files from a multifile must "
+ "be loaded quickly, without paying the cost of an expensive hash on "
+ "each subfile in order to decrypt it.");
+
+ConfigVariableBool use_vfs
+("use-vfs", true,
+ "Set this true to use the VirtualFileSystem mechanism for loading "
+ "models, etc.  Since the VirtualFileSystem maps to the same as the "
+ "actual file system by default, there is probably no reason to set "
+ "this false, except for testing or if you mistrust the new code.");
+
+ConfigVariableBool collect_tcp
+("collect-tcp", false,
+ "Set this true to enable accumulation of several small consecutive "
+ "TCP datagrams into one large datagram before sending it, to reduce "
+ "overhead from the TCP/IP protocol.  See "
+ "Connection::set_collect_tcp() or SocketStream::set_collect_tcp().");
+
+ConfigVariableDouble collect_tcp_interval
+("collect-tcp-interval", 0.2);
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libexpress
 //     Function: init_libexpress
@@ -151,115 +162,104 @@ init_libexpress() {
   VirtualFileSimple::init_type();
   VirtualFileSimple::init_type();
 
 
   init_system_type_handles();
   init_system_type_handles();
-
-  string text_encoding = config_express.GetString("text-encoding", "iso8859");
-  if (text_encoding == "iso8859") {
-    TextEncoder::set_default_encoding(TextEncoder::E_iso8859);
-  } else if (text_encoding == "utf8") {
-    TextEncoder::set_default_encoding(TextEncoder::E_utf8);
-  } else if (text_encoding == "unicode") {
-    TextEncoder::set_default_encoding(TextEncoder::E_unicode);
-  } else {
-    express_cat.error()
-      << "Invalid text-encoding: " << text_encoding << "\n";
-  }
-
-  string clock_mode_str = config_express.GetString("clock-mode", "normal");
-  if (clock_mode_str == "normal") {
-    clock_mode = ClockObject::M_normal;
-  } else if (clock_mode_str == "non-real-time") {
-    clock_mode = ClockObject::M_non_real_time;
-  } else if (clock_mode_str == "forced") {
-    clock_mode = ClockObject::M_forced;
-  } else if (clock_mode_str == "degrade") {
-    clock_mode = ClockObject::M_degrade;
-  } else {
-    express_cat.error()
-      << "Invalid clock-mode: " << clock_mode_str << "\n";
-  }
 }
 }
 
 
 
 
-// Set leak-memory true to disable the actual deletion of
-// ReferenceCount-derived objects.  This is sometimes useful to track
-// a reference counting bug, since the formerly deleted objects will
-// still remain (with a reference count of -100) without being
-// overwritten with a newly-allocated object, and the assertion tests
-// in ReferenceCount may more accurately detect the first instance of
-// an error.
 bool
 bool
 get_leak_memory() {
 get_leak_memory() {
-  static bool got_leak_memory = false;
-  static bool leak_memory;
-
-  if (!got_leak_memory) {
-    leak_memory = config_express.GetBool("leak-memory", false);
-    got_leak_memory = true;
+  static ConfigVariableBool *leak_memory = NULL;
+
+  if (leak_memory == (ConfigVariableBool *)NULL) {
+    leak_memory = new ConfigVariableBool
+      ("leak-memory", false,
+       "Set leak-memory true to disable the actual deletion of "
+       "ReferenceCount-derived objects.  This is sometimes useful to track "
+       "a reference counting bug, since the formerly deleted objects will "
+       "still remain (with a reference count of -100) without being "
+       "overwritten with a newly-allocated object, and the assertion tests "
+       "in ReferenceCount may more accurately detect the first instance of "
+       "an error.");
   }
   }
 
 
-  return leak_memory;
+  return *leak_memory;
 }
 }
 
 
-// never-destruct is similar to leak-memory, above, except that not
-// only will memory not be freed, but the destructor will not even be
-// called (on ReferenceCount objects, at least).  This will leak gobs
-// of memory, but ensures that every pointer to a ReferenceCount
-// object will always be valid, and may be useful for tracking down
-// certain kinds of errors.
-
-// never-destruct is only respected if leak-memory, above, is true.
 bool
 bool
 get_never_destruct() {
 get_never_destruct() {
-  static bool got_never_destruct = false;
-  static bool never_destruct;
-
-  if (!got_never_destruct) {
-    never_destruct = config_express.GetBool("never-destruct", false);
-    got_never_destruct = true;
+  static ConfigVariableBool *never_destruct = NULL;
+
+  if (never_destruct == (ConfigVariableBool *)NULL) {
+    never_destruct = new ConfigVariableBool
+      ("never-destruct", false,
+       "never-destruct is similar to leak-memory, except that not "
+       "only will memory not be freed, but the destructor will not even be "
+       "called (on ReferenceCount objects, at least).  This will leak gobs "
+       "of memory, but ensures that every pointer to a ReferenceCount "
+       "object will always be valid, and may be useful for tracking down "
+       "certain kinds of errors.  "
+       "never-destruct is only respected if leak-memory is true.");
   }
   }
 
 
-  return never_destruct;
+  return *never_destruct;
 }
 }
 
 
-//const bool track_memory_usage = config_express.GetBool("track-memory-usage", false);
-
-// Set this to false to avoid using the high-precision clock, even if
-// it is available.
 bool
 bool
 get_use_high_res_clock() {
 get_use_high_res_clock() {
-  return config_express.GetBool("use-high-res-clock", true);
+  static ConfigVariableBool *use_high_res_clock = NULL;
+
+  if (use_high_res_clock == (ConfigVariableBool *)NULL) {
+    use_high_res_clock = new ConfigVariableBool
+      ("use-high-res-clock", true,
+       "Set this to false to avoid using the high-precision clock, even if "
+       "it is available.");
+  }
+
+  return *use_high_res_clock;
 }
 }
 
 
-// Set this to true to double-check the results of the high-resolution
-// clock against the system clock.  This has no effect if NDEBUG is
-// defined.
 bool
 bool
 get_paranoid_clock() {
 get_paranoid_clock() {
-  return config_express.GetBool("paranoid-clock", false);
+  static ConfigVariableBool *paranoid_clock = NULL;
+
+  if (paranoid_clock == (ConfigVariableBool *)NULL) {
+    paranoid_clock = new ConfigVariableBool
+      ("paranoid-clock", false,
+       "Set this to true to double-check the results of the high-resolution "
+       "clock against the system clock.  This has no effect if NDEBUG is "
+       "defined.");
+  }
+
+  return *paranoid_clock;
 }
 }
 
 
-// Set this to true to double-check the test for inheritance of
-// TypeHandles, e.g. via is_of_type().  This has no effect if NDEBUG
-// is defined.
 bool
 bool
 get_paranoid_inheritance() {
 get_paranoid_inheritance() {
-  return config_express.GetBool("paranoid-inheritance", true);
+  static ConfigVariableBool *paranoid_inheritance = NULL;
+
+  if (paranoid_inheritance == (ConfigVariableBool *)NULL) {
+    paranoid_inheritance = new ConfigVariableBool
+      ("paranoid-inheritance", true,
+       "Set this to true to double-check the test for inheritance of "
+       "TypeHandles, e.g. via is_of_type().  This has no effect if NDEBUG "
+       "is defined.");
+  }
+
+  return *paranoid_inheritance;
 }
 }
 
 
-// Set this to true to verify that every attempted DCAST operation in
-// fact references the correct type, or false otherwise.  This has no
-// effect if NDEBUG is defined, in which case it is never tested.
 bool
 bool
 get_verify_dcast() {
 get_verify_dcast() {
-  static bool got_verify_dcast = false;
-  static bool verify_dcast;
-
-  if (!got_verify_dcast) {
-    verify_dcast = config_express.GetBool("verify-dcast", true);
-    got_verify_dcast = true;
+  static ConfigVariableBool *verify_dcast = NULL;
+
+  if (verify_dcast == (ConfigVariableBool *)NULL) {
+    verify_dcast = new ConfigVariableBool
+      ("verify-dcast", true,
+       "Set this to true to verify that every attempted DCAST operation in "
+       "fact references the correct type, or false otherwise.  This has no "
+       "effect if NDEBUG is defined, in which case it is never tested.");
   }
   }
 
 
-  return verify_dcast;
+  return *verify_dcast;
 }
 }
 
 
 // Returns the configure object for accessing config variables from a
 // Returns the configure object for accessing config variables from a

+ 17 - 17
panda/src/express/config_express.h

@@ -59,28 +59,28 @@ EXPCL_PANDAEXPRESS bool get_paranoid_clock();
 EXPCL_PANDAEXPRESS bool get_paranoid_inheritance();
 EXPCL_PANDAEXPRESS bool get_paranoid_inheritance();
 EXPCL_PANDAEXPRESS bool get_verify_dcast();
 EXPCL_PANDAEXPRESS bool get_verify_dcast();
 
 
-extern const int patchfile_window_size;
-extern const int patchfile_increment_size;
-extern const int patchfile_buffer_size;
-extern const int patchfile_zone_size;
+extern ConfigVariableInt patchfile_window_size;
+extern ConfigVariableInt patchfile_increment_size;
+extern ConfigVariableInt patchfile_buffer_size;
+extern ConfigVariableInt patchfile_zone_size;
 
 
-extern const bool keep_temporary_files;
-extern const double average_frame_rate_interval;
+extern ConfigVariableBool keep_temporary_files;
+extern ConfigVariableDouble average_frame_rate_interval;
 
 
-extern ClockObject::Mode clock_mode;
-extern const double clock_frame_rate;
-extern const double clock_degrade_factor;
-extern const double max_dt;
-extern const double sleep_precision;
+extern ConfigVariableDouble clock_frame_rate;
+extern ConfigVariableDouble clock_degrade_factor;
+extern ConfigVariableDouble max_dt;
+extern ConfigVariableDouble sleep_precision;
 
 
-extern const string encryption_algorithm;
-extern const int encryption_key_length;
-extern const int encryption_iteration_count;
+extern ConfigVariableString encryption_algorithm;
+extern ConfigVariableInt encryption_key_length;
+extern ConfigVariableInt encryption_iteration_count;
+extern ConfigVariableInt multifile_encryption_iteration_count;
 
 
-extern EXPCL_PANDAEXPRESS const bool use_vfs;
+extern EXPCL_PANDAEXPRESS ConfigVariableBool use_vfs;
 
 
-extern EXPCL_PANDAEXPRESS const bool collect_tcp;
-extern EXPCL_PANDAEXPRESS const double collect_tcp_interval;
+extern EXPCL_PANDAEXPRESS ConfigVariableBool collect_tcp;
+extern EXPCL_PANDAEXPRESS ConfigVariableDouble collect_tcp_interval;
 
 
 // Expose the Config variable for Python access.
 // Expose the Config variable for Python access.
 BEGIN_PUBLISH
 BEGIN_PUBLISH

+ 88 - 0
panda/src/express/encryptStream.I

@@ -61,6 +61,38 @@ close() {
   return *this;
   return *this;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: IDecryptStream::get_algorithm
+//       Access: Public
+//  Description: Returns the encryption algorithm that was read from
+//               the stream.
+////////////////////////////////////////////////////////////////////
+INLINE const string &IDecryptStream::
+get_algorithm() const {
+  return _buf.get_algorithm();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IDecryptStream::get_key_length
+//       Access: Public
+//  Description: Returns the encryption key length, in bits, that was
+//               read from the stream.
+////////////////////////////////////////////////////////////////////
+INLINE int IDecryptStream::
+get_key_length() const {
+  return _buf.get_key_length();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IDecryptStream::get_iteration_count
+//       Access: Public
+//  Description: Returns the value that was was read from the stream.
+////////////////////////////////////////////////////////////////////
+INLINE int IDecryptStream::
+get_iteration_count() const {
+  return _buf.get_iteration_count();
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: OEncryptStream::Constructor
 //     Function: OEncryptStream::Constructor
@@ -107,3 +139,59 @@ close() {
   return *this;
   return *this;
 }
 }
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: OEncryptStream::set_algorithm
+//       Access: Public
+//  Description: Specifies the encryption algorithm that should be
+//               used for future calls to open().  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 open() will
+//               fail.
+////////////////////////////////////////////////////////////////////
+INLINE void OEncryptStream::
+set_algorithm(const string &algorithm) {
+  _buf.set_algorithm(algorithm);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OEncryptStream::set_key_length
+//       Access: Public
+//  Description: Specifies the length of the key, in bits, that should
+//               be used to encrypt the stream in future calls to
+//               open().  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 open() will fail.
+////////////////////////////////////////////////////////////////////
+INLINE void OEncryptStream::
+set_key_length(int key_length) {
+  _buf.set_key_length(key_length);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: OEncryptStream::set_iteration_count
+//       Access: Public
+//  Description: Specifies the number of times to repeatedly hash the
+//               key before writing it to the stream in future calls
+//               to open().  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
+//               encryption-iteration-count config variable.
+////////////////////////////////////////////////////////////////////
+INLINE void OEncryptStream::
+set_iteration_count(int iteration_count) {
+  _buf.set_iteration_count(iteration_count);
+}

+ 8 - 0
panda/src/express/encryptStream.h

@@ -48,6 +48,10 @@ public:
                               const string &password);
                               const string &password);
   INLINE IDecryptStream &close();
   INLINE IDecryptStream &close();
 
 
+  INLINE const string &get_algorithm() const;
+  INLINE int get_key_length() const;
+  INLINE int get_iteration_count() const;
+
 private:
 private:
   EncryptStreamBuf _buf;
   EncryptStreamBuf _buf;
 };
 };
@@ -73,6 +77,10 @@ public:
                               const string &password);
                               const string &password);
   INLINE OEncryptStream &close();
   INLINE OEncryptStream &close();
 
 
+  INLINE void set_algorithm(const string &algorithm);
+  INLINE void set_key_length(int key_length);
+  INLINE void set_iteration_count(int iteration_count);
+
 private:
 private:
   EncryptStreamBuf _buf;
   EncryptStreamBuf _buf;
 };
 };

+ 110 - 0
panda/src/express/encryptStreamBuf.I

@@ -0,0 +1,110 @@
+// Filename: encryptStreamBuf.I
+// Created by:  drose (09Dec04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: EncryptStreamBuf::set_algorithm
+//       Access: Public
+//  Description: Specifies the encryption algorithm that should be
+//               used for future calls to open_write().  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 open_write() will
+//               fail.
+////////////////////////////////////////////////////////////////////
+INLINE void EncryptStreamBuf::
+set_algorithm(const string &algorithm) {
+  _algorithm = algorithm;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EncryptStreamBuf::get_algorithm
+//       Access: Public
+//  Description: Returns the encryption algorithm that was specified
+//               by set_algorithm(), or was read from the stream by
+//               the last successful open_read().
+////////////////////////////////////////////////////////////////////
+INLINE const string &EncryptStreamBuf::
+get_algorithm() const {
+  return _algorithm;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EncryptStreamBuf::set_key_length
+//       Access: Public
+//  Description: Specifies the length of the key, in bits, that should
+//               be used to encrypt the stream in future calls to
+//               open_write().  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 open_write() will fail.
+////////////////////////////////////////////////////////////////////
+INLINE void EncryptStreamBuf::
+set_key_length(int key_length) {
+  _key_length = key_length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EncryptStreamBuf::get_key_length
+//       Access: Public
+//  Description: Returns the encryption key length, in bits, that was
+//               specified by set_key_length(), or was read from the
+//               stream by the last successful open_read().
+////////////////////////////////////////////////////////////////////
+INLINE int EncryptStreamBuf::
+get_key_length() const {
+  return _key_length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EncryptStreamBuf::set_iteration_count
+//       Access: Public
+//  Description: Specifies the number of times to repeatedly hash the
+//               key before writing it to the stream in future calls
+//               to open_write().  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
+//               encryption-iteration-count config variable.
+////////////////////////////////////////////////////////////////////
+INLINE void EncryptStreamBuf::
+set_iteration_count(int iteration_count) {
+  _iteration_count = iteration_count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EncryptStreamBuf::get_iteration_count
+//       Access: Public
+//  Description: Returns the value that was specified by
+//               set_iteration_count(), or was read from the stream by
+//               the last successful open_read().
+////////////////////////////////////////////////////////////////////
+INLINE int EncryptStreamBuf::
+get_iteration_count() const {
+  return _iteration_count;
+}

+ 28 - 10
panda/src/express/encryptStreamBuf.cxx

@@ -46,6 +46,10 @@ EncryptStreamBuf() {
   _dest = (ostream *)NULL;
   _dest = (ostream *)NULL;
   _owns_dest = false;
   _owns_dest = false;
 
 
+  _algorithm = encryption_algorithm;
+  _key_length = encryption_key_length;
+  _iteration_count = encryption_iteration_count;
+
   _read_valid = false;
   _read_valid = false;
   _write_valid = false;
   _write_valid = false;
 
 
@@ -103,9 +107,17 @@ open_read(istream *source, bool owns_source, const string &password) {
     return;
     return;
   }
   }
 
 
-  express_cat.debug()
-    << "Using decryption algorithm " << OBJ_nid2sn(nid) << " with key length "
-    << key_length * 8 << " bits.\n";
+  _algorithm = OBJ_nid2sn(nid);
+  _key_length = key_length * 8;
+  _iteration_count = count * iteration_count_factor;
+
+  if (express_cat.is_debug()) {
+    express_cat.debug()
+      << "Using decryption algorithm " << _algorithm << " with key length "
+      << _key_length << " bits.\n";
+    express_cat.debug()
+      << "Key is hashed " << _iteration_count << " extra times.\n";
+  }
 
 
   int iv_length = EVP_CIPHER_iv_length(cipher);
   int iv_length = EVP_CIPHER_iv_length(cipher);
   _read_block_size = EVP_CIPHER_block_size(cipher);
   _read_block_size = EVP_CIPHER_block_size(cipher);
@@ -186,11 +198,11 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
   _write_valid = false;
   _write_valid = false;
 
 
   const EVP_CIPHER *cipher = 
   const EVP_CIPHER *cipher = 
-    EVP_get_cipherbyname(encryption_algorithm.c_str());
+    EVP_get_cipherbyname(_algorithm.c_str());
 
 
   if (cipher == NULL) {
   if (cipher == NULL) {
     express_cat.error()
     express_cat.error()
-      << "Unknown encryption algorithm: " << encryption_algorithm << "\n";
+      << "Unknown encryption algorithm: " << _algorithm << "\n";
     return;
     return;
   };
   };
 
 
@@ -210,7 +222,7 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   // Store the appropriate key length in the context.
   // Store the appropriate key length in the context.
-  int key_length = (encryption_key_length + 7) / 8;
+  int key_length = (_key_length + 7) / 8;
   if (key_length == 0) {
   if (key_length == 0) {
     key_length = EVP_CIPHER_CTX_key_length(cipher);
     key_length = EVP_CIPHER_CTX_key_length(cipher);
   }
   }
@@ -223,12 +235,18 @@ open_write(ostream *dest, bool owns_dest, const string &password) {
     return;
     return;
   }
   }
 
 
-  express_cat.debug()
-    << "Using encryption algorithm " << OBJ_nid2sn(nid) << " with key length "
-    << key_length * 8 << " bits.\n";
+  int count = _iteration_count / iteration_count_factor;
+
+  if (express_cat.is_debug()) {
+    express_cat.debug()
+      << "Using encryption algorithm " << OBJ_nid2sn(nid) << " with key length "
+      << key_length * 8 << " bits.\n";
+    express_cat.debug()
+      << "Hashing key " << count * iteration_count_factor
+      << " extra times.\n";
+  }
 
 
   // Hash the supplied password into a key of the appropriate length.
   // Hash the supplied password into a key of the appropriate length.
-  int count = encryption_iteration_count / iteration_count_factor;
   unsigned char *key = (unsigned char *)alloca(key_length);
   unsigned char *key = (unsigned char *)alloca(key_length);
   result =
   result =
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),

+ 15 - 0
panda/src/express/encryptStreamBuf.h

@@ -42,6 +42,15 @@ public:
   void open_write(ostream *dest, bool owns_dest, const string &password);
   void open_write(ostream *dest, bool owns_dest, const string &password);
   void close_write();
   void close_write();
 
 
+  INLINE void set_algorithm(const string &algorithm);
+  INLINE const string &get_algorithm() const;
+
+  INLINE void set_key_length(int key_length);
+  INLINE int get_key_length() const;
+
+  INLINE void set_iteration_count(int iteration_count);
+  INLINE int get_iteration_count() const;
+
 protected:
 protected:
   virtual int overflow(int c);
   virtual int overflow(int c);
   virtual int sync(void);
   virtual int sync(void);
@@ -57,6 +66,10 @@ private:
 
 
   ostream *_dest;
   ostream *_dest;
   bool _owns_dest;
   bool _owns_dest;
+
+  string _algorithm;
+  int _key_length;
+  int _iteration_count;
   
   
   bool _read_valid;
   bool _read_valid;
   EVP_CIPHER_CTX _read_ctx;
   EVP_CIPHER_CTX _read_ctx;
@@ -69,6 +82,8 @@ private:
   size_t _write_block_size;
   size_t _write_block_size;
 };
 };
 
 
+#include "encryptStreamBuf.I"
+
 #endif  // HAVE_SSL
 #endif  // HAVE_SSL
 
 
 #endif
 #endif

+ 12 - 12
panda/src/express/memoryUsage.cxx

@@ -379,19 +379,19 @@ MemoryUsage() {
   // time, and who knows when the code in config_express will be
   // time, and who knows when the code in config_express will be
   // executed.
   // executed.
 
 
-  // track-memory-usage should be true to enable full-force tracking
-  // of C++ allocations and recordkeeping by type.  It's quite
-  // expensive.
-  _track_memory_usage =
-    config_express.GetBool("track-memory-usage", false);
-
-  // count-memory-usage is a much lighter-weight version, and only
-  // tracks the total memory allocation.  However, it only works for
-  // certain build environments (in particular, only in an Opt1 or
-  // Opt2 build on Windows).
+  _track_memory_usage = ConfigVariableBool
+    ("track-memory-usage", false,
+     "Set this to true to enable full-force tracking of C++ allocations "
+     "and recordkeeping by type.  It's quite expensive.");
+
 #if defined(WIN32_VC) && defined(_DEBUG)
 #if defined(WIN32_VC) && defined(_DEBUG)
-  _count_memory_usage = config_express.GetBool("count-memory-usage", 
-                                               _track_memory_usage);
+  _count_memory_usage = ConfigVariableBool
+    ("count-memory-usage", _track_memory_usage,
+     "This is a much lighter-weight version of track-memory-usage, and it "
+     "only tracks the total memory allocation.  However, it only exists in "
+     "certain build environments (in particular, only in an Opt1 or "
+     "Opt2 build on Windows.");
+     
 #else
 #else
   _count_memory_usage = false;
   _count_memory_usage = false;
 #endif
 #endif

+ 5 - 2
panda/src/express/multifile.cxx

@@ -1573,8 +1573,11 @@ write_data(ostream &write, istream *read, streampos fpos,
 #else  // HAVE_ZLIB
 #else  // HAVE_ZLIB
     if ((_flags & SF_encrypted) != 0) {
     if ((_flags & SF_encrypted) != 0) {
       // Write it encrypted.
       // Write it encrypted.
-      putter = new OEncryptStream(putter, delete_putter, 
-                                  multifile->_encryption_password);
+      OEncryptStream *encrypt = new OEncryptStream;
+      encrypt->set_iteration_count(multifile_encryption_iteration_count);
+      encrypt->open(putter, delete_putter, multifile->_encryption_password);
+
+      putter = encrypt;
       delete_putter = true;
       delete_putter = true;
 
 
       // Also write the encrypt_header to the beginning of the
       // Also write the encrypt_header to the beginning of the

+ 48 - 1
panda/src/express/textEncoder.cxx

@@ -21,7 +21,10 @@
 #include "unicodeLatinMap.h"
 #include "unicodeLatinMap.h"
 
 
 TypeHandle TextEncoder::_type_handle;
 TypeHandle TextEncoder::_type_handle;
-TextEncoder::Encoding TextEncoder::_default_encoding;
+ConfigVariableEnum<TextEncoder::Encoding> TextEncoder::_default_encoding
+("default-encoding", TextEncoder::E_iso8859,
+ "Specifies how international characters are represented in strings "
+ "of 8-byte characters presented to Panda.  See TextEncoder::set_encoding().");
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TextEncoder::make_upper
 //     Function: TextEncoder::make_upper
@@ -321,3 +324,47 @@ expand_amp_sequence(StringDecoder &decoder) const {
 }
 }
 */
 */
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextEncoder::Encoding ostream operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, TextEncoder::Encoding encoding) {
+  switch (encoding) {
+  case TextEncoder::E_iso8859:
+    return out << "iso8859";
+
+  case TextEncoder::E_utf8:
+    return out << "utf8";
+
+  case TextEncoder::E_unicode:
+    return out << "unicode";
+  };
+
+  return out << "**invalid TextEncoder::Encoding(" << (int)encoding << ")**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextEncoder::Encoding istream operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+istream &
+operator >> (istream &in, TextEncoder::Encoding &encoding) {
+  string word;
+  in >> word;
+
+  if (word == "iso8859") {
+    encoding = TextEncoder::E_iso8859;
+  } else if (word == "utf8") {
+    encoding = TextEncoder::E_utf8;
+  } else if (word == "unicode") {
+    encoding = TextEncoder::E_unicode;
+  } else {
+    express_cat.error()
+      << "Invalid TextEncoder::Encoding: " << word << "\n";
+    encoding = TextEncoder::E_iso8859;
+  }
+
+  return in;
+}

+ 5 - 1
panda/src/express/textEncoder.h

@@ -21,6 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 #include "unicodeLatinMap.h"
 #include "unicodeLatinMap.h"
+#include "configVariableEnum.h"
 
 
 class StringDecoder;
 class StringDecoder;
 
 
@@ -112,7 +113,7 @@ private:
   string _text;
   string _text;
   wstring _wtext;
   wstring _wtext;
 
 
-  static Encoding _default_encoding;
+  static ConfigVariableEnum<Encoding> _default_encoding;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -126,6 +127,9 @@ private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 };
 };
 
 
+ostream &operator << (ostream &out, TextEncoder::Encoding encoding);
+istream &operator >> (istream &in, TextEncoder::Encoding &encoding);
+
 #include "textEncoder.I"
 #include "textEncoder.I"
 
 
 #endif
 #endif

+ 56 - 61
panda/src/express/virtualFileSystem.cxx

@@ -504,72 +504,67 @@ get_global_ptr() {
     _global_ptr->chdir(ExecutionEnvironment::get_cwd());
     _global_ptr->chdir(ExecutionEnvironment::get_cwd());
 
 
     // Then, we add whatever mounts are listed in the Configrc file.
     // Then, we add whatever mounts are listed in the Configrc file.
-    Config::ConfigTable::Symbol mounts;
-    config_express.GetAll("vfs-mount", mounts);
-
-    // When we use GetAll(), we might inadvertently read duplicate
-    // lines.  Filter them out with a set.
-    pset<string> already_read;
-
-    Config::ConfigTable::Symbol::iterator si;
-    for (si = mounts.begin(); si != mounts.end(); ++si) {
-      string mount_desc = (*si).Val();
-      if (already_read.insert(mount_desc).second) {
-
-        // The vfs-mount syntax is:
-
-        // vfs-mount system-filename mount-point [options]
-
-        // The last two spaces mark the beginning of the mount point,
-        // and of the options, respectively.  There might be multiple
-        // spaces in the system filename, which are part of the
-        // filename.
-
-        // The last space marks the beginning of the mount point.
-        // Spaces before that are part of the system filename.
-        size_t space = mount_desc.rfind(' ');
-        if (space == string::npos) {
-          express_cat.warning()
-            << "No space in vfs-mount descriptor: " << mount_desc << "\n";
-          
-        } else {
-          string mount_point = mount_desc.substr(space + 1);
+    ConfigVariableList mounts
+      ("vfs-mount",
+       "vfs-mount system-filename mount-point [options]");
+
+    int num_unique_values = mounts.get_num_unique_values();
+    for (int i = 0; i < num_unique_values; i++) {
+      string mount_desc = mounts.get_unique_value(i);
+
+      // The vfs-mount syntax is:
+      
+      // vfs-mount system-filename mount-point [options]
+      
+      // The last two spaces mark the beginning of the mount point,
+      // and of the options, respectively.  There might be multiple
+      // spaces in the system filename, which are part of the
+      // filename.
+      
+      // The last space marks the beginning of the mount point.
+      // Spaces before that are part of the system filename.
+      size_t space = mount_desc.rfind(' ');
+      if (space == string::npos) {
+        express_cat.warning()
+          << "No space in vfs-mount descriptor: " << mount_desc << "\n";
+        
+      } else {
+        string mount_point = mount_desc.substr(space + 1);
+        while (space > 0 && isspace(mount_desc[space - 1])) {
+          space--;
+        }
+        mount_desc = mount_desc.substr(0, space);
+        string options;
+        
+        space = mount_desc.rfind(' ');
+        if (space != string::npos) {
+          // If there's another space, we have the optional options field.
+          options = mount_point;
+          mount_point = mount_desc.substr(space + 1);
           while (space > 0 && isspace(mount_desc[space - 1])) {
           while (space > 0 && isspace(mount_desc[space - 1])) {
             space--;
             space--;
           }
           }
           mount_desc = mount_desc.substr(0, space);
           mount_desc = mount_desc.substr(0, space);
-          string options;
-
-          space = mount_desc.rfind(' ');
-          if (space != string::npos) {
-            // If there's another space, we have the optional options field.
-            options = mount_point;
-            mount_point = mount_desc.substr(space + 1);
-            while (space > 0 && isspace(mount_desc[space - 1])) {
-              space--;
-            }
-            mount_desc = mount_desc.substr(0, space);
-          }
-
-          mount_desc = ExecutionEnvironment::expand_string(mount_desc);
-          Filename physical_filename = Filename::from_os_specific(mount_desc);
-
-          int flags = 0;
-          string password;
-
-          // Split the options up by commas.
-          size_t p = 0;
-          size_t q = options.find(',', p);
-          while (q != string::npos) {
-            parse_option(options.substr(p, q - p),
-                         flags, password);
-            p = q + 1;
-            q = options.find(',', p);
-          }
-          parse_option(options.substr(p), flags, password);
-
-          _global_ptr->mount(physical_filename, mount_point, flags, password);
         }
         }
+        
+        mount_desc = ExecutionEnvironment::expand_string(mount_desc);
+        Filename physical_filename = Filename::from_os_specific(mount_desc);
+        
+        int flags = 0;
+        string password;
+        
+        // Split the options up by commas.
+        size_t p = 0;
+        size_t q = options.find(',', p);
+        while (q != string::npos) {
+          parse_option(options.substr(p, q - p),
+                       flags, password);
+          p = q + 1;
+          q = options.find(',', p);
+        }
+        parse_option(options.substr(p), flags, password);
+        
+        _global_ptr->mount(physical_filename, mount_point, flags, password);
       }
       }
     }
     }
   }
   }