Panda3D
bamFile.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file bamFile.cxx
10  * @author drose
11  * @date 2000-07-02
12  */
13 
14 #include "bamFile.h"
15 #include "config_pgraph.h"
16 
17 #include "bam.h"
18 #include "bamCacheRecord.h"
19 #include "config_putil.h"
20 #include "bamReader.h"
21 #include "bamWriter.h"
22 #include "filename.h"
23 #include "config_express.h"
24 #include "virtualFileSystem.h"
25 #include "dcast.h"
26 
27 using std::string;
28 
29 /**
30  *
31  */
32 BamFile::
33 BamFile() {
34  _reader = nullptr;
35  _writer = nullptr;
36 }
37 
38 /**
39  *
40  */
41 BamFile::
42 ~BamFile() {
43  close();
44 }
45 
46 /**
47  * Attempts to open the indicated filename for reading. Returns true if
48  * successful, false on error.
49  */
50 bool BamFile::
51 open_read(const Filename &bam_filename, bool report_errors) {
52  close();
53 
54  if (!_din.open(bam_filename)) {
55  return false;
56  }
57 
58  return continue_open_read(bam_filename, report_errors);
59 }
60 
61 /**
62  * Attempts to open the indicated stream for reading. The filename is just
63  * for information purposes only. Returns true if successful, false on error.
64  */
65 bool BamFile::
66 open_read(std::istream &in, const string &bam_filename, bool report_errors) {
67  close();
68 
69  if (!_din.open(in)) {
70  return false;
71  }
72 
73  return continue_open_read(bam_filename, report_errors);
74 }
75 
76 /**
77  * Reads and returns the next object from the Bam file, or NULL if the end of
78  * the file has been reached, or if there is an error condition. Use is_eof()
79  * to differentiate these two cases.
80  *
81  * The pointers returned by this method will not be valid for use until
82  * resolve() is subsequently called.
83  */
86  if (_reader == nullptr) {
87  return nullptr;
88  }
89 
90  return _reader->read_object();
91 }
92 
93 /**
94  * Returns true if the reader has reached end-of-file, false otherwise. This
95  * call is only valid after a call to read_object().
96  */
97 bool BamFile::
98 is_eof() const {
99  return _reader != nullptr && _reader->is_eof();
100 }
101 
102 /**
103  * This must be called after one or more objects have been read via calls to
104  * read_object() in order to resolve all internal pointer references in the
105  * objects read and make all the pointers valid. It returns true if all
106  * objects are successfully resolved, or false if some have not been (in which
107  * case you must call resolve() again later).
108  */
109 bool BamFile::
111  if (_reader == nullptr) {
112  return false;
113  }
114 
115  return _reader->resolve();
116 }
117 
118 /**
119  * Although the bam file format is general enough to store a list of objects
120  * of arbitrary type, bam files on disk usually contain just one object, a
121  * PandaNode that is the root of a scene graph. (Bam files that store other
122  * kinds of things are usually given the extension "boo", for "binary other
123  * objects", to differentiate them from the normal scene graph type file.)
124  *
125  * This is a convenience method for when you believe you are reading a scene
126  * graph bam file. It reads the one PandaNode and returns it. It also calls
127  * resolve() to fully resolve the object, since we expect this will be the
128  * only object in the file.
129  *
130  * If the bam file contains something other than a PandaNode, an error is
131  * printed and NULL is returned.
132  */
133 PT(PandaNode) BamFile::
134 read_node(bool report_errors) {
135  PT(PandaNode) result;
136 
137  TypedWritable *object = read_object();
138 
139  if (object != nullptr &&
140  object->is_exact_type(BamCacheRecord::get_class_type())) {
141  // Here's a special case: if the first object in the file is a
142  // BamCacheRecord, it's really a cache data file and not a true bam file;
143  // but skip over the cache data record and let the user treat it like an
144  // ordinary bam file.
145  object = read_object();
146  }
147 
148  if (object == TypedWritable::Null) {
149  if (report_errors) {
150  loader_cat.error() << "Bam file " << _bam_filename << " is empty.\n";
151  }
152 
153  } else if (!object->is_of_type(PandaNode::get_class_type())) {
154  if (report_errors) {
155  loader_cat.error()
156  << "Bam file " << _bam_filename
157  << " contains a " << object->get_type() << ", not a PandaNode.\n";
158  }
159 
160  } else {
161  result = DCAST(PandaNode, object);
162 
163  if (report_errors) {
164  read_object();
165  if (!is_eof()) {
166  loader_cat.warning()
167  << "Ignoring extra objects in " << _bam_filename << "\n";
168  }
169  }
170  }
171 
172  if (!resolve()) {
173  if (report_errors) {
174  loader_cat.error()
175  << "Unable to resolve Bam file.\n";
176  }
177  result = nullptr;
178  }
179 
180  return result;
181 }
182 
183 
184 /**
185  * Attempts to open the indicated file for writing. If another file by the
186  * same name already exists, it will be silently removed. Returns true if
187  * successful, false otherwise.
188  */
189 bool BamFile::
190 open_write(const Filename &bam_filename, bool report_errors) {
191  close();
192 
194  vfs->delete_file(bam_filename);
195  if (!_dout.open(bam_filename)) {
196  if (report_errors) {
197  loader_cat.error() << "Unable to open " << bam_filename << "\n";
198  }
199  return false;
200  }
201 
202  return continue_open_write(bam_filename, report_errors);
203 }
204 
205 /**
206  * Attempts to open the indicated stream for writing. The filename is just
207  * for information purposes only. Returns true if successful, false on error.
208  */
209 bool BamFile::
210 open_write(std::ostream &out, const string &bam_filename, bool report_errors) {
211  close();
212 
213  if (!_dout.open(out)) {
214  loader_cat.error() << "Could not write bam: " << bam_filename << "\n";
215  return false;
216  }
217 
218  return continue_open_write(bam_filename, report_errors);
219 }
220 
221 /**
222  * Writes the indicated object to the Bam file. Returns true if successful,
223  * false on error.
224  */
225 bool BamFile::
226 write_object(const TypedWritable *object) {
227  if (_writer == nullptr) {
228  return false;
229  }
230 
231  if (!_writer->write_object(object)) {
232  close();
233  return false;
234  }
235 
236  return true;
237 }
238 
239 /**
240  * Closes the input or output stream.
241  */
242 void BamFile::
243 close() {
244  if (_reader != nullptr) {
245  // resolve();
246  delete _reader;
247  _reader = nullptr;
248  }
249  if (_writer != nullptr) {
250  delete _writer;
251  _writer = nullptr;
252  }
253  _din.close();
254  _dout.close();
255 }
256 
257 
258 /**
259  * Returns the major version number of the file currently being read, or the
260  * system current major version number if no file is currently open for
261  * reading.
262  */
263 int BamFile::
265  if (_reader == nullptr) {
266  return _bam_major_ver;
267  }
268  return _reader->get_file_major_ver();
269 }
270 
271 /**
272  * Returns the minor version number of the file currently being read, or the
273  * system current minor version number if no file is currently open for
274  * reading.
275  */
276 int BamFile::
278  if (_reader == nullptr) {
279  return _bam_minor_ver;
280  }
281  return _reader->get_file_minor_ver();
282 }
283 
284 /**
285  * Returns the endian preference indicated by the Bam file currently being
286  * read or written.
287  */
288 BamFile::BamEndian BamFile::
289 get_file_endian() const {
290  if (_writer != nullptr) {
291  return _writer->get_file_endian();
292  }
293  if (_reader != nullptr) {
294  return _reader->get_file_endian();
295  }
296 
297  return bam_endian;
298 }
299 
300 /**
301  * Returns true if the file stores all "standard" floats as 64-bit doubles, or
302  * false if they are 32-bit floats.
303  */
304 bool BamFile::
305 get_file_stdfloat_double() const {
306  if (_writer != nullptr) {
307  return _writer->get_file_stdfloat_double();
308  }
309  if (_reader != nullptr) {
310  return _reader->get_file_stdfloat_double();
311  }
312 
313  return bam_stdfloat_double;
314 }
315 
316 /**
317  * Returns the system current major version number. This is the version
318  * number that will be assigned to any generated Bam files.
319  */
320 int BamFile::
322  return _bam_major_ver;
323 }
324 
325 /**
326  * Returns the system current minor version number. This is the version
327  * number that will be assigned to any generated Bam files.
328  */
329 int BamFile::
331  return _bam_minor_ver;
332 }
333 
334 /**
335  * Returns the BamReader in charge of performing the read operations. This
336  * will return NULL unless open_read() was called.
337  */
338 BamReader *BamFile::
339 get_reader() {
340  return _reader;
341 }
342 
343 /**
344  * Returns the BamWriter in charge of performing the write operations. This
345  * will return NULL unless open_write() was called.
346  */
347 BamWriter *BamFile::
348 get_writer() {
349  return _writer;
350 }
351 
352 /**
353  * Reads the header of the recently-opened bam stream and prepares to read the
354  * contents of the file. Returns true if successful, false otherwise.
355  */
356 bool BamFile::
357 continue_open_read(const string &bam_filename, bool report_errors) {
358  _bam_filename = bam_filename;
359 
360  if (!_bam_filename.empty()) {
361  loader_cat.info()
362  << "Reading " << _bam_filename << "\n";
363  }
364 
365  string head;
366  if (!_din.read_header(head, _bam_header.size())) {
367  if (report_errors) {
368  loader_cat.error() << _bam_filename << " is not a valid BAM file.\n";
369  }
370  return false;
371  }
372 
373  if (head != _bam_header) {
374  if (report_errors) {
375  loader_cat.error() << _bam_filename << " is not a valid BAM file.\n";
376  }
377  return false;
378  }
379 
380  _reader = new BamReader(&_din);
381  if (!_reader->init()) {
382  close();
383  return false;
384  }
385 
386  return true;
387 }
388 
389 /**
390  * Writers the header of the recently-opened bam stream and prepares to write
391  * the contents of the file. Returns true if successful, false otherwise.
392  */
393 bool BamFile::
394 continue_open_write(const string &bam_filename, bool report_errors) {
395  _bam_filename = bam_filename;
396 
397  if (!_bam_filename.empty()) {
398  loader_cat.info() << "Writing " << _bam_filename << "\n";
399  }
400 
401  if (!_dout.write_header(_bam_header)) {
402  if (report_errors) {
403  loader_cat.error() << "Unable to write to " << _bam_filename << "\n";
404  }
405  return false;
406  }
407 
408  _writer = new BamWriter(&_dout);
409 
410  if (!_writer->init()) {
411  close();
412  return false;
413  }
414 
415  return true;
416 }
bool write_object(const TypedWritable *object)
Writes the indicated object to the Bam file.
Definition: bamFile.cxx:226
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
Definition: bamFile.cxx:51
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
bool resolve()
This must be called after one or more objects have been read via calls to read_object() in order to r...
Definition: bamFile.cxx:110
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(PandaNode) BamFile
Although the bam file format is general enough to store a list of objects of arbitrary type,...
Definition: bamFile.cxx:133
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
bool resolve()
This may be called at any time during processing of the Bam file to resolve all the known pointers so...
Definition: bamReader.cxx:325
int get_file_major_ver()
Returns the major version number of the file currently being read, or the system current major versio...
Definition: bamFile.cxx:264
A hierarchy of directories and files that appears to be one continuous file system,...
TypedWritable * read_object()
Reads a single object from the Bam file.
Definition: bamReader.cxx:224
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
bool read_header(std::string &header, size_t num_bytes)
Reads a sequence of bytes from the beginning of the datagram file.
bool write_header(const std::string &header)
Writes a sequence of bytes to the beginning of the datagram file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void close()
Closes the file.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
bool open(const FileReference *file)
Opens the indicated filename for reading.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void close()
Closes the input or output stream.
Definition: bamFile.cxx:243
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
bool open(const FileReference *file)
Opens the indicated filename for writing.
int get_file_major_ver() const
Returns the major version number of the Bam file currently being read.
Definition: bamReader.I:75
bool init()
Initializes the BamReader prior to reading any objects from its source.
Definition: bamReader.cxx:85
bool is_eof() const
Returns true if the reader has reached end-of-file, false otherwise.
Definition: bamFile.cxx:98
get_file_stdfloat_double
Returns true if the file stores all "standard" floats as 64-bit doubles, or false if they are 32-bit ...
Definition: bamReader.h:160
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_current_minor_ver()
Returns the system current minor version number.
Definition: bamFile.cxx:330
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
bool write_object(const TypedWritable *obj)
Writes a single object to the Bam file, so that the BamReader::read_object() can later correctly rest...
Definition: bamWriter.cxx:204
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_current_major_ver()
Returns the system current major version number.
Definition: bamFile.cxx:321
get_file_endian
Returns the endian preference indicated by the Bam file currently being read.
Definition: bamReader.h:159
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
get_file_endian
Returns the endian preference indicated by the Bam file currently being written.
Definition: bamWriter.h:93
get_file_stdfloat_double
Returns true if the file will store all "standard" floats as 64-bit doubles, or false if they are 32-...
Definition: bamWriter.h:94
bool delete_file(const Filename &filename)
Attempts to delete the indicated file or directory.
bool open_write(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated file for writing.
Definition: bamFile.cxx:190
void close()
Closes the file.
bool init()
Initializes the BamWriter prior to writing any objects to its output stream.
Definition: bamWriter.cxx:147
int get_file_minor_ver()
Returns the minor version number of the file currently being read, or the system current minor versio...
Definition: bamFile.cxx:277
bool is_eof() const
Returns true if the reader has reached end-of-file, false otherwise.
Definition: bamReader.I:66
TypedWritable * read_object()
Reads and returns the next object from the Bam file, or NULL if the end of the file has been reached,...
Definition: bamFile.cxx:85
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.