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