27 using std::istringstream;
29 using std::ostringstream;
32 DCPacker::StackElement *DCPacker::StackElement::_deleted_chain =
nullptr;
33 int DCPacker::StackElement::_num_ever_allocated = 0;
41 _unpack_data =
nullptr;
43 _owns_unpack_data =
false;
45 _live_catalog =
nullptr;
74 nassertv(_mode == M_idle);
83 _live_catalog =
nullptr;
85 _current_field = root;
86 _current_parent =
nullptr;
87 _current_field_index = 0;
88 _num_nested_fields = 0;
99 nassertr(_mode == M_pack,
false);
103 if (_stack !=
nullptr || _current_field !=
nullptr || _current_parent !=
nullptr) {
118 nassertv(_mode == M_idle);
120 char *buffer =
new char[data.size()];
121 memcpy(buffer, data.data(), data.size());
131 bool owns_unpack_data) {
132 nassertv(_mode == M_idle);
134 if (_owns_unpack_data) {
135 delete[] _unpack_data;
137 _unpack_data = unpack_data;
138 _unpack_length = unpack_length;
139 _owns_unpack_data = owns_unpack_data;
154 nassertv(_mode == M_idle);
155 nassertv(_unpack_data !=
nullptr);
158 _parse_error =
false;
160 _range_error =
false;
164 _live_catalog =
nullptr;
166 _current_field = root;
167 _current_parent =
nullptr;
168 _current_field_index = 0;
169 _num_nested_fields = 0;
180 nassertr(_mode == M_unpack,
false);
184 if (_stack !=
nullptr || _current_field !=
nullptr || _current_parent !=
nullptr) {
190 if (_catalog ==
nullptr) {
214 nassertv(_mode == M_idle);
215 nassertv(_unpack_data !=
nullptr);
216 nassertv(_unpack_p == 0);
219 _parse_error =
false;
221 _range_error =
false;
229 if (_live_catalog ==
nullptr) {
235 _current_field =
nullptr;
236 _current_parent =
nullptr;
237 _current_field_index = 0;
238 _num_nested_fields = 0;
249 nassertr(_mode == M_repack,
false);
252 _pack_data.
append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
270 seek(
const string &field_name) {
271 if (_catalog ==
nullptr) {
275 nassertr(_catalog !=
nullptr,
false);
276 if (_live_catalog ==
nullptr) {
282 if (seek_index < 0) {
288 return seek(seek_index);
301 if (_catalog ==
nullptr) {
305 nassertr(_catalog !=
nullptr,
false);
306 if (_live_catalog ==
nullptr) {
311 if (_mode == M_unpack) {
317 _current_field = entry._field;
318 _current_parent = entry._parent;
319 _current_field_index = entry._field_index;
321 _unpack_p = _live_catalog->
get_begin(seek_index);
327 _push_marker = _unpack_p;
332 }
else if (_mode == M_repack) {
333 nassertr(_catalog !=
nullptr,
false);
335 if (_stack !=
nullptr || _current_field !=
nullptr) {
343 if (entry._parent->as_switch_parameter() !=
nullptr) {
353 size_t begin = _live_catalog->
get_begin(seek_index);
354 if (begin < _unpack_p) {
357 _pack_data.
append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
366 if (_live_catalog ==
nullptr) {
371 begin = _live_catalog->
get_begin(seek_index);
377 _pack_data.
append_data(_unpack_data + _unpack_p, begin - _unpack_p);
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);
389 _push_marker = begin;
390 _pop_marker = _live_catalog->
get_end(seek_index);
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;
423 _current_parent = _current_field;
431 if (_mode == M_pack || _mode == M_repack) {
437 }
else if (_mode == M_unpack) {
439 _push_marker = _unpack_p;
442 if (length_bytes != 0) {
443 if (_unpack_p + length_bytes > _unpack_length) {
448 if (length_bytes == 4) {
449 length = DCPackerInterface::do_unpack_uint32
450 (_unpack_data + _unpack_p);
453 length = DCPackerInterface::do_unpack_uint16
454 (_unpack_data + _unpack_p);
457 _pop_marker = _unpack_p + length;
462 num_nested_fields = 0;
474 _num_nested_fields = num_nested_fields;
475 _current_field_index = 0;
477 if (_num_nested_fields >= 0 &&
478 _current_field_index >= _num_nested_fields) {
479 _current_field =
nullptr;
496 if (_current_field !=
nullptr && _num_nested_fields >= 0) {
500 }
else if (_mode == M_unpack && _pop_marker != 0 &&
501 _unpack_p != _pop_marker) {
506 if (_stack ==
nullptr) {
516 if (_mode == M_pack || _mode == M_repack) {
518 if (length_bytes != 0) {
520 size_t length = _pack_data.
get_length() - _push_marker - length_bytes;
521 if (length_bytes == 4) {
522 DCPackerInterface::do_pack_uint32
526 DCPackerInterface::do_pack_uint16
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;
539 StackElement *next = _stack->_next;
553 nassertv(_mode == M_pack || _mode == M_repack);
554 if (_current_field ==
nullptr) {
579 nassertv(_mode == M_unpack);
580 if (_current_field ==
nullptr) {
584 if (_current_field->
unpack_validate(_unpack_data, _unpack_length, _unpack_p,
585 _pack_error, _range_error)) {
605 nassertv(_mode == M_unpack);
606 if (_current_field ==
nullptr) {
610 if (_current_field->
unpack_skip(_unpack_data, _unpack_length, _unpack_p,
633 pack_object(PyObject *
object) {
634 nassertv(_mode == M_pack || _mode == M_repack);
643 if(PyLong_Check(
object))
648 #if PY_MAJOR_VERSION < 3 649 else if (PyInt_Check(
object))
657 if(PyLong_Check(
object))
662 #if PY_MAJOR_VERSION < 3 663 else if(PyInt_Check(
object))
665 PyObject *obj1 = PyNumber_Long(
object);
666 pack_int(PyLong_AsUnsignedLongLong(obj1));
673 if(PyLong_Check(
object))
678 #if PY_MAJOR_VERSION < 3 679 else if (PyInt_Check(
object))
687 if(PyLong_Check(
object))
689 pack_uint(PyLong_AsUnsignedLong(
object));
692 #if PY_MAJOR_VERSION < 3 693 else if (PyInt_Check(
object))
695 PyObject *obj1 = PyNumber_Long(
object);
705 if (PyLong_Check(
object)) {
707 #if PY_MAJOR_VERSION < 3 708 }
else if (PyInt_Check(
object)) {
711 }
else if (PyFloat_Check(
object)) {
713 }
else if (PyLong_Check(
object)) {
715 #if PY_MAJOR_VERSION >= 3 716 }
else if (PyUnicode_Check(
object)) {
719 buffer = PyUnicode_AsUTF8AndSize(
object, &length);
723 }
else if (PyBytes_Check(
object)) {
724 const unsigned char *buffer;
726 PyBytes_AsStringAndSize(
object, (
char **)&buffer, &length);
728 pack_blob(vector_uchar(buffer, buffer + length));
731 }
else if (PyString_Check(
object) || PyUnicode_Check(
object)) {
734 PyString_AsStringAndSize(
object, &buffer, &length);
744 (PySequence_Check(
object) != 0) &&
745 (PyObject_HasAttrString(
object,
"__len__") != 0);
746 bool is_instance =
false;
748 const DCClass *dclass =
nullptr;
750 if (current_field !=
nullptr) {
752 if (class_param !=
nullptr) {
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);
780 if (dclass !=
nullptr && (is_instance || !is_sequence)) {
783 pack_class_object(dclass,
object);
784 }
else if (is_sequence) {
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);
795 std::cerr <<
"Unable to extract item " << i <<
" from sequence.\n";
803 strm <<
"Don't know how to pack object: " 804 << DCField::get_pystr(
object);
805 nassert_raise(strm.str());
810 #endif // HAVE_PYTHON 821 PyObject *
object =
nullptr;
835 object = PyFloat_FromDouble(value);
842 #if PY_MAJOR_VERSION >= 3 843 object = PyLong_FromLong(value);
845 object = PyInt_FromLong(value);
853 #if PY_MAJOR_VERSION >= 3 854 object = PyLong_FromLong(value);
856 if (value & 0x80000000) {
857 object = PyLong_FromUnsignedLong(value);
859 object = PyInt_FromLong(value);
868 object = PyLong_FromLongLong(value);
875 object = PyLong_FromUnsignedLongLong(value);
880 #if PY_MAJOR_VERSION >= 3 884 object = PyBytes_FromStringAndSize(str.data(), str.size());
894 #if PY_MAJOR_VERSION >= 3 895 object = PyUnicode_FromStringAndSize(str.data(), str.size());
897 object = PyString_FromStringAndSize(str.data(), str.size());
905 if (class_param !=
nullptr) {
907 if (dclass->has_class_def()) {
910 object = unpack_class_object(dclass);
911 if (
object ==
nullptr) {
912 std::cerr <<
"Unable to construct object of class " 927 object = PyList_New(0);
931 PyObject *element = unpack_object();
932 PyList_Append(
object, element);
937 if (pack_type != PT_array) {
940 PyObject *tuple = PyList_AsTuple(
object);
948 nassertr(
object !=
nullptr,
nullptr);
951 #endif // HAVE_PYTHON 961 istringstream strm(formatted_object);
972 dc_init_parser_parameter_value(in,
"parse_and_pack", *
this);
976 bool parse_error = (dc_error_count() != 0);
1004 nassertv(_current_field !=
nullptr);
1005 const DCField *field = _current_field->as_field();
1006 if (field !=
nullptr &&
1007 field->as_parameter() !=
nullptr) {
1012 switch (pack_type) {
1047 switch (pack_type) {
1073 switch (pack_type) {
1099 for (string::const_iterator pi = str.begin();
1102 if ((*pi) == quote_mark || (*pi) ==
'\\') {
1103 out <<
'\\' << (*pi);
1105 }
else if (!isprint(*pi)) {
1107 sprintf(buffer,
"%02x", (
unsigned char)(*pi));
1108 out <<
"\\x" << buffer;
1123 for (vector_uchar::const_iterator pi = str.begin();
1127 sprintf(buffer,
"%02x", (
unsigned char)(*pi));
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.
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);
1151 }
else if (_mode == M_unpack) {
1152 new_parent = switch_parameter->apply_switch
1153 (_unpack_data + _push_marker, _unpack_p - _push_marker);
1156 if (new_parent ==
nullptr) {
1158 _range_error =
true;
1162 _last_switch = switch_parameter;
1167 _current_parent = new_parent;
1170 if (_num_nested_fields < 0 ||
1171 _current_field_index < _num_nested_fields) {
1182 _current_field =
nullptr;
1183 _current_parent =
nullptr;
1184 _current_field_index = 0;
1185 _num_nested_fields = 0;
1188 _last_switch =
nullptr;
1190 if (_live_catalog !=
nullptr) {
1192 _live_catalog =
nullptr;
1203 while (_stack !=
nullptr) {
1204 StackElement *next = _stack->_next;
1217 pack_class_object(
const DCClass *dclass, PyObject *
object) {
1221 nassertv(field !=
nullptr);
1222 get_class_element(dclass,
object, field);
1226 #endif // HAVE_PYTHON 1233 PyObject *DCPacker::
1234 unpack_class_object(
const DCClass *dclass) {
1235 PyObject *class_def = dclass->get_class_def();
1236 nassertr(class_def !=
nullptr,
nullptr);
1238 PyObject *
object =
nullptr;
1243 object = PyObject_CallObject(class_def,
nullptr);
1244 if (
object ==
nullptr) {
1253 nassertr(field !=
nullptr,
object);
1256 set_class_element(class_def,
object, field);
1259 if (
object ==
nullptr) {
1265 nassertr(field !=
nullptr,
object);
1267 set_class_element(class_def,
object, field);
1273 #endif // HAVE_PYTHON 1282 set_class_element(PyObject *class_def, PyObject *&
object,
1284 string field_name = field->
get_name();
1287 if (field_name.empty()) {
1288 switch (pack_type) {
1296 nassertv(field !=
nullptr);
1297 nassertv(
object !=
nullptr);
1298 set_class_element(class_def,
object, field);
1313 PyObject *element = unpack_object();
1315 if (pack_type == PT_field) {
1316 if (
object ==
nullptr) {
1319 object = PyObject_CallObject(class_def, element);
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);
1333 nassertv(
object !=
nullptr);
1334 PyObject_SetAttrString(
object, (
char *)field_name.c_str(), element);
1340 #endif // HAVE_PYTHON 1348 get_class_element(
const DCClass *dclass, PyObject *
object,
1350 string field_name = field->
get_name();
1353 if (field_name.empty()) {
1354 switch (pack_type) {
1362 nassertv(field !=
nullptr);
1363 get_class_element(dclass,
object, field);
1378 if (!dclass->pack_required_field(*
this,
object, field)) {
1383 #endif // HAVE_PYTHON uint64_t unpack_uint64()
Unpacks the current numeric or string value from the stream.
bool had_error() const
Returns true if there has been any error (either a pack error or a range error) since the most recent...
DCPackType get_pack_type() const
Returns the type of value expected by the current field.
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
void pack_int(int value)
Packs the indicated numeric or string value into the stream.
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...
bool end_repack()
Finishes the repacking session.
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
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 pack_blob(const vector_uchar &value)
Packs the indicated numeric or string value into the stream.
This represents a class (or struct) object used as a parameter itself.
A single field of a Distributed Class, either atomic or molecular.
void clear()
Empties the contents of the data (without necessarily freeing its allocated memory).
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const DCPackerInterface * get_current_field() const
Returns the field that will be referenced by the next call to pack_*() or unpack_*().
bool seek(const std::string &field_name)
Sets the current unpack (or repack) position to the named field.
void append_junk(size_t size)
Adds some uninitialized bytes to the end of the data.
int get_num_nested_fields() const
Returns the number of nested fields required by this field type.
unsigned int unpack_uint()
Unpacks the current numeric or string value from the stream.
Defines a particular DistributedClass as read from an input .dc file.
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
void pack_uint(unsigned int value)
Packs the indicated numeric or string value into the stream.
bool had_pack_error() const
Returns true if there has been an packing error since the most recent call to begin(); in particular,...
const DCClass * get_class() const
Returns the class object this parameter represents.
void pack_uint64(uint64_t value)
Packs the indicated numeric or string value into the stream.
int64_t unpack_int64()
Unpacks the current numeric or string value from the stream.
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...
void begin_repack(const DCPackerInterface *root)
Begins a repacking session.
double unpack_double()
Unpacks the current numeric or string value from the stream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_nested_fields() const
Returns true if the current field has any nested fields (and thus expects a push() .
static void output_hex_string(std::ostream &out, const vector_uchar &str)
Outputs the indicated string as a hex constant.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 set_unpack_data(const vector_uchar &data)
Sets up the unpack_data pointer.
void pack_default_value()
Adds the default value for the current element into the stream.
bool more_nested_fields() const
Returns true if there are more nested fields to pack or unpack in the current push sequence,...
const DCPackerCatalog * get_catalog() const
Returns the DCPackerCatalog associated with this field, listing all of the nested fields by name.
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...
void push()
Marks the beginning of a nested series of fields.
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...
char * take_data()
Returns the pointer to the beginning of the data buffer, and transfers ownership of the buffer to the...
size_t get_length() const
Returns the current length of the buffer.
static void enquote_string(std::ostream &out, char quote_mark, const std::string &str)
Outputs the indicated string within quotation marks.
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
std::string unpack_string()
Unpacks the current numeric or string value from the stream.
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....
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...
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
int unpack_int()
Unpacks the current numeric or string value from the stream.
size_t get_begin(int n) const
Returns the beginning of the indicated field within the live data.
const char * get_data() const
Returns the beginning of the data buffer.
const std::string & get_name() const
Returns the name of this class.
virtual int calc_num_nested_fields(size_t length_bytes) const
This flavor of get_num_nested_fields is used during unpacking.
bool parse_and_pack(const std::string &formatted_object)
Parses an object's value according to the DC file syntax (e.g.
bool has_constructor() const
Returns true if this class has a constructor method, false if it just uses the default constructor.
void unpack_skip()
Skips the current field without unpacking it and advances to the next field.
char * get_rewrite_pointer(size_t position, size_t size)
Returns a pointer into the middle of the data at the indicated point.
vector_uchar unpack_literal_value()
Returns the literal string that represents the packed value of the current field, and advances the fi...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool validate_num_nested_fields(int num_nested_fields) const
After a number of fields have been packed via push() .
bool end_pack()
Finishes a packing session.
void pack_double(double value)
Packs the indicated numeric or string value into the stream.
void pop()
Marks the end of a nested series of fields.
const Entry & get_entry(int n) const
Returns the nth entry in the 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 ...
This defines the internal interface for packing values into a DCField.
void pack_string(const std::string &value)
Packs the indicated numeric or string value into the stream.
void clear_data()
Empties the data in the pack buffer and unpack buffer.
void begin_unpack(const DCPackerInterface *root)
Begins an unpacking session.
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.
void pack_int64(int64_t value)
Packs the indicated numeric or string value into the stream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void unpack_validate()
Internally unpacks the current numeric or string value and validates it against the type range limits...