Browse Source

support reading and writing bam streams instead of just files

David Rose 22 năm trước cách đây
mục cha
commit
6fc94e9f03

+ 163 - 29
panda/src/pgraph/bamFile.cxx

@@ -26,6 +26,7 @@
 #include "filename.h"
 #include "config_express.h"
 #include "virtualFileSystem.h"
+#include "dcast.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamFile::Constructor
@@ -55,11 +56,9 @@ BamFile::
 //               Returns true if successful, false on error.
 ////////////////////////////////////////////////////////////////////
 bool BamFile::
-open_read(const Filename &filename, bool report_errors) {
+open_read(const Filename &bam_filename, bool report_errors) {
   close();
 
-  Filename bam_filename(filename);
-
   if (use_vfs) {
     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
     if (!vfs->exists(bam_filename)) {
@@ -84,24 +83,26 @@ open_read(const Filename &filename, bool report_errors) {
     return false;
   }
 
-  string head;
-  if (!_din.read_header(head, _bam_header.size())) {
-    loader_cat.error() << bam_filename << " is not a valid BAM file.\n";
-    return false;
-  }
+  return continue_open_read(bam_filename, report_errors);
+}
 
-  if (head != _bam_header) {
-    loader_cat.error() << bam_filename << " is not a valid BAM file.\n";
-    return false;
-  }
+////////////////////////////////////////////////////////////////////
+//     Function: BamFile::open_read
+//       Access: Public
+//  Description: Attempts to open the indicated stream for reading.
+//               The filename is just for information purposes only.
+//               Returns true if successful, false on error.
+////////////////////////////////////////////////////////////////////
+bool BamFile::
+open_read(istream &in, const string &bam_filename, bool report_errors) {
+  close();
 
-  _reader = new BamReader(&_din);
-  if (!_reader->init()) {
-    close();
+  if (!_din.open(in)) {
+    loader_cat.error() << "Could not read bam: " << bam_filename << "\n";
     return false;
   }
 
-  return true;
+  return continue_open_read(bam_filename, report_errors);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -156,6 +157,67 @@ resolve() {
   return _reader->resolve();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: BamFile::read_node
+//       Access: Public
+//  Description: Although the bam file format is general enough to
+//               store a list of objects of arbitrary type, bam files
+//               on disk usually contain just one object, a PandaNode
+//               that is the root of a scene graph.  (Bam files that
+//               store other kinds of things are usually given the
+//               extension "boo", for "binary other objects", to
+//               differentiate them from the normal scene graph type
+//               file.)
+//
+//               This is a convenience method for when you believe you
+//               are reading a scene graph bam file.  It reads the one
+//               PandaNode and returns it.  It also calls resolve() to
+//               fully resolve the object, since we expect this will
+//               be the only object in the file.
+//
+//               If the bam file contains something other than a
+//               PandaNode, an error is printed and NULL is returned.
+////////////////////////////////////////////////////////////////////
+PT(PandaNode) BamFile::
+read_node(bool report_errors) {
+  PT(PandaNode) result;
+
+  TypedWritable *object = read_object();
+  if (object == TypedWritable::Null) {
+    if (report_errors) {
+      loader_cat.error() << "Bam file " << _bam_filename << " is empty.\n";
+    }
+
+  } else if (!object->is_of_type(PandaNode::get_class_type())) {
+    if (report_errors) {
+      loader_cat.error()
+        << "Bam file " << _bam_filename
+        << " contains a " << object->get_type() << ", not a PandaNode.\n";
+    }
+
+  } else {
+    result = DCAST(PandaNode, object);
+
+    if (report_errors) {
+      read_object();
+      if (!is_eof()) {
+        loader_cat.warning()
+          << "Ignoring extra objects in " << _bam_filename << "\n";
+      }
+    }
+  }
+
+  if (!resolve()) {
+    if (report_errors) {
+      loader_cat.error()
+        << "Unable to resolve Bam file.\n";
+      result = (PandaNode *)NULL;
+    }
+  }
+
+  return result;
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: BamFile::open_write
@@ -166,30 +228,39 @@ resolve() {
 //               false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool BamFile::
-open_write(const Filename &filename, bool) {
+open_write(const Filename &bam_filename, bool report_errors) {
   close();
 
-  loader_cat.info() << "Writing " << filename << "\n";
+  loader_cat.info() << "Writing " << bam_filename << "\n";
 
-  filename.unlink();
-  if (!_dout.open(filename)) {
-    loader_cat.error() << "Unable to open " << filename << "\n";
+  bam_filename.unlink();
+  if (!_dout.open(bam_filename)) {
+    if (report_errors) {
+      loader_cat.error() << "Unable to open " << bam_filename << "\n";
+    }
     return false;
   }
 
-  if (!_dout.write_header(_bam_header)) {
-    loader_cat.error() << "Unable to write to " << filename << "\n";
-    return false;
-  }
+  return continue_open_write(bam_filename, report_errors);
+}
 
-  _writer = new BamWriter(&_dout);
+////////////////////////////////////////////////////////////////////
+//     Function: BamFile::open_write
+//       Access: Public
+//  Description: Attempts to open the indicated stream for writing.
+//               The filename is just for information purposes only.
+//               Returns true if successful, false on error.
+////////////////////////////////////////////////////////////////////
+bool BamFile::
+open_write(ostream &out, const string &bam_filename, bool report_errors) {
+  close();
 
-  if (!_writer->init()) {
-    close();
+  if (!_dout.open(out)) {
+    loader_cat.error() << "Could not write bam: " << bam_filename << "\n";
     return false;
   }
 
-  return true;
+  return continue_open_write(bam_filename, report_errors);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -288,3 +359,66 @@ int BamFile::
 get_current_minor_ver() {
   return _bam_minor_ver;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamFile::continue_open_read
+//       Access: Private
+//  Description: Reads the header of the recently-opened bam stream
+//               and prepares to read the contents of the file.
+//               Returns true if successful, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool BamFile::
+continue_open_read(const string &bam_filename, bool report_errors) {
+  _bam_filename = bam_filename;
+
+  string head;
+  if (!_din.read_header(head, _bam_header.size())) {
+    if (report_errors) {
+      loader_cat.error() << _bam_filename << " is not a valid BAM file.\n";
+    }
+    return false;
+  }
+
+  if (head != _bam_header) {
+    if (report_errors) {
+      loader_cat.error() << _bam_filename << " is not a valid BAM file.\n";
+    }
+    return false;
+  }
+
+  _reader = new BamReader(&_din);
+  if (!_reader->init()) {
+    close();
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamFile::continue_open_write
+//       Access: Private
+//  Description: Writers the header of the recently-opened bam stream
+//               and prepares to write the contents of the file.
+//               Returns true if successful, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool BamFile::
+continue_open_write(const string &bam_filename, bool report_errors) {
+  _bam_filename = bam_filename;
+
+  if (!_dout.write_header(_bam_header)) {
+    if (report_errors) {
+      loader_cat.error() << "Unable to write to " << _bam_filename << "\n";
+    }
+    return false;
+  }
+
+  _writer = new BamWriter(&_dout);
+
+  if (!_writer->init()) {
+    close();
+    return false;
+  }
+
+  return true;
+}

+ 14 - 2
panda/src/pgraph/bamFile.h

@@ -23,6 +23,8 @@
 
 #include "datagramInputFile.h"
 #include "datagramOutputFile.h"
+#include "pandaNode.h"
+#include "pointerTo.h"
 
 class BamReader;
 class BamWriter;
@@ -49,12 +51,18 @@ PUBLISHED:
   BamFile();
   ~BamFile();
 
-  bool open_read(const Filename &filename, bool report_errors = true);
+  bool open_read(const Filename &bam_filename, bool report_errors = true);
+  bool open_read(istream &in, const string &bam_filename = "stream",
+                 bool report_errors = true);
   TypedWritable *read_object();
   bool is_eof() const;
   bool resolve();
 
-  bool open_write(const Filename &filename, bool report_errors = true);
+  PT(PandaNode) read_node(bool report_errors = true);
+
+  bool open_write(const Filename &bam_filename, bool report_errors = true);
+  bool open_write(ostream &out, const string &bam_filename = "stream",
+                  bool report_errors = true);
   bool write_object(const TypedWritable *object);
 
   void close();
@@ -68,6 +76,10 @@ PUBLISHED:
   int get_current_minor_ver();
 
 private:
+  bool continue_open_read(const string &bam_filename, bool report_errors);
+  bool continue_open_write(const string &bam_filename, bool report_errors);
+
+  string _bam_filename;
   DatagramInputFile _din;
   DatagramOutputFile _dout;
   BamReader *_reader;

+ 1 - 36
panda/src/pgraph/loaderFileTypeBam.cxx

@@ -65,41 +65,6 @@ load_file(const Filename &path, bool report_errors) const {
     return NULL;
   }
 
-  PT(PandaNode) result;
-
-  TypedWritable *object = bam_file.read_object();
-  if (object == TypedWritable::Null) {
-    if (report_errors) {
-      loader_cat.error() << "Bam file " << path << " is empty.\n";
-    }
-
-  } else if (!object->is_of_type(PandaNode::get_class_type())) {
-    if (report_errors) {
-      loader_cat.error()
-        << "Bam file " << path
-        << " contains a " << object->get_type() << ", not a PandaNode.\n";
-    }
-
-  } else {
-    result = DCAST(PandaNode, object);
-
-    if (report_errors) {
-      bam_file.read_object();
-      if (!bam_file.is_eof()) {
-        loader_cat.warning()
-          << "Ignoring extra objects in " << path << "\n";
-      }
-    }
-  }
-
-  if (!bam_file.resolve()) {
-    if (report_errors) {
-      loader_cat.error()
-        << "Unable to resolve Bam file.\n";
-      result = (PandaNode *)NULL;
-    }
-  }
-
-  return result;
+  return bam_file.read_node(report_errors);
 }
 

+ 1 - 17
panda/src/putil/datagramInputFile.I

@@ -24,24 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 INLINE DatagramInputFile::
 DatagramInputFile() {
-  _error = true;
+  _error = false;
   _read_first_datagram = false;
   _in = (istream *)NULL;
   _owns_in = false;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: DatagramInputFile::close
-//       Access: Public
-//  Description: Closes the file.  This is also implicitly done when
-//               the DatagramInputFile destructs.
-////////////////////////////////////////////////////////////////////
-INLINE void DatagramInputFile::
-close() {
-  _in_file.close();
-  if (_owns_in) {
-    delete _in;
-    _in = (istream *)NULL;
-    _owns_in = false;
-  }
-}

+ 48 - 4
panda/src/putil/datagramInputFile.cxx

@@ -35,13 +35,13 @@
 //     Function: DatagramInputFile::open
 //       Access: Public
 //  Description: Opens the indicated filename for reading.  Returns
-//               true if successful, false on failure.
+//               true on success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool DatagramInputFile::
 open(Filename filename) {
+  close();
+
   // DatagramInputFiles are always binary.
-  _read_first_datagram = false;
-  _error = false;
   filename.set_binary();
 
   if (use_vfs) {
@@ -62,6 +62,44 @@ open(Filename filename) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramInputFile::open
+//       Access: Public
+//  Description: Starts reading from the indicated stream.  Returns
+//               true on success, false on failure.  The
+//               DatagramInputFile does not take ownership of the
+//               stream; you are responsible for closing or deleting
+//               it when you are done.
+////////////////////////////////////////////////////////////////////
+bool DatagramInputFile::
+open(istream &in) {
+  close();
+
+  _in = &in;
+  _owns_in = false;
+
+  return !_in->fail();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramInputFile::close
+//       Access: Public
+//  Description: Closes the file.  This is also implicitly done when
+//               the DatagramInputFile destructs.
+////////////////////////////////////////////////////////////////////
+void DatagramInputFile::
+close() {
+  _in_file.close();
+  if (_owns_in) {
+    delete _in;
+  }
+  _in = (istream *)NULL;
+  _owns_in = false;
+
+  _read_first_datagram = false;
+  _error = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DatagramInputFile::read_header
 //       Access: Public
@@ -74,6 +112,7 @@ open(Filename filename) {
 bool DatagramInputFile::
 read_header(string &header, size_t num_bytes) {
   nassertr(!_read_first_datagram, false);
+  nassertr(_in != (istream *)NULL, false);
 
   char *buffer = (char *)alloca(num_bytes);
   nassertr(buffer != (char *)NULL, false);
@@ -99,6 +138,7 @@ get_datagram(Datagram &data) {
   #ifdef SKYLER_TIMER //[
     Skyler_timer_file.on();
   #endif //]
+  nassertr(_in != (istream *)NULL, false);
   _read_first_datagram = true;
 
   // First, get the size of the upcoming datagram.  We do this with
@@ -147,7 +187,7 @@ get_datagram(Datagram &data) {
 ////////////////////////////////////////////////////////////////////
 bool DatagramInputFile::
 is_eof() {
-  return _in->eof();
+  return _in != (istream *)NULL ? _in->eof() : true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -158,6 +198,10 @@ is_eof() {
 ////////////////////////////////////////////////////////////////////
 bool DatagramInputFile::
 is_error() {
+  if (_in == (istream *)NULL) {
+    return true;
+  }
+
   if (_in->fail()) {
     _error = true;
   }

+ 4 - 3
panda/src/putil/datagramInputFile.h

@@ -19,7 +19,7 @@
 #ifndef DATAGRAMINPUTFILE_H
 #define DATAGRAMINPUTFILE_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "datagramGenerator.h"
 #include "filename.h"
@@ -35,14 +35,15 @@ public:
   INLINE DatagramInputFile();
 
   bool open(Filename filename);
+  bool open(istream &in);
+
+  void close();
 
   bool read_header(string &header, size_t num_bytes);
   virtual bool get_datagram(Datagram &data);
   virtual bool is_eof();
   virtual bool is_error();
 
-  INLINE void close();
-
 private:
   bool _read_first_datagram;
   bool _error;

+ 3 - 27
panda/src/putil/datagramOutputFile.I

@@ -24,32 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 INLINE DatagramOutputFile::
 DatagramOutputFile() {
-  _error = true;
-  _wrote_first_datagram = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DatagramOutputFile::open
-//       Access: Public
-//  Description: Opens the indicated filename for reading.  Returns
-//               true if successful, false on failure.
-////////////////////////////////////////////////////////////////////
-INLINE bool DatagramOutputFile::
-open(Filename filename) {
-  // DatagramOutputFiles are always binary.
-  _wrote_first_datagram = false;
   _error = false;
-  filename.set_binary();
-  return filename.open_write(_out);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DatagramOutputFile::close
-//       Access: Public
-//  Description: Closes the file.  This is also implicitly done when
-//               the DatagramOutputFile destructs.
-////////////////////////////////////////////////////////////////////
-INLINE void DatagramOutputFile::
-close() {
-  _out.close();
+  _wrote_first_datagram = false;
+  _out = (ostream *)NULL;
+  _owns_out = false;
 }

+ 68 - 6
panda/src/putil/datagramOutputFile.cxx

@@ -18,6 +18,62 @@
 
 #include "datagramOutputFile.h"
 
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramOutputFile::open
+//       Access: Public
+//  Description: Opens the indicated filename for reading.  Returns
+//               true if successful, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DatagramOutputFile::
+open(Filename filename) {
+  close();
+
+  // DatagramOutputFiles are always binary.
+  filename.set_binary();
+
+  _out = &_out_file;
+  _owns_out = false;
+  return filename.open_write(_out_file);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramOutputFile::open
+//       Access: Public
+//  Description: Starts writing to the indicated stream.  Returns
+//               true on success, false on failure.  The
+//               DatagramOutputFile does not take ownership of the
+//               stream; you are responsible for closing or deleting
+//               it when you are done.
+////////////////////////////////////////////////////////////////////
+bool DatagramOutputFile::
+open(ostream &out) {
+  close();
+
+  _out = &out;
+  _owns_out = false;
+
+  return !_out->fail();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DatagramOutputFile::close
+//       Access: Public
+//  Description: Closes the file.  This is also implicitly done when
+//               the DatagramOutputFile destructs.
+////////////////////////////////////////////////////////////////////
+void DatagramOutputFile::
+close() {
+  _out_file.close();
+  if (_owns_out) {
+    delete _out;
+  }
+  _out = (ostream *)NULL;
+  _owns_out = false;
+
+  _wrote_first_datagram = false;
+  _error = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DatagramOutputFile::write_header
 //       Access: Public
@@ -29,10 +85,11 @@
 ////////////////////////////////////////////////////////////////////
 bool DatagramOutputFile::
 write_header(const string &header) {
+  nassertr(_out != (ostream *)NULL, false);
   nassertr(!_wrote_first_datagram, false);
 
-  _out.write(header.data(), header.size());
-  return !_out.fail();
+  _out->write(header.data(), header.size());
+  return !_out->fail();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -43,18 +100,19 @@ write_header(const string &header) {
 ////////////////////////////////////////////////////////////////////
 bool DatagramOutputFile::
 put_datagram(const Datagram &data) {
+  nassertr(_out != (ostream *)NULL, false);
   _wrote_first_datagram = true;
 
   // First, write the size of the upcoming datagram.  We do this with
   // the help of a second datagram.
   Datagram size;
   size.add_uint32(data.get_length());
-  _out.write((const char *)size.get_data(), size.get_length());
+  _out->write((const char *)size.get_data(), size.get_length());
 
   // Now, write the datagram itself.
-  _out.write((const char *)data.get_data(), data.get_length());
+  _out->write((const char *)data.get_data(), data.get_length());
 
-  return !_out.fail();
+  return !_out->fail();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -65,7 +123,11 @@ put_datagram(const Datagram &data) {
 ////////////////////////////////////////////////////////////////////
 bool DatagramOutputFile::
 is_error() {
-  if (_out.fail()) {
+  if (_out == (ostream *)NULL) {
+    return true;
+  }
+
+  if (_out->fail()) {
     _error = true;
   }
   return _error;

+ 8 - 5
panda/src/putil/datagramOutputFile.h

@@ -19,7 +19,7 @@
 #ifndef DATAGRAMOUTPUTFILE_H
 #define DATAGRAMOUTPUTFILE_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "datagramSink.h"
 #include "filename.h"
@@ -34,18 +34,21 @@ class EXPCL_PANDA DatagramOutputFile : public DatagramSink {
 public:
   INLINE DatagramOutputFile();
 
-  INLINE bool open(Filename filename);
+  bool open(Filename filename);
+  bool open(ostream &out);
+
+  void close();
 
   bool write_header(const string &header);
   virtual bool put_datagram(const Datagram &data);
   virtual bool is_error();
 
-  INLINE void close();
-
 private:
   bool _wrote_first_datagram;
   bool _error;
-  ofstream _out;
+  ofstream _out_file;
+  ostream *_out;
+  bool _owns_out;
 };
 
 #include "datagramOutputFile.I"