Panda3D

dcPacker.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 dcPacker.cxx
10 * @author drose
11 * @date 2004-06-15
12 */
13
14 #include "dcPacker.h"
15 #include "dcSwitch.h"
16 #include "dcParserDefs.h"
17 #include "dcLexerDefs.h"
18 #include "dcClassParameter.h"
19 #include "dcSwitchParameter.h"
20 #include "dcClass.h"
21
22 #ifdef HAVE_PYTHON
23 #include "py_panda.h"
24 #endif
25
26 using std::istream;
27 using std::istringstream;
28 using std::ostream;
29 using std::ostringstream;
30 using std::string;
31
32 DCPacker::StackElement *DCPacker::StackElement::_deleted_chain = nullptr;
33 int DCPacker::StackElement::_num_ever_allocated = 0;
34
35 /**
36 *
37 */
38 DCPacker::
39 DCPacker() {
40 _mode = M_idle;
41 _unpack_data = nullptr;
42 _unpack_length = 0;
43 _owns_unpack_data = false;
44 _unpack_p = 0;
45 _live_catalog = nullptr;
46 _parse_error = false;
47 _pack_error = false;
48 _range_error = false;
49 _stack = nullptr;
50
51 clear();
52 }
53
54 /**
55 *
56 */
57 DCPacker::
58 ~DCPacker() {
59 clear_data();
60 clear();
61 }
62
63 /**
64 * Begins a packing session. The parameter is the DC object that describes
65 * the packing format; it may be a DCParameter or DCField.
66 *
67 * Unless you call clear_data() between sessions, multiple packing sessions
68 * will be concatenated together into the same buffer. If you wish to add
69 * bytes to the buffer between packing sessions, use append_data() or
70 * get_write_pointer().
71 */
72 void DCPacker::
73 begin_pack(const DCPackerInterface *root) {
74 nassertv(_mode == M_idle);
75
76 _mode = M_pack;
77 _parse_error = false;
78 _pack_error = false;
79 _range_error = false;
80
81 _root = root;
82 _catalog = nullptr;
83 _live_catalog = nullptr;
84
85 _current_field = root;
86 _current_parent = nullptr;
87 _current_field_index = 0;
88 _num_nested_fields = 0;
89 }
90
91 /**
92 * Finishes a packing session.
93 *
94 * The return value is true on success, or false if there has been some error
95 * during packing.
96 */
97 bool DCPacker::
98 end_pack() {
99 nassertr(_mode == M_pack, false);
100
101 _mode = M_idle;
102
103 if (_stack != nullptr || _current_field != nullptr || _current_parent != nullptr) {
104 _pack_error = true;
105 }
106
107 clear();
108
109 return !had_error();
110 }
111
112 /**
113 * Sets up the unpack_data pointer. You may call this before calling the
114 * version of begin_unpack() that takes only one parameter.
115 */
116 void DCPacker::
117 set_unpack_data(const vector_uchar &data) {
118 nassertv(_mode == M_idle);
119
120 char *buffer = new char[data.size()];
121 memcpy(buffer, data.data(), data.size());
122 set_unpack_data(buffer, data.size(), true);
123 }
124
125 /**
126 * Sets up the unpack_data pointer. You may call this before calling the
127 * version of begin_unpack() that takes only one parameter.
128 */
129 void DCPacker::
130 set_unpack_data(const char *unpack_data, size_t unpack_length,
131 bool owns_unpack_data) {
132 nassertv(_mode == M_idle);
133
134 if (_owns_unpack_data) {
135 delete[] _unpack_data;
136 }
137 _unpack_data = unpack_data;
138 _unpack_length = unpack_length;
139 _owns_unpack_data = owns_unpack_data;
140 _unpack_p = 0;
141 }
142
143 /**
144 * Begins an unpacking session. You must have previously called
145 * set_unpack_data() to specify a buffer to unpack.
146 *
147 * If there was data left in the buffer after a previous begin_unpack() ..
148 * end_unpack() session, the new session will resume from the current point.
149 * This method may be used, therefore, to unpack a sequence of objects from
150 * the same buffer.
151 */
152 void DCPacker::
153 begin_unpack(const DCPackerInterface *root) {
154 nassertv(_mode == M_idle);
155 nassertv(_unpack_data != nullptr);
156
157 _mode = M_unpack;
158 _parse_error = false;
159 _pack_error = false;
160 _range_error = false;
161
162 _root = root;
163 _catalog = nullptr;
164 _live_catalog = nullptr;
165
166 _current_field = root;
167 _current_parent = nullptr;
168 _current_field_index = 0;
169 _num_nested_fields = 0;
170 }
171
172 /**
173 * Finishes the unpacking session.
174 *
175 * The return value is true on success, or false if there has been some error
176 * during unpacking (or if all fields have not been unpacked).
177 */
178 bool DCPacker::
179 end_unpack() {
180 nassertr(_mode == M_unpack, false);
181
182 _mode = M_idle;
183
184 if (_stack != nullptr || _current_field != nullptr || _current_parent != nullptr) {
185 // This happens if we have not unpacked all of the fields. However, this
186 // is not an error if we have called seek() during the unpack session (in
187 // which case the _catalog will be non-NULL). On the other hand, if the
188 // catalog is still NULL, then we have never called seek() and it is an
189 // error not to unpack all values.
190 if (_catalog == nullptr) {
191 _pack_error = true;
192 }
193 }
194
195 clear();
196
197 return !had_error();
198 }
199
200 /**
201 * Begins a repacking session. You must have previously called
202 * set_unpack_data() to specify a buffer to unpack.
203 *
204 * Unlike begin_pack() or begin_unpack() you may not concatenate the results
205 * of multiple begin_repack() sessions in one buffer.
206 *
207 * Also, unlike in packing or unpacking modes, you may not walk through the
208 * fields from beginning to end, or even pack two consecutive fields at once.
209 * Instead, you must call seek() for each field you wish to modify and pack
210 * only that one field; then call seek() again to modify another field.
211 */
212 void DCPacker::
213 begin_repack(const DCPackerInterface *root) {
214 nassertv(_mode == M_idle);
215 nassertv(_unpack_data != nullptr);
216 nassertv(_unpack_p == 0);
217
218 _mode = M_repack;
219 _parse_error = false;
220 _pack_error = false;
221 _range_error = false;
222 _pack_data.clear();
223
224 // In repack mode, we immediately get the catalog, since we know we'll need
225 // it.
226 _root = root;
227 _catalog = _root->get_catalog();
228 _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
229 if (_live_catalog == nullptr) {
230 _pack_error = true;
231 }
232
233 // We don't begin at the first field in repack mode. Instead, you must
234 // explicitly call seek().
235 _current_field = nullptr;
236 _current_parent = nullptr;
237 _current_field_index = 0;
238 _num_nested_fields = 0;
239 }
240
241 /**
242 * Finishes the repacking session.
243 *
244 * The return value is true on success, or false if there has been some error
245 * during repacking (or if all fields have not been repacked).
246 */
247 bool DCPacker::
248 end_repack() {
249 nassertr(_mode == M_repack, false);
250
251 // Put the rest of the data onto the pack stream.
252 _pack_data.append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
253
254 _mode = M_idle;
255 clear();
256
257 return !had_error();
258 }
259
260 /**
261 * Sets the current unpack (or repack) position to the named field. In unpack
262 * mode, the next call to unpack_*() or push() will begin to read the named
263 * field. In repack mode, the next call to pack_*() or push() will modify the
264 * named field.
265 *
266 * Returns true if successful, false if the field is not known (or if the
267 * packer is in an invalid mode).
268 */
269 bool DCPacker::
270 seek(const string &field_name) {
271 if (_catalog == nullptr) {
272 _catalog = _root->get_catalog();
273 _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
274 }
275 nassertr(_catalog != nullptr, false);
276 if (_live_catalog == nullptr) {
277 _pack_error = true;
278 return false;
279 }
280
281 int seek_index = _live_catalog->find_entry_by_name(field_name);
282 if (seek_index < 0) {
283 // The field was not known.
284 _pack_error = true;
285 return false;
286 }
287
288 return seek(seek_index);
289 }
290
291 /**
292 * Seeks to the field indentified by seek_index, which was returned by an
293 * earlier call to DCField::find_seek_index() to get the index of some nested
294 * field. Also see the version of seek() that accepts a field name.
295 *
296 * Returns true if successful, false if the field is not known (or if the
297 * packer is in an invalid mode).
298 */
299 bool DCPacker::
300 seek(int seek_index) {
301 if (_catalog == nullptr) {
302 _catalog = _root->get_catalog();
303 _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
304 }
305 nassertr(_catalog != nullptr, false);
306 if (_live_catalog == nullptr) {
307 _pack_error = true;
308 return false;
309 }
310
311 if (_mode == M_unpack) {
312 const DCPackerCatalog::Entry &entry = _live_catalog->get_entry(seek_index);
313
314 // If we are seeking, we don't need to remember our current stack
315 // position.
316 clear_stack();
317 _current_field = entry._field;
318 _current_parent = entry._parent;
319 _current_field_index = entry._field_index;
320 _num_nested_fields = _current_parent->get_num_nested_fields();
321 _unpack_p = _live_catalog->get_begin(seek_index);
322
323 // We don't really need _push_marker and _pop_marker now, except that we
324 // should set _push_marker in case we have just seeked to a switch
325 // parameter, and we should set _pop_marker to 0 just so it won't get in
326 // the way.
327 _push_marker = _unpack_p;
328 _pop_marker = 0;
329
330 return true;
331
332 } else if (_mode == M_repack) {
333 nassertr(_catalog != nullptr, false);
334
335 if (_stack != nullptr || _current_field != nullptr) {
336 // It is an error to reseek while the stack is nonempty--that means we
337 // haven't finished packing the current field.
338 _pack_error = true;
339 return false;
340 }
341 const DCPackerCatalog::Entry &entry = _live_catalog->get_entry(seek_index);
342
343 if (entry._parent->as_switch_parameter() != nullptr) {
344 // If the parent is a DCSwitch, that can only mean that the seeked field
345 // is a switch parameter. We can't support seeking to a switch
346 // parameter and modifying it directly--what would happen to all of the
347 // related fields? Instead, you'll have to seek to the switch itself
348 // and repack the whole entity.
349 _pack_error = true;
350 return false;
351 }
352
353 size_t begin = _live_catalog->get_begin(seek_index);
354 if (begin < _unpack_p) {
355 // Whoops, we are seeking fields out-of-order. That means we need to
356 // write the entire record and start again.
357 _pack_data.append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
358 size_t length = _pack_data.get_length();
359 char *buffer = _pack_data.take_data();
360 set_unpack_data(buffer, length, true);
361 _unpack_p = 0;
362
363 _catalog->release_live_catalog(_live_catalog);
364 _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
365
366 if (_live_catalog == nullptr) {
367 _pack_error = true;
368 return false;
369 }
370
371 begin = _live_catalog->get_begin(seek_index);
372 }
373
374 // Now copy the bytes from _unpack_p to begin from the _unpack_data to the
375 // _pack_data. These are the bytes we just skipped over with the call to
376 // seek().
377 _pack_data.append_data(_unpack_data + _unpack_p, begin - _unpack_p);
378
379 // And set the packer up to pack the indicated field (but no subsequent
380 // fields).
381 _current_field = entry._field;
382 _current_parent = entry._parent;
383 _current_field_index = entry._field_index;
384 _num_nested_fields = 1;
385 _unpack_p = _live_catalog->get_end(seek_index);
386
387 // Set up push_marker and pop_marker so we won't try to advance beyond
388 // this field.
389 _push_marker = begin;
390 _pop_marker = _live_catalog->get_end(seek_index);
391
392 return true;
393 }
394
395 // Invalid mode.
396 _pack_error = true;
397 return false;
398 }
399
400 /**
401 * Marks the beginning of a nested series of fields.
402 *
403 * This must be called before filling the elements of an array or the
404 * individual fields in a structure field. It must also be balanced by a
405 * matching pop().
406 *
407 * It is necessary to use push() / pop() only if has_nested_fields() returns
408 * true.
409 */
410 void DCPacker::
411 push() {
412 if (!has_nested_fields()) {
413 _pack_error = true;
414
415 } else {
416 StackElement *element = new StackElement;
417 element->_current_parent = _current_parent;
418 element->_current_field_index = _current_field_index;
419 element->_push_marker = _push_marker;
420 element->_pop_marker = _pop_marker;
421 element->_next = _stack;
422 _stack = element;
423 _current_parent = _current_field;
424
425
426 // Now deal with the length prefix that might or might not be before a
427 // sequence of nested fields.
428 int num_nested_fields = _current_parent->get_num_nested_fields();
429 size_t length_bytes = _current_parent->get_num_length_bytes();
430
431 if (_mode == M_pack || _mode == M_repack) {
432 // Reserve length_bytes for when we figure out what the length is.
433 _push_marker = _pack_data.get_length();
434 _pop_marker = 0;
435 _pack_data.append_junk(length_bytes);
436
437 } else if (_mode == M_unpack) {
438 // Read length_bytes to determine the end of this nested sequence.
439 _push_marker = _unpack_p;
440 _pop_marker = 0;
441
442 if (length_bytes != 0) {
443 if (_unpack_p + length_bytes > _unpack_length) {
444 _pack_error = true;
445
446 } else {
447 size_t length;
448 if (length_bytes == 4) {
449 length = DCPackerInterface::do_unpack_uint32
450 (_unpack_data + _unpack_p);
451 _unpack_p += 4;
452 } else {
453 length = DCPackerInterface::do_unpack_uint16
454 (_unpack_data + _unpack_p);
455 _unpack_p += 2;
456 }
457 _pop_marker = _unpack_p + length;
458
459 // The explicit length trumps the number of nested fields reported
460 // by get_num_nested_fields().
461 if (length == 0) {
462 num_nested_fields = 0;
463 } else {
464 num_nested_fields = _current_parent->calc_num_nested_fields(length);
465 }
466 }
467 }
468 } else {
469 _pack_error = true;
470 }
471
472
473 // Now point to the first field in the nested range.
474 _num_nested_fields = num_nested_fields;
475 _current_field_index = 0;
476
477 if (_num_nested_fields >= 0 &&
478 _current_field_index >= _num_nested_fields) {
479 _current_field = nullptr;
480
481 } else {
482 _current_field = _current_parent->get_nested_field(_current_field_index);
483 }
484 }
485 }
486
487 /**
488 * Marks the end of a nested series of fields.
489 *
490 * This must be called to match a previous push() only after all the expected
491 * number of nested fields have been packed. It is an error to call it too
492 * early, or too late.
493 */
494 void DCPacker::
495 pop() {
496 if (_current_field != nullptr && _num_nested_fields >= 0) {
497 // Oops, didn't pack or unpack enough values.
498 _pack_error = true;
499
500 } else if (_mode == M_unpack && _pop_marker != 0 &&
501 _unpack_p != _pop_marker) {
502 // Didn't unpack the right number of values.
503 _pack_error = true;
504 }
505
506 if (_stack == nullptr) {
507 // Unbalanced pop().
508 _pack_error = true;
509
510 } else {
511 if (!_current_parent->validate_num_nested_fields(_current_field_index)) {
512 // Incorrect number of nested elements.
513 _pack_error = true;
514 }
515
516 if (_mode == M_pack || _mode == M_repack) {
517 size_t length_bytes = _current_parent->get_num_length_bytes();
518 if (length_bytes != 0) {
519 // Now go back and fill in the length of the array.
520 size_t length = _pack_data.get_length() - _push_marker - length_bytes;
521 if (length_bytes == 4) {
522 DCPackerInterface::do_pack_uint32
523 (_pack_data.get_rewrite_pointer(_push_marker, 4), length);
524 } else {
525 DCPackerInterface::validate_uint_limits(length, 16, _range_error);
526 DCPackerInterface::do_pack_uint16
527 (_pack_data.get_rewrite_pointer(_push_marker, 2), length);
528 }
529 }
530 }
531
532 _current_field = _current_parent;
533 _current_parent = _stack->_current_parent;
534 _current_field_index = _stack->_current_field_index;
535 _push_marker = _stack->_push_marker;
536 _pop_marker = _stack->_pop_marker;
537 _num_nested_fields = (_current_parent == nullptr) ? 0 : _current_parent->get_num_nested_fields();
538
539 StackElement *next = _stack->_next;
540 delete _stack;
541 _stack = next;
542 }
543
544 advance();
545 }
546
547 /**
548 * Adds the default value for the current element into the stream. If no
549 * default has been set for the current element, creates a sensible default.
550 */
551 void DCPacker::
552 pack_default_value() {
553 nassertv(_mode == M_pack || _mode == M_repack);
554 if (_current_field == nullptr) {
555 _pack_error = true;
556 } else {
557 if (_current_field->pack_default_value(_pack_data, _pack_error)) {
558 advance();
559
560 } else {
561 // If the single field didn't know how to pack a default value, try
562 // packing nested fields.
563 push();
564 while (more_nested_fields()) {
565 pack_default_value();
566 }
567 pop();
568 }
569 }
570 }
571
572 /**
573 * Internally unpacks the current numeric or string value and validates it
574 * against the type range limits, but does not return the value. If the
575 * current field contains nested fields, validates all of them.
576 */
577 void DCPacker::
578 unpack_validate() {
579 nassertv(_mode == M_unpack);
580 if (_current_field == nullptr) {
581 _pack_error = true;
582
583 } else {
584 if (_current_field->unpack_validate(_unpack_data, _unpack_length, _unpack_p,
585 _pack_error, _range_error)) {
586 advance();
587 } else {
588 // If the single field couldn't be validated, try validating nested
589 // fields.
590 push();
591 while (more_nested_fields()) {
592 unpack_validate();
593 }
594 pop();
595 }
596 }
597 }
598
599 /**
600 * Skips the current field without unpacking it and advances to the next
601 * field. If the current field contains nested fields, skips all of them.
602 */
603 void DCPacker::
604 unpack_skip() {
605 nassertv(_mode == M_unpack);
606 if (_current_field == nullptr) {
607 _pack_error = true;
608
609 } else {
610 if (_current_field->unpack_skip(_unpack_data, _unpack_length, _unpack_p,
611 _pack_error)) {
612 advance();
613
614 } else {
615 // If the single field couldn't be skipped, try skipping nested fields.
616 push();
617 while (more_nested_fields()) {
618 unpack_skip();
619 }
620 pop();
621 }
622 }
623 }
624
625 #ifdef HAVE_PYTHON
626 /**
627 * Packs the Python object of whatever type into the packer. Each numeric
628 * object and string object maps to the corresponding pack_value() call; a
629 * tuple or sequence maps to a push() followed by all of the tuple's contents
630 * followed by a pop().
631 */
632 void DCPacker::
633 pack_object(PyObject *object) {
634 nassertv(_mode == M_pack || _mode == M_repack);
635 DCPackType pack_type = get_pack_type();
636
637 // had to add this for basic 64 and unsigned data to get packed right .. Not
638 // sure if we can just do the rest this way..
639
640 switch(pack_type)
641 {
642 case PT_int64:
643 if(PyLong_Check(object))
644 {
645 pack_int64(PyLong_AsLongLong(object));
646 return;
647 }
648 #if PY_MAJOR_VERSION < 3
649 else if (PyInt_Check(object))
650 {
651 pack_int64(PyInt_AsLong(object));
652 return;
653 }
654 #endif
655 break;
656 case PT_uint64:
657 if(PyLong_Check(object))
658 {
659 pack_uint64(PyLong_AsUnsignedLongLong(object));
660 return;
661 }
662 #if PY_MAJOR_VERSION < 3
663 else if(PyInt_Check(object))
664 {
665 PyObject *obj1 = PyNumber_Long(object);
666 pack_int(PyLong_AsUnsignedLongLong(obj1));
667 Py_DECREF(obj1);
668 return;
669 }
670 #endif
671 break;
672 case PT_int:
673 if(PyLong_Check(object))
674 {
675 pack_int(PyLong_AsLong(object));
676 return;
677 }
678 #if PY_MAJOR_VERSION < 3
679 else if (PyInt_Check(object))
680 {
681 pack_int(PyInt_AsLong(object));
682 return;
683 }
684 #endif
685 break;
686 case PT_uint:
687 if(PyLong_Check(object))
688 {
689 pack_uint(PyLong_AsUnsignedLong(object));
690 return;
691 }
692 #if PY_MAJOR_VERSION < 3
693 else if (PyInt_Check(object))
694 {
695 PyObject *obj1 = PyNumber_Long(object);
696 pack_uint(PyLong_AsUnsignedLong(obj1));
697 Py_DECREF(obj1);
698 return;
699 }
700 #endif
701 break;
702 default:
703 break;
704 }
705 if (PyLong_Check(object)) {
706 pack_int(PyLong_AsLong(object));
707 #if PY_MAJOR_VERSION < 3
708 } else if (PyInt_Check(object)) {
709 pack_int(PyInt_AS_LONG(object));
710 #endif
711 } else if (PyFloat_Check(object)) {
712 pack_double(PyFloat_AS_DOUBLE(object));
713 } else if (PyLong_Check(object)) {
714 pack_int64(PyLong_AsLongLong(object));
715 #if PY_MAJOR_VERSION >= 3
716 } else if (PyUnicode_Check(object)) {
717 const char *buffer;
718 Py_ssize_t length;
719 buffer = PyUnicode_AsUTF8AndSize(object, &length);
720 if (buffer) {
721 pack_string(string(buffer, length));
722 }
723 } else if (PyBytes_Check(object)) {
724 const unsigned char *buffer;
725 Py_ssize_t length;
726 PyBytes_AsStringAndSize(object, (char **)&buffer, &length);
727 if (buffer) {
728 pack_blob(vector_uchar(buffer, buffer + length));
729 }
730 #else
731 } else if (PyString_Check(object) || PyUnicode_Check(object)) {
732 char *buffer;
733 Py_ssize_t length;
734 PyString_AsStringAndSize(object, &buffer, &length);
735 if (buffer) {
736 pack_string(string(buffer, length));
737 }
738 #endif
739 } else {
740 // For some reason, PySequence_Check() is incorrectly reporting that a
741 // class instance is a sequence, even if it doesn't provide __len__, so we
742 // double-check by testing for __len__ explicitly.
743 bool is_sequence =
744 (PySequence_Check(object) != 0) &&
745 (PyObject_HasAttrString(object, "__len__") != 0);
746 bool is_instance = false;
747
748 const DCClass *dclass = nullptr;
749 const DCPackerInterface *current_field = get_current_field();
750 if (current_field != nullptr) {
751 const DCClassParameter *class_param = get_current_field()->as_class_parameter();
752 if (class_param != nullptr) {
753 dclass = class_param->get_class();
754
755 if (dclass->has_class_def()) {
756 PyObject *class_def = dclass->get_class_def();
757 is_instance = (PyObject_IsInstance(object, dclass->get_class_def()) != 0);
758 Py_DECREF(class_def);
759 }
760 }
761 }
762
763 // If dclass is not NULL, the packer is expecting a class object. There
764 // are then two cases: (1) the user has supplied a matching class object,
765 // or (2) the user has supplied a sequence object. Unfortunately, it may
766 // be difficult to differentiate these two cases, since a class object may
767 // also be a sequence object.
768
769 // The rule to differentiate them is:
770
771 // (1) If the supplied class object is an instance of the expected class
772 // object, it is considered to be a class object.
773
774 // (2) Otherwise, if the supplied class object has a __len__() method
775 // (i.e. PySequence_Check() returns true), then it is considered to be a
776 // sequence.
777
778 // (3) Otherwise, it is considered to be a class object.
779
780 if (dclass != nullptr && (is_instance || !is_sequence)) {
781 // The supplied object is either an instance of the expected class
782 // object, or it is not a sequence--this is case (1) or (3).
783 pack_class_object(dclass, object);
784 } else if (is_sequence) {
785 // The supplied object is not an instance of the expected class object,
786 // but it is a sequence. This is case (2).
787 push();
788 int size = PySequence_Size(object);
789 for (int i = 0; i < size; ++i) {
790 PyObject *element = PySequence_GetItem(object, i);
791 if (element != nullptr) {
792 pack_object(element);
793 Py_DECREF(element);
794 } else {
795 std::cerr << "Unable to extract item " << i << " from sequence.\n";
796 }
797 }
798 pop();
799 } else {
800 // The supplied object is not a sequence, and we weren't expecting a
801 // class parameter. This is none of the above, an error.
802 ostringstream strm;
803 strm << "Don't know how to pack object: "
804 << DCField::get_pystr(object);
805 nassert_raise(strm.str());
806 _pack_error = true;
807 }
808 }
809 }
810 #endif // HAVE_PYTHON
811
812 #ifdef HAVE_PYTHON
813 /**
814 * Unpacks a Python object of the appropriate type from the stream for the
815 * current field. This may be an integer or a string for a simple field
816 * object; if the current field represents a list of fields it will be a
817 * tuple.
818 */
819 PyObject *DCPacker::
820 unpack_object() {
821 PyObject *object = nullptr;
822
823 DCPackType pack_type = get_pack_type();
824
825 switch (pack_type) {
826 case PT_invalid:
827 object = Py_None;
828 Py_INCREF(object);
829 unpack_skip();
830 break;
831
832 case PT_double:
833 {
834 double value = unpack_double();
835 object = PyFloat_FromDouble(value);
836 }
837 break;
838
839 case PT_int:
840 {
841 int value = unpack_int();
842 #if PY_MAJOR_VERSION >= 3
843 object = PyLong_FromLong(value);
844 #else
845 object = PyInt_FromLong(value);
846 #endif
847 }
848 break;
849
850 case PT_uint:
851 {
852 unsigned int value = unpack_uint();
853 #if PY_MAJOR_VERSION >= 3
854 object = PyLong_FromLong(value);
855 #else
856 if (value & 0x80000000) {
857 object = PyLong_FromUnsignedLong(value);
858 } else {
859 object = PyInt_FromLong(value);
860 }
861 #endif
862 }
863 break;
864
865 case PT_int64:
866 {
867 int64_t value = unpack_int64();
868 object = PyLong_FromLongLong(value);
869 }
870 break;
871
872 case PT_uint64:
873 {
874 uint64_t value = unpack_uint64();
875 object = PyLong_FromUnsignedLongLong(value);
876 }
877 break;
878
879 case PT_blob:
880 #if PY_MAJOR_VERSION >= 3
881 {
882 string str;
883 unpack_string(str);
884 object = PyBytes_FromStringAndSize(str.data(), str.size());
885 }
886 break;
887 #endif
888 // On Python 2, fall through to below.
889
890 case PT_string:
891 {
892 string str;
893 unpack_string(str);
894 #if PY_MAJOR_VERSION >= 3
895 object = PyUnicode_FromStringAndSize(str.data(), str.size());
896 #else
897 object = PyString_FromStringAndSize(str.data(), str.size());
898 #endif
899 }
900 break;
901
902 case PT_class:
903 {
904 const DCClassParameter *class_param = get_current_field()->as_class_parameter();
905 if (class_param != nullptr) {
906 const DCClass *dclass = class_param->get_class();
907 if (dclass->has_class_def()) {
908 // If we know what kind of class object this is and it has a valid
909 // constructor, create the class object instead of just a tuple.
910 object = unpack_class_object(dclass);
911 if (object == nullptr) {
912 std::cerr << "Unable to construct object of class "
913 << dclass->get_name() << "\n";
914 } else {
915 break;
916 }
917 }
918 }
919 }
920 // Fall through (if no constructor)
921
922 // If we don't know what kind of class object it is, or it doesn't have a
923 // constructor, fall through and make a tuple.
924 default:
925 {
926 // First, build up a list from the nested objects.
927 object = PyList_New(0);
928
929 push();
930 while (more_nested_fields()) {
931 PyObject *element = unpack_object();
932 PyList_Append(object, element);
933 Py_DECREF(element);
934 }
935 pop();
936
937 if (pack_type != PT_array) {
938 // For these other kinds of objects, we'll convert the list into a
939 // tuple.
940 PyObject *tuple = PyList_AsTuple(object);
941 Py_DECREF(object);
942 object = tuple;
943 }
944 }
945 break;
946 }
947
948 nassertr(object != nullptr, nullptr);
949 return object;
950 }
951 #endif // HAVE_PYTHON
952
953
954 /**
955 * Parses an object's value according to the DC file syntax (e.g. as a
956 * default value string) and packs it. Returns true on success, false on a
957 * parse error.
958 */
959 bool DCPacker::
960 parse_and_pack(const string &formatted_object) {
961 istringstream strm(formatted_object);
962 return parse_and_pack(strm);
963 }
964
965 /**
966 * Parses an object's value according to the DC file syntax (e.g. as a
967 * default value string) and packs it. Returns true on success, false on a
968 * parse error.
969 */
970 bool DCPacker::
971 parse_and_pack(istream &in) {
972 dc_init_parser_parameter_value(in, "parse_and_pack", *this);
973 dcyyparse();
974 dc_cleanup_parser();
975
976 bool parse_error = (dc_error_count() != 0);
977 if (parse_error) {
978 _parse_error = true;
979 }
980
981 return !parse_error;
982 }
983
984 /**
985 * Unpacks an object and formats its value into a syntax suitable for parsing
986 * in the dc file (e.g. as a default value), or as an input to parse_object.
987 */
988 string DCPacker::
989 unpack_and_format(bool show_field_names) {
990 ostringstream strm;
991 unpack_and_format(strm, show_field_names);
992 return strm.str();
993 }
994
995 /**
996 * Unpacks an object and formats its value into a syntax suitable for parsing
997 * in the dc file (e.g. as a default value), or as an input to parse_object.
998 */
999 void DCPacker::
1000 unpack_and_format(ostream &out, bool show_field_names) {
1001 DCPackType pack_type = get_pack_type();
1002
1003 if (show_field_names && !get_current_field_name().empty()) {
1004 nassertv(_current_field != nullptr);
1005 const DCField *field = _current_field->as_field();
1006 if (field != nullptr &&
1007 field->as_parameter() != nullptr) {
1008 out << field->get_name() << " = ";
1009 }
1010 }
1011
1012 switch (pack_type) {
1013 case PT_invalid:
1014 out << "<invalid>";
1015 break;
1016
1017 case PT_double:
1018 out << unpack_double();
1019 break;
1020
1021 case PT_int:
1022 out << unpack_int();
1023 break;
1024
1025 case PT_uint:
1026 out << unpack_uint();
1027 break;
1028
1029 case PT_int64:
1030 out << unpack_int64();
1031 break;
1032
1033 case PT_uint64:
1034 out << unpack_uint64();
1035 break;
1036
1037 case PT_string:
1038 enquote_string(out, '"', unpack_string());
1039 break;
1040
1041 case PT_blob:
1042 output_hex_string(out, unpack_literal_value());
1043 break;
1044
1045 default:
1046 {
1047 switch (pack_type) {
1048 case PT_array:
1049 out << '[';
1050 break;
1051
1052 case PT_field:
1053 case PT_switch:
1054 out << '(';
1055 break;
1056
1057 case PT_class:
1058 default:
1059 out << '{';
1060 break;
1061 }
1062
1063 push();
1064 while (more_nested_fields() && !had_pack_error()) {
1065 unpack_and_format(out, show_field_names);
1066
1067 if (more_nested_fields()) {
1068 out << ", ";
1069 }
1070 }
1071 pop();
1072
1073 switch (pack_type) {
1074 case PT_array:
1075 out << ']';
1076 break;
1077
1078 case PT_field:
1079 case PT_switch:
1080 out << ')';
1081 break;
1082
1083 case PT_class:
1084 default:
1085 out << '}';
1086 break;
1087 }
1088 }
1089 break;
1090 }
1091 }
1092
1093 /**
1094 * Outputs the indicated string within quotation marks.
1095 */
1096 void DCPacker::
1097 enquote_string(ostream &out, char quote_mark, const string &str) {
1098 out << quote_mark;
1099 for (string::const_iterator pi = str.begin();
1100 pi != str.end();
1101 ++pi) {
1102 if ((*pi) == quote_mark || (*pi) == '\\') {
1103 out << '\\' << (*pi);
1104
1105 } else if (!isprint(*pi) || (*pi) == '\t') {
1106 char buffer[10];
1107 sprintf(buffer, "%02x", (unsigned char)(*pi));
1108 out << "\\x" << buffer;
1109
1110 } else {
1111 out << (*pi);
1112 }
1113 }
1114 out << quote_mark;
1115 }
1116
1117 /**
1118 * Outputs the indicated string as a hex constant.
1119 */
1120 void DCPacker::
1121 output_hex_string(ostream &out, const vector_uchar &str) {
1122 out << '<';
1123 for (vector_uchar::const_iterator pi = str.begin();
1124 pi != str.end();
1125 ++pi) {
1126 char buffer[10];
1127 sprintf(buffer, "%02x", (unsigned char)(*pi));
1128 out << buffer;
1129 }
1130 out << '>';
1131 }
1132
1133 /**
1134 * When we advance past the key field on a switch record, we suddenly have
1135 * more fields available--all the appropriate alternate fields in the switch.
1136 *
1137 * This function is called when we detect this condition; it switches the
1138 * _current_parent to the appropriate case of the switch record.
1139 */
1140 void DCPacker::
1141 handle_switch(const DCSwitchParameter *switch_parameter) {
1142 // First, get the value from the key. This is either found in the unpack or
1143 // the pack data, depending on what mode we're in.
1144 const DCPackerInterface *new_parent = nullptr;
1145
1146 if (_mode == M_pack || _mode == M_repack) {
1147 const char *data = _pack_data.get_data();
1148 new_parent = switch_parameter->apply_switch
1149 (data + _push_marker, _pack_data.get_length() - _push_marker);
1150
1151 } else if (_mode == M_unpack) {
1152 new_parent = switch_parameter->apply_switch
1153 (_unpack_data + _push_marker, _unpack_p - _push_marker);
1154 }
1155
1156 if (new_parent == nullptr) {
1157 // This means an invalid value was packed for the key.
1158 _range_error = true;
1159 return;
1160 }
1161
1162 _last_switch = switch_parameter;
1163
1164 // Now substitute in the switch case for the previous parent (which replaces
1165 // the switch node itself). This will suddenly make a slew of new fields
1166 // appear.
1167 _current_parent = new_parent;
1168 _num_nested_fields = _current_parent->get_num_nested_fields();
1169
1170 if (_num_nested_fields < 0 ||
1171 _current_field_index < _num_nested_fields) {
1172 _current_field = _current_parent->get_nested_field(_current_field_index);
1173 }
1174 }
1175
1176 /**
1177 * Resets the data structures after a pack or unpack sequence.
1178 */
1179 void DCPacker::
1180 clear() {
1181 clear_stack();
1182 _current_field = nullptr;
1183 _current_parent = nullptr;
1184 _current_field_index = 0;
1185 _num_nested_fields = 0;
1186 _push_marker = 0;
1187 _pop_marker = 0;
1188 _last_switch = nullptr;
1189
1190 if (_live_catalog != nullptr) {
1191 _catalog->release_live_catalog(_live_catalog);
1192 _live_catalog = nullptr;
1193 }
1194 _catalog = nullptr;
1195 _root = nullptr;
1196 }
1197
1198 /**
1199 * Empties the stack.
1200 */
1201 void DCPacker::
1202 clear_stack() {
1203 while (_stack != nullptr) {
1204 StackElement *next = _stack->_next;
1205 delete _stack;
1206 _stack = next;
1207 }
1208 }
1209
1210 #ifdef HAVE_PYTHON
1211 /**
1212 * Given that the current element is a ClassParameter for a Python class
1213 * object, try to extract the appropriate values from the class object and
1214 * pack in.
1215 */
1216 void DCPacker::
1217 pack_class_object(const DCClass *dclass, PyObject *object) {
1218 push();
1219 while (more_nested_fields() && !_pack_error) {
1220 const DCField *field = get_current_field()->as_field();
1221 nassertv(field != nullptr);
1222 get_class_element(dclass, object, field);
1223 }
1224 pop();
1225 }
1226 #endif // HAVE_PYTHON
1227
1228 #ifdef HAVE_PYTHON
1229 /**
1230 * Given that the current element is a ClassParameter for a Python class for
1231 * which we have a valid constructor, unpack it and fill in its values.
1232 */
1233 PyObject *DCPacker::
1234 unpack_class_object(const DCClass *dclass) {
1235 PyObject *class_def = dclass->get_class_def();
1236 nassertr(class_def != nullptr, nullptr);
1237
1238 PyObject *object = nullptr;
1239
1240 if (!dclass->has_constructor()) {
1241 // If the class uses a default constructor, go ahead and create the Python
1242 // object for it now.
1243 object = PyObject_CallObject(class_def, nullptr);
1244 if (object == nullptr) {
1245 return nullptr;
1246 }
1247 }
1248
1249 push();
1250 if (object == nullptr && more_nested_fields()) {
1251 // The first nested field will be the constructor.
1252 const DCField *field = get_current_field()->as_field();
1253 nassertr(field != nullptr, object);
1254 nassertr(field == dclass->get_constructor(), object);
1255
1256 set_class_element(class_def, object, field);
1257
1258 // By now, the object should have been constructed.
1259 if (object == nullptr) {
1260 return nullptr;
1261 }
1262 }
1263 while (more_nested_fields()) {
1264 const DCField *field = get_current_field()->as_field();
1265 nassertr(field != nullptr, object);
1266
1267 set_class_element(class_def, object, field);
1268 }
1269 pop();
1270
1271 return object;
1272 }
1273 #endif // HAVE_PYTHON
1274
1275
1276 #ifdef HAVE_PYTHON
1277 /**
1278 * Unpacks the current element and stuffs it on the Python class object in
1279 * whatever way is appropriate.
1280 */
1281 void DCPacker::
1282 set_class_element(PyObject *class_def, PyObject *&object,
1283 const DCField *field) {
1284 string field_name = field->get_name();
1285 DCPackType pack_type = get_pack_type();
1286
1287 if (field_name.empty()) {
1288 switch (pack_type) {
1289 case PT_class:
1290 case PT_switch:
1291 // If the field has no name, but it is one of these container objects,
1292 // we want to unpack its nested objects directly into the class.
1293 push();
1294 while (more_nested_fields()) {
1295 const DCField *field = get_current_field()->as_field();
1296 nassertv(field != nullptr);
1297 nassertv(object != nullptr);
1298 set_class_element(class_def, object, field);
1299 }
1300 pop();
1301 break;
1302
1303 default:
1304 // Otherwise, we just skip over the field.
1305 unpack_skip();
1306 }
1307
1308 } else {
1309 // If the field does have a name, we will want to store it on the class,
1310 // either by calling a method (for a PT_field pack_type) or by setting a
1311 // value (for any other kind of pack_type).
1312
1313 PyObject *element = unpack_object();
1314
1315 if (pack_type == PT_field) {
1316 if (object == nullptr) {
1317 // If the object hasn't been constructed yet, assume this is the
1318 // constructor.
1319 object = PyObject_CallObject(class_def, element);
1320
1321 } else {
1322 if (PyObject_HasAttrString(object, (char *)field_name.c_str())) {
1323 PyObject *func = PyObject_GetAttrString(object, (char *)field_name.c_str());
1324 if (func != nullptr) {
1325 PyObject *result = PyObject_CallObject(func, element);
1326 Py_XDECREF(result);
1327 Py_DECREF(func);
1328 }
1329 }
1330 }
1331
1332 } else {
1333 nassertv(object != nullptr);
1334 PyObject_SetAttrString(object, (char *)field_name.c_str(), element);
1335 }
1336
1337 Py_DECREF(element);
1338 }
1339 }
1340 #endif // HAVE_PYTHON
1341
1342
1343 #ifdef HAVE_PYTHON
1344 /**
1345 * Gets the current element from the Python object and packs it.
1346 */
1347 void DCPacker::
1348 get_class_element(const DCClass *dclass, PyObject *object,
1349 const DCField *field) {
1350 string field_name = field->get_name();
1351 DCPackType pack_type = get_pack_type();
1352
1353 if (field_name.empty()) {
1354 switch (pack_type) {
1355 case PT_class:
1356 case PT_switch:
1357 // If the field has no name, but it is one of these container objects,
1358 // we want to get its nested objects directly from the class.
1359 push();
1360 while (more_nested_fields() && !_pack_error) {
1361 const DCField *field = get_current_field()->as_field();
1362 nassertv(field != nullptr);
1363 get_class_element(dclass, object, field);
1364 }
1365 pop();
1366 break;
1367
1368 default:
1369 // Otherwise, we just pack the default value.
1370 pack_default_value();
1371 }
1372
1373 } else {
1374 // If the field does have a name, we will want to get it from the class
1375 // and pack it. It just so happens that there's already a method that
1376 // does this on DCClass.
1377
1378 if (!dclass->pack_required_field(*this, object, field)) {
1379 _pack_error = true;
1380 }
1381 }
1382 }
1383 #endif // HAVE_PYTHON
DCClassParameter
This represents a class (or struct) object used as a parameter itself.
Definition: dcClassParameter.h:26
DCClassParameter::get_class
const DCClass * get_class() const
Returns the class object this parameter represents.
Definition: dcClassParameter.cxx:111
DCClass
Defines a particular DistributedClass as read from an input .dc file.
Definition: dcClass.h:44
DCClass::get_constructor
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
Definition: dcClass.cxx:162
DCClass::has_constructor
bool has_constructor() const
Returns true if this class has a constructor method, false if it just uses the default constructor.
Definition: dcClass.cxx:153
DCClass::get_name
const std::string & get_name() const
Returns the name of this class.
Definition: dcClass.I:26
DCField
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:37
DCPackData::get_data
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPackData.I:115
DCPackData::take_data
char * take_data()
Returns the pointer to the beginning of the data buffer, and transfers ownership of the buffer to the...
Definition: dcPackData.I:129
DCPackData::get_rewrite_pointer
char * get_rewrite_pointer(size_t position, size_t size)
Returns a pointer into the middle of the data at the indicated point.
Definition: dcPackData.I:84
DCPackData::append_junk
void append_junk(size_t size)
Adds some uninitialized bytes to the end of the data.
Definition: dcPackData.I:66
DCPackData::append_data
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
Definition: dcPackData.I:47
DCPackData::get_length
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPackData.I:102
DCPackData::clear
void clear()
Empties the contents of the data (without necessarily freeing its allocated memory).
Definition: dcPackData.I:39
DCPackerCatalog::Entry
Definition: dcPackerCatalog.h:38
DCPackerCatalog::LiveCatalog::get_begin
size_t get_begin(int n) const
Returns the beginning of the indicated field within the live data.
Definition: dcPackerCatalog.I:18
DCPackerCatalog::LiveCatalog::find_entry_by_name
int find_entry_by_name(const std::string &name) const
Returns the index number of the entry with the indicated name, or -1 if no entry has the indicated na...
Definition: dcPackerCatalog.I:55
DCPackerCatalog::LiveCatalog::get_entry
const Entry & get_entry(int n) const
Returns the nth entry in the catalog.
Definition: dcPackerCatalog.I:45
DCPackerCatalog::LiveCatalog::get_end
size_t get_end(int n) const
Returns the end of the indicated field (the byte position of the first following field) within the li...
Definition: dcPackerCatalog.I:28
DCPackerCatalog::release_live_catalog
void release_live_catalog(const LiveCatalog *live_catalog) const
Releases the LiveCatalog object that was returned by an earlier call to get_live_catalog().
Definition: dcPackerCatalog.cxx:144
DCPackerCatalog::get_live_catalog
const LiveCatalog * get_live_catalog(const char *data, size_t length) const
Returns a LiveCatalog object indicating the positions within the indicated data record of each field ...
Definition: dcPackerCatalog.cxx:96
DCPackerInterface
This defines the internal interface for packing values into a DCField.
Definition: dcPackerInterface.h:67
DCPackerInterface::validate_uint_limits
static void validate_uint_limits(unsigned int value, int num_bits, bool &range_error)
Confirms that the unsigned value fits within num_bits bits.
Definition: dcPackerInterface.I:359
DCPackerInterface::get_catalog
const DCPackerCatalog * get_catalog() const
Returns the DCPackerCatalog associated with this field, listing all of the nested fields by name.
Definition: dcPackerInterface.cxx:387
DCPackerInterface::get_name
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
Definition: dcPackerInterface.I:18
DCPackerInterface::get_num_nested_fields
int get_num_nested_fields() const
Returns the number of nested fields required by this field type.
Definition: dcPackerInterface.I:101
DCPackerInterface::unpack_validate
virtual bool unpack_validate(const char *data, size_t length, size_t &p, bool &pack_error, bool &range_error) const
Internally unpacks the current numeric or string value and validates it against the type range limits...
Definition: dcPackerInterface.cxx:332
DCPackerInterface::calc_num_nested_fields
virtual int calc_num_nested_fields(size_t length_bytes) const
This flavor of get_num_nested_fields is used during unpacking.
Definition: dcPackerInterface.cxx:178
DCPackerInterface::get_num_length_bytes
size_t get_num_length_bytes() const
Returns the number of bytes that should be written into the stream on a push() to record the number o...
Definition: dcPackerInterface.I:79
DCPackerInterface::validate_num_nested_fields
virtual bool validate_num_nested_fields(int num_nested_fields) const
After a number of fields have been packed via push() .
Definition: dcPackerInterface.cxx:199
DCPackerInterface::get_nested_field
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
Definition: dcPackerInterface.cxx:188
DCPackerInterface::unpack_skip
virtual bool unpack_skip(const char *data, size_t length, size_t &p, bool &pack_error) const
Increments p to the end of the current field without actually unpacking any data or performing any ra...
Definition: dcPackerInterface.cxx:346
DCPackerInterface::pack_default_value
virtual bool pack_default_value(DCPackData &pack_data, bool &pack_error) const
Packs the field's specified default value (or a sensible default if no value is specified) into the s...
Definition: dcPackerInterface.cxx:265
DCPacker::get_current_field
const DCPackerInterface * get_current_field() const
Returns the field that will be referenced by the next call to pack_*() or unpack_*().
Definition: dcPacker.I:87
DCPacker::unpack_validate
void unpack_validate()
Internally unpacks the current numeric or string value and validates it against the type range limits...
Definition: dcPacker.cxx:578
DCPacker::push
void push()
Marks the beginning of a nested series of fields.
Definition: dcPacker.cxx:411
DCPacker::more_nested_fields
bool more_nested_fields() const
Returns true if there are more nested fields to pack or unpack in the current push sequence,...
Definition: dcPacker.I:67
DCPacker::unpack_string
std::string unpack_string()
Unpacks the current numeric or string value from the stream.
Definition: dcPacker.I:347
DCPacker::clear_data
void clear_data()
Empties the data in the pack buffer and unpack buffer.
Definition: dcPacker.I:20
DCPacker::pack_blob
void pack_blob(const std::vector< unsigned char > &value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:223
DCPacker::unpack_int
int unpack_int()
Unpacks the current numeric or string value from the stream.
Definition: dcPacker.I:271
DCPacker::pack_uint
void pack_uint(unsigned int value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:167
DCPacker::unpack_literal_value
std::vector< unsigned char > unpack_literal_value()
Returns the literal string that represents the packed value of the current field, and advances the fi...
Definition: dcPacker.I:386
DCPacker::begin_pack
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
DCPacker::pack_int
void pack_int(int value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:153
DCPacker::begin_unpack
void begin_unpack(const DCPackerInterface *root)
Begins an unpacking session.
Definition: dcPacker.cxx:153
DCPacker::begin_repack
void begin_repack(const DCPackerInterface *root)
Begins a repacking session.
Definition: dcPacker.cxx:213
DCPacker::end_repack
bool end_repack()
Finishes the repacking session.
Definition: dcPacker.cxx:248
DCPacker::get_pack_type
DCPackType get_pack_type() const
Returns the type of value expected by the current field.
Definition: dcPacker.I:114
DCPacker::end_unpack
bool end_unpack()
Finishes the unpacking session.
Definition: dcPacker.cxx:179
DCPacker::has_nested_fields
bool has_nested_fields() const
Returns true if the current field has any nested fields (and thus expects a push() .
Definition: dcPacker.I:37
DCPacker::pack_uint64
void pack_uint64(uint64_t value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:195
DCPacker::had_error
bool had_error() const
Returns true if there has been any error (either a pack error or a range error) since the most recent...
Definition: dcPacker.I:563
DCPacker::unpack_double
double unpack_double()
Unpacks the current numeric or string value from the stream.
Definition: dcPacker.I:252
DCPacker::pop
void pop()
Marks the end of a nested series of fields.
Definition: dcPacker.cxx:495
DCPacker::had_pack_error
bool had_pack_error() const
Returns true if there has been an packing error since the most recent call to begin(); in particular,...
Definition: dcPacker.I:539
DCPacker::end_pack
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
DCPacker::pack_int64
void pack_int64(int64_t value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:181
DCPacker::unpack_skip
void unpack_skip()
Skips the current field without unpacking it and advances to the next field.
Definition: dcPacker.cxx:604
DCPacker::output_hex_string
static void output_hex_string(std::ostream &out, const std::vector< unsigned char > &str)
Outputs the indicated string as a hex constant.
Definition: dcPacker.cxx:1121
DCPacker::seek
bool seek(const std::string &field_name)
Sets the current unpack (or repack) position to the named field.
Definition: dcPacker.cxx:270
DCPacker::set_unpack_data
void set_unpack_data(const std::vector< unsigned char > &data)
Sets up the unpack_data pointer.
Definition: dcPacker.cxx:117
DCPacker::parse_and_pack
bool parse_and_pack(const std::string &formatted_object)
Parses an object's value according to the DC file syntax (e.g.
Definition: dcPacker.cxx:960
DCPacker::pack_default_value
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
DCPacker::enquote_string
static void enquote_string(std::ostream &out, char quote_mark, const std::string &str)
Outputs the indicated string within quotation marks.
Definition: dcPacker.cxx:1097
DCPacker::unpack_and_format
std::string unpack_and_format(bool show_field_names=true)
Unpacks an object and formats its value into a syntax suitable for parsing in the dc file (e....
Definition: dcPacker.cxx:989
DCPacker::pack_double
void pack_double(double value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:139
DCPacker::unpack_int64
int64_t unpack_int64()
Unpacks the current numeric or string value from the stream.
Definition: dcPacker.I:309
DCPacker::get_current_field_name
std::string get_current_field_name() const
Returns the name of the current field, if it has a name, or the empty string if the field does not ha...
Definition: dcPacker.I:127
DCPacker::unpack_uint
unsigned int unpack_uint()
Unpacks the current numeric or string value from the stream.
Definition: dcPacker.I:290
DCPacker::unpack_uint64
uint64_t unpack_uint64()
Unpacks the current numeric or string value from the stream.
Definition: dcPacker.I:328
DCPacker::pack_string
void pack_string(const std::string &value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:209
dcClassParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcClass.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcLexerDefs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcPacker.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcParserDefs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcSwitchParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcSwitch.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
py_panda.h