Panda3D
bamReader.h
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 bamReader.h
10  * @author jason
11  * @date 2000-06-12
12  */
13 
14 #ifndef __BAM_READER_
15 #define __BAM_READER_
16 
17 #include "pandabase.h"
18 #include "pnotify.h"
19 
20 #include "typedWritable.h"
22 #include "pointerTo.h"
23 #include "datagramGenerator.h"
24 #include "datagramIterator.h"
25 #include "bamReaderParam.h"
26 #include "bamEnums.h"
27 #include "subfileInfo.h"
28 #include "loaderOptions.h"
29 #include "factory.h"
30 #include "vector_int.h"
31 #include "pset.h"
32 #include "pmap.h"
33 #include "pdeque.h"
34 #include "dcast.h"
35 #include "pipelineCyclerBase.h"
36 #include "referenceCount.h"
37 
38 #include <algorithm>
39 
40 
41 // A handy macro for reading PointerToArrays.
42 #define READ_PTA(Manager, source, Read_func, array) \
43 { \
44  void *t; \
45  if ((t = Manager->get_pta(source)) == nullptr) \
46  { \
47  array = Read_func(Manager, source); \
48  Manager->register_pta(array.get_void_ptr()); \
49  } \
50  else \
51  { \
52  array.set_void_ptr(t); \
53  } \
54 }
55 
56 /**
57  * Stores auxiliary data that may be piggybacked on the BamReader during each
58  * object's read pass. To use this, subclass BamReaderAuxData and add
59  * whatever additional data you require.
60  */
61 class EXPCL_PANDA_PUTIL BamReaderAuxData : public TypedReferenceCount {
62 public:
63  INLINE BamReaderAuxData();
64 
65 public:
66  virtual TypeHandle get_type() const {
67  return get_class_type();
68  }
69  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
70  static TypeHandle get_class_type() {
71  return _type_handle;
72  }
73 
74 public:
75  static void init_type() {
76  TypedReferenceCount::init_type();
77  register_type(_type_handle, "BamReaderAuxData",
78  TypedReferenceCount::get_class_type());
79  }
80 
81 private:
82  static TypeHandle _type_handle;
83 };
84 
85 /**
86  * This is the fundamental interface for extracting binary objects from a Bam
87  * file, as generated by a BamWriter.
88  *
89  * A Bam file can be thought of as a linear collection of objects. Each
90  * object is an instance of a class that inherits, directly or indirectly,
91  * from TypedWritable. The objects may include pointers to other objects
92  * within the Bam file; the BamReader automatically manages these (with help
93  * from code within each class) and restores the pointers correctly.
94  *
95  * This is the abstract interface and does not specifically deal with disk
96  * files, but rather with a DatagramGenerator of some kind, which is simply a
97  * linear source of Datagrams. It is probably from a disk file, but it might
98  * conceivably be streamed directly from a network or some such nonsense.
99  *
100  * Bam files are most often used to store scene graphs or subgraphs, and by
101  * convention they are given filenames ending in the extension ".bam" when
102  * they are used for this purpose. However, a Bam file may store any
103  * arbitrary list of TypedWritable objects; in this more general usage, they
104  * are given filenames ending in ".boo" to differentiate them from the more
105  * common scene graph files.
106  *
107  * See also BamFile, which defines a higher-level interface to read and write
108  * Bam files on disk.
109  */
110 class EXPCL_PANDA_PUTIL BamReader : public BamEnums {
111 public:
113  static BamReader *const Null;
114  static WritableFactory *const NullFactory;
115 
116 PUBLISHED:
117  // The primary interface for a caller.
118  explicit BamReader(DatagramGenerator *source = nullptr);
119  ~BamReader();
120 
121  void set_source(DatagramGenerator *source);
122  INLINE DatagramGenerator *get_source();
123 
124  bool init();
125 
126  class AuxData;
127  void set_aux_data(TypedWritable *obj, const std::string &name, AuxData *data);
128  AuxData *get_aux_data(TypedWritable *obj, const std::string &name) const;
129 
130  INLINE const Filename &get_filename() const;
131 
132  INLINE const LoaderOptions &get_loader_options() const;
133  INLINE void set_loader_options(const LoaderOptions &options);
134 
135  BLOCKING TypedWritable *read_object();
136  BLOCKING bool read_object(TypedWritable *&ptr, ReferenceCount *&ref_ptr);
137 
138  INLINE bool is_eof() const;
139  bool resolve();
140 
141  bool change_pointer(const TypedWritable *orig_pointer, const TypedWritable *new_pointer);
142 
143  INLINE int get_file_major_ver() const;
144  INLINE int get_file_minor_ver() const;
145  INLINE BamEndian get_file_endian() const;
146  INLINE bool get_file_stdfloat_double() const;
147 
148  INLINE int get_current_major_ver() const;
149  INLINE int get_current_minor_ver() const;
150 
151  EXTENSION(PyObject *get_file_version() const);
152 
153 PUBLISHED:
154  MAKE_PROPERTY(source, get_source, set_source);
155  MAKE_PROPERTY(filename, get_filename);
156  MAKE_PROPERTY(loader_options, get_loader_options, set_loader_options);
157 
158  MAKE_PROPERTY(file_version, get_file_version);
159  MAKE_PROPERTY(file_endian, get_file_endian);
160  MAKE_PROPERTY(file_stdfloat_double, get_file_stdfloat_double);
161 
162 public:
163  // Functions to support classes that read themselves from the Bam.
164 
165  bool read_pointer(DatagramIterator &scan);
166  void read_pointers(DatagramIterator &scan, int count);
167  void skip_pointer(DatagramIterator &scan);
168 
169  void read_file_data(SubfileInfo &info);
170 
171  void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler);
172  void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler,
173  void *extra_data);
174 
175  void set_int_tag(const std::string &tag, int value);
176  int get_int_tag(const std::string &tag) const;
177 
178  void set_aux_tag(const std::string &tag, BamReaderAuxData *value);
179  BamReaderAuxData *get_aux_tag(const std::string &tag) const;
180 
181  void register_finalize(TypedWritable *whom);
182 
183  typedef TypedWritable *(*ChangeThisFunc)(TypedWritable *object, BamReader *manager);
184  typedef PT(TypedWritableReferenceCount) (*ChangeThisRefFunc)(TypedWritableReferenceCount *object, BamReader *manager);
185  void register_change_this(ChangeThisFunc func, TypedWritable *whom);
186  void register_change_this(ChangeThisRefFunc func, TypedWritableReferenceCount *whom);
187 
188  void finalize_now(TypedWritable *whom);
189 
190  void *get_pta(DatagramIterator &scan);
191  void register_pta(void *ptr);
192 
193  TypeHandle read_handle(DatagramIterator &scan);
194 
195  INLINE const FileReference *get_file();
196  INLINE VirtualFile *get_vfile();
197  INLINE std::streampos get_file_pos();
198 
199 public:
200  INLINE static void register_factory(TypeHandle type, WritableFactory::CreateFunc *func,
201  void *user_data = nullptr);
202  INLINE static WritableFactory *get_factory();
203 
204 PUBLISHED:
205  EXTENSION(static void register_factory(TypeHandle handle, PyObject *func));
206 
207 private:
208  INLINE static void create_factory();
209 
210 private:
211  class PointerReference;
212 
213  void free_object_ids(DatagramIterator &scan);
214  int read_object_id(DatagramIterator &scan);
215  int read_pta_id(DatagramIterator &scan);
216  int p_read_object();
217  bool resolve_object_pointers(TypedWritable *object, PointerReference &pref);
218  bool resolve_cycler_pointers(PipelineCyclerBase *cycler, const vector_int &pointer_ids,
219  bool require_fully_complete);
220  void finalize();
221 
222  INLINE bool get_datagram(Datagram &datagram);
223 
224 public:
225  // Inherit from this class to piggyback additional temporary data on the
226  // bamReader (via set_aux_data() and get_aux_data()) for any particular
227  // objects during the bam reading process.
228  class AuxData : public ReferenceCount {
229  public:
230  INLINE AuxData();
231  virtual ~AuxData() = default;
232  };
233 
234 private:
235  static WritableFactory *_factory;
236 
237  DatagramGenerator *_source;
238  bool _needs_init;
239 
240  bool _long_object_id;
241  bool _long_pta_id;
242 
243  // This maps the type index numbers encountered within the Bam file to
244  // actual TypeHandles.
245  typedef phash_map<int, TypeHandle, int_hash> IndexMap;
246  IndexMap _index_map;
247 
248  LoaderOptions _loader_options;
249 
250  // This maps the object ID numbers encountered within the Bam file to the
251  // actual pointers of the corresponding generated objects.
252  class CreatedObj {
253  public:
254  INLINE CreatedObj();
255  INLINE ~CreatedObj();
256  INLINE void set_ptr(TypedWritable *ptr, ReferenceCount *ref_ptr);
257 
258  public:
259  bool _created;
260  TypedWritable *_ptr;
261  ReferenceCount *_ref_ptr;
262  ChangeThisFunc _change_this;
263  ChangeThisRefFunc _change_this_ref;
264  };
265  typedef phash_map<int, CreatedObj, int_hash> CreatedObjs;
266  CreatedObjs _created_objs;
267  // This is the iterator into the above map for the object we are currently
268  // reading in p_read_object(). It is carefully maintained during recursion.
269  // We need this so we can associate read_pointer() calls with the proper
270  // objects.
271  CreatedObjs::iterator _now_creating;
272  // This is the pointer to the current PipelineCycler we are reading, if we
273  // are within a read_cdata() call.
274  PipelineCyclerBase *_reading_cycler;
275 
276  // This is the reverse lookup into the above map.
277  typedef phash_map<const TypedWritable *, vector_int, pointer_hash> CreatedObjsByPointer;
278  CreatedObjsByPointer _created_objs_by_pointer;
279 
280  // This records all the objects that still need their pointers completed,
281  // along with the object ID's of the pointers they need, in the order in
282  // which read_pointer() was called, so that we may call the appropriate
283  // complete_pointers() later.
284  typedef phash_map<PipelineCyclerBase *, vector_int, pointer_hash> CyclerPointers;
285  typedef pmap<std::string, int> IntTags;
286  typedef pmap<std::string, PT(BamReaderAuxData) > AuxTags;
287  class PointerReference {
288  public:
289  vector_int _objects;
290  CyclerPointers _cycler_pointers;
291  IntTags _int_tags;
292  AuxTags _aux_tags;
293  };
294  typedef phash_map<int, PointerReference, int_hash> ObjectPointers;
295  ObjectPointers _object_pointers;
296 
297  // This is the number of extra objects that must still be read (and saved in
298  // the _created_objs map) before returning from read_object(). It is only
299  // used when read bam versions prior to 6.20.
300  int _num_extra_objects;
301 
302  // The current nesting level. We are not done reading an object until we
303  // return to our starting nesting level. It is only used when reading bam
304  // versions of 6.20 or higher.
305  int _nesting_level;
306 
307  // This is the set of all objects that registered themselves for
308  // finalization.
309  typedef phash_set<TypedWritable *, pointer_hash> Finalize;
310  Finalize _finalize_list;
311 
312  // These are used by get_pta() and register_pta() to unify multiple
313  // references to the same PointerToArray.
314  typedef phash_map<int, void *, int_hash> PTAMap;
315  PTAMap _pta_map;
316  int _pta_id;
317 
318  // This is a queue of the currently-pending file data blocks that we have
319  // recently encountered in the stream and still expect a subsequent object
320  // to request.
321  typedef pdeque<SubfileInfo> FileDataRecords;
322  FileDataRecords _file_data_records;
323 
324  // This is used internally to record all of the new types created on-the-fly
325  // to satisfy bam requirements. We keep track of this just so we can
326  // suppress warning messages from attempts to create objects of these types.
327  typedef phash_set<TypeHandle> NewTypes;
328  static NewTypes _new_types;
329 
330  // This is used in support of set_aux_data() and get_aux_data().
331  typedef pmap<std::string, PT(AuxData)> AuxDataNames;
332  typedef phash_map<TypedWritable *, AuxDataNames, pointer_hash> AuxDataTable;
333  AuxDataTable _aux_data;
334 
335  int _file_major, _file_minor;
336  BamEndian _file_endian;
337  bool _file_stdfloat_double;
338  static const int _cur_major;
339  static const int _cur_minor;
340 };
341 
343 
344 // Useful function for taking apart the Factory Params in the static functions
345 // that need to be defined in each writable class that will be generated by a
346 // factory. Sets the DatagramIterator and the BamReader pointers.
347 INLINE void
348 parse_params(const FactoryParams &params,
349  DatagramIterator &scan, BamReader *&manager);
350 
351 #include "bamReader.I"
352 
353 #endif
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Keeps a reference-counted pointer to a file on disk.
Definition: fileReference.h:26
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Stores auxiliary data that may be piggybacked on the BamReader during each object's read pass.
Definition: bamReader.h:61
A Factory can be used to create an instance of a particular subclass of some general base class.
Definition: factory.h:34
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Definition: register_type.I:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the trivial, non-threaded implementation of PipelineCyclerBase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for all things that want to be reference-counted.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:26
A class to retrieve the individual data elements previously stored in a Datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This class defines the abstract interace to any source of datagrams, whether it be from a file or fro...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class exists just to provide scoping for the enums shared by BamReader and BamWriter.
Definition: bamEnums.h:23