Przeglądaj źródła

loader uses vfs

David Rose 23 lat temu
rodzic
commit
fa59c3e37f

+ 14 - 8
panda/src/downloadertools/multify.cxx

@@ -94,12 +94,15 @@ add_directory(Multifile &multifile, const Filename &directory_name) {
       okflag = false;
 
     } else {
-      if (verbose) {
-        cout << subfile_name << "\n";
-      }
-      if (!multifile.add_subfile(subfile_name, subfile_name)) {
+      string new_subfile_name =
+        multifile.add_subfile(subfile_name, subfile_name);
+      if (new_subfile_name.empty()) {
         cerr << "Unable to add " << subfile_name << ".\n";
         okflag = false;
+      } else {
+        if (verbose) {
+          cout << new_subfile_name << "\n";
+        }
       }
     }
   }
@@ -140,12 +143,15 @@ add_files(int argc, char *argv[]) {
       okflag = false;
 
     } else {
-      if (verbose) {
-        cout << subfile_name << "\n";
-      }
-      if (!multifile.add_subfile(subfile_name, subfile_name)) {
+      string new_subfile_name =
+        multifile.add_subfile(subfile_name, subfile_name);
+      if (new_subfile_name.empty()) {
         cerr << "Unable to add " << subfile_name << ".\n";
         okflag = false;
+      } else {
+        if (verbose) {
+          cout << new_subfile_name << "\n";
+        }
       }
     }
   }

+ 65 - 22
panda/src/egg/eggData.cxx

@@ -24,9 +24,10 @@
 #include "eggPoolUniquifier.h"
 #include "config_egg.h"
 
-#include <config_util.h>
-#include <string_utils.h>
-#include <dSearchPath.h>
+#include "config_util.h"
+#include "string_utils.h"
+#include "dSearchPath.h"
+#include "virtualFileSystem.h"
 
 extern int eggyyparse(void);
 #include "parserDefs.h"
@@ -45,15 +46,30 @@ TypeHandle EggData::_type_handle;
 ////////////////////////////////////////////////////////////////////
 bool EggData::
 resolve_egg_filename(Filename &egg_filename, const DSearchPath &searchpath) {
-  if (egg_filename.is_fully_qualified() && egg_filename.exists()) {
-    return true;
-  }
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+    if (egg_filename.is_fully_qualified() && vfs->exists(egg_filename)) {
+      return true;
+    }
+
+    vfs->resolve_filename(egg_filename, searchpath, "egg") ||
+      vfs->resolve_filename(egg_filename, get_egg_path(), "egg") ||
+      vfs->resolve_filename(egg_filename, get_model_path(), "egg");
 
-  egg_filename.resolve_filename(searchpath, "egg") ||
-    egg_filename.resolve_filename(get_egg_path(), "egg") ||
-    egg_filename.resolve_filename(get_model_path(), "egg");
+    return vfs->exists(egg_filename);
 
-  return egg_filename.exists();
+  } else {
+    if (egg_filename.is_fully_qualified() && egg_filename.exists()) {
+      return true;
+    }
+
+    egg_filename.resolve_filename(searchpath, "egg") ||
+      egg_filename.resolve_filename(get_egg_path(), "egg") ||
+      egg_filename.resolve_filename(get_model_path(), "egg");
+    
+    return egg_filename.exists();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -76,19 +92,46 @@ read(Filename filename) {
     return false;
   }
 
-  filename.set_text();
-  set_egg_filename(filename);
-
-  ifstream file;
-  if (!filename.open_read(file)) {
-    egg_cat.error() << "Unable to open " << filename << "\n";
-    return false;
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    
+    filename.set_text();
+    set_egg_filename(filename);
+    
+    istream *file = vfs->open_read_file(filename);
+    if (file == (istream *)NULL) {
+      egg_cat.error() << "Unable to open " << filename << "\n";
+      return false;
+    }
+    
+    egg_cat.info()
+      << "Reading " << filename << "\n";
+
+    bool read_ok = read(*file);
+    delete file;
+    return read_ok;
+
+  } else {
+    if (!resolve_egg_filename(filename)) {
+      egg_cat.error()
+        << "Could not find " << filename << "\n";
+      return false;
+    }
+    
+    filename.set_text();
+    set_egg_filename(filename);
+    
+    ifstream file;
+    if (!filename.open_read(file)) {
+      egg_cat.error() << "Unable to open " << filename << "\n";
+      return false;
+    }
+    
+    egg_cat.info()
+      << "Reading " << filename << "\n";
+    
+    return read(file);
   }
-
-  egg_cat.info()
-    << "Reading " << filename << "\n";
-
-  return read(file);
 }
 
 

+ 40 - 11
panda/src/egg2pg/load_egg_file.cxx

@@ -20,6 +20,8 @@
 #include "eggLoader.h"
 #include "config_egg2pg.h"
 #include "sceneGraphReducer.h"
