diff --git a/panda/src/downloader/extractor.cxx b/panda/src/downloader/extractor.cxx index 8de908c49a..e77db8e2c6 100644 --- a/panda/src/downloader/extractor.cxx +++ b/panda/src/downloader/extractor.cxx @@ -123,13 +123,13 @@ run() { _subfile_length = _multifile.get_subfile_length(_subfile_index); _subfile_pos = 0; - _read = &_multifile.open_read_subfile(_subfile_index); + _read = _multifile.open_read_subfile(_subfile_index); } else if (_subfile_pos >= _subfile_length) { // Time to close this subfile. - _multifile.close_subfile(); - _write.close(); + delete _read; _read = (istream *)NULL; + _write.close(); _subfile_index++; } else { @@ -195,7 +195,10 @@ cleanup() { return; } + if (_read != (istream *)NULL) { + delete _read; + _read = (istream *)NULL; + } _multifile.close(); _write.close(); - _read = (istream *)NULL; } diff --git a/panda/src/express/multifile.I b/panda/src/express/multifile.I index 0c3e192cb9..18f06aa496 100644 --- a/panda/src/express/multifile.I +++ b/panda/src/express/multifile.I @@ -17,6 +17,17 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: Multifile::get_multifile_name +// Access: Published +// Description: Returns the filename of the Multifile, if it is +// available. +//////////////////////////////////////////////////////////////////// +INLINE const Filename &Multifile:: +get_multifile_name() const { + return _multifile_name; +} + //////////////////////////////////////////////////////////////////// // Function: Multifile::is_read_valid // Access: Published @@ -26,8 +37,7 @@ //////////////////////////////////////////////////////////////////// INLINE bool Multifile:: is_read_valid() const { - return (_read != (istream *)NULL && !_read->fail() && - _open_subfile == (Subfile *)NULL); + return (_read != (istream *)NULL && !_read->fail()); } //////////////////////////////////////////////////////////////////// @@ -39,8 +49,7 @@ is_read_valid() const { //////////////////////////////////////////////////////////////////// INLINE bool Multifile:: is_write_valid() const { - return (_write != (ostream *)NULL && !_write->fail() && - _open_subfile == (Subfile *)NULL); + return (_write != (ostream *)NULL && !_write->fail()); } //////////////////////////////////////////////////////////////////// @@ -51,39 +60,7 @@ is_write_valid() const { //////////////////////////////////////////////////////////////////// INLINE bool Multifile:: needs_repack() const { - return _needs_repack; -} - -//////////////////////////////////////////////////////////////////// -// Function: Multifile::set_scale_factor -// Access: Published -// Description: Changes the internal scale factor for this Multifile. -// -// This is normally 1, but it may be set to any -// arbitrary value (greater than zero) to support -// Multifile archives that exceed 4GB, if necessary. -// (Individual subfiles may still not exceed 4GB.) -// -// All addresses within the file are rounded up to the -// next multiple of _scale_factor, and zeros are written -// to the file to fill the resulting gaps. Then the -// address is divided by _scale_factor and written out -// as a 32-bit integer. Thus, setting a scale factor of -// 2 supports up to 8GB files, 3 supports 12GB files, -// etc. -// -// Calling this function on an already-existing -// Multifile forces an immediate repack() operation. -//////////////////////////////////////////////////////////////////// -INLINE void Multifile:: -set_scale_factor(size_t scale_factor) { - nassertv(scale_factor != (size_t)0); - if (_scale_factor != scale_factor) { - _scale_factor = scale_factor; - if (_next_index != (streampos)0) { - repack(); - } - } + return _needs_repack || (_scale_factor != _new_scale_factor); } //////////////////////////////////////////////////////////////////// @@ -94,7 +71,7 @@ set_scale_factor(size_t scale_factor) { //////////////////////////////////////////////////////////////////// INLINE size_t Multifile:: get_scale_factor() const { - return _scale_factor; + return _new_scale_factor; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index fe74484007..9022145b43 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -84,9 +84,9 @@ Multifile() { _last_index = 0; _needs_repack = false; _scale_factor = 1; + _new_scale_factor = 1; _file_major_ver = 0; _file_minor_ver = 0; - _open_subfile = (Subfile *)NULL; } //////////////////////////////////////////////////////////////////// @@ -99,6 +99,26 @@ Multifile:: close(); } +//////////////////////////////////////////////////////////////////// +// Function: Multifile::Copy Constructor +// Access: Private +// Description: Don't try to copy Multifiles. +//////////////////////////////////////////////////////////////////// +Multifile:: +Multifile(const Multifile ©) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: Multifile::Copy Assignment Operator +// Access: Private +// Description: Don't try to copy Multifiles. +//////////////////////////////////////////////////////////////////// +void Multifile:: +operator = (const Multifile ©) { + nassertv(false); +} + //////////////////////////////////////////////////////////////////// // Function: Multifile::open_read // Access: Published @@ -192,14 +212,21 @@ open_read_write(const Filename &multifile_name) { //////////////////////////////////////////////////////////////////// void Multifile:: close() { - close_subfile(); - flush(); + if (_new_scale_factor != _scale_factor) { + // If we have changed the scale factor recently, we need to force + // a repack. + repack(); + } else { + flush(); + } + _read = (istream *)NULL; _write = (ostream *)NULL; _next_index = 0; _last_index = 0; _needs_repack = false; _scale_factor = 1; + _new_scale_factor = 1; _file_major_ver = 0; _file_minor_ver = 0; @@ -211,6 +238,49 @@ close() { clear_subfiles(); } +//////////////////////////////////////////////////////////////////// +// Function: Multifile::set_scale_factor +// Access: Published +// Description: Changes the internal scale factor for this Multifile. +// +// This is normally 1, but it may be set to any +// arbitrary value (greater than zero) to support +// Multifile archives that exceed 4GB, if necessary. +// (Individual subfiles may still not exceed 4GB.) +// +// All addresses within the file are rounded up to the +// next multiple of _scale_factor, and zeros are written +// to the file to fill the resulting gaps. Then the +// address is divided by _scale_factor and written out +// as a 32-bit integer. Thus, setting a scale factor of +// 2 supports up to 8GB files, 3 supports 12GB files, +// etc. +// +// Calling this function on an already-existing +// Multifile will have no immediate effect until a +// future call to repack() or close() (or until the +// Multifile is destructed). +//////////////////////////////////////////////////////////////////// +void Multifile:: +set_scale_factor(size_t scale_factor) { + nassertv(is_write_valid()); + nassertv(scale_factor != (size_t)0); + + if (_next_index == (streampos)0) { + // If it's a brand new Multifile, we can go ahead and set it + // immediately. + _scale_factor = scale_factor; + } else { + // Otherwise, we'd better have read access so we can repack it + // later. + nassertv(is_read_valid()); + } + + // Setting the _new_scale_factor different from the _scale_factor + // will force a repack operation on close. + _new_scale_factor = scale_factor; +} + //////////////////////////////////////////////////////////////////// // Function: Multifile::add_subfile // Access: Published @@ -378,6 +448,12 @@ flush() { //////////////////////////////////////////////////////////////////// bool Multifile:: repack() { + if (_next_index == (streampos)0) { + // If the Multifile hasn't yet been written, this is really just a + // flush operation. + return flush(); + } + nassertr(is_write_valid() && is_read_valid(), false); nassertr(!_multifile_name.empty(), false); @@ -407,6 +483,7 @@ repack() { copy(_subfiles.begin(), _subfiles.end(), back_inserter(_new_subfiles)); _next_index = 0; _last_index = 0; + _scale_factor = _new_scale_factor; // And we write our contents to our new temporary file. _write = &temp; @@ -535,14 +612,14 @@ read_subfile(int index, Datagram &data) { nassertv(index >= 0 && index < (int)_subfiles.size()); data.clear(); - istream &in = open_read_subfile(index); - int byte = in.get(); - while (!in.eof() && !in.fail()) { + istream *in = open_read_subfile(index); + int byte = in->get(); + while (!in->eof() && !in->fail()) { data.add_int8(byte); - byte = in.get(); + byte = in->get(); } - bool failed = in.fail(); - close_subfile(); + bool failed = in->fail(); + delete in; nassertv(!failed); } @@ -570,6 +647,31 @@ extract_subfile(int index, const Filename &filename) { return extract_subfile_to(index, out); } +//////////////////////////////////////////////////////////////////// +// Function: Multifile::output +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void Multifile:: +output(ostream &out) const { + out << "Multifile " << _multifile_name << ", " << get_num_subfiles() + << " subfiles.\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: Multifile::ls +// Access: Published +// Description: Shows a list of all subfiles within the Multifile. +//////////////////////////////////////////////////////////////////// +void Multifile:: +ls(ostream &out) const { + int num_subfiles = get_num_subfiles(); + for (int i = 0; i < num_subfiles; i++) { + string subfile_name = get_subfile_name(i); + out << subfile_name << "\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: Multifile::open_read // Access: Public @@ -662,16 +764,16 @@ extract_subfile_to(int index, ostream &out) { nassertr(is_read_valid(), false); nassertr(index >= 0 && index < (int)_subfiles.size(), false); - istream &in = open_read_subfile(index); + istream *in = open_read_subfile(index); - int byte = in.get(); - while (!in.fail() && !in.eof()) { + int byte = in->get(); + while (!in->fail() && !in->eof()) { out.put(byte); - byte = in.get(); + byte = in->get(); } - bool failed = (in.fail() && !in.eof()); - close_subfile(); + bool failed = (in->fail() && !in->eof()); + delete in; nassertr(!failed, false); return (!out.fail()); @@ -682,64 +784,47 @@ extract_subfile_to(int index, ostream &out) { // Access: Public // Description: Returns an istream that may be used to read the // indicated subfile. You may seek() within this -// istream to your heart's content; even though it is -// probably a reference to the already-opened fstream of -// the Multifile itself, byte 0 appears to be the -// beginning of the subfile and EOF appears to be the -// end of the subfile. +// istream to your heart's content; even though it will +// be a reference to the already-opened fstream of the +// Multifile itself, byte 0 appears to be the beginning +// of the subfile and EOF appears to be the end of the +// subfile. // -// It is not valid to perform any additional operations -// on this Multifile until close_subfile() has -// subsequently been called. +// The returned istream will have been allocated via +// new; you should delete it when you are finished +// reading the subfile. +// +// Any future calls to repack() or close() (or the +// Multifile destructor) will invalidate all currently +// open subfile pointers. +// +// The return value will never be NULL. If there is a +// problem, an unopened fstream is returned. //////////////////////////////////////////////////////////////////// -istream &Multifile:: +istream *Multifile:: open_read_subfile(int index) { -#ifndef NDEBUG - static ifstream empty_stream; - nassertr(_open_subfile == (Subfile *)NULL, empty_stream); - nassertr(is_read_valid(), empty_stream); - nassertr(index >= 0 && index < (int)_subfiles.size(), empty_stream); -#endif - _open_subfile = _subfiles[index]; + nassertr(is_read_valid(), new fstream); + nassertr(index >= 0 && index < (int)_subfiles.size(), new fstream); + Subfile *subfile = _subfiles[index]; - if (_open_subfile->_source != (istream *)NULL) { - // The subfile has not yet been incorporated, and it is defined - // with an istream; return the istream directly. - _open_subfile->_source->seekg(0); - return *_open_subfile->_source; + if (subfile->_source != (istream *)NULL || + !subfile->_source_filename.empty()) { + // The subfile has not yet been copied into the physical + // Multifile. Force a flush operation to incorporate it. + flush(); + + // That shouldn't change the subfile index or delete the subfile + // pointer. + nassertr(subfile == _subfiles[index], new fstream); } - if (!_open_subfile->_source_filename.empty()) { - // The subfile has not yet been incorporated, and it is defined - // with a filename; open the filename and return that. - _open_subfile->_source_filename.open_read(_subfile_fstream); - return _subfile_fstream; - } - - // The subfile has been incorporated; return an ISubStream object - // that references into the open Multifile istream. - nassertr(_open_subfile->_data_start != (streampos)0, empty_stream); - _subfile_substream.open(_read, _open_subfile->_data_start, - _open_subfile->_data_start + (streampos)_open_subfile->_data_length); - return _subfile_substream; -} - -//////////////////////////////////////////////////////////////////// -// Function: Multifile::close_subfile -// Access: Public -// Description: "Closes" the istream that was returned via a previous -// call to open_read_subfile(), and makes other -// operations on the Multifile valid once more. -//////////////////////////////////////////////////////////////////// -void Multifile:: -close_subfile() { - if (_open_subfile != (Subfile *)NULL && - _open_subfile->_source != (istream *)NULL) { - _open_subfile->_source->seekg(0); - } - _open_subfile = (Subfile *)NULL; - _subfile_fstream.close(); - _subfile_substream.close(); + // Return an ISubStream object that references into the open + // Multifile istream. + nassertr(subfile->_data_start != (streampos)0, new fstream); + ISubStream *stream = new ISubStream; + stream->open(_read, subfile->_data_start, + subfile->_data_start + (streampos)subfile->_data_length); + return stream; } //////////////////////////////////////////////////////////////////// @@ -850,6 +935,7 @@ read_index() { _file_major_ver = dgi.get_int16(); _file_minor_ver = dgi.get_int16(); _scale_factor = dgi.get_uint32(); + _new_scale_factor = _scale_factor; if (_file_major_ver != _current_major_ver || (_file_major_ver == _current_major_ver && diff --git a/panda/src/express/multifile.h b/panda/src/express/multifile.h index 60ca473be5..d48f07a50e 100644 --- a/panda/src/express/multifile.h +++ b/panda/src/express/multifile.h @@ -38,16 +38,23 @@ PUBLISHED: Multifile(); ~Multifile(); +private: + Multifile(const Multifile ©); + void operator = (const Multifile ©); + +PUBLISHED: bool open_read(const Filename &multifile_name); bool open_write(const Filename &multifile_name); bool open_read_write(const Filename &multifile_name); void close(); + INLINE const Filename &get_multifile_name() const; + INLINE bool is_read_valid() const; INLINE bool is_write_valid() const; INLINE bool needs_repack() const; - INLINE void set_scale_factor(size_t scale_factor); + 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); @@ -63,6 +70,9 @@ PUBLISHED: void read_subfile(int index, Datagram &datagram); bool extract_subfile(int index, const Filename &filename); + void output(ostream &out) const; + void ls(ostream &out = cout) const; + public: // Special interfaces to work with iostreams, not necessarily files. bool open_read(istream *multifile_stream); @@ -71,8 +81,7 @@ public: bool add_subfile(const string &subfile_name, istream *subfile_data); bool extract_subfile_to(int index, ostream &out); - istream &open_read_subfile(int index); - void close_subfile(); + istream *open_read_subfile(int index); private: enum SubfileFlags { @@ -129,6 +138,7 @@ private: bool _needs_repack; size_t _scale_factor; + size_t _new_scale_factor; ifstream _read_file; ofstream _write_file; @@ -138,11 +148,6 @@ private: int _file_major_ver; int _file_minor_ver; - // These are used to open a subfile for reading. - Subfile *_open_subfile; - ifstream _subfile_fstream; - ISubStream _subfile_substream; - static const char _header[]; static const size_t _header_size; static const int _current_major_ver; diff --git a/panda/src/express/subStreamBuf.cxx b/panda/src/express/subStreamBuf.cxx index 54b52d87af..3e35e128d3 100644 --- a/panda/src/express/subStreamBuf.cxx +++ b/panda/src/express/subStreamBuf.cxx @@ -49,6 +49,7 @@ SubStreamBuf() { //////////////////////////////////////////////////////////////////// SubStreamBuf:: ~SubStreamBuf() { + close(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 1908d2e24b..a8f0c30a5e 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -46,6 +46,12 @@ typedWritableReferenceCount.h updateSeq.I updateSeq.h \ vector_double.h vector_float.h vector_typedWritable.h \ vector_ushort.h vector_writable.h \ + virtualFileComposite.h virtualFileComposite.I virtualFile.h \ + virtualFile.I virtualFileList.I virtualFileList.h virtualFileMount.h \ + virtualFileMount.I virtualFileMountMultifile.h \ + virtualFileMountMultifile.I virtualFileMountSystem.h \ + virtualFileMountSystem.I virtualFileSimple.h virtualFileSimple.I \ + virtualFileSystem.h virtualFileSystem.I \ writableConfigurable.h \ writableParam.I writableParam.h @@ -75,6 +81,10 @@ vector_double.cxx vector_float.cxx \ vector_typedWritable.cxx \ vector_ushort.cxx vector_writable.cxx \ + virtualFileComposite.cxx virtualFile.cxx virtualFileList.cxx \ + virtualFileMount.cxx \ + virtualFileMountMultifile.cxx virtualFileMountSystem.cxx \ + virtualFileSimple.cxx virtualFileSystem.cxx \ writableConfigurable.cxx writableParam.cxx #define INSTALL_HEADERS \ @@ -113,6 +123,12 @@ typedWritableReferenceCount.h updateSeq.I updateSeq.h \ vector_double.h vector_float.h vector_typedWritable.h \ vector_ushort.h vector_writable.h \ + virtualFileComposite.h virtualFileComposite.I virtualFile.h \ + virtualFile.I virtualFileList.I virtualFileList.h virtualFileMount.h \ + virtualFileMount.I virtualFileMountMultifile.h \ + virtualFileMountMultifile.I virtualFileMountSystem.h \ + virtualFileMountSystem.I virtualFileSimple.h virtualFileSimple.I \ + virtualFileSystem.h virtualFileSystem.I \ writableConfigurable.h writableParam.I \ writableParam.h diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 6b7c09e8e6..35875dab4c 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -30,6 +30,12 @@ #include "datagram.h" #include "typedWritable.h" #include "typedWritableReferenceCount.h" +#include "virtualFileComposite.h" +#include "virtualFile.h" +#include "virtualFileMount.h" +#include "virtualFileMountMultifile.h" +#include "virtualFileMountSystem.h" +#include "virtualFileSimple.h" #include "writableParam.h" #include "bamReaderParam.h" #include "writableConfigurable.h" @@ -57,6 +63,12 @@ ConfigureFn(config_util) { WritableParam::init_type(); BamReaderParam::init_type(); TypedWritableReferenceCount::init_type(); + VirtualFileComposite::init_type(); + VirtualFile::init_type(); + VirtualFileMount::init_type(); + VirtualFileMountMultifile::init_type(); + VirtualFileMountSystem::init_type(); + VirtualFileSimple::init_type(); WritableConfigurable::init_type(); } diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index 881953fb73..4f16d250c4 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -16,6 +16,14 @@ #include "vector_typedWritable.cxx" #include "vector_ushort.cxx" #include "vector_writable.cxx" +#include "virtualFile.cxx" +#include "virtualFileComposite.cxx" +#include "virtualFileList.cxx" +#include "virtualFileMount.cxx" +#include "virtualFileMountMultifile.cxx" +#include "virtualFileMountSystem.cxx" +#include "virtualFileSimple.cxx" +#include "virtualFileSystem.cxx" #include "writableConfigurable.cxx" #include "writableParam.cxx" diff --git a/panda/src/putil/virtualFile.I b/panda/src/putil/virtualFile.I new file mode 100644 index 0000000000..a4fdf39dc5 --- /dev/null +++ b/panda/src/putil/virtualFile.I @@ -0,0 +1,35 @@ +// Filename: virtualFile.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFile:: +VirtualFile() { +} + + +INLINE ostream & +operator << (ostream &out, const VirtualFile &file) { + file.output(out); + return out; +} + diff --git a/panda/src/putil/virtualFile.cxx b/panda/src/putil/virtualFile.cxx new file mode 100644 index 0000000000..1ca5b55230 --- /dev/null +++ b/panda/src/putil/virtualFile.cxx @@ -0,0 +1,233 @@ +// Filename: virtualFile.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFile.h" +#include "virtualFileSystem.h" +#include "virtualFileList.h" +#include "config_util.h" + +TypeHandle VirtualFile::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::is_directory +// Access: Published, Virtual +// Description: Returns true if this file represents a directory (and +// scan_directory() may be called), false otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFile:: +is_directory() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::is_regular_file +// Access: Published, Virtual +// Description: Returns true if this file represents a regular file +// (and read_file() may be called), false otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFile:: +is_regular_file() const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::read_file +// Access: Published +// Description: Fills up the indicated Datagram with the contents of +// the file, if it is a regular file. Returns true on +// success, false otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFile:: +read_file(Datagram &data) const { + data.clear(); + + istream *in = open_read_file(); + if (in == (istream *)NULL) { + util_cat.info() + << "Unable to read " << get_filename() << "\n"; + return false; + } + int byte = in->get(); + while (!in->eof() && !in->fail()) { + data.add_int8(byte); + byte = in->get(); + } + bool failed = in->fail(); + delete in; + + if (failed) { + util_cat.info() + << "Error while reading " << get_filename() << "\n"; + } + return failed; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::open_read_file +// Access: Published, Virtual +// Description: Opens the file for reading. Returns a newly +// allocated istream on success (which you should +// eventually delete when you are done reading). +// Returns NULL on failure. +//////////////////////////////////////////////////////////////////// +istream *VirtualFile:: +open_read_file() const { + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::scan_directory +// Access: Published +// Description: If the file represents a directory (that is, +// is_directory() returns true), this returns the list +// of files within the directory at the current time. +// Returns NULL if the file is not a directory or if the +// directory cannot be read. +//////////////////////////////////////////////////////////////////// +PT(VirtualFileList) VirtualFile:: +scan_directory() const { + // First, we have to make sure there aren't any mount points attached + // under this directory. These will override any local filenames. + VirtualFileSystem *file_system = get_file_system(); + Filename this_filename = get_filename(); + vector_string mount_points_flat; + file_system->scan_mount_points(mount_points_flat, this_filename); + + // Copy the set of nested mount points to a sorted list so we can + // search it quickly. + ov_set mount_points; + copy(mount_points_flat.begin(), mount_points_flat.end(), + back_inserter(mount_points)); + mount_points.sort(); + + + PT(VirtualFileList) file_list = new VirtualFileList; + + // Each of those mount points maps to a directory root or something + // from the file system. + ov_set::const_iterator mi; + for (mi = mount_points.begin(); mi != mount_points.end(); ++mi) { + const string &basename = (*mi); + Filename filename(this_filename, basename); + PT(VirtualFile) file = file_system->get_file(filename); + file_list->add_file(file); + } + + // Now, get the actual local files in this directory. + vector_string names; + if (!scan_local_directory(file_list, mount_points)) { + // Not a directory, or unable to read directory. + if (file_list->get_num_files() == 0) { + return NULL; + } + + // We couldn't read the physical directory, but we do have some + // mounted files to return. + return file_list; + } + + return file_list; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::output +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void VirtualFile:: +output(ostream &out) const { + out << get_filename(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::ls +// Access: Published +// Description: If the file represents a directory, lists its +// contents. +//////////////////////////////////////////////////////////////////// +void VirtualFile:: +ls(ostream &out) const { + CPT(VirtualFileList) contents = scan_directory(); + if (contents == NULL) { + if (!is_directory()) { + out << get_filename() << " is not a directory.\n"; + } else { + out << get_filename() << " cannot be read.\n"; + } + return; + } + + int num_files = contents->get_num_files(); + for (int i = 0; i < num_files; i++) { + VirtualFile *file = contents->get_file(i); + out << file->get_filename().get_basename() << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::ls_all +// Access: Published +// Description: If the file represents a directory, recursively lists +// its contents and those of all subdirectories. +//////////////////////////////////////////////////////////////////// +void VirtualFile:: +ls_all(ostream &out) const { + if (!is_directory()) { + out << get_filename() << " is not a directory.\n"; + } else { + r_ls_all(out, get_filename()); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::scan_local_directory +// Access: Protected, Virtual +// Description: Fills file_list up with the list of files that are +// within this directory, excluding those whose +// basenames are listed in mount_points. Returns true +// if successful, false if the file is not a directory +// or the directory cannot be read. +//////////////////////////////////////////////////////////////////// +bool VirtualFile:: +scan_local_directory(VirtualFileList *, const ov_set &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFile::r_ls_all +// Access: Private +// Description: The recursive implementation of ls_all(). +//////////////////////////////////////////////////////////////////// +void VirtualFile:: +r_ls_all(ostream &out, const Filename &root) const { + CPT(VirtualFileList) contents = scan_directory(); + if (contents == NULL) { + return; + } + + int num_files = contents->get_num_files(); + for (int i = 0; i < num_files; i++) { + VirtualFile *file = contents->get_file(i); + Filename filename = file->get_filename(); + filename.make_relative_to(root); + out << filename << "\n"; + if (file->is_directory()) { + file->r_ls_all(out, root); + } + } +} diff --git a/panda/src/putil/virtualFile.h b/panda/src/putil/virtualFile.h new file mode 100644 index 0000000000..2296069ffb --- /dev/null +++ b/panda/src/putil/virtualFile.h @@ -0,0 +1,90 @@ +// Filename: virtualFile.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILE_H +#define VIRTUALFILE_H + +#include "pandabase.h" + +#include "filename.h" +#include "pointerTo.h" +#include "typedReferenceCount.h" +#include "ordered_vector.h" + +class VirtualFileMount; +class VirtualFileList; +class VirtualFileSystem; + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFile +// Description : The abstract base class for a file or directory +// within the VirtualFileSystem. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFile : public TypedReferenceCount { +public: + INLINE VirtualFile(); + +PUBLISHED: + virtual VirtualFileSystem *get_file_system() const=0; + virtual Filename get_filename() const=0; + + virtual bool is_directory() const; + virtual bool is_regular_file() const; + + bool read_file(Datagram &data) const; + virtual istream *open_read_file() const; + + PT(VirtualFileList) scan_directory() const; + + void output(ostream &out) const; + void ls(ostream &out = cout) const; + void ls_all(ostream &out = cout) const; + +protected: + virtual bool scan_local_directory(VirtualFileList *file_list, + const ov_set &mount_points) const; + +private: + void r_ls_all(ostream &out, const Filename &root) const; + + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "VirtualFile", + TypedReferenceCount::get_class_type()); + } + +private: + static TypeHandle _type_handle; + + friend class VirtualFileComposite; +}; + +INLINE ostream &operator << (ostream &out, const VirtualFile &file); + +#include "virtualFile.I" + +#endif diff --git a/panda/src/putil/virtualFileComposite.I b/panda/src/putil/virtualFileComposite.I new file mode 100644 index 0000000000..c42302a7a6 --- /dev/null +++ b/panda/src/putil/virtualFileComposite.I @@ -0,0 +1,46 @@ +// Filename: virtualFileComposite.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileComposite::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileComposite:: +VirtualFileComposite(VirtualFileSystem *file_system, const Filename &filename) : + _file_system(file_system), + _filename(filename) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileComposite::add_component +// Access: Public +// Description: Adds one more component to the composite directory. +// The component should be a directory and the file +// system and filename should match the composite. +//////////////////////////////////////////////////////////////////// +INLINE void VirtualFileComposite:: +add_component(VirtualFile *file) { + nassertv(file->is_directory()); + nassertv(file->get_file_system() == _file_system); + nassertv(file->get_filename() == _filename); + + _components.push_back(file); +} diff --git a/panda/src/putil/virtualFileComposite.cxx b/panda/src/putil/virtualFileComposite.cxx new file mode 100644 index 0000000000..c018f5b896 --- /dev/null +++ b/panda/src/putil/virtualFileComposite.cxx @@ -0,0 +1,78 @@ +// Filename: virtualFileComposite.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileComposite.h" + +TypeHandle VirtualFileComposite::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileComposite::get_file_system +// Access: Published, Virtual +// Description: Returns the VirtualFileSystem this file is associated +// with. +//////////////////////////////////////////////////////////////////// +VirtualFileSystem *VirtualFileComposite:: +get_file_system() const { + return _file_system; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileComposite::get_filename +// Access: Published, Virtual +// Description: Returns the full pathname to this file within the +// virtual file system. +//////////////////////////////////////////////////////////////////// +Filename VirtualFileComposite:: +get_filename() const { + return _filename; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileComposite::is_directory +// Access: Published, Virtual +// Description: Returns true if this file represents a directory (and +// scan_directory() may be called), false otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFileComposite:: +is_directory() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileComposite::scan_local_directory +// Access: Protected, Virtual +// Description: Fills file_list up with the list of files that are +// within this directory, excluding those whose +// basenames are listed in mount_points. Returns true +// if successful, false if the file is not a directory +// or the directory cannot be read. +//////////////////////////////////////////////////////////////////// +bool VirtualFileComposite:: +scan_local_directory(VirtualFileList *file_list, + const ov_set &mount_points) const { + bool any_ok = false; + Components::const_iterator ci; + for (ci = _components.begin(); ci != _components.end(); ++ci) { + if ((*ci)->scan_local_directory(file_list, mount_points)) { + any_ok = true; + } + } + + return any_ok; +} diff --git a/panda/src/putil/virtualFileComposite.h b/panda/src/putil/virtualFileComposite.h new file mode 100644 index 0000000000..27218de727 --- /dev/null +++ b/panda/src/putil/virtualFileComposite.h @@ -0,0 +1,79 @@ +// Filename: virtualFileComposite.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILECOMPOSITE_H +#define VIRTUALFILECOMPOSITE_H + +#include "pandabase.h" + +#include "virtualFile.h" + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileComposite +// Description : A composite directory within the VirtualFileSystem: +// this maps to more than one directory on different +// mount points. The resulting directory appears to be +// the union of all the individual simple directories. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileComposite : public VirtualFile { +public: + INLINE VirtualFileComposite(VirtualFileSystem *file_system, + const Filename &filename); + + INLINE void add_component(VirtualFile *file); + + virtual VirtualFileSystem *get_file_system() const; + virtual Filename get_filename() const; + + virtual bool is_directory() const; + +protected: + virtual bool scan_local_directory(VirtualFileList *file_list, + const ov_set &mount_points) const; + +private: + VirtualFileSystem *_file_system; + Filename _filename; + typedef pvector< PT(VirtualFile) > Components; + Components _components; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +PUBLISHED: + static TypeHandle get_class_type() { + return _type_handle; + } + +public: + static void init_type() { + VirtualFile::init_type(); + register_type(_type_handle, "VirtualFileComposite", + VirtualFile::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "virtualFileComposite.I" + +#endif diff --git a/panda/src/putil/virtualFileList.I b/panda/src/putil/virtualFileList.I new file mode 100644 index 0000000000..36c75ae6fa --- /dev/null +++ b/panda/src/putil/virtualFileList.I @@ -0,0 +1,67 @@ +// Filename: virtualFileList.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileList::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileList:: +VirtualFileList() { +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileList::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileList:: +~VirtualFileList() { +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileList::add_file +// Access: Public +// Description: Adds a new file to the list. +//////////////////////////////////////////////////////////////////// +INLINE void VirtualFileList:: +add_file(VirtualFile *file) { + _files.push_back(file); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileList::get_num_files +// Access: Published +// Description: Returns the number of files in the list. +//////////////////////////////////////////////////////////////////// +INLINE int VirtualFileList:: +get_num_files() const { + return _files.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileList::get_file +// Access: Published +// Description: Returns the nth file in the list. +//////////////////////////////////////////////////////////////////// +INLINE VirtualFile *VirtualFileList:: +get_file(int n) const { + nassertr(n >= 0 && n < (int)_files.size(), NULL); + return _files[n]; +} diff --git a/panda/src/putil/virtualFileList.cxx b/panda/src/putil/virtualFileList.cxx new file mode 100644 index 0000000000..9259b2099b --- /dev/null +++ b/panda/src/putil/virtualFileList.cxx @@ -0,0 +1,19 @@ +// Filename: virtualFileList.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileList.h" diff --git a/panda/src/putil/virtualFileList.h b/panda/src/putil/virtualFileList.h new file mode 100644 index 0000000000..d3d3d9014f --- /dev/null +++ b/panda/src/putil/virtualFileList.h @@ -0,0 +1,53 @@ +// Filename: virtualFileList.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILELIST_H +#define VIRTUALFILELIST_H + +#include "pandabase.h" + +#include "virtualFile.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileList +// Description : A list of VirtualFiles, as returned by +// VirtualDirectory::scan(). +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileList : public ReferenceCount { +public: + INLINE VirtualFileList(); + +PUBLISHED: + INLINE ~VirtualFileList(); + +public: + INLINE void add_file(VirtualFile *file); + +PUBLISHED: + INLINE int get_num_files() const; + INLINE VirtualFile *get_file(int n) const; + +private: + typedef pvector< PT(VirtualFile) > Files; + Files _files; +}; + +#include "virtualFileList.I" + +#endif diff --git a/panda/src/putil/virtualFileMount.I b/panda/src/putil/virtualFileMount.I new file mode 100644 index 0000000000..996c633861 --- /dev/null +++ b/panda/src/putil/virtualFileMount.I @@ -0,0 +1,88 @@ +// Filename: virtualFileMount.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileMount:: +VirtualFileMount(VirtualFileSystem *file_system, + const Filename &physical_filename, + const Filename &mount_point, + int mount_flags) : + _file_system(file_system), + _physical_filename(physical_filename), + _mount_point(mount_point), + _mount_flags(mount_flags) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::get_file_system +// Access: Public +// Description: Returns the file system this mount object is attached +// to. +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileSystem *VirtualFileMount:: +get_file_system() const { + return _file_system; +} + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::get_physical_filename +// Access: Public +// Description: Returns the name of the source file on the OS +// filesystem of the directory or file that is mounted. +//////////////////////////////////////////////////////////////////// +INLINE const Filename &VirtualFileMount:: +get_physical_filename() const { + return _physical_filename; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::get_mount_point +// Access: Public +// Description: Returns the name of the directory within the virtual +// file system that this mount object is attached to. +// This directory name will end with a slash. +//////////////////////////////////////////////////////////////////// +INLINE const Filename &VirtualFileMount:: +get_mount_point() const { + return _mount_point; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::get_mount_flags +// Access: Public +// Description: Returns the set of flags passed by the user to the +// VirtualFileSystem::mount() command. +//////////////////////////////////////////////////////////////////// +INLINE int VirtualFileMount:: +get_mount_flags() const { + return _mount_flags; +} + + +INLINE ostream & +operator << (ostream &out, const VirtualFileMount &mount) { + mount.output(out); + return out; +} diff --git a/panda/src/putil/virtualFileMount.cxx b/panda/src/putil/virtualFileMount.cxx new file mode 100644 index 0000000000..ea689441e8 --- /dev/null +++ b/panda/src/putil/virtualFileMount.cxx @@ -0,0 +1,51 @@ +// Filename: virtualFileMount.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileMount.h" + +TypeHandle VirtualFileMount::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +VirtualFileMount:: +~VirtualFileMount() { +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::output +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void VirtualFileMount:: +output(ostream &out) const { + out << get_physical_filename(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMount::write +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +void VirtualFileMount:: +write(ostream &out) const { + out << get_physical_filename() << " on /" << get_mount_point() << "\n"; +} diff --git a/panda/src/putil/virtualFileMount.h b/panda/src/putil/virtualFileMount.h new file mode 100644 index 0000000000..4221ddb359 --- /dev/null +++ b/panda/src/putil/virtualFileMount.h @@ -0,0 +1,90 @@ +// Filename: virtualFileMount.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILEMOUNT_H +#define VIRTUALFILEMOUNT_H + +#include "pandabase.h" + +#include "filename.h" +#include "pointerTo.h" +#include "typedObject.h" + +class VirtualFileSystem; + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileMount +// Description : The abstract base class for a mount definition used +// within a VirtualFileSystem. Normally users don't +// need to monkey with this class directly. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileMount : public TypedObject { +public: + INLINE VirtualFileMount(VirtualFileSystem *file_system, + const Filename &physical_filename, + const Filename &mount_point, + int mount_flags); + virtual ~VirtualFileMount(); + + INLINE VirtualFileSystem *get_file_system() const; + INLINE const Filename &get_physical_filename() const; + INLINE const Filename &get_mount_point() const; + INLINE int get_mount_flags() const; + + virtual bool has_file(const Filename &file) const=0; + virtual bool is_directory(const Filename &file) const=0; + virtual bool is_regular_file(const Filename &file) const=0; + + virtual istream *open_read_file(const Filename &file) const=0; + virtual bool scan_directory(vector_string &contents, + const Filename &dir) const=0; + + + virtual void output(ostream &out) const; + virtual void write(ostream &out) const; + +protected: + VirtualFileSystem *_file_system; + Filename _physical_filename; + Filename _mount_point; + int _mount_flags; + + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedObject::init_type(); + register_type(_type_handle, "VirtualFileMount", + TypedObject::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +INLINE ostream &operator << (ostream &out, const VirtualFileMount &mount); + +#include "virtualFileMount.I" + +#endif diff --git a/panda/src/putil/virtualFileMountMultifile.I b/panda/src/putil/virtualFileMountMultifile.I new file mode 100644 index 0000000000..b12071c8bf --- /dev/null +++ b/panda/src/putil/virtualFileMountMultifile.I @@ -0,0 +1,45 @@ +// Filename: virtualFileMountMultifile.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileMountMultifile:: +VirtualFileMountMultifile(VirtualFileSystem *file_system, + Multifile *multifile, + const Filename &mount_point, + int mount_flags) : + VirtualFileMount(file_system, multifile->get_multifile_name(), + mount_point, mount_flags), + _multifile(multifile) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::get_multifile +// Access: Public +// Description: Returns the Multifile pointer that this mount object +// is based on. +//////////////////////////////////////////////////////////////////// +INLINE Multifile *VirtualFileMountMultifile:: +get_multifile() const { + return _multifile; +} diff --git a/panda/src/putil/virtualFileMountMultifile.cxx b/panda/src/putil/virtualFileMountMultifile.cxx new file mode 100644 index 0000000000..514e20ecd7 --- /dev/null +++ b/panda/src/putil/virtualFileMountMultifile.cxx @@ -0,0 +1,99 @@ +// Filename: virtualFileMountMultifile.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileMountMultifile.h" +#include "virtualFileSystem.h" + +TypeHandle VirtualFileMountMultifile::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +VirtualFileMountMultifile:: +~VirtualFileMountMultifile() { + if ((_mount_flags & VirtualFileSystem::MF_owns_pointer) != 0) { + // Delete the _multifile pointer if we own it. + nassertv(_multifile != (Multifile *)NULL); + delete _multifile; + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::has_file +// Access: Public, Virtual +// Description: Returns true if the indicated file exists within the +// mount system. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountMultifile:: +has_file(const Filename &file) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::is_directory +// Access: Public, Virtual +// Description: Returns true if the indicated file exists within the +// mount system and is a directory. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountMultifile:: +is_directory(const Filename &file) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::is_regular_file +// Access: Public, Virtual +// Description: Returns true if the indicated file exists within the +// mount system and is a regular file. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountMultifile:: +is_regular_file(const Filename &file) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::open_read_file +// Access: Public, Virtual +// Description: Opens the file for reading, if it exists. Returns a +// newly allocated istream on success (which you should +// eventually delete when you are done reading). +// Returns NULL or an invalid istream on failure. +//////////////////////////////////////////////////////////////////// +istream *VirtualFileMountMultifile:: +open_read_file(const Filename &file) const { + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountMultifile::scan_directory +// Access: Public, Virtual +// Description: Fills the given vector up with the sorted list of +// filenames that are local to this directory, if the +// filename is a directory. Returns true if successful, +// or false if the file is not a directory or cannot be +// read. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountMultifile:: +scan_directory(vector_string &contents, const Filename &dir) const { + return false; +} + diff --git a/panda/src/putil/virtualFileMountMultifile.h b/panda/src/putil/virtualFileMountMultifile.h new file mode 100644 index 0000000000..630c73de73 --- /dev/null +++ b/panda/src/putil/virtualFileMountMultifile.h @@ -0,0 +1,75 @@ +// Filename: virtualFileMountMultifile.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILEMOUNTMULTIFILE_H +#define VIRTUALFILEMOUNTMULTIFILE_H + +#include "pandabase.h" + +#include "virtualFileMount.h" +#include "multifile.h" + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileMountMultifile +// Description : Maps a Multifile's contents into the +// VirtualFileSystem. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileMountMultifile : public VirtualFileMount { +public: + INLINE VirtualFileMountMultifile(VirtualFileSystem *file_system, + Multifile *multifile, + const Filename &mount_point, + int mount_flags); + virtual ~VirtualFileMountMultifile(); + + INLINE Multifile *get_multifile() const; + + virtual bool has_file(const Filename &file) const; + virtual bool is_directory(const Filename &file) const; + virtual bool is_regular_file(const Filename &file) const; + + virtual istream *open_read_file(const Filename &file) const; + virtual bool scan_directory(vector_string &contents, + const Filename &dir) const; + + +private: + Multifile *_multifile; + + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + VirtualFileMount::init_type(); + register_type(_type_handle, "VirtualFileMountMultifile", + VirtualFileMount::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "virtualFileMountMultifile.I" + +#endif diff --git a/panda/src/putil/virtualFileMountSystem.I b/panda/src/putil/virtualFileMountSystem.I new file mode 100644 index 0000000000..eab0f05a6c --- /dev/null +++ b/panda/src/putil/virtualFileMountSystem.I @@ -0,0 +1,32 @@ +// Filename: virtualFileMountSystem.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountSystem::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileMountSystem:: +VirtualFileMountSystem(VirtualFileSystem *file_system, + const Filename &physical_filename, + const Filename &mount_point, + int mount_flags) : + VirtualFileMount(file_system, physical_filename, mount_point, mount_flags) +{ +} diff --git a/panda/src/putil/virtualFileMountSystem.cxx b/panda/src/putil/virtualFileMountSystem.cxx new file mode 100644 index 0000000000..e1c3c40dcd --- /dev/null +++ b/panda/src/putil/virtualFileMountSystem.cxx @@ -0,0 +1,95 @@ +// Filename: virtualFileMountSystem.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileMountSystem.h" + +TypeHandle VirtualFileMountSystem::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountSystem::has_file +// Access: Public, Virtual +// Description: Returns true if the indicated file exists within the +// mount system. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountSystem:: +has_file(const Filename &file) const { + Filename pathname(_physical_filename, file); + return pathname.exists(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountSystem::is_directory +// Access: Public, Virtual +// Description: Returns true if the indicated file exists within the +// mount system and is a directory. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountSystem:: +is_directory(const Filename &file) const { + Filename pathname(_physical_filename, file); + return pathname.is_directory(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountSystem::is_regular_file +// Access: Public, Virtual +// Description: Returns true if the indicated file exists within the +// mount system and is a regular file. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountSystem:: +is_regular_file(const Filename &file) const { + Filename pathname(_physical_filename, file); + return pathname.is_regular_file(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountSystem::open_read_file +// Access: Public, Virtual +// Description: Opens the file for reading, if it exists. Returns a +// newly allocated istream on success (which you should +// eventually delete when you are done reading). +// Returns NULL or an invalid istream on failure. +//////////////////////////////////////////////////////////////////// +istream *VirtualFileMountSystem:: +open_read_file(const Filename &file) const { + Filename pathname(_physical_filename, file); + ifstream *stream = new ifstream; + if (!pathname.open_read(*stream)) { + // Couldn't open the file for some reason. + delete stream; + return NULL; + } + + return stream; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileMountSystem::scan_directory +// Access: Public, Virtual +// Description: Fills the given vector up with the sorted list of +// filenames that are local to this directory, if the +// filename is a directory. Returns true if successful, +// or false if the file is not a directory or cannot be +// read. +//////////////////////////////////////////////////////////////////// +bool VirtualFileMountSystem:: +scan_directory(vector_string &contents, const Filename &dir) const { + Filename pathname(_physical_filename, dir); + return pathname.scan_directory(contents); +} + diff --git a/panda/src/putil/virtualFileMountSystem.h b/panda/src/putil/virtualFileMountSystem.h new file mode 100644 index 0000000000..7af270b780 --- /dev/null +++ b/panda/src/putil/virtualFileMountSystem.h @@ -0,0 +1,68 @@ +// Filename: virtualFileMountSystem.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILEMOUNTSYSTEM_H +#define VIRTUALFILEMOUNTSYSTEM_H + +#include "pandabase.h" + +#include "virtualFileMount.h" + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileMountSystem +// Description : Maps an actual OS directory into the +// VirtualFileSystem. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileMountSystem : public VirtualFileMount { +public: + INLINE VirtualFileMountSystem(VirtualFileSystem *file_system, + const Filename &physical_filename, + const Filename &mount_point, + int mount_flags); + + + virtual bool has_file(const Filename &file) const; + virtual bool is_directory(const Filename &file) const; + virtual bool is_regular_file(const Filename &file) const; + + virtual istream *open_read_file(const Filename &file) const; + virtual bool scan_directory(vector_string &contents, + const Filename &dir) const; + + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + VirtualFileMount::init_type(); + register_type(_type_handle, "VirtualFileMountSystem", + VirtualFileMount::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "virtualFileMountSystem.I" + +#endif diff --git a/panda/src/putil/virtualFileSimple.I b/panda/src/putil/virtualFileSimple.I new file mode 100644 index 0000000000..18c509e364 --- /dev/null +++ b/panda/src/putil/virtualFileSimple.I @@ -0,0 +1,30 @@ +// Filename: virtualFileSimple.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileSimple:: +VirtualFileSimple(VirtualFileMount *mount, const Filename &local_filename) : + _mount(mount), + _local_filename(local_filename) +{ +} diff --git a/panda/src/putil/virtualFileSimple.cxx b/panda/src/putil/virtualFileSimple.cxx new file mode 100644 index 0000000000..3d1274d376 --- /dev/null +++ b/panda/src/putil/virtualFileSimple.cxx @@ -0,0 +1,130 @@ +// Filename: virtualFileSimple.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileSimple.h" + +TypeHandle VirtualFileSimple::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::get_file_system +// Access: Published, Virtual +// Description: Returns the VirtualFileSystem this file is associated +// with. +//////////////////////////////////////////////////////////////////// +VirtualFileSystem *VirtualFileSimple:: +get_file_system() const { + return _mount->get_file_system(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::get_filename +// Access: Published, Virtual +// Description: Returns the full pathname to this file within the +// virtual file system. +//////////////////////////////////////////////////////////////////// +Filename VirtualFileSimple:: +get_filename() const { + string mount_point = _mount->get_mount_point(); + if (_local_filename.empty()) { + if (mount_point.empty()) { + return "/"; + } else { + return string("/") + mount_point; + } + + } else { + if (mount_point.empty()) { + return string("/") + _local_filename.get_fullpath(); + } else { + return string("/") + mount_point + string("/") + _local_filename.get_fullpath(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::is_directory +// Access: Published, Virtual +// Description: Returns true if this file represents a directory (and +// scan_directory() may be called), false otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSimple:: +is_directory() const { + return _mount->is_directory(_local_filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::is_regular_file +// Access: Published, Virtual +// Description: Returns true if this file represents a regular file +// (and read_file() may be called), false otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSimple:: +is_regular_file() const { + return _mount->is_regular_file(_local_filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::open_read_file +// Access: Published, Virtual +// Description: Opens the file for reading. Returns a newly +// allocated istream on success (which you should +// eventually delete when you are done reading). +// Returns NULL on failure. +//////////////////////////////////////////////////////////////////// +istream *VirtualFileSimple:: +open_read_file() const { + return _mount->open_read_file(_local_filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::scan_local_directory +// Access: Protected, Virtual +// Description: Fills file_list up with the list of files that are +// within this directory, excluding those whose +// basenames are listed in mount_points. Returns true +// if successful, false if the file is not a directory +// or the directory cannot be read. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSimple:: +scan_local_directory(VirtualFileList *file_list, + const ov_set &mount_points) const { + vector_string names; + if (!_mount->scan_directory(names, _local_filename)) { + return false; + } + + // Now the scan above gave us a list of basenames. Turn these back + // into VirtualFile pointers. + + // Each of the files returned by the mount will be just a simple + // file within the same mount tree, unless it is shadowed by a + // mount point listed in mount_points. + + vector_string::const_iterator ni; + for (ni = names.begin(); ni != names.end(); ++ni) { + const string &basename = (*ni); + if (mount_points.find(basename) == mount_points.end()) { + Filename filename(_local_filename, basename); + VirtualFileSimple *file = new VirtualFileSimple(_mount, filename); + file_list->add_file(file); + } + } + + return true; +} diff --git a/panda/src/putil/virtualFileSimple.h b/panda/src/putil/virtualFileSimple.h new file mode 100644 index 0000000000..27d30ffdc9 --- /dev/null +++ b/panda/src/putil/virtualFileSimple.h @@ -0,0 +1,78 @@ +// Filename: virtualFileSimple.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILESIMPLE_H +#define VIRTUALFILESIMPLE_H + +#include "pandabase.h" + +#include "virtualFile.h" + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileSimple +// Description : A simple file or directory within the +// VirtualFileSystem: this maps to exactly one file on +// one mount point. Most directories, and all regular +// files, are of this kind. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileSimple : public VirtualFile { +public: + INLINE VirtualFileSimple(VirtualFileMount *mount, + const Filename &local_filename); + + virtual VirtualFileSystem *get_file_system() const; + virtual Filename get_filename() const; + + virtual bool is_directory() const; + virtual bool is_regular_file() const; + + virtual istream *open_read_file() const; + +protected: + virtual bool scan_local_directory(VirtualFileList *file_list, + const ov_set &mount_points) const; + +private: + VirtualFileMount *_mount; + Filename _local_filename; + +public: + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +PUBLISHED: + static TypeHandle get_class_type() { + return _type_handle; + } + +public: + static void init_type() { + VirtualFile::init_type(); + register_type(_type_handle, "VirtualFileSimple", + VirtualFile::get_class_type()); + } + +private: + static TypeHandle _type_handle; +}; + +#include "virtualFileSimple.I" + +#endif diff --git a/panda/src/putil/virtualFileSystem.I b/panda/src/putil/virtualFileSystem.I new file mode 100644 index 0000000000..9b676a19c4 --- /dev/null +++ b/panda/src/putil/virtualFileSystem.I @@ -0,0 +1,17 @@ +// Filename: virtualFileSystem.I +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/virtualFileSystem.cxx b/panda/src/putil/virtualFileSystem.cxx new file mode 100644 index 0000000000..d39cdf3b19 --- /dev/null +++ b/panda/src/putil/virtualFileSystem.cxx @@ -0,0 +1,500 @@ +// Filename: virtualFileSystem.cxx +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "virtualFileSystem.h" +#include "virtualFileMount.h" +#include "virtualFileMountMultifile.h" +#include "virtualFileMountSystem.h" +#include "dSearchPath.h" +#include "dcast.h" + +VirtualFileSystem *VirtualFileSystem::_global_ptr = NULL; + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +VirtualFileSystem:: +VirtualFileSystem() { + _cwd = "/"; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +VirtualFileSystem:: +~VirtualFileSystem() { + unmount_all(); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::mount +// Access: Published +// Description: Mounts the indicated Multifile at the given mount +// point. If flags contains MF_owns_pointer, the +// Multifile will be deleted when it is eventually +// unmounted. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSystem:: +mount(Multifile *multifile, const string &mount_point, int flags) { + VirtualFileMountMultifile *mount = + new VirtualFileMountMultifile(this, multifile, + normalize_mount_point(mount_point), + flags); + _mounts.push_back(mount); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::mount +// Access: Published +// Description: Mounts the indicated system file or directory at the +// given mount point. If the named file is a directory, +// mounts the directory. If the named file is a +// Multifile, mounts it as a Multifile. Returns true on +// success, false on failure. +// +// A given system directory may be mounted to multiple +// different mount point, and the same mount point may +// share multiple system directories. In the case of +// ambiguities, the most-recently mounted system wins. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSystem:: +mount(const Filename &physical_filename, const string &mount_point, + int flags) { + if (!physical_filename.exists()) { + util_cat.warning() + << "Attempt to mount " << physical_filename << ", not found.\n"; + return false; + } + + if (physical_filename.is_directory()) { + flags &= ~MF_owns_pointer; + VirtualFileMountSystem *mount = + new VirtualFileMountSystem(this, physical_filename, + normalize_mount_point(mount_point), + flags); + _mounts.push_back(mount); + return true; + + } else { + // It's not a directory; it must be a Multifile. + Multifile *multifile = new Multifile; + + // For now these are always opened read only. Maybe later we'll + // support read-write on Multifiles. + flags |= MF_read_only; + if (!multifile->open_read(physical_filename)) { + delete multifile; + return false; + } + + // We want to delete this pointer when we're done. + flags |= MF_owns_pointer; + return mount(multifile, mount_point, flags); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::unmount +// Access: Published +// Description: Unmounts all appearances of the indicated Multifile +// from the file system. Returns the number of +// appearances unmounted. +//////////////////////////////////////////////////////////////////// +int VirtualFileSystem:: +unmount(Multifile *multifile) { + Mounts::iterator ri, wi; + wi = ri = _mounts.begin(); + while (ri != _mounts.end()) { + VirtualFileMount *mount = (*ri); + (*wi) = mount; + + if (mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) { + VirtualFileMountMultifile *mmount = + DCAST(VirtualFileMountMultifile, mount); + if (mmount->get_multifile() == multifile) { + // Remove this one. Don't increment wi. + delete mount; + } else { + // Don't remove this one. + ++wi; + } + } else { + // Don't remove this one. + ++wi; + } + ++ri; + } + + int num_removed = _mounts.end() - wi; + _mounts.erase(wi, _mounts.end()); + return num_removed; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::unmount +// Access: Published +// Description: Unmounts all appearances of the indicated physical +// filename (either a directory name or a Multifile +// name) from the file system. Returns the number of +// appearances unmounted. +//////////////////////////////////////////////////////////////////// +int VirtualFileSystem:: +unmount(const Filename &physical_filename) { + Mounts::iterator ri, wi; + wi = ri = _mounts.begin(); + while (ri != _mounts.end()) { + VirtualFileMount *mount = (*ri); + (*wi) = mount; + + if (mount->get_physical_filename() == physical_filename) { + // Remove this one. Don't increment wi. + delete mount; + } else { + // Don't remove this one. + ++wi; + } + ++ri; + } + + int num_removed = _mounts.end() - wi; + _mounts.erase(wi, _mounts.end()); + return num_removed; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::unmount_point +// Access: Published +// Description: Unmounts all systems attached to the given mount +// point from the file system. Returns the number of +// appearances unmounted. +//////////////////////////////////////////////////////////////////// +int VirtualFileSystem:: +unmount_point(const string &mount_point) { + Filename nmp = normalize_mount_point(mount_point); + Mounts::iterator ri, wi; + wi = ri = _mounts.begin(); + while (ri != _mounts.end()) { + VirtualFileMount *mount = (*ri); + (*wi) = mount; + + if (mount->get_mount_point() == nmp) { + // Remove this one. Don't increment wi. + delete mount; + } else { + // Don't remove this one. + ++wi; + } + ++ri; + } + + int num_removed = _mounts.end() - wi; + _mounts.erase(wi, _mounts.end()); + return num_removed; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::unmount_all +// Access: Published +// Description: Unmounts all files from the file system. Returns the +// number of systems unmounted. +//////////////////////////////////////////////////////////////////// +int VirtualFileSystem:: +unmount_all() { + Mounts::iterator mi; + for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) { + VirtualFileMount *mount = (*mi); + delete mount; + } + + int num_removed = _mounts.size(); + _mounts.clear(); + return num_removed; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::chdir +// Access: Published +// Description: Changes the current directory. This is used to +// resolve relative pathnames in get_file() and/or +// find_file(). Returns true if successful, false +// otherwise. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSystem:: +chdir(const Filename &new_directory) { + if (new_directory == "/") { + // We can always return to the root. + _cwd = new_directory; + return true; + } + + PT(VirtualFile) file = get_file(new_directory); + if (file != (VirtualFile *)NULL && file->is_directory()) { + _cwd = file->get_filename(); + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::get_cwd +// Access: Published +// Description: Returns the current directory name. See chdir(). +//////////////////////////////////////////////////////////////////// +const Filename &VirtualFileSystem:: +get_cwd() const { + return _cwd; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::get_file +// Access: Published +// Description: Looks up the file by the indicated name in the file +// system. Returns a VirtualFile pointer representing +// 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); + if (pathname.is_local()) { + pathname = Filename(_cwd, file); + } + pathname.standardize(); + string strpath = pathname.get_fullpath().substr(1); + + // Now scan all the mount points, from the back (since later mounts + // override more recent ones), until a match is found. + PT(VirtualFile) found_file = NULL; + VirtualFileComposite *composite_file = NULL; + + Mounts::const_reverse_iterator rmi; + for (rmi = _mounts.rbegin(); rmi != _mounts.rend(); ++rmi) { + VirtualFileMount *mount = (*rmi); + string mount_point = mount->get_mount_point(); + if (strpath == mount_point) { + // Here's an exact match on the mount point. This filename is + // the root directory of this mount object. + if (found_match(found_file, composite_file, mount, "")) { + return found_file; + } + + } else if (mount_point.empty()) { + // This is the root mount point; all files are in here. + if (mount->has_file(strpath)) { + // Bingo! + if (found_match(found_file, composite_file, mount, strpath)) { + return found_file; + } + } + + } else if (strpath.length() > mount_point.length() && + strpath.substr(0, mount_point.length()) == mount_point && + strpath[mount_point.length()] == '/') { + // This pathname falls within this mount system. + Filename local_filename = strpath.substr(mount_point.length() + 1); + if (mount->has_file(local_filename)) { + // Bingo! + if (found_match(found_file, composite_file, mount, local_filename)) { + return found_file; + } + } + } + } + return found_file; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::find_file +// Access: Published +// Description: Uses the indicated search path to find the file +// within the file system. Returns the first occurrence +// of the file found, or NULL if the file cannot be +// found. +//////////////////////////////////////////////////////////////////// +PT(VirtualFile) VirtualFileSystem:: +find_file(const Filename &file, const DSearchPath &searchpath) const { + if (file.is_local()) { + return get_file(file); + } + + int num_directories = searchpath.get_num_directories(); + for (int i = 0; i < num_directories; i++) { + Filename match(searchpath.get_directory(i), file); + PT(VirtualFile) found_file = get_file(match); + if (found_file != (VirtualFile *)NULL) { + return found_file; + } + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::write +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void VirtualFileSystem:: +write(ostream &out) const { + Mounts::const_iterator mi; + for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) { + VirtualFileMount *mount = (*mi); + mount->write(out); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::get_global_ptr +// Access: Published, Static +// Description: Returns the default global VirtualFileSystem. You +// may create your own personal VirtualFileSystem +// objects and use them for whatever you like, but Panda +// will attempt to load models and stuff from this +// default object. +// +// Initially, the global VirtualFileSystem is set up to +// mount the OS filesystem to root; i.e. it is +// equivalent to the OS filesystem. This may be +// subsequently adjusted by the user. +//////////////////////////////////////////////////////////////////// +VirtualFileSystem *VirtualFileSystem:: +get_global_ptr() { + if (_global_ptr == (VirtualFileSystem *)NULL) { + _global_ptr = new VirtualFileSystem; + _global_ptr->mount("/", "/", 0); + } + + return _global_ptr; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::scan_mount_points +// Access: Public +// Description: Adds to names a list of all the mount points in use +// that are one directory below path, if any. That is, +// these are the external files or directories mounted +// directly to the indicated path. +// +// The names vector is filled with a set of basenames, +// the basename part of the mount point. +//////////////////////////////////////////////////////////////////// +void VirtualFileSystem:: +scan_mount_points(vector_string &names, const Filename &path) const { + nassertv(!path.empty() && !path.is_local()); + string prefix = path.get_fullpath().substr(1); + Mounts::const_iterator mi; + for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) { + VirtualFileMount *mount = (*mi); + + string mount_point = mount->get_mount_point(); + if (prefix.empty()) { + // The indicated path is the root. Is the mount point on the + // root? + if (mount_point.find('/') == string::npos) { + // No embedded slashes, so the mount point is only one + // directory below the root. + names.push_back(mount_point); + } + } else { + if (mount_point.substr(0, prefix.length()) == prefix && + mount_point.length() > prefix.length() && + mount_point[prefix.length()] == '/') { + // This mount point is below the indicated path. Is it only one + // directory below? + string basename = mount_point.substr(prefix.length()); + if (basename.find('/') == string::npos) { + // No embedded slashes, so it's only one directory below. + names.push_back(basename); + } + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::normalize_mount_point +// Access: Private +// Description: Converts the mount point string supplied by the user +// to standard form (relative to the current directory, +// with no double slashes, and not terminating with a +// slash). The initial slash is removed. +//////////////////////////////////////////////////////////////////// +Filename VirtualFileSystem:: +normalize_mount_point(const string &mount_point) const { + Filename nmp = mount_point; + if (nmp.is_local()) { + nmp = Filename(_cwd, mount_point); + } + nmp.standardize(); + nassertr(!nmp.empty() && nmp[0] == '/', nmp); + return nmp.get_fullpath().substr(1); +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::found_match +// Access: Private +// Description: Evaluates one match found during a get_file() +// operation. There may be multiple matches for a +// particular filename due to the ambiguities introduced +// by allowing multiple mount points, so we may have to +// keep searching even after the first match is found. +// +// Returns true if the search should terminate now, or +// false if it should keep iterating. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSystem:: +found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file, + VirtualFileMount *mount, const string &local_filename) const { + if (found_file == (VirtualFile *)NULL) { + // This was our first match. Save it. + found_file = new VirtualFileSimple(mount, local_filename); + if (!mount->is_directory(local_filename)) { + // If it's not a directory, we're done. + return true; + } + + } else { + // This was our second match. The previous match(es) must + // have been directories. + if (!mount->is_directory(local_filename)) { + // However, this one isn't a directory. We're done. + return true; + } + + // At least two directories matched to the same path. We + // need a composite directory. + if (composite_file == (VirtualFileComposite *)NULL) { + composite_file = + new VirtualFileComposite((VirtualFileSystem *)this, found_file->get_filename()); + composite_file->add_component(found_file); + found_file = composite_file; + } + composite_file->add_component(new VirtualFileSimple(mount, local_filename)); + } + + // Keep going, looking for more directories. + return false; +} + diff --git a/panda/src/putil/virtualFileSystem.h b/panda/src/putil/virtualFileSystem.h new file mode 100644 index 0000000000..0461b481df --- /dev/null +++ b/panda/src/putil/virtualFileSystem.h @@ -0,0 +1,86 @@ +// Filename: virtualFileSystem.h +// Created by: drose (03Aug02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef VIRTUALFILESYSTEM_H +#define VIRTUALFILESYSTEM_H + +#include "pandabase.h" + +#include "filename.h" +#include "pmap.h" + +class Multifile; +class VirtualFileMount; + +//////////////////////////////////////////////////////////////////// +// Class : VirtualFileSystem +// Description : A hierarchy of directories and files that appears to +// be one continuous file system, even though the files +// may originate from several different sources that may +// not be related to the actual OS's file system. +// +// For instance, a VirtualFileSystem can transparently +// mount one or more Multifiles as their own +// subdirectory hierarchies. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA VirtualFileSystem { +PUBLISHED: + VirtualFileSystem(); + ~VirtualFileSystem(); + + enum MountFlags { + MF_owns_pointer = 0x0001, + MF_read_only = 0x0002, + }; + + bool mount(Multifile *multifile, const string &mount_point, int flags); + bool mount(const Filename &physical_filename, const string &mount_point, int flags); + int unmount(Multifile *multifile); + int unmount(const Filename &physical_filename); + int unmount_point(const string &mount_point); + int unmount_all(); + + bool chdir(const Filename &new_directory); + const Filename &get_cwd() const; + + PT(VirtualFile) get_file(const Filename &file) const; + PT(VirtualFile) find_file(const Filename &file, + const DSearchPath &searchpath) const; + + void write(ostream &out) const; + + static VirtualFileSystem *get_global_ptr(); + +public: + void scan_mount_points(vector_string &names, const Filename &path) const; + +private: + Filename normalize_mount_point(const string &mount_point) const; + bool found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file, + VirtualFileMount *mount, const string &local_filename) const; + + typedef pvector Mounts; + Mounts _mounts; + Filename _cwd; + + static VirtualFileSystem *_global_ptr; +}; + +#include "virtualFileSystem.I" + +#endif