Переглянути джерело

initial virtual file system

David Rose 23 роки тому
батько
коміт
255bcd1299
32 змінених файлів з 2408 додано та 116 видалено
  1. 7 4
      panda/src/downloader/extractor.cxx
  2. 15 38
      panda/src/express/multifile.I
  3. 152 66
      panda/src/express/multifile.cxx
  4. 13 8
      panda/src/express/multifile.h
  5. 1 0
      panda/src/express/subStreamBuf.cxx
  6. 16 0
      panda/src/putil/Sources.pp
  7. 12 0
      panda/src/putil/config_util.cxx
  8. 8 0
      panda/src/putil/putil_composite2.cxx
  9. 35 0
      panda/src/putil/virtualFile.I
  10. 233 0
      panda/src/putil/virtualFile.cxx
  11. 90 0
      panda/src/putil/virtualFile.h
  12. 46 0
      panda/src/putil/virtualFileComposite.I
  13. 78 0
      panda/src/putil/virtualFileComposite.cxx
  14. 79 0
      panda/src/putil/virtualFileComposite.h
  15. 67 0
      panda/src/putil/virtualFileList.I
  16. 19 0
      panda/src/putil/virtualFileList.cxx
  17. 53 0
      panda/src/putil/virtualFileList.h
  18. 88 0
      panda/src/putil/virtualFileMount.I
  19. 51 0
      panda/src/putil/virtualFileMount.cxx
  20. 90 0
      panda/src/putil/virtualFileMount.h
  21. 45 0
      panda/src/putil/virtualFileMountMultifile.I
  22. 99 0
      panda/src/putil/virtualFileMountMultifile.cxx
  23. 75 0
      panda/src/putil/virtualFileMountMultifile.h
  24. 32 0
      panda/src/putil/virtualFileMountSystem.I
  25. 95 0
      panda/src/putil/virtualFileMountSystem.cxx
  26. 68 0
      panda/src/putil/virtualFileMountSystem.h
  27. 30 0
      panda/src/putil/virtualFileSimple.I
  28. 130 0
      panda/src/putil/virtualFileSimple.cxx
  29. 78 0
      panda/src/putil/virtualFileSimple.h
  30. 17 0
      panda/src/putil/virtualFileSystem.I
  31. 500 0
      panda/src/putil/virtualFileSystem.cxx
  32. 86 0
      panda/src/putil/virtualFileSystem.h

+ 7 - 4
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;
 }

+ 15 - 38
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;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 152 - 66
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 &copy) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Multifile::Copy Assignment Operator
+//       Access: Private
+//  Description: Don't try to copy Multifiles.
+////////////////////////////////////////////////////////////////////
+void Multifile::
+operator = (const Multifile &copy) {
+  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.
+//
+//               The returned istream will have been allocated via
+//               new; you should delete it when you are finished
+//               reading the subfile.
 //
-//               It is not valid to perform any additional operations
-//               on this Multifile until close_subfile() has
-//               subsequently been called.
+//               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();
 
-  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;
+    // That shouldn't change the subfile index or delete the subfile
+    // pointer.
+    nassertr(subfile == _subfiles[index], new 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 && 

+ 13 - 8
panda/src/express/multifile.h

@@ -38,16 +38,23 @@ PUBLISHED:
   Multifile();
   ~Multifile();
 
+private:
+  Multifile(const Multifile &copy);
+  void operator = (const Multifile &copy);
+
+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;

+ 1 - 0
panda/src/express/subStreamBuf.cxx

@@ -49,6 +49,7 @@ SubStreamBuf() {
 ////////////////////////////////////////////////////////////////////
 SubStreamBuf::
 ~SubStreamBuf() {
+  close();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 16 - 0
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
 

+ 12 - 0
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();
 }
 

+ 8 - 0
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"
 

+ 35 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFile::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE VirtualFile::
+VirtualFile() {
+}
+
+
+INLINE ostream &
+operator << (ostream &out, const VirtualFile &file) {
+  file.output(out);
+  return out;
+}
+

+ 233 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<string> 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<string>::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<string> &) 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);
+    }
+  }
+}

+ 90 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<string> &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

+ 46 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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);
+}

+ 78 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<string> &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;
+}

+ 79 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<string> &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

+ 67 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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];
+}

+ 19 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "virtualFileList.h"

+ 53 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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

+ 88 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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;
+}

+ 51 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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";
+}

+ 90 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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

+ 45 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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;
+}

+ 99 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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;
+}
+

+ 75 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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

+ 32 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     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)
+{
+}

+ 95 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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);
+}
+

+ 68 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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

+ 30 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSimple::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE VirtualFileSimple::
+VirtualFileSimple(VirtualFileMount *mount, const Filename &local_filename) :
+  _mount(mount),
+  _local_filename(local_filename)
+{
+}

+ 130 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<string> &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;
+}

+ 78 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<string> &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

+ 17 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////

+ 500 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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;
+}
+

+ 86 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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<VirtualFileMount *> Mounts;
+  Mounts _mounts;
+  Filename _cwd;
+
+  static VirtualFileSystem *_global_ptr;
+};
+
+#include "virtualFileSystem.I"
+
+#endif