diff --git a/panda/src/downloadertools/multify.cxx b/panda/src/downloadertools/multify.cxx index e85b866c89..fee982c6e2 100644 --- a/panda/src/downloadertools/multify.cxx +++ b/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"; + } } } } diff --git a/panda/src/egg/eggData.cxx b/panda/src/egg/eggData.cxx index f0f0a28fe1..b1bbedaca7 100644 --- a/panda/src/egg/eggData.cxx +++ b/panda/src/egg/eggData.cxx @@ -24,9 +24,10 @@ #include "eggPoolUniquifier.h" #include "config_egg.h" -#include -#include -#include +#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"); + + return vfs->exists(egg_filename); + + } 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(); } - - 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); + 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"; - ifstream file; - if (!filename.open_read(file)) { - egg_cat.error() << "Unable to open " << filename << "\n"; - return false; + 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); } diff --git a/panda/src/egg2pg/load_egg_file.cxx b/panda/src/egg2pg/load_egg_file.cxx index 682201877e..6022f6451b 100644 --- a/panda/src/egg2pg/load_egg_file.cxx +++ b/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; - if (!loader._data.read(file)) { + } 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 (!okflag) { egg2pg_cat.error() << "Error reading " << egg_filename << "\n"; return NULL; diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index 92348cd483..042f68a658 100644 --- a/panda/src/express/Sources.pp +++ b/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 \ diff --git a/panda/src/express/express_composite1.cxx b/panda/src/express/express_composite1.cxx index 59d8bc0d12..6aa3b797a3 100644 --- a/panda/src/express/express_composite1.cxx +++ b/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" diff --git a/panda/src/express/multifile.I b/panda/src/express/multifile.I index 18f06aa496..fd6fe1ee2b 100644 --- a/panda/src/express/multifile.I +++ b/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; diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index 8d81c977f6..bedc48f89e 100644 --- a/panda/src/express/multifile.cxx +++ b/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 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()) { diff --git a/panda/src/express/multifile.h b/panda/src/express/multifile.h index 32141f4a69..862db73567 100644 --- a/panda/src/express/multifile.h +++ b/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(); diff --git a/panda/src/gobj/texturePool.cxx b/panda/src/gobj/texturePool.cxx index 37305aba93..592c418caf 100644 --- a/panda/src/gobj/texturePool.cxx +++ b/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); diff --git a/panda/src/pgraph/bamFile.cxx b/panda/src/pgraph/bamFile.cxx index a764d5bb01..b01d683da0 100644 --- a/panda/src/pgraph/bamFile.cxx +++ b/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"; diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 99306b57bf..a6960f95df 100644 --- a/panda/src/pgraph/loader.cxx +++ b/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); + } } } diff --git a/panda/src/pgraph/loaderFileTypeBam.cxx b/panda/src/pgraph/loaderFileTypeBam.cxx index 90f94e255b..7a059b1c57 100644 --- a/panda/src/pgraph/loaderFileTypeBam.cxx +++ b/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()); + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index a8f0c30a5e..8c8c8cae66 100644 --- a/panda/src/putil/Sources.pp +++ b/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 \ diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 35875dab4c..6d501413e4 100644 --- a/panda/src/putil/config_util.cxx +++ b/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); diff --git a/panda/src/putil/config_util.h b/panda/src/putil/config_util.h index 9a76aeb499..f1b0ebb463 100644 --- a/panda/src/putil/config_util.h +++ b/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__ */ diff --git a/panda/src/express/datagramInputFile.I b/panda/src/putil/datagramInputFile.I similarity index 70% rename from panda/src/express/datagramInputFile.I rename to panda/src/putil/datagramInputFile.I index a9e1c059e9..c45f6333cd 100644 --- a/panda/src/express/datagramInputFile.I +++ b/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; + } } diff --git a/panda/src/express/datagramInputFile.cxx b/panda/src/putil/datagramInputFile.cxx similarity index 75% rename from panda/src/express/datagramInputFile.cxx rename to panda/src/putil/datagramInputFile.cxx index 7af60ae324..9983d0d18e 100644 --- a/panda/src/express/datagramInputFile.cxx +++ b/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; diff --git a/panda/src/express/datagramInputFile.h b/panda/src/putil/datagramInputFile.h similarity index 94% rename from panda/src/express/datagramInputFile.h rename to panda/src/putil/datagramInputFile.h index 2841cfec8c..ae18083e34 100644 --- a/panda/src/express/datagramInputFile.h +++ b/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" diff --git a/panda/src/express/datagramOutputFile.I b/panda/src/putil/datagramOutputFile.I similarity index 100% rename from panda/src/express/datagramOutputFile.I rename to panda/src/putil/datagramOutputFile.I diff --git a/panda/src/express/datagramOutputFile.cxx b/panda/src/putil/datagramOutputFile.cxx similarity index 100% rename from panda/src/express/datagramOutputFile.cxx rename to panda/src/putil/datagramOutputFile.cxx diff --git a/panda/src/express/datagramOutputFile.h b/panda/src/putil/datagramOutputFile.h similarity index 100% rename from panda/src/express/datagramOutputFile.h rename to panda/src/putil/datagramOutputFile.h diff --git a/panda/src/putil/putil_composite1.cxx b/panda/src/putil/putil_composite1.cxx index 3c27fb8148..4af4cff73a 100644 --- a/panda/src/putil/putil_composite1.cxx +++ b/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" diff --git a/panda/src/putil/virtualFile.cxx b/panda/src/putil/virtualFile.cxx index b89de9f186..b43501125a 100644 --- a/panda/src/putil/virtualFile.cxx +++ b/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"; } diff --git a/panda/src/putil/virtualFileMountSystem.cxx b/panda/src/putil/virtualFileMountSystem.cxx index 7713e41a68..469639c94c 100644 --- a/panda/src/putil/virtualFileMountSystem.cxx +++ b/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. diff --git a/panda/src/putil/virtualFileSystem.I b/panda/src/putil/virtualFileSystem.I index 9b676a19c4..2f4a36fa3b 100644 --- a/panda/src/putil/virtualFileSystem.I +++ b/panda/src/putil/virtualFileSystem.I @@ -15,3 +15,112 @@ // panda3d@yahoogroups.com . // //////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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(); + } +} diff --git a/panda/src/putil/virtualFileSystem.cxx b/panda/src/putil/virtualFileSystem.cxx index d39cdf3b19..4cd4fb40a6 100644 --- a/panda/src/putil/virtualFileSystem.cxx +++ b/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; diff --git a/panda/src/putil/virtualFileSystem.h b/panda/src/putil/virtualFileSystem.h index 0461b481df..a26cb93bb4 100644 --- a/panda/src/putil/virtualFileSystem.h +++ b/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;