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