+#include "virtualFileSystem.h"
+#include "config_util.h"
 
 static PT(PandaNode)
 load_from_loader(EggLoader &loader) {
@@ -54,29 +56,56 @@ load_from_loader(EggLoader &loader) {
 PT(PandaNode)
 load_egg_file(const string &filename, CoordinateSystem cs) {
   Filename egg_filename = Filename::text_filename(filename);
-  if (!egg_filename.exists()) {
-    egg2pg_cat.error()
-      << "Could not find " << egg_filename << "\n";
-    return NULL;
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    if (!vfs->exists(egg_filename)) {
+      egg2pg_cat.error()
+        << "Could not find " << egg_filename << "\n";
+      return NULL;
+    }
+
+  } else {
+    if (!egg_filename.exists()) {
+      egg2pg_cat.error()
+        << "Could not find " << egg_filename << "\n";
+      return NULL;
+    }
   }
 
   egg2pg_cat.info()
     << "Reading " << egg_filename << "\n";
 
-  ifstream file;
-  if (!egg_filename.open_read(file)) {
-    egg2pg_cat.error()
-      << "Could not open " << egg_filename << " for reading.\n";
-    return NULL;
-  }
 
   EggLoader loader;
   loader._data.set_egg_filename(egg_filename);
   if (cs != CS_default) {
     loader._data.set_coordinate_system(cs);
   }
+  bool okflag;
+  
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    istream *istr = vfs->open_read_file(egg_filename);
+    if (istr == (istream *)NULL) {
+      egg2pg_cat.error()
+        << "Could not open " << egg_filename << " for reading.\n";
+      return NULL;
+    }
+    okflag = loader._data.read(*istr);
+    delete istr;
+
+  } else {
+    ifstream file;
+
+    if (!egg_filename.open_read(file)) {
+      egg2pg_cat.error()
+        << "Could not open " << egg_filename << " for reading.\n";
+      return NULL;
+    } 
+    okflag = loader._data.read(file);
+  }
 
-  if (!loader._data.read(file)) {
+  if (!okflag) {
     egg2pg_cat.error()
       << "Error reading " << egg_filename << "\n";
     return NULL;

+ 7 - 9
panda/src/express/Sources.pp

@@ -13,9 +13,8 @@
     checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
     circBuffer.h clockObject.I clockObject.h config_express.h \
     datagram.I datagram.h datagramGenerator.I \
-    datagramGenerator.h datagramInputFile.I datagramInputFile.h \
-    datagramIterator.I datagramIterator.h datagramOutputFile.I \
-    datagramOutputFile.h datagramSink.I datagramSink.h \
+    datagramGenerator.h \
+    datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \
     dcast.T dcast.h \
     error_utils.h \
     get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
@@ -51,8 +50,8 @@
   #define INCLUDED_SOURCES  \
     buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
     config_express.cxx datagram.cxx datagramGenerator.cxx \
-    datagramInputFile.cxx datagramIterator.cxx \
-    datagramOutputFile.cxx datagramSink.cxx dcast.cxx error_utils.cxx \
+    datagramIterator.cxx \
+    datagramSink.cxx dcast.cxx error_utils.cxx \
     get_config_path.cxx \
     hashGeneratorBase.cxx hashVal.cxx indent.cxx \
     memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
@@ -71,10 +70,9 @@
     bigEndian.h buffer.I buffer.h checksumHashGenerator.I  \
     checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
     clockObject.h config_express.h datagram.I datagram.h \
-    datagramGenerator.I datagramGenerator.h datagramInputFile.I \
-    datagramInputFile.h datagramIterator.I datagramIterator.h \
-    datagramOutputFile.I datagramOutputFile.h datagramSink.I \
-    datagramSink.h dcast.T dcast.h \
+    datagramGenerator.I datagramGenerator.h \
+    datagramIterator.I datagramIterator.h \
+    datagramSink.I datagramSink.h dcast.T dcast.h \
     error_utils.h get_config_path.h hashGeneratorBase.I \
     hashGeneratorBase.h hashVal.I hashVal.h \
     indent.I indent.h \

+ 0 - 2
panda/src/express/express_composite1.cxx

@@ -5,9 +5,7 @@
 #include "config_express.cxx"
 #include "datagram.cxx"
 #include "datagramGenerator.cxx"
-#include "datagramInputFile.cxx"
 #include "datagramIterator.cxx"
-#include "datagramOutputFile.cxx"
 #include "datagramSink.cxx"
 #include "dcast.cxx"
 #include "get_config_path.cxx"

+ 1 - 3
panda/src/express/multifile.I

@@ -114,9 +114,7 @@ normalize_streampos(streampos fpos) const {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE Multifile::Subfile::
-Subfile(const string &name) :
-  _name(name)
-{
+Subfile() {
   _index_start = 0;
   _data_start = 0;
   _data_length = 0;

+ 39 - 20
panda/src/express/multifile.cxx

@@ -288,21 +288,21 @@ set_scale_factor(size_t scale_factor) {
 //               The file named by filename will be read and added to
 //               the Multifile at the next call to flush().
 //
-//               Returns true on success, false on failure.
+//               Returns the subfile name on success (it might have
+//               been modified slightly), or empty string on failure.
 ////////////////////////////////////////////////////////////////////
-bool Multifile::
+string Multifile::
 add_subfile(const string &subfile_name, const Filename &filename) {
-  nassertr(is_write_valid(), false);
+  nassertr(is_write_valid(), string());
 
   if (!filename.exists()) {
-    return false;
+    return string();
   }
-  Subfile *subfile = new Subfile(subfile_name);
-
+  Subfile *subfile = new Subfile;
   subfile->_source_filename = filename;
   subfile->_source_filename.set_binary();
 
-  return add_new_subfile(subfile);
+  return add_new_subfile(subfile_name, subfile);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -537,7 +537,8 @@ get_num_subfiles() const {
 ////////////////////////////////////////////////////////////////////
 int Multifile::
 find_subfile(const string &subfile_name) const {
-  Subfile find_subfile(subfile_name);
+  Subfile find_subfile;
+  find_subfile._name = subfile_name;
   Subfiles::const_iterator fi;
   fi = _subfiles.find(&find_subfile);
   if (fi == _subfiles.end()) {
@@ -561,7 +562,8 @@ has_directory(const string &subfile_name) const {
   if (!prefix.empty()) {
     prefix += '/';
   }
-  Subfile find_subfile(prefix);
+  Subfile find_subfile;
+  find_subfile._name = prefix;
   Subfiles::const_iterator fi;
   fi = _subfiles.upper_bound(&find_subfile);
   if (fi == _subfiles.end()) {
@@ -597,7 +599,8 @@ scan_directory(vector_string &contents, const string &subfile_name) const {
   if (!prefix.empty()) {
     prefix += '/';
   }
-  Subfile find_subfile(prefix);
+  Subfile find_subfile;
+  find_subfile._name = prefix;
   Subfiles::const_iterator fi;
   fi = _subfiles.upper_bound(&find_subfile);
 
@@ -818,16 +821,18 @@ open_read_write(iostream *multifile_stream) {
 //  Description: Adds a file on disk as a subfile to the Multifile.
 //               The indicated istream will be read and its contents
 //               added to the Multifile at the next call to flush().
+//
+//               Returns the subfile name on success (it might have
+//               been modified slightly), or empty string on failure.
 ////////////////////////////////////////////////////////////////////
-bool Multifile::
+string Multifile::
 add_subfile(const string &subfile_name, istream *subfile_data) {
-  nassertr(is_write_valid(), false);
-
-  Subfile *subfile = new Subfile(subfile_name);
+  nassertr(is_write_valid(), string());
 
+  Subfile *subfile = new Subfile;
   subfile->_source = subfile_data;
 
-  return add_new_subfile(subfile);
+  return add_new_subfile(subfile_name, subfile);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -930,14 +935,28 @@ pad_to_streampos(streampos fpos) {
 //  Description: Adds a newly-allocated Subfile pointer to the
 //               Multifile.
 ////////////////////////////////////////////////////////////////////
-bool Multifile::
-add_new_subfile(Subfile *subfile) {
+string Multifile::
+add_new_subfile(const string &subfile_name, Subfile *subfile) {
   if (_next_index != (streampos)0) {
     // If we're adding a Subfile to an already-existing Multifile, we
     // will eventually need to repack the file.
     _needs_repack = true;
   }
 
+  // Normalize the Subfile name: eliminate ./, leading slash, etc.
+  Filename name = subfile_name;
+  name.standardize();
+  if (name.empty() || name == "/") {
+    // Invalid empty name.
+    return name;
+  }
+
+  if (name[0] == '/') {
+    subfile->_name = name.get_fullpath().substr(1);
+  } else {
+    subfile->_name = name;
+  }
+
   pair<Subfiles::iterator, bool> insert_result = _subfiles.insert(subfile);
   if (!insert_result.second) {
     // Hmm, unable to insert.  There must already be a subfile by that
@@ -949,7 +968,7 @@ add_new_subfile(Subfile *subfile) {
   }
 
   _new_subfiles.push_back(subfile);
-  return true;
+  return subfile->_name;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1031,7 +1050,7 @@ read_index() {
   _last_index = 0;
   streampos index_forward;
 
-  Subfile *subfile = new Subfile("");
+  Subfile *subfile = new Subfile;
   index_forward = subfile->read_index(*_read, _next_index, this);
   while (index_forward != (streampos)0) {
     _last_index = _next_index;
@@ -1049,7 +1068,7 @@ read_index() {
     }
     _read->seekg(index_forward);
     _next_index = index_forward;
-    subfile = new Subfile("");
+    subfile = new Subfile;
     index_forward = subfile->read_index(*_read, _next_index, this);
   }
   if (subfile->is_index_invalid()) {

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

@@ -57,7 +57,7 @@ PUBLISHED:
   void set_scale_factor(size_t scale_factor);
   INLINE size_t get_scale_factor() const;
 
-  bool add_subfile(const string &subfile_name, const Filename &filename);
+  string add_subfile(const string &subfile_name, const Filename &filename);
   bool flush();
   bool repack();
 
@@ -81,7 +81,7 @@ public:
   bool open_read(istream *multifile_stream);
   bool open_write(ostream *multifile_stream);
   bool open_read_write(iostream *multifile_stream);
-  bool add_subfile(const string &subfile_name, istream *subfile_data);
+  string add_subfile(const string &subfile_name, istream *subfile_data);
 
   bool extract_subfile_to(int index, ostream &out);
   istream *open_read_subfile(int index);
@@ -95,7 +95,7 @@ private:
 
   class Subfile {
   public:
-    INLINE Subfile(const string &name);
+    INLINE Subfile();
     INLINE bool operator < (const Subfile &other) const;
     streampos read_index(istream &read, streampos fpos,
                          Multifile *multfile);
@@ -122,7 +122,7 @@ private:
   INLINE streampos normalize_streampos(streampos fpos) const;
   streampos pad_to_streampos(streampos fpos);
 
-  bool add_new_subfile(Subfile *subfile);
+  string add_new_subfile(const string &subfile_name, Subfile *subfile);
   void clear_subfiles();
   bool read_index();
   bool write_header();

+ 33 - 8
panda/src/gobj/texturePool.cxx

@@ -19,6 +19,7 @@
 #include "texturePool.h"
 #include "config_gobj.h"
 #include "config_util.h"
+#include "virtualFileSystem.h"
 
 
 TexturePool *TexturePool::_global_ptr = (TexturePool *)NULL;
@@ -35,8 +36,15 @@ ns_has_texture(Filename filename) {
     filename = fake_texture_image;
   }
 
-  filename.resolve_filename(get_texture_path());
-  filename.resolve_filename(get_model_path());
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(filename, get_texture_path());
+    vfs->resolve_filename(filename, get_model_path());
+
+  } else {
+    filename.resolve_filename(get_texture_path());
+    filename.resolve_filename(get_model_path());
+  }
 
   Textures::const_iterator ti;
   ti = _textures.find(filename);
@@ -59,8 +67,15 @@ ns_load_texture(Filename filename) {
     filename = fake_texture_image;
   }
 
-  filename.resolve_filename(get_texture_path());
-  filename.resolve_filename(get_model_path());
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(filename, get_texture_path());
+    vfs->resolve_filename(filename, get_model_path());
+
+  } else {
+    filename.resolve_filename(get_texture_path());
+    filename.resolve_filename(get_model_path());
+  }
 
   Textures::const_iterator ti;
   ti = _textures.find(filename);
@@ -93,11 +108,21 @@ ns_load_texture(Filename filename, Filename grayfilename) {
     return ns_load_texture(fake_texture_image);
   }
 
-  filename.resolve_filename(get_texture_path());
-  filename.resolve_filename(get_model_path());
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(filename, get_texture_path());
+    vfs->resolve_filename(filename, get_model_path());
 
-  grayfilename.resolve_filename(get_texture_path());
-  grayfilename.resolve_filename(get_model_path());
+    vfs->resolve_filename(grayfilename, get_texture_path());
+    vfs->resolve_filename(grayfilename, get_model_path());
+
+  } else {
+    filename.resolve_filename(get_texture_path());
+    filename.resolve_filename(get_model_path());
+
+    grayfilename.resolve_filename(get_texture_path());
+    grayfilename.resolve_filename(get_model_path());
+  }
 
   Textures::const_iterator ti;
   ti = _textures.find(filename);

+ 15 - 4
panda/src/pgraph/bamFile.cxx

@@ -24,6 +24,7 @@
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "filename.h"
+#include "virtualFileSystem.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamFile::Constructor
@@ -58,11 +59,21 @@ open_read(const Filename &filename, bool report_errors) {
 
   Filename bam_filename(filename);
 
-  if (!bam_filename.exists()) {
-    if (report_errors) {
-      loader_cat.error() << "Could not find " << bam_filename << "\n";
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    if (!vfs->exists(bam_filename)) {
+      if (report_errors) {
+        loader_cat.error() << "Could not find " << bam_filename << "\n";
+      }
+      return false;
+    }
+  } else {
+    if (!bam_filename.exists()) {
+      if (report_errors) {
+        loader_cat.error() << "Could not find " << bam_filename << "\n";
+      }
+      return false;
     }
-    return false;
   }
 
   loader_cat.info() << "Reading " << bam_filename << "\n";

+ 22 - 4
panda/src/pgraph/loader.cxx

@@ -21,6 +21,8 @@
 #include "loaderFileTypeRegistry.h"
 #include "config_pgraph.h"
 
+#include "config_util.h"
+#include "virtualFileSystem.h"
 #include "event.h"
 #include "pt_Event.h"
 #include "throw_event.h"
@@ -370,6 +372,8 @@ load_unknown_file_type(const Filename &filename) const {
     return (PandaNode *)NULL;
   }
 
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
   for (int i = 0; i < num_types; i++) {
     LoaderConsiderFile consider;
     consider._type = reg->get_type(i);
@@ -381,8 +385,14 @@ load_unknown_file_type(const Filename &filename) const {
       consider._type->resolve_filename(consider._path);
     }
 
-    if (consider._path.exists()) {
-      files.push_back(consider);
+    if (use_vfs) {
+      if (vfs->exists(consider._path)) {
+        files.push_back(consider);
+      }
+    } else {
+      if (consider._path.exists()) {
+        files.push_back(consider);
+      }
     }
   }
 
@@ -456,6 +466,8 @@ resolve_unknown_file_type(Filename &filename) const {
     return;
   }
 
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
   for (int i = 0; i < num_types; i++) {
     LoaderConsiderFile consider;
     consider._type = reg->get_type(i);
@@ -467,8 +479,14 @@ resolve_unknown_file_type(Filename &filename) const {
       consider._type->resolve_filename(consider._path);
     }
 
-    if (consider._path.exists()) {
-      files.push_back(consider);
+    if (use_vfs) {
+      if (vfs->exists(consider._path)) {
+        files.push_back(consider);
+      }
+    } else {
+      if (consider._path.exists()) {
+        files.push_back(consider);
+      }
     }
   }
 

+ 9 - 2
panda/src/pgraph/loaderFileTypeBam.cxx

@@ -20,6 +20,7 @@
 #include "config_pgraph.h"
 #include "bamFile.h"
 
+#include "virtualFileSystem.h"
 #include "config_util.h"
 #include "dcast.h"
 
@@ -63,8 +64,14 @@ get_extension() const {
 ////////////////////////////////////////////////////////////////////
 void LoaderFileTypeBam::
 resolve_filename(Filename &path) const {
-  path.resolve_filename(get_bam_path());
-  path.resolve_filename(get_model_path());
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    vfs->resolve_filename(path, get_bam_path());
+    vfs->resolve_filename(path, get_model_path());
+  } else {
+    path.resolve_filename(get_bam_path());
+    path.resolve_filename(get_model_path());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 5 - 0
panda/src/putil/Sources.pp

@@ -20,6 +20,8 @@
     cycleData.h cycleData.I \
     cycleDataReader.h cycleDataReader.I \
     cycleDataWriter.h cycleDataWriter.I \
+    datagramInputFile.I datagramInputFile.h \
+    datagramOutputFile.I datagramOutputFile.h \
     drawMask.h \
     factoryBase.I factoryBase.h \
     factoryParam.I factoryParam.h factoryParams.I \
@@ -64,6 +66,7 @@
     cycleData.cxx \
     cycleDataReader.cxx \
     cycleDataWriter.cxx \
+    datagramInputFile.cxx datagramOutputFile.cxx \
     factoryBase.cxx \
     factoryParam.cxx factoryParams.cxx globPattern.cxx \
     globalPointerRegistry.cxx ioPtaDatagramFloat.cxx \
@@ -99,6 +102,8 @@
     cycleData.h cycleData.I \
     cycleDataReader.h cycleDataReader.I \
     cycleDataWriter.h cycleDataWriter.I \
+    datagramInputFile.I datagramInputFile.h \
+    datagramOutputFile.I datagramOutputFile.h \
     drawMask.h \
     factoryBase.I factoryBase.h factoryParam.I factoryParam.h \
     factoryParams.I factoryParams.h \

+ 6 - 0
panda/src/putil/config_util.cxx

@@ -100,3 +100,9 @@ get_sound_path() {
   static DSearchPath *sound_path = NULL;
   return get_config_path("sound-path", sound_path);
 }
+
+// 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_util.GetBool("use-vfs", false);

+ 2 - 0
panda/src/putil/config_util.h

@@ -46,4 +46,6 @@ EXPCL_PANDA DSearchPath &get_texture_path();
 EXPCL_PANDA DSearchPath &get_sound_path();
 END_PUBLISH
 
+extern EXPCL_PANDA const bool use_vfs;
+
 #endif /* __CONFIG_UTIL_H__ */

+ 8 - 16
panda/src/express/datagramInputFile.I → panda/src/putil/datagramInputFile.I

@@ -26,21 +26,8 @@ INLINE DatagramInputFile::
 DatagramInputFile() {
   _error = true;
   _read_first_datagram = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DatagramInputFile::open
-//       Access: Public
-//  Description: Opens the indicated filename for reading.  Returns
-//               true if successful, false on failure.
-////////////////////////////////////////////////////////////////////
-INLINE bool DatagramInputFile::
-open(Filename filename) {
-  // DatagramInputFiles are always binary.
-  _read_first_datagram = false;
-  _error = false;
-  filename.set_binary();
-  return filename.open_read(_in);
+  _in = (istream *)NULL;
+  _owns_in = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -51,5 +38,10 @@ open(Filename filename) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DatagramInputFile::
 close() {
-  _in.close();
+  _in_file.close();
+  if (_owns_in) {
+    delete _in;
+    _in = (istream *)NULL;
+    _owns_in = false;
+  }
 }

+ 41 - 8
panda/src/express/datagramInputFile.cxx → panda/src/putil/datagramInputFile.cxx

@@ -20,6 +20,8 @@
 #include "numeric_types.h"
 #include "datagramIterator.h"
 #include "profileTimer.h"
+#include "config_util.h"
+#include "virtualFileSystem.h"
 
 #include "datagramInputFile.h"
 
@@ -28,6 +30,37 @@
   EXPCL_PANDAEXPRESS ProfileTimer Skyler_timer_file;
 #endif //]
 
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramInputFile::open
+//       Access: Public
+//  Description: Opens the indicated filename for reading.  Returns
+//               true if successful, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DatagramInputFile::
+open(Filename filename) {
+  // DatagramInputFiles are always binary.
+  _read_first_datagram = false;
+  _error = false;
+  filename.set_binary();
+
+  if (use_vfs) {
+    VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+    PT(VirtualFile) file = vfs->get_file(filename);
+    if (file == (VirtualFile *)NULL) {
+      // No such file.
+      return false;
+    }
+    _in = file->open_read_file();
+    _owns_in = (_in != (istream *)NULL);
+    return _owns_in && !_in->fail();
+    
+  } else {
+    _in = &_in_file;
+    _owns_in = false;
+    return filename.open_read(_in_file);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DatagramInputFile::read_header
 //       Access: Public
@@ -44,8 +77,8 @@ read_header(string &header, size_t num_bytes) {
   char *buffer = (char *)alloca(num_bytes);
   nassertr(buffer != (char *)NULL, false);
 
-  _in.read(buffer, num_bytes);
-  if (_in.fail() || _in.eof()) {
+  _in->read(buffer, num_bytes);
+  if (_in->fail() || _in->eof()) {
     return false;
   }
 
@@ -70,8 +103,8 @@ get_datagram(Datagram &data) {
   // First, get the size of the upcoming datagram.  We do this with
   // the help of a second datagram.
   char sizebuf[sizeof(PN_uint32)];
-  _in.read(sizebuf, sizeof(PN_uint32));
-  if (_in.fail() || _in.eof()) {
+  _in->read(sizebuf, sizeof(PN_uint32));
+  if (_in->fail() || _in->eof()) {
     #ifdef SKYLER_TIMER //[
       Skyler_timer_file.off("DatagramInputFile::get_datagram");
     #endif //]
@@ -86,8 +119,8 @@ get_datagram(Datagram &data) {
   char *buffer = new char[num_bytes];
   nassertr(buffer != (char *)NULL, false);
 
-  _in.read(buffer, num_bytes);
-  if (_in.fail() || _in.eof()) {
+  _in->read(buffer, num_bytes);
+  if (_in->fail() || _in->eof()) {
     _error = true;
     delete[] buffer;
     #ifdef SKYLER_TIMER //[
@@ -113,7 +146,7 @@ get_datagram(Datagram &data) {
 ////////////////////////////////////////////////////////////////////
 bool DatagramInputFile::
 is_eof() {
-  return _in.eof();
+  return _in->eof();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -124,7 +157,7 @@ is_eof() {
 ////////////////////////////////////////////////////////////////////
 bool DatagramInputFile::
 is_error() {
-  if (_in.fail()) {
+  if (_in->fail()) {
     _error = true;
   }
   return _error;

+ 4 - 2
panda/src/express/datagramInputFile.h → panda/src/putil/datagramInputFile.h

@@ -34,7 +34,7 @@ class EXPCL_PANDAEXPRESS DatagramInputFile : public DatagramGenerator {
 public:
   INLINE DatagramInputFile();
 
-  INLINE bool open(Filename filename);
+  bool open(Filename filename);
 
   bool read_header(string &header, size_t num_bytes);
   virtual bool get_datagram(Datagram &data);
@@ -46,7 +46,9 @@ public:
 private:
   bool _read_first_datagram;
   bool _error;
-  ifstream _in;
+  ifstream _in_file;
+  istream *_in;
+  bool _owns_in;
 };
 
 #include "datagramInputFile.I"

+ 0 - 0
panda/src/express/datagramOutputFile.I → panda/src/putil/datagramOutputFile.I


+ 0 - 0
panda/src/express/datagramOutputFile.cxx → panda/src/putil/datagramOutputFile.cxx


+ 0 - 0
panda/src/express/datagramOutputFile.h → panda/src/putil/datagramOutputFile.h


+ 2 - 0
panda/src/putil/putil_composite1.cxx

@@ -11,6 +11,8 @@
 #include "cycleData.cxx"
 #include "cycleDataReader.cxx"
 #include "cycleDataWriter.cxx"
+#include "datagramInputFile.cxx"
+#include "datagramOutputFile.cxx"
 #include "factoryBase.cxx"
 #include "factoryParam.cxx"
 #include "factoryParams.cxx"

+ 1 - 1
panda/src/putil/virtualFile.cxx

@@ -165,7 +165,7 @@ ls(ostream &out) const {
   CPT(VirtualFileList) contents = scan_directory();
   if (contents == NULL) {
     if (!is_directory()) {
-      out << get_filename() << " is not a directory.\n";
+      out << get_filename() << "\n";
     } else {
       out << get_filename() << " cannot be read.\n";
     }

+ 1 - 0
panda/src/putil/virtualFileMountSystem.cxx

@@ -68,6 +68,7 @@ is_regular_file(const Filename &file) const {
 istream *VirtualFileMountSystem::
 open_read_file(const Filename &file) const {
   Filename pathname(_physical_filename, file);
+  pathname.set_binary();
   ifstream *stream = new ifstream;
   if (!pathname.open_read(*stream)) {
     // Couldn't open the file for some reason.

+ 109 - 0
panda/src/putil/virtualFileSystem.I

@@ -15,3 +15,112 @@
 // [email protected] .
 //
 ////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::exists
+//       Access: Published
+//  Description: Convenience function; returns true if the named file
+//               exists.
+////////////////////////////////////////////////////////////////////
+INLINE bool VirtualFileSystem::
+exists(const Filename &filename) const {
+  return get_file(filename) != (VirtualFile *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::is_directory
+//       Access: Published
+//  Description: Convenience function; returns true if the named file
+//               exists and is a directory.
+////////////////////////////////////////////////////////////////////
+INLINE bool VirtualFileSystem::
+is_directory(const Filename &filename) const {
+  PT(VirtualFile) file = get_file(filename);
+  return (file != (VirtualFile *)NULL && file->is_directory());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::is_regular_file
+//       Access: Published
+//  Description: Convenience function; returns true if the named file
+//               exists and is a regular file.
+////////////////////////////////////////////////////////////////////
+INLINE bool VirtualFileSystem::
+is_regular_file(const Filename &filename) const {
+  PT(VirtualFile) file = get_file(filename);
+  return (file != (VirtualFile *)NULL && file->is_regular_file());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::read_file
+//       Access: Published
+//  Description: Convenience function; fills the datagram up with the
+//               data from the indicated file, if it exists and can be
+//               read.  Returns true on success, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool VirtualFileSystem::
+read_file(const Filename &filename, Datagram &data) const {
+  PT(VirtualFile) file = get_file(filename);
+  return (file != (VirtualFile *)NULL && file->read_file(data));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::open_read_file
+//       Access: Published
+//  Description: Convenience function; returns a newly allocated
+//               istream if the file exists and can be read, or NULL
+//               otherwise.  Does not return an invalid istream.
+////////////////////////////////////////////////////////////////////
+INLINE istream *VirtualFileSystem::
+open_read_file(const Filename &filename) const {
+  PT(VirtualFile) file = get_file(filename);
+  if (file == (VirtualFile *)NULL) {
+    return NULL;
+  }
+  istream *str = file->open_read_file();
+  if (str != (istream *)NULL && str->fail()) {
+    delete str;
+    str = (istream *)NULL;
+  }
+  return str;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::ls
+//       Access: Published
+//  Description: Convenience function; lists the files within the
+//               indicated directory.  This accepts a string instead
+//               of a Filename purely for programmer convenience at
+//               the Python prompt.
+////////////////////////////////////////////////////////////////////
+INLINE void VirtualFileSystem::
+ls(const string &filename) const {
+  PT(VirtualFile) file = get_file(filename);
+  if (file == (VirtualFile *)NULL) {
+    util_cat.info()
+      << "Not found: " << filename << "\n";
+  } else {
+    file->ls();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::ls_all
+//       Access: Published
+//  Description: Convenience function; lists the files within the
+//               indicated directory, and all files below,
+//               recursively.  This accepts a string instead of a
+//               Filename purely for programmer convenience at the
+//               Python prompt.
+////////////////////////////////////////////////////////////////////
+INLINE void VirtualFileSystem::
+ls_all(const string &filename) const {
+  PT(VirtualFile) file = get_file(filename);
+  if (file == (VirtualFile *)NULL) {
+    util_cat.info()
+      << "Not found: " << filename << "\n";
+  } else {
+    file->ls_all();
+  }
+}

+ 93 - 9
panda/src/putil/virtualFileSystem.cxx

@@ -22,6 +22,8 @@
 #include "virtualFileMountSystem.h"
 #include "dSearchPath.h"
 #include "dcast.h"
+#include "config_util.h"
+#include "executionEnvironment.h"
 
 VirtualFileSystem *VirtualFileSystem::_global_ptr = NULL;
 
@@ -239,9 +241,12 @@ unmount_all() {
 //               resolve relative pathnames in get_file() and/or
 //               find_file().  Returns true if successful, false
 //               otherwise.
+//
+//               This accepts a string rather than a Filename simply
+//               for programmer convenience from the Python prompt.
 ////////////////////////////////////////////////////////////////////
 bool VirtualFileSystem::
-chdir(const Filename &new_directory) {
+chdir(const string &new_directory) {
   if (new_directory == "/") {
     // We can always return to the root.
     _cwd = new_directory;
@@ -274,11 +279,11 @@ get_cwd() const {
 //               the file if it is found, or NULL if it is not.
 ////////////////////////////////////////////////////////////////////
 PT(VirtualFile) VirtualFileSystem::
-get_file(const Filename &file) const {
-  nassertr(!file.empty(), NULL);
-  Filename pathname(file);
+get_file(const Filename &filename) const {
+  nassertr(!filename.empty(), NULL);
+  Filename pathname(filename);
   if (pathname.is_local()) {
-    pathname = Filename(_cwd, file);
+    pathname = Filename(_cwd, filename);
   }
   pathname.standardize();
   string strpath = pathname.get_fullpath().substr(1);
@@ -333,14 +338,14 @@ get_file(const Filename &file) const {
 //               found.
 ////////////////////////////////////////////////////////////////////
 PT(VirtualFile) VirtualFileSystem::
-find_file(const Filename &file, const DSearchPath &searchpath) const {
-  if (file.is_local()) {
-    return get_file(file);
+find_file(const Filename &filename, const DSearchPath &searchpath) const {
+  if (!filename.is_local()) {
+    return get_file(filename);
   }
 
   int num_directories = searchpath.get_num_directories();
   for (int i = 0; i < num_directories; i++) {
-    Filename match(searchpath.get_directory(i), file);
+    Filename match(searchpath.get_directory(i), filename);
     PT(VirtualFile) found_file = get_file(match);
     if (found_file != (VirtualFile *)NULL) {
       return found_file;
@@ -350,6 +355,58 @@ find_file(const Filename &file, const DSearchPath &searchpath) const {
   return NULL;
 }
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::resolve_filename
+//       Access: Public
+//  Description: Searches the given search path for the filename.  If
+//               it is found, updates the filename to the full
+//               pathname found and returns true; otherwise, returns
+//               false.
+////////////////////////////////////////////////////////////////////
+bool VirtualFileSystem::
+resolve_filename(Filename &filename,
+                 const DSearchPath &searchpath,
+                 const string &default_extension) const {
+  PT(VirtualFile) found;
+
+  if (filename.is_local()) {
+    found = find_file(filename.get_fullpath(), searchpath);
+
+    if (found.is_null()) {
+      // We didn't find it with the given extension; can we try the
+      // default extension?
+      if (filename.get_extension().empty() && !default_extension.empty()) {
+        Filename try_ext = filename;
+        try_ext.set_extension(default_extension);
+        found = find_file(try_ext.get_fullpath(), searchpath);
+      }
+    }
+
+  } else {
+    if (exists(filename)) {
+      // The full pathname exists.  Return true.
+      return true;
+
+    } else {
+      // The full pathname doesn't exist with the given extension;
+      // does it exist with the default extension?
+      if (filename.get_extension().empty() && !default_extension.empty()) {
+        Filename try_ext = filename;
+        try_ext.set_extension(default_extension);
+        found = get_file(try_ext);
+      }
+    }
+  }
+
+  if (!found.is_null()) {
+    filename = found->get_filename();
+    return true;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileSystem::write
 //       Access: Published
@@ -383,7 +440,34 @@ VirtualFileSystem *VirtualFileSystem::
 get_global_ptr() {
   if (_global_ptr == (VirtualFileSystem *)NULL) {
     _global_ptr = new VirtualFileSystem;
+    
+    // Set up the default mounts.  First, there is always the root
+    // mount.
     _global_ptr->mount("/", "/", 0);
+
+    // Then, we add whatever mounts are listed in the Configrc file.
+    Config::ConfigTable::Symbol mounts;
+    config_util.GetAll("vfs-mount", mounts);
+    Config::ConfigTable::Symbol::iterator si;
+    for (si = mounts.begin(); si != mounts.end(); ++si) {
+      string mount_desc = (*si).Val();
+
+      // 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) {
+        util_cat.warning()
+          << "No space in vfs-mount descriptor: " << mount_desc << "\n";
+
+      } else {
+        string fn = trim_right(mount_desc.substr(0, space));
+        fn = ExecutionEnvironment::expand_string(fn);
+        Filename physical_filename = Filename::from_os_specific(fn);
+
+        string mount_point = mount_desc.substr(space + 1);
+        _global_ptr->mount(physical_filename, mount_point, 0);
+      }
+    }
   }
 
   return _global_ptr;

+ 20 - 3
panda/src/putil/virtualFileSystem.h

@@ -21,11 +21,15 @@
 
 #include "pandabase.h"
 
+#include "virtualFile.h"
 #include "filename.h"
+#include "pointerTo.h"
 #include "pmap.h"
+#include "config_util.h"
 
 class Multifile;
 class VirtualFileMount;
+class VirtualFileComposite;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : VirtualFileSystem
@@ -55,12 +59,25 @@ PUBLISHED:
   int unmount_point(const string &mount_point);
   int unmount_all();
 
-  bool chdir(const Filename &new_directory);
+  bool chdir(const string &new_directory);
   const Filename &get_cwd() const;
 
-  PT(VirtualFile) get_file(const Filename &file) const;
-  PT(VirtualFile) find_file(const Filename &file, 
+  PT(VirtualFile) get_file(const Filename &filename) const;
+  PT(VirtualFile) find_file(const Filename &filename, 
                             const DSearchPath &searchpath) const;
+  bool resolve_filename(Filename &filename,
+                        const DSearchPath &searchpath,
+                        const string &default_extension = string()) const;
+
+  INLINE bool exists(const Filename &filename) const;
+  INLINE bool is_directory(const Filename &filename) const;
+  INLINE bool is_regular_file(const Filename &filename) const;
+
+  INLINE bool read_file(const Filename &filename, Datagram &data) const;
+  INLINE istream *open_read_file(const Filename &filename) const;
+
+  INLINE void ls(const string &filename) const;
+  INLINE void ls_all(const string &filename) const;
 
   void write(ostream &out) const;