Panda3D
Loading...
Searching...
No Matches
bamReader.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 bamReader.cxx
10 * @author jason
11 * @date 2000-06-12
12 */
13
14#include "pandabase.h"
15#include "pnotify.h"
16
17#include "bam.h"
18#include "bamReader.h"
19#include "datagramIterator.h"
20#include "config_putil.h"
21#include "pipelineCyclerBase.h"
22
23using std::string;
24
25TypeHandle BamReaderAuxData::_type_handle;
26
27WritableFactory *BamReader::_factory = nullptr;
28BamReader *const BamReader::Null = nullptr;
29WritableFactory *const BamReader::NullFactory = nullptr;
30
31BamReader::NewTypes BamReader::_new_types;
32
33const int BamReader::_cur_major = _bam_major_ver;
34const int BamReader::_cur_minor = _bam_minor_ver;
35
36
37/**
38 *
39 */
40BamReader::
41BamReader(DatagramGenerator *source)
42 : _source(source)
43{
44 _needs_init = true;
45 _num_extra_objects = 0;
46 _nesting_level = 0;
47 _now_creating = _created_objs.end();
48 _reading_cycler = nullptr;
49 _pta_id = -1;
50 _long_object_id = false;
51 _long_pta_id = false;
52}
53
54
55/**
56 *
57 */
58BamReader::
59~BamReader() {
60 nassertv(_num_extra_objects == 0);
61 nassertv(_nesting_level == 0);
62}
63
64/**
65 * Changes the source of future datagrams for this BamReader. This also
66 * implicitly calls init() if it has not already been called.
67 */
68void BamReader::
70 _source = source;
71 if (_needs_init && _source != nullptr) {
72 bool success = init();
73 nassertv(success);
74 }
75}
76
77/**
78 * Initializes the BamReader prior to reading any objects from its source.
79 * This includes reading the Bam header.
80 *
81 * This returns true if the BamReader successfully initialized, false
82 * otherwise.
83 */
85init() {
86 nassertr(_source != nullptr, false);
87 nassertr(_needs_init, false);
88 _needs_init = false;
89 Datagram header;
90
91 if (_source->is_error()) {
92 return false;
93 }
94
95 if (!get_datagram(header)) {
96 bam_cat.error()
97 << "Unable to read Bam header.\n";
98 return false;
99 }
100
101 DatagramIterator scan(header);
102
103 _file_major = scan.get_uint16();
104 _file_minor = scan.get_uint16();
105
106 // If the major version is different, or the minor version is *newer*, we
107 // can't safely load the file.
108 if (_file_major != _bam_major_ver ||
109 _file_minor < _bam_first_minor_ver ||
110 _file_minor > _bam_last_minor_ver) {
111 bam_cat.error()
112 << "Bam file is version " << _file_major << "." << _file_minor
113 << ".\n";
114
115 if (_bam_minor_ver == _bam_first_minor_ver) {
116 bam_cat.error()
117 << "This program can only load version "
118 << _bam_major_ver << "." << _bam_first_minor_ver << " bams.\n";
119 } else {
120 bam_cat.error()
121 << "This program can only load version "
122 << _bam_major_ver << "." << _bam_first_minor_ver << " through "
123 << _bam_major_ver << "." << _bam_last_minor_ver << " bams.\n";
124 }
125
126 return false;
127 }
128
129 _file_endian = (BamEndian)scan.get_uint8();
130
131 _file_stdfloat_double = false;
132 if (_file_minor >= 27) {
133 _file_stdfloat_double = scan.get_bool();
134 }
135
136 if (scan.get_current_index() > header.get_length()) {
137 bam_cat.error()
138 << "Bam header is too short.\n";
139 return false;
140 }
141
142 return true;
143}
144
145/**
146 * Associates an arbitrary block of data with the indicated object (or NULL),
147 * and the indicated name.
148 *
149 * This is intended to provide a place for temporary storage for objects
150 * reading themselves from the bam file. To use it, inherit from
151 * BamReader::AuxData and store whatever data you like there. Then associate
152 * your AuxData with the object as it is being read with set_aux_data(). You
153 * may later set the aux data to NULL to remove it; or it will automatically
154 * be removed (and deleted) after finalize() is called for the object in
155 * question.
156 *
157 * If the TypedWritable pointer is NULL, the the aux data is stored globally
158 * for the BamReader in general. This pointer is available to any bam
159 * objects, and will not be automatically removed until the BamReader itself
160 * destructs.
161 *
162 * In either case, the name is just an arbitrary user-defined key. If there
163 * is already a data pointer stored for the obj/name pair, that data pointer
164 * will be replaced (and deleted).
165 */
167set_aux_data(TypedWritable *obj, const string &name, BamReader::AuxData *data) {
168 if (data == nullptr) {
169 AuxDataTable::iterator ti = _aux_data.find(obj);
170 if (ti != _aux_data.end()) {
171 AuxDataNames &names = (*ti).second;
172 names.erase(name);
173 if (names.empty()) {
174 _aux_data.erase(ti);
175 }
176 }
177
178 } else {
179 _aux_data[obj][name] = data;
180 }
181}
182
183/**
184 * Returns the pointer previously associated with the bam reader by a previous
185 * call to set_aux_data(), or NULL if data with the indicated key has not been
186 * set.
187 */
189get_aux_data(TypedWritable *obj, const string &name) const {
190 AuxDataTable::const_iterator ti = _aux_data.find(obj);
191 if (ti != _aux_data.end()) {
192 const AuxDataNames &names = (*ti).second;
193 AuxDataNames::const_iterator ni = names.find(name);
194 if (ni != names.end()) {
195 return (*ni).second;
196 }
197 }
198
199 return nullptr;
200}
201
202
203/**
204 * Reads a single object from the Bam file. If the object type is known, a
205 * new object of the appropriate type is created and returned; otherwise, NULL
206 * is returned. NULL is also returned when the end of the file is reached.
207 * is_eof() may be called to differentiate between these two cases.
208 *
209 * This may be called repeatedly to extract out all the objects in the Bam
210 * file, but typically (especially for scene graph files, indicated with the
211 * .bam extension), only one object is retrieved directly from the Bam file:
212 * the root of the scene graph. The remaining objects will all be retrieved
213 * recursively by the first object.
214 *
215 * Note that the object returned may not yet be complete. In particular, some
216 * of its pointers may not be filled in; you must call resolve() to fill in
217 * all the available pointers before you can safely use any objects returned
218 * by read_object().
219 *
220 * This flavor of read_object() requires the caller to know what type of
221 * object it has received in order to properly manage the reference counts.
222 */
224read_object() {
225 TypedWritable *ptr;
226 ReferenceCount *ref_ptr;
227
228 if (!read_object(ptr, ref_ptr)) {
229 return nullptr;
230 }
231
232 return ptr;
233}
234
235/**
236 * Reads a single object from the Bam file.
237 *
238 * This flavor of read_object() returns both a TypedWritable and a
239 * ReferenceCount pointer to the same object, so the reference count may be
240 * tracked reliably, without having to know precisely what type of object we
241 * have.
242 * @return true on success, or false on failure.
243 */
245read_object(TypedWritable *&ptr, ReferenceCount *&ref_ptr) {
246 ptr = nullptr;
247 ref_ptr = nullptr;
248 nassertr(_num_extra_objects == 0, false);
249
250 int start_level = _nesting_level;
251
252 // First, read the base object.
253 int object_id = p_read_object();
254
255 // Now that object might have included some pointers to other objects, which
256 // may still need to be read. And those objects might in turn require
257 // reading additional objects. Read all the remaining objects.
258
259 // Prior to 6.21, we kept track of _num_extra_objects to know when we're
260 // done.
261 while (_num_extra_objects > 0) {
262 p_read_object();
263 _num_extra_objects--;
264 }
265
266 // Beginning with 6.21, we use explicit nesting commands to know when we're
267 // done.
268 while (_nesting_level > start_level) {
269 p_read_object();
270 }
271
272 // Now look up the pointer of the object we read first. It should be
273 // available now.
274 if (object_id == 0) {
275 if (bam_cat.is_spam()) {
276 bam_cat.spam()
277 << "Returning false\n";
278 }
279 return false;
280 }
281
282 CreatedObjs::iterator oi = _created_objs.find(object_id);
283
284 if (oi == _created_objs.end()) {
285 bam_cat.error()
286 << "Undefined object encountered!\n";
287 return false;
288
289 } else {
290 CreatedObj &created_obj = (*oi).second;
291 ptr = created_obj._ptr;
292 ref_ptr = created_obj._ref_ptr;
293
294 if (bam_cat.is_spam()) {
295 if (ptr != nullptr) {
296 bam_cat.spam()
297 << "Returning object of type " << ptr->get_type() << "\n";
298 }
299 }
300 if (created_obj._change_this != nullptr ||
301 created_obj._change_this_ref != nullptr) {
302 bam_cat.warning()
303 << "Returning pointer to " << ptr->get_type()
304 << " that might change.\n";
305 }
306
307 return true;
308 }
309}
310
311/**
312 * This may be called at any time during processing of the Bam file to resolve
313 * all the known pointers so far. It is usually called at the end of the
314 * processing, after all objects have been read, which is generally the best
315 * time to call it.
316 *
317 * This must be called at least once after reading a particular object via
318 * read_object() in order to validate that object.
319 *
320 * The return value is true if all objects have been resolved, or false if
321 * some objects are still outstanding (in which case you will need to call
322 * resolve() again later).
323 */
325resolve() {
326 bool all_completed;
327 bool any_completed_this_pass;
328
329 do {
330 if (bam_cat.is_spam()) {
331 bam_cat.spam()
332 << "resolve pass begin\n";
333 }
334 all_completed = true;
335 any_completed_this_pass = false;
336
337 ObjectPointers::iterator oi;
338 oi = _object_pointers.begin();
339 while (oi != _object_pointers.end()) {
340 int object_id = (*oi).first;
341 PointerReference &pref = (*oi).second;
342
343 CreatedObjs::iterator ci = _created_objs.find(object_id);
344 nassertr(ci != _created_objs.end(), false);
345
346 CreatedObj &created_obj = (*ci).second;
347
348 TypedWritable *object_ptr = created_obj._ptr;
349
350 // Update _now_creating, so a call to get_int_tag() from within
351 // complete_pointers() will come to the right place.
352 CreatedObjs::iterator was_creating = _now_creating;
353 _now_creating = ci;
354
355 if (resolve_object_pointers(object_ptr, pref)) {
356 // Now remove this object from the list of things that need
357 // completion. We have to be a bit careful when deleting things from
358 // the STL container while we are traversing it.
359 ObjectPointers::iterator old = oi;
360 ++oi;
361 _object_pointers.erase(old);
362 any_completed_this_pass = true;
363
364 // Does the pointer need to change?
365 if (created_obj._change_this_ref != nullptr) {
366 // Reference-counting variant.
367 TypedWritableReferenceCount *object_ref_ptr = (TypedWritableReferenceCount *)object_ptr;
368 nassertr(created_obj._ref_ptr == nullptr || created_obj._ref_ptr == object_ref_ptr, false);
369 PT(TypedWritableReferenceCount) new_ptr = created_obj._change_this_ref(object_ref_ptr, this);
370 if (new_ptr != object_ref_ptr) {
371 // Also update the reverse
372 vector_int &old_refs = _created_objs_by_pointer[object_ptr];
373 vector_int &new_refs = _created_objs_by_pointer[new_ptr];
374 for (vector_int::const_iterator oi = old_refs.begin();
375 oi != old_refs.end();
376 ++oi) {
377 new_refs.push_back(*oi);
378 }
379 _created_objs_by_pointer.erase(object_ptr);
380
381 // Remove the pointer from the finalize list (the new pointer
382 // presumably doesn't require finalizing).
383 _finalize_list.erase(object_ptr);
384 }
385 created_obj.set_ptr(new_ptr, new_ptr);
386 created_obj._change_this = nullptr;
387 created_obj._change_this_ref = nullptr;
388
389 } else if (created_obj._change_this != nullptr) {
390 // Non-reference-counting variant.
391 TypedWritable *new_ptr = created_obj._change_this(object_ptr, this);
392 if (new_ptr != object_ptr) {
393 // Also update the reverse
394 vector_int &old_refs = _created_objs_by_pointer[object_ptr];
395 vector_int &new_refs = _created_objs_by_pointer[new_ptr];
396 for (vector_int::const_iterator oi = old_refs.begin();
397 oi != old_refs.end();
398 ++oi) {
399 new_refs.push_back(*oi);
400 }
401 _created_objs_by_pointer.erase(object_ptr);
402
403 // Remove the pointer from the finalize list (the new pointer
404 // presumably doesn't require finalizing).
405 _finalize_list.erase(object_ptr);
406 }
407 created_obj.set_ptr(new_ptr, new_ptr->as_reference_count());
408 created_obj._change_this = nullptr;
409 created_obj._change_this_ref = nullptr;
410 }
411
412 } else {
413 // Couldn't complete this object yet; it'll wait for next time.
414 ++oi;
415 all_completed = false;
416 }
417
418 _now_creating = was_creating;
419 }
420
421 if (bam_cat.is_spam()) {
422 bam_cat.spam()
423 << "resolve pass end: all_completed = " << all_completed
424 << " any_completed_this_pass = " << any_completed_this_pass
425 << "\n";
426 }
427 } while (!all_completed && any_completed_this_pass);
428
429 if (all_completed) {
430 finalize();
431 } else {
432 // Report all the uncompleted objects for no good reason. This will
433 // probably have to come out later when we have cases in which some
434 // objects might legitimately be uncompleted after calling resolve(), but
435 // for now we expect resolve() to always succeed.
436 ObjectPointers::const_iterator oi;
437 for (oi = _object_pointers.begin();
438 oi != _object_pointers.end();
439 ++oi) {
440 int object_id = (*oi).first;
441 CreatedObjs::iterator ci = _created_objs.find(object_id);
442 nassertr(ci != _created_objs.end(), false);
443 CreatedObj &created_obj = (*ci).second;
444 TypedWritable *object_ptr = created_obj._ptr;
445
446 bam_cat.warning()
447 << "Unable to complete " << object_ptr->get_type() << "\n";
448 }
449 }
450
451 return all_completed;
452}
453
454/**
455 * Indicates that an object recently read from the bam stream should be
456 * replaced with a new object. Any future occurrences of the original object
457 * in the stream will henceforth return the new object instead.
458 *
459 * The return value is true if the replacement was successfully made, or false
460 * if the object was not read from the stream (or if change_pointer had
461 * already been called on it).
462 */
464change_pointer(const TypedWritable *orig_pointer, const TypedWritable *new_pointer) {
465 if (orig_pointer == new_pointer) {
466 return false;
467 }
468 CreatedObjsByPointer::iterator ci = _created_objs_by_pointer.find(orig_pointer);
469 if (ci == _created_objs_by_pointer.end()) {
470 // No record of this object.
471 return false;
472 }
473
474 if (bam_cat.is_spam()) {
475 bam_cat.spam()
476 << "change_pointer(" << (void *)orig_pointer << ", "
477 << (void *)new_pointer << ") (" << new_pointer->get_type() << ")\n";
478 }
479
480 const vector_int &old_refs = (*ci).second;
481 vector_int &new_refs = _created_objs_by_pointer[new_pointer];
482
483 for (vector_int::const_iterator oi = old_refs.begin();
484 oi != old_refs.end();
485 ++oi) {
486 int object_id = (*oi);
487
488 CreatedObjs::iterator ci = _created_objs.find(object_id);
489 nassertr(ci != _created_objs.end(), false);
490 nassertr((*ci).second._ptr == orig_pointer, false);
491
492 TypedWritable *ptr = (TypedWritable *)new_pointer;
493 (*ci).second.set_ptr(ptr, ptr->as_reference_count());
494 new_refs.push_back(object_id);
495 }
496
497 _created_objs_by_pointer.erase(ci);
498
499 // Also change the pointer on the finalize_list.
500 Finalize::iterator fi = _finalize_list.find((TypedWritable *)orig_pointer);
501 if (fi != _finalize_list.end()) {
502 _finalize_list.insert((TypedWritable *)new_pointer);
503 _finalize_list.erase(fi);
504 }
505
506 return true;
507}
508
509
510/**
511 * Reads a TypeHandle out of the Datagram.
512 */
515 // We encode TypeHandles within the Bam file by writing a unique index
516 // number for each one to the file. When we write a particular TypeHandle
517 // for the first time, we assign it a new index number and then immediately
518 // follow it by its definition; when we write the same TypeHandle on
519 // subsequent times we only write the index number.
520
521 // Thus, to read a TypeHandle, we first read the index number. If it is a
522 // number we have not yet encountered, we must then read the definition.
523
524 // Here's the index number.
525 int id = scan.get_uint16();
526
527 if (id == 0) {
528 // Index number 0 is always, by convention, TypeHandle::none().
529 return TypeHandle::none();
530 }
531
532 IndexMap::const_iterator mi = _index_map.find(id);
533 if (mi != _index_map.end()) {
534 // We've encountered this index number before, so there should be no type
535 // definition following the id. Simply return the TypeHandle we
536 // previously associated with the id.
537 TypeHandle type = (*mi).second;
538 return type;
539 }
540
541 // We haven't encountered this index number before. This means it will be
542 // immediately followed by the type definition. This consists of the string
543 // name, followed by the list of parent TypeHandles for this type.
544
545 string name = scan.get_string();
546 bool new_type = false;
547
548 TypeHandle type = TypeRegistry::ptr()->find_type(name);
549 if (type == TypeHandle::none()) {
550 // We've never heard of this type before! This is really an error
551 // condition, but we'll do the best we can and declare it on-the-fly.
552
554 bam_cat.warning()
555 << "Bam file '" << get_filename() << "' contains objects of unknown type: "
556 << type << "\n";
557 new_type = true;
558 _new_types.insert(type);
559 }
560
561 // Now pick up the derivation information.
562 int num_parent_classes = scan.get_uint8();
563 for (int i = 0; i < num_parent_classes; i++) {
564 TypeHandle parent_type = read_handle(scan);
565 if (new_type) {
566 TypeRegistry::ptr()->record_derivation(type, parent_type);
567 } else {
568 if (type.get_parent_towards(parent_type) != parent_type) {
569 if (bam_cat.is_debug()) {
570 bam_cat.debug()
571 << "Bam file indicates a derivation of " << type
572 << " from " << parent_type << " which is no longer true.\n";
573 }
574 }
575 }
576 }
577
578 bool inserted = _index_map.insert(IndexMap::value_type(id, type)).second;
579 nassertr(inserted, type);
580
581 if (bam_cat.is_spam()) {
582 bam_cat.spam()
583 << "Read TypeHandle for " << type << ".\n";
584 }
585
586 return type;
587}
588
589/**
590 * The interface for reading a pointer to another object from a Bam file.
591 * Objects reading themselves from a Bam file should call this when they
592 * expect to read a pointer to some other object. This function reads
593 * whatever is stored in the bam file to represent the pointer, and advances
594 * the datagram iterator accordingly.
595 *
596 * Rather than returning a pointer immediately, this function reads the
597 * internal pointer information from the datagram and queues up the request.
598 * The pointer itself may not be available until later (it may be a pointer to
599 * an object that appears later in the Bam file). Later, when all pointers
600 * are available, the complete_pointers() callback function will be called
601 * with an array of actual pointers, one for each time read_pointer() was
602 * called. It is then the calling object's responsibility to store these
603 * pointers in the object properly.
604 *
605 * We don't know what the final pointer will be yet, but we do know whether it
606 * was NULL, so this method returns true if the pointer is non-NULL, false if
607 * NULL.
608 */
612
613 nassertr(_now_creating != _created_objs.end(), false);
614 int requestor_id = (*_now_creating).first;
615
616 // Read the object ID, and associate it with the requesting object.
617 int object_id = read_object_id(scan);
618
619 PointerReference &pref = _object_pointers[requestor_id];
620 if (_reading_cycler == nullptr) {
621 // This is not being read within a read_cdata() call.
622 pref._objects.push_back(object_id);
623 } else {
624 // This *is* being read within a read_cdata() call.
625 pref._cycler_pointers[_reading_cycler].push_back(object_id);
626 }
627
628 // If the object ID is zero (which indicates a NULL pointer), we don't have
629 // to do anything else.
630 if (object_id != 0) {
631 /*
632 CreatedObj new_created_obj;
633 _created_objs.insert(CreatedObjs::value_type(object_id, new_created_obj)).second;
634 */
635
636 if (get_file_minor_ver() < 21) {
637 // Prior to bam version 6.21, we expect to read an adjunct object for
638 // each non-NULL pointer we read.
639 _num_extra_objects++;
640 }
641
642 return true;
643 } else {
644 return false;
645 }
646}
647
648/**
649 * A convenience function to read a contiguous list of pointers. This is
650 * equivalent to calling read_pointer() count times.
651 */
653read_pointers(DatagramIterator &scan, int count) {
654 for (int i = 0; i < count; i++) {
655 read_pointer(scan);
656 }
657}
658
659/**
660 * Reads and discards a pointer value from the Bam file. This pointer will
661 * not be counted among the pointers read for a given object, and will not be
662 * in the list of pointers passed to complete_pointers().
663 */
666 read_object_id(scan);
667}
668
669/**
670 * Reads a block of auxiliary file data from the Bam file. This can be a
671 * block of arbitrary size, and it is assumed it may be quite large. Rather
672 * than reading the entire block into memory, a file reference is returned to
673 * locate the block on disk. The data must have been written by a matching
674 * call to write_file_data().
675 */
678 // write_file_data() actually writes the blocks in datagrams prior to this
679 // particular datagram. Assume we get the calls to read_file_data() in the
680 // same order as the corresponding calls to write_file_data(), and just pop
681 // the first one off the queue. There's no actual data written to the
682 // stream at this point.
683 nassertv(!_file_data_records.empty());
684 info = _file_data_records.front();
685 _file_data_records.pop_front();
686}
687
688/**
689 * Reads in the indicated CycleData object. This should be used by classes
690 * that store some or all of their data within a CycleData subclass, in
691 * support of pipelining. This will call the virtual CycleData::fillin()
692 * method to do the actual reading.
693 */
696 PipelineCyclerBase *old_cycler = _reading_cycler;
697 _reading_cycler = &cycler;
698 CycleData *cdata = cycler.write(Thread::get_current_thread());
699 cdata->fillin(scan, this);
700 cycler.release_write(cdata);
701 _reading_cycler = old_cycler;
702}
703
704/**
705 * This flavor of read_cdata allows passing an additional parameter to
706 * cdata->fillin().
707 */
710 void *extra_data) {
711 PipelineCyclerBase *old_cycler = _reading_cycler;
712 _reading_cycler = &cycler;
713 CycleData *cdata = cycler.write(Thread::get_current_thread());
714 cdata->fillin(scan, this, extra_data);
715 cycler.release_write(cdata);
716 _reading_cycler = old_cycler;
717}
718
719/**
720 * Allows the creating object to store a temporary data value on the
721 * BamReader. This method may be called during an object's fillin() method;
722 * it will associate an integer value with an arbitrary string key (which is
723 * in turn associated with the calling object only). Later, in the
724 * complete_pointers() method, the same object may query this data again via
725 * get_int_tag().
726 *
727 * The tag string need not be unique between different objects, but it should
728 * be unique between an object and its CData object(s).
729 */
731set_int_tag(const string &tag, int value) {
732 nassertv(_now_creating != _created_objs.end());
733 int requestor_id = (*_now_creating).first;
734
735 PointerReference &pref = _object_pointers[requestor_id];
736 pref._int_tags[tag] = value;
737}
738
739/**
740 * Returns the value previously set via set_int_tag(). It is an error if no
741 * value has been set.
742 */
744get_int_tag(const string &tag) const {
745 nassertr(_now_creating != _created_objs.end(), 0);
746 int requestor_id = (*_now_creating).first;
747
748 ObjectPointers::const_iterator opi = _object_pointers.find(requestor_id);
749 nassertr(opi != _object_pointers.end(), 0);
750 const PointerReference &pref = (*opi).second;
751
752 IntTags::const_iterator iti = pref._int_tags.find(tag);
753 nassertr(iti != pref._int_tags.end(), 0);
754 return (*iti).second;
755}
756
757/**
758 * Allows the creating object to store a temporary data value on the
759 * BamReader. This method may be called during an object's fillin() method;
760 * it will associate a newly-allocated BamReaderAuxData construct with an
761 * arbitrary string key (which is in turn associated with the calling object
762 * only). Later, in the complete_pointers() method, the same object may query
763 * this data again via get_aux_tag().
764 *
765 * The BamReader will maintain the reference count on the BamReaderAuxData,
766 * and destruct it when it is cleaned up.
767 *
768 * The tag string need not be unique between different objects, but it should
769 * be unique between an object and its CData object(s).
770 */
772set_aux_tag(const string &tag, BamReaderAuxData *value) {
773 nassertv(_now_creating != _created_objs.end());
774 int requestor_id = (*_now_creating).first;
775
776 PointerReference &pref = _object_pointers[requestor_id];
777 pref._aux_tags[tag] = value;
778}
779
780/**
781 * Returns the value previously set via set_aux_tag(). It is an error if no
782 * value has been set.
783 */
785get_aux_tag(const string &tag) const {
786 nassertr(_now_creating != _created_objs.end(), nullptr);
787 int requestor_id = (*_now_creating).first;
788
789 ObjectPointers::const_iterator opi = _object_pointers.find(requestor_id);
790 nassertr(opi != _object_pointers.end(), nullptr);
791 const PointerReference &pref = (*opi).second;
792
793 AuxTags::const_iterator ati = pref._aux_tags.find(tag);
794 nassertr(ati != pref._aux_tags.end(), nullptr);
795 return (*ati).second;
796}
797
798/**
799 * Should be called by an object reading itself from the Bam file to indicate
800 * that this particular object would like to receive the finalize() callback
801 * when all the objects and pointers in the Bam file are completely read.
802 *
803 * This provides a hook for objects that need to do any additional
804 * finalization work after all of their related pointers are guaranteed to be
805 * filled in.
806 */
809 nassertv(whom != nullptr);
810
811 if (bam_cat.is_spam()) {
812 bam_cat.spam()
813 << "register_finalize(" << (void *)whom << ") (" << whom->get_type()
814 << ")\n";
815 }
816
817 _finalize_list.insert(whom);
818}
819
820/**
821 * Called by an object reading itself from the bam file to indicate that the
822 * object pointer that will be returned is temporary, and will eventually need
823 * to be replaced with another pointer.
824 *
825 * The supplied function pointer will later be called on the object,
826 * immediately after complete_pointers() is called; it should return the new
827 * and final pointer.
828 *
829 * We use a static function pointer instead of a virtual function (as in
830 * finalize()), to allow the function to destruct the old pointer if
831 * necessary. (It is invalid to destruct the this pointer within a virtual
832 * function.)
833 */
835register_change_this(ChangeThisFunc func, TypedWritable *object) {
836 nassertv(_now_creating != _created_objs.end());
837 CreatedObj &created_obj = (*_now_creating).second;
838
839#ifndef NDEBUG
840 // Sanity check the pointer--it should always be the same pointer after we
841 // set it the first time.
842 if (created_obj._ptr == nullptr) {
843 created_obj.set_ptr(object, object->as_reference_count());
844 } else {
845 // We've previously assigned this pointer, and we should have assigned it
846 // to the same this pointer we have now.
847 nassertv(created_obj._ptr == object);
848 }
849#endif // NDEBUG
850
851 created_obj._change_this = func;
852 created_obj._change_this_ref = nullptr;
853}
854
855/**
856 * Called by an object reading itself from the bam file to indicate that the
857 * object pointer that will be returned is temporary, and will eventually need
858 * to be replaced with another pointer.
859 *
860 * The supplied function pointer will later be called on the object,
861 * immediately after complete_pointers() is called; it should return the new
862 * and final pointer.
863 *
864 * We use a static function pointer instead of a virtual function (as in
865 * finalize()), to allow the function to destruct the old pointer if
866 * necessary. (It is invalid to destruct the this pointer within a virtual
867 * function.)
868 */
870register_change_this(ChangeThisRefFunc func, TypedWritableReferenceCount *object) {
871 nassertv(_now_creating != _created_objs.end());
872 CreatedObj &created_obj = (*_now_creating).second;
873
874#ifndef NDEBUG
875 // Sanity check the pointer--it should always be the same pointer after we
876 // set it the first time.
877 if (created_obj._ptr == nullptr) {
878 created_obj.set_ptr(object, object);
879 } else {
880 // We've previously assigned this pointer, and we should have assigned it
881 // to the same this pointer we have now.
882 nassertv(created_obj._ptr == object);
883 nassertv(created_obj._ref_ptr == object);
884 }
885#endif // NDEBUG
886
887 created_obj._change_this = nullptr;
888 created_obj._change_this_ref = func;
889}
890
891/**
892 * Forces the finalization of a particular object. This may be called by any
893 * of the objects during finalization, to guarantee finalization ordering
894 * where it is important.
895 */
898 if (whom == nullptr) {
899 return;
900 }
901
902 Finalize::iterator fi = _finalize_list.find(whom);
903 if (fi != _finalize_list.end()) {
904 _finalize_list.erase(fi);
905 if (bam_cat.is_spam()) {
906 bam_cat.spam()
907 << "finalizing " << (void *)whom << " (" << whom->get_type()
908 << ")\n";
909 }
910 whom->finalize(this);
911 }
912}
913
914/**
915 * This function works in conjection with register_pta(), below, to read a
916 * PointerToArray (PTA) from the Bam file, and unify references to the same
917 * PTA.
918 *
919 * The first time get_pta() encounters a particular PTA, it will return NULL.
920 * This is the indication that the caller should then read in the data
921 * associated with the PTA, and subsequently call register_pta() with the
922 * address of the filled-in array.
923 *
924 * The next time (and all subsequent times) that get_pta() encounters this
925 * same PTA, it will return the pointer that was passed with register_pta().
926 *
927 * Also see the READ_PTA() macro, which consolidates all the work that must be
928 * done to read a PTA.
929 */
932 nassertr(_pta_id == -1, nullptr);
933 int id = read_pta_id(scan);
934
935 if (id == 0) {
936 // As always, a 0 ID indicates a NULL pointer. The caller will not be
937 // able to differentiate this case from that of a previously-read pointer,
938 // but that's OK because the next data in the Bam file is the length of
939 // the array, which will be zero--indicating an empty or NULL array.
940 return nullptr;
941 }
942
943 PTAMap::iterator pi = _pta_map.find(id);
944 if (pi == _pta_map.end()) {
945 // This is the first time we've encountered this particular ID, meaning we
946 // need to read the data now and register it.
947 _pta_id = id;
948 return nullptr;
949 }
950
951 return (*pi).second;
952}
953
954/**
955 * The second part of read_pta(), this should be called with the pointer to
956 * the array that was read in after read_pta() returned NULL. This associates
957 * the pointer with the ID that was previously read, so that future calls to
958 * read_pta() will return the same pointer.
959 *
960 * Also see the READ_PTA() macro, which consolidates all the work that must be
961 * done to read a PTA.
962 */
964register_pta(void *ptr) {
965 if (_pta_id != -1) {
966 bool inserted = _pta_map.insert(PTAMap::value_type(_pta_id, ptr)).second;
967 _pta_id = -1;
968 nassertv(inserted);
969 }
970}
971
972/**
973 * Handles a record that begins with the _remove_flag TypeHandle; this
974 * contains a list of object ID's that will no longer be used in this file and
975 * can safely be removed.
976 */
977void BamReader::
978free_object_ids(DatagramIterator &scan) {
979 // We have to fully complete any objects before we remove them. Might as
980 // well try to complete everything before we get started.
981 resolve();
982
983 while (scan.get_remaining_size() > 0) {
984 int object_id = read_object_id(scan);
985
986 CreatedObjs::iterator ci = _created_objs.find(object_id);
987 if (ci == _created_objs.end()) {
988 util_cat.warning()
989 << "Bam file suggests eliminating object_id " << object_id
990 << ", already gone.\n";
991 } else {
992
993 // Make sure the object was successfully completed.
994 ObjectPointers::iterator oi = _object_pointers.find(object_id);
995 if (oi != _object_pointers.end()) {
996 util_cat.warning()
997 << "Unable to resolve object " << object_id
998 << " before removing from table.\n";
999 }
1000
1001 _created_objs_by_pointer.erase((*ci).second._ptr);
1002 _created_objs.erase(ci);
1003 }
1004 }
1005}
1006
1007
1008/**
1009 * Reads an object id from the datagram.
1010 */
1011int BamReader::
1012read_object_id(DatagramIterator &scan) {
1013 int object_id;
1014
1015 if (_long_object_id) {
1016 object_id = scan.get_uint32();
1017
1018 } else {
1019 object_id = scan.get_uint16();
1020 if (object_id == 0xffff) {
1021 _long_object_id = true;
1022 }
1023 }
1024
1025 return object_id;
1026}
1027
1028/**
1029 * Reads an pta id from the datagram.
1030 */
1031int BamReader::
1032read_pta_id(DatagramIterator &scan) {
1033 int pta_id;
1034
1035 if (_long_pta_id) {
1036 pta_id = scan.get_uint32();
1037
1038 } else {
1039 pta_id = scan.get_uint16();
1040 if (pta_id == 0xffff) {
1041 _long_pta_id = true;
1042 }
1043 }
1044
1045 return pta_id;
1046}
1047
1048/**
1049 * The private implementation of read_object(); this reads an object from the
1050 * file and returns its object ID.
1051 */
1052int BamReader::
1053p_read_object() {
1054 Datagram dg;
1055
1056 // First, read a datagram for the object.
1057 if (!get_datagram(dg)) {
1058 // When we run out of datagrams, we're at the end of the file.
1059 if (bam_cat.is_debug()) {
1060 bam_cat.debug()
1061 << "Reached end of bam source.\n";
1062 }
1063 return 0;
1064 }
1065
1066 // Now extract the object definition from the datagram.
1067 DatagramIterator scan(dg);
1068
1069 // First, read the BamObjectCode. In bam versions prior to 6.21, there was
1070 // no BamObjectCode in the stream.
1071 BamObjectCode boc = BOC_adjunct;
1072 if (get_file_minor_ver() >= 21) {
1073 boc = (BamObjectCode)scan.get_uint8();
1074 }
1075 switch (boc) {
1076 case BOC_push:
1077 ++_nesting_level;
1078 break;
1079
1080 case BOC_pop:
1081 --_nesting_level;
1082 return 0;
1083
1084 case BOC_adjunct:
1085 break;
1086
1087 case BOC_remove:
1088 // The BOC_remove code is a special case; it begins a record that simply
1089 // lists all of the object ID's that are no longer important to the file
1090 // and may be released.
1091 free_object_ids(scan);
1092
1093 // Now that we've freed all of the object id's indicate, read the next
1094 // object id in the stream. It's easiest to do this by calling
1095 // recursively.
1096 return p_read_object();
1097
1098 case BOC_file_data:
1099 // Another special case. This marks an auxiliary file data record that we
1100 // skip over for now, but we note its position within the stream, so that
1101 // we can hand it to a future object who may request it.
1102 {
1103 SubfileInfo info;
1104 if (!_source->save_datagram(info)) {
1105 bam_cat.error()
1106 << "Failed to read file data.\n";
1107 return 0;
1108 }
1109 _file_data_records.push_back(info);
1110 }
1111
1112 return p_read_object();
1113
1114 default:
1115 bam_cat.error()
1116 << "Encountered invalid BamObjectCode 0x" << std::hex << (int)boc << std::dec << ".\n";
1117 return 0;
1118 }
1119
1120 // An object definition in a Bam file consists of a TypeHandle definition,
1121 // defining the object's type, followed by an object ID index, defining the
1122 // particular instance (e.g. pointer) of this object.
1123
1124 TypeHandle type = read_handle(scan);
1125
1126 int object_id = read_object_id(scan);
1127
1128 if (scan.get_current_index() > dg.get_length()) {
1129 bam_cat.error()
1130 << "Found truncated datagram in bam stream\n";
1131 return 0;
1132 }
1133
1134 // There are two cases (not counting the special _remove_flag case, above).
1135 // Either this is a new object definition, or this is a reference to an
1136 // object that was previously defined.
1137
1138 // We use the TypeHandle to differentiate these two cases. By convention,
1139 // we write a TypeHandle::none() to the Bam file when we are writing a
1140 // reference to a previously-defined object, but we write the object's
1141 // actual type when we are writing its definition right now.
1142
1143 // Therefore, if the type is TypeHandle::none(), then we must have already
1144 // read in and created the object (although its pointers may not be fully
1145 // instantiated yet). On the other hand, if the type is anything else, then
1146 // we must read the definition to follow.
1147
1148 if (type != TypeHandle::none()) {
1149 // Now we are going to read and create a new object.
1150
1151 // First, we must add an entry into the map for this object ID, so that in
1152 // case this function is called recursively during the object's factory
1153 // constructor, we will have some definition for the object. For now, we
1154 // give it a NULL pointer.
1155 CreatedObj new_created_obj;
1156 CreatedObjs::iterator oi =
1157 _created_objs.insert(CreatedObjs::value_type(object_id, new_created_obj)).first;
1158 CreatedObj &created_obj = (*oi).second;
1159
1160 if (created_obj._ptr != nullptr) {
1161 // This object had already existed; thus, we are just receiving an
1162 // update for it.
1163
1164 if (_object_pointers.find(object_id) != _object_pointers.end()) {
1165 // Aieee! This object isn't even complete from the last time we
1166 // encountered it in the stream! This should never happen. Something's
1167 // corrupt or the stream was maliciously crafted.
1168 bam_cat.error()
1169 << "Found object " << object_id << " in bam stream again while "
1170 << "trying to resolve its own pointers.\n";
1171 return 0;
1172 }
1173
1174 // Update _now_creating during this call so if this function calls
1175 // read_pointer() or register_change_this() we'll match it up properly.
1176 // This might recursively call back into this p_read_object(), so be
1177 // sure to save and restore the original value of _now_creating.
1178 CreatedObjs::iterator was_creating = _now_creating;
1179 _now_creating = oi;
1180 created_obj._ptr->fillin(scan, this);
1181 _now_creating = was_creating;
1182
1183 if (scan.get_remaining_size() > 0) {
1184 bam_cat.warning()
1185 << "Skipping " << scan.get_remaining_size() << " remaining bytes "
1186 << "in datagram containing type " << type << "\n";
1187 }
1188
1189 } else {
1190 // We are receiving a new object. Now we can call the factory to create
1191 // the object.
1192
1193 // Define the parameters for passing to the object factory.
1194 FactoryParams fparams;
1195 fparams.add_param(new BamReaderParam(scan, this));
1196
1197 // As above, we update and preserve _now_creating during this call.
1198 CreatedObjs::iterator was_creating = _now_creating;
1199 _now_creating = oi;
1200 TypedWritable *object =
1201 _factory->make_instance_more_general(type, fparams);
1202 _now_creating = was_creating;
1203
1204 // And now we can store the new object pointer in the map.
1205 nassertr(created_obj._ptr == object || created_obj._ptr == nullptr, object_id);
1206 if (object == nullptr) {
1207 created_obj.set_ptr(nullptr, nullptr);
1208 } else {
1209 created_obj.set_ptr(object, object->as_reference_count());
1210 }
1211 created_obj._created = true;
1212
1213 if (created_obj._change_this_ref != nullptr) {
1214 // If the pointer is scheduled to change after complete_pointers(),
1215 // but we have no entry in _object_pointers for this object (and hence
1216 // no plan to call complete_pointers()), then just change the pointer
1217 // immediately.
1218 ObjectPointers::const_iterator ri = _object_pointers.find(object_id);
1219 if (ri == _object_pointers.end()) {
1220 PT(TypedWritableReferenceCount) object_ref = (*created_obj._change_this_ref)((TypedWritableReferenceCount *)object, this);
1221 TypedWritable *new_ptr = object_ref;
1222 created_obj.set_ptr(object_ref, object_ref);
1223 created_obj._change_this = nullptr;
1224 created_obj._change_this_ref = nullptr;
1225
1226 // Remove the pointer from the finalize list (the new pointer
1227 // presumably doesn't require finalizing).
1228 if (new_ptr != object) {
1229 _finalize_list.erase(object);
1230 }
1231 object = new_ptr;
1232 }
1233
1234 } else if (created_obj._change_this != nullptr) {
1235 // Non-reference-counting variant.
1236 ObjectPointers::const_iterator ri = _object_pointers.find(object_id);
1237 if (ri == _object_pointers.end()) {
1238 TypedWritable *new_ptr = (*created_obj._change_this)(object, this);
1239 created_obj.set_ptr(new_ptr, new_ptr->as_reference_count());
1240 created_obj._change_this = nullptr;
1241 created_obj._change_this_ref = nullptr;
1242
1243 if (new_ptr != object) {
1244 _finalize_list.erase(object);
1245 }
1246 object = new_ptr;
1247 }
1248 }
1249
1250 _created_objs_by_pointer[created_obj._ptr].push_back(object_id);
1251
1252 // Just some sanity checks
1253 if (object == nullptr) {
1254 if (bam_cat.is_debug()) {
1255 bam_cat.debug()
1256 << "Unable to create an object of type " << type << std::endl;
1257 }
1258
1259 } else if (object->get_type() != type) {
1260 if (_new_types.find(type) != _new_types.end()) {
1261 // This was a type we hadn't heard of before, so it's not really
1262 // surprising we didn't know how to create it. Suppress the warning
1263 // (make it a debug statement instead).
1264 if (bam_cat.is_debug()) {
1265 bam_cat.warning()
1266 << "Attempted to create a " << type.get_name() \
1267 << " but a " << object->get_type() \
1268 << " was created instead." << std::endl;
1269 }
1270
1271 } else {
1272 // This was a normal type that we should have known how to create.
1273 // Report the error.
1274 bam_cat.warning()
1275 << "Attempted to create a " << type.get_name() \
1276 << " but a " << object->get_type() \
1277 << " was created instead." << std::endl;
1278 }
1279
1280 } else {
1281 if (bam_cat.is_spam()) {
1282 bam_cat.spam()
1283 << "Read a " << object->get_type() << ": " << (void *)object
1284 << " (id=" << object_id << ")\n";
1285 }
1286 }
1287 }
1288
1289 // Sanity check that we read the expected number of bytes.
1290 if (scan.get_current_index() > dg.get_length()) {
1291 bam_cat.error()
1292 << "End of datagram reached while reading bam object "
1293 << type << ": " << (void *)created_obj._ptr << "\n";
1294 }
1295 }
1296
1297 return object_id;
1298}
1299
1300/**
1301 * Checks whether all of the pointers a particular object is waiting for have
1302 * been filled in yet. If they have, calls complete_pointers() on the object
1303 * and returns true; otherwise, returns false.
1304 */
1305bool BamReader::
1306resolve_object_pointers(TypedWritable *object,
1307 BamReader::PointerReference &pref) {
1308 // Some objects further require all of their nested objects to have been
1309 // completed (i.e. complete_pointers has been called on each nested object)
1310 // before they can themselves be completed.
1311 bool require_fully_complete = object->require_fully_complete();
1312
1313 // First do the PipelineCycler objects.
1314 CyclerPointers::iterator ci;
1315 ci = pref._cycler_pointers.begin();
1316 while (ci != pref._cycler_pointers.end()) {
1317 PipelineCyclerBase *cycler = (*ci).first;
1318 const vector_int &pointer_ids = (*ci).second;
1319
1320 if (resolve_cycler_pointers(cycler, pointer_ids, require_fully_complete)) {
1321 // Now remove this cycler from the list of things that need completion.
1322 // We have to be a bit careful when deleting things from the STL
1323 // container while we are traversing it.
1324 CyclerPointers::iterator old = ci;
1325 ++ci;
1326 pref._cycler_pointers.erase(old);
1327
1328 } else {
1329 // Couldn't complete this cycler yet; it'll wait for next time.
1330 ++ci;
1331 }
1332 }
1333
1334 if (!pref._cycler_pointers.empty()) {
1335 // If we didn't get all the cyclers, we have to wait.
1336 if (bam_cat.is_spam()) {
1337 bam_cat.spam()
1338 << "some cyclers pending: complete_pointers for " << (void *)object
1339 << " (" << object->get_type() << ")\n";
1340 }
1341 return false;
1342 }
1343
1344 // Now make sure we have all of the pointers this object is waiting for. If
1345 // any of the pointers has not yet been read in, we can't resolve this
1346 // object--we can't do anything for a given object until we have *all*
1347 // outstanding pointers for that object.
1348 bool is_complete = true;
1349
1350 vector_typedWritable references;
1351 references.reserve(pref._objects.size());
1352
1353 vector_int::const_iterator pi;
1354 for (pi = pref._objects.begin();
1355 pi != pref._objects.end() && is_complete;
1356 ++pi) {
1357 int child_id = (*pi);
1358 if (child_id == 0) {
1359 // A NULL pointer is a NULL pointer.
1360 references.push_back(nullptr);
1361 continue;
1362 }
1363
1364 // See if we have the pointer available now.
1365 CreatedObjs::const_iterator oi = _created_objs.find(child_id);
1366 if (oi == _created_objs.end()) {
1367 // No, too bad.
1368 is_complete = false;
1369 break;
1370 }
1371
1372 const CreatedObj &child_obj = (*oi).second;
1373 if (!child_obj._created) {
1374 // The child object hasn't yet been created.
1375 is_complete = false;
1376 break;
1377 }
1378
1379 if (child_obj._change_this != nullptr || child_obj._change_this_ref != nullptr) {
1380 // It's been created, but the pointer might still change.
1381 is_complete = false;
1382 break;
1383 }
1384
1385 if (require_fully_complete &&
1386 _object_pointers.find(child_id) != _object_pointers.end()) {
1387 // It's not yet complete itself.
1388 is_complete = false;
1389 break;
1390 }
1391
1392 // Yes, it's ready.
1393 references.push_back(child_obj._ptr);
1394 }
1395
1396 if (is_complete) {
1397 // Okay, here's the complete list of pointers for you!
1398 nassertr(references.size() == pref._objects.size(), false);
1399
1400 if (bam_cat.is_spam()) {
1401 bam_cat.spam()
1402 << "complete_pointers for " << (void *)object
1403 << " (" << object->get_type() << "), " << references.size()
1404 << " pointers.\n";
1405 }
1406 int num_completed = 0;
1407 if (!references.empty()) {
1408 num_completed = object->complete_pointers(&references[0], this);
1409 }
1410 if (num_completed != (int)references.size()) {
1411 bam_cat.warning()
1412 << object->get_type() << " completed " << num_completed
1413 << " of " << references.size() << " pointers.\n";
1414 nassertr(num_completed < (int)references.size(), true);
1415 }
1416 return true;
1417
1418 } else {
1419 if (bam_cat.is_spam()) {
1420 bam_cat.spam()
1421 << "not ready: complete_pointers for " << (void *)object
1422 << " (" << object->get_type() << ")\n";
1423 }
1424 }
1425
1426 return false;
1427}
1428
1429/**
1430 * Checks whether all of the pointers a particular PipelineCycler is waiting
1431 * for have been filled in yet. If they have, calls complete_pointers() on
1432 * the cycler and returns true; otherwise, returns false.
1433 */
1434bool BamReader::
1435resolve_cycler_pointers(PipelineCyclerBase *cycler,
1436 const vector_int &pointer_ids,
1437 bool require_fully_complete) {
1438 // Now make sure we have all of the pointers this cycler is waiting for. If
1439 // any of the pointers has not yet been read in, we can't resolve this
1440 // cycler--we can't do anything for a given cycler until we have *all*
1441 // outstanding pointers for that cycler.
1442
1443 bool is_complete = true;
1444 vector_typedWritable references;
1445
1446 vector_int::const_iterator pi;
1447 for (pi = pointer_ids.begin(); pi != pointer_ids.end() && is_complete; ++pi) {
1448 int child_id = (*pi);
1449
1450 if (child_id == 0) {
1451 // A NULL pointer is a NULL pointer.
1452 references.push_back(nullptr);
1453 continue;
1454 }
1455
1456 // See if we have the pointer available now.
1457 CreatedObjs::const_iterator oi = _created_objs.find(child_id);
1458 if (oi == _created_objs.end()) {
1459 // No, too bad.
1460 is_complete = false;
1461 break;
1462 }
1463
1464 const CreatedObj &child_obj = (*oi).second;
1465 if (child_obj._change_this != nullptr || child_obj._change_this_ref != nullptr) {
1466 // It's been created, but the pointer might still change.
1467 is_complete = false;
1468 break;
1469 }
1470
1471 if (require_fully_complete &&
1472 _object_pointers.find(child_id) != _object_pointers.end()) {
1473 // It's not yet complete itself.
1474 is_complete = false;
1475 break;
1476 }
1477
1478 // Yes, it's ready.
1479 references.push_back(child_obj._ptr);
1480 }
1481
1482 if (is_complete) {
1483 // Okay, here's the complete list of pointers for you!
1484 CycleData *cdata = cycler->write(Thread::get_current_thread());
1485 if (bam_cat.is_spam()) {
1486 bam_cat.spam()
1487 << "complete_pointers for CycleData object " << (void *)cdata
1488 << "\n";
1489 }
1490 int num_completed = cdata->complete_pointers(&references[0], this);
1491 cycler->release_write(cdata);
1492 if (num_completed != (int)references.size()) {
1493 bam_cat.warning()
1494 << "CycleData object completed " << num_completed
1495 << " of " << references.size() << " pointers.\n";
1496 nassertr(num_completed < (int)references.size(), true);
1497 }
1498 return true;
1499 }
1500
1501 return false;
1502}
1503
1504/**
1505 * Should be called after all objects have been read, this will finalize all
1506 * the objects that registered themselves for the finalize callback.
1507 */
1508void BamReader::
1509finalize() {
1510 if (bam_cat.is_debug()) {
1511 bam_cat.debug()
1512 << "Finalizing bam source\n";
1513 }
1514
1515 Finalize::iterator fi = _finalize_list.begin();
1516 while (fi != _finalize_list.end()) {
1517 TypedWritable *object = (*fi);
1518 nassertv(object != nullptr);
1519 _finalize_list.erase(fi);
1520 if (bam_cat.is_spam()) {
1521 bam_cat.spam()
1522 << "finalizing " << (void *)object << " (" << object->get_type()
1523 << ")\n";
1524 }
1525 object->finalize(this);
1526 _aux_data.erase(object);
1527 fi = _finalize_list.begin();
1528 }
1529
1530 // Now clear the aux data of all objects, except the NULL object.
1531 if (!_aux_data.empty()) {
1532 AuxDataTable::iterator ti = _aux_data.find(nullptr);
1533
1534 if (ti != _aux_data.end()) {
1535 if (_aux_data.size() > 1) {
1536 // Move the NULL data to the new table; remove the rest.
1537 AuxDataTable new_aux_data;
1538 AuxDataTable::iterator nti =
1539 new_aux_data.insert(AuxDataTable::value_type(nullptr, AuxDataNames())).first;
1540 (*nti).second.swap((*ti).second);
1541 _aux_data.swap(new_aux_data);
1542 }
1543 } else {
1544 // There's no NULL data; clear the whole table.
1545 _aux_data.clear();
1546 }
1547 }
1548}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamEndian
This defines an enumerated type used to represent the endianness of certain numeric values stored in ...
Definition bamEnums.h:32
BamObjectCode
This is the code written along with each object.
Definition bamEnums.h:46
Stores auxiliary data that may be piggybacked on the BamReader during each object's read pass.
Definition bamReader.h:61
The parameters that are passed through the Factory to any object constructing itself from a Bam file.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
TypeHandle read_handle(DatagramIterator &scan)
Reads a TypeHandle out of the Datagram.
bool change_pointer(const TypedWritable *orig_pointer, const TypedWritable *new_pointer)
Indicates that an object recently read from the bam stream should be replaced with a new object.
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
void read_file_data(SubfileInfo &info)
Reads a block of auxiliary file data from the Bam file.
int get_int_tag(const std::string &tag) const
Returns the value previously set via set_int_tag().
void register_pta(void *ptr)
The second part of read_pta(), this should be called with the pointer to the array that was read in a...
void skip_pointer(DatagramIterator &scan)
Reads and discards a pointer value from the Bam file.
BamReaderAuxData * get_aux_tag(const std::string &tag) const
Returns the value previously set via set_aux_tag().
void finalize_now(TypedWritable *whom)
Forces the finalization of a particular object.
bool resolve()
This may be called at any time during processing of the Bam file to resolve all the known pointers so...
void set_aux_tag(const std::string &tag, BamReaderAuxData *value)
Allows the creating object to store a temporary data value on the BamReader.
bool init()
Initializes the BamReader prior to reading any objects from its source.
Definition bamReader.cxx:85
void set_aux_data(TypedWritable *obj, const std::string &name, AuxData *data)
Associates an arbitrary block of data with the indicated object (or NULL), and the indicated name.
get_filename
If a BAM is a file, then the BamReader should contain the name of the file.
Definition bamReader.h:155
void * get_pta(DatagramIterator &scan)
This function works in conjection with register_pta(), below, to read a PointerToArray (PTA) from the...
TypedWritable * read_object()
Reads a single object from the Bam file.
void register_change_this(ChangeThisFunc func, TypedWritable *whom)
Called by an object reading itself from the bam file to indicate that the object pointer that will be...
void set_int_tag(const std::string &tag, int value)
Allows the creating object to store a temporary data value on the BamReader.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition bamReader.I:83
AuxData * get_aux_data(TypedWritable *obj, const std::string &name) const
Returns the pointer previously associated with the bam reader by a previous call to set_aux_data(),...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
set_source
Changes the source of future datagrams for this BamReader.
Definition bamReader.h:154
A single page of data maintained by a PipelineCycler.
Definition cycleData.h:50
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
Definition cycleData.cxx:58
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition cycleData.cxx:48
This class defines the abstract interace to any source of datagrams, whether it be from a file or fro...
virtual bool save_datagram(SubfileInfo &info)
Skips over the next datagram without extracting it, but saves the relevant file information in the Su...
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
bool get_bool()
Extracts a boolean value.
std::string get_string()
Extracts a variable-length string.
size_t get_current_index() const
Returns the current position within the datagram of the next piece of data to extract.
size_t get_remaining_size() const
Return the bytes left in the datagram.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
size_t get_length() const
Returns the number of bytes in the datagram.
Definition datagram.I:335
An instance of this class is passed to the Factory when requesting it to do its business and construc...
A Factory can be used to create an instance of a particular subclass of some general base class.
Definition factory.h:34
Type * make_instance_more_general(TypeHandle handle, const FactoryParams &params=FactoryParams())
Attempts to create an instance of the type requested, or some base type of the type requested.
Definition factory.I:48
A base class for all things that want to be reference-counted.
This class records a particular byte sub-range within an existing file on disk.
Definition subfileInfo.h:26
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
Definition thread.I:212
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
get_name
Returns the name of the type.
Definition typeHandle.h:136
TypeHandle get_parent_towards(TypeHandle ancestor, TypedObject *object=nullptr) const
Returns the parent class that is in a direct line of inheritance to the indicated ancestor class.
Definition typeHandle.I:170
TypeHandle register_dynamic_type(const std::string &name)
Registers a new type on-the-fly, presumably at runtime.
void record_derivation(TypeHandle child, TypeHandle parent)
Records that the type referenced by child inherits directly from the type referenced by parent.
static TypeRegistry * ptr()
Returns the pointer to the global TypeRegistry object.
TypeHandle find_type(const std::string &name) const
Looks for a previously-registered type of the given name.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Base class for objects that can be written to and read from Bam files.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
virtual ReferenceCount * as_reference_count()
Returns the pointer cast to a ReferenceCount pointer, if it is in fact of that type.
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
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.
This is the trivial, non-threaded implementation of PipelineCyclerBase.
CycleData * write(Thread *current_thread)
Returns a non-const CycleData pointer, filled with a unique copy of the data for the current stage of...
void release_write(CycleData *pointer)
Releases a pointer previously obtained via a call to write().