27using std::istringstream;
29using std::ostringstream;
32DCPacker::StackElement *DCPacker::StackElement::_deleted_chain =
nullptr;
33int 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);
270seek(
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);
300seek(
int 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,
633pack_object(PyObject *
object) {
634 nassertv(_mode == M_pack || _mode == M_repack);
642 if (PyLong_Check(
object)) {
646#if PY_MAJOR_VERSION < 3
647 else if (PyInt_Check(
object)) {
655 if (PyLong_Check(
object)) {
659#if PY_MAJOR_VERSION < 3
660 else if (PyInt_Check(
object)) {
661 PyObject *obj1 = PyNumber_Long(
object);
662 pack_int(PyLong_AsUnsignedLongLong(obj1));
670 if (PyLong_Check(
object)) {
674#if PY_MAJOR_VERSION < 3
675 else if (PyInt_Check(
object)) {
683 if (PyLong_Check(
object)) {
684 pack_uint(PyLong_AsUnsignedLong(
object));
687#if PY_MAJOR_VERSION < 3
688 else if (PyInt_Check(
object)) {
689 PyObject *obj1 = PyNumber_Long(
object);
701 if (PyLong_Check(
object)) {
703#if PY_MAJOR_VERSION < 3
704 }
else if (PyInt_Check(
object)) {
707 }
else if (PyFloat_Check(
object)) {
709 }
else if (PyLong_Check(
object)) {
711#if PY_MAJOR_VERSION >= 3
712 }
else if (PyUnicode_Check(
object)) {
715 buffer = PyUnicode_AsUTF8AndSize(
object, &length);
719 }
else if (PyBytes_Check(
object)) {
720 const unsigned char *buffer;
722 PyBytes_AsStringAndSize(
object, (
char **)&buffer, &length);
724 pack_blob(vector_uchar(buffer, buffer + length));
727 }
else if (PyString_Check(
object) || PyUnicode_Check(
object)) {
730 PyString_AsStringAndSize(
object, &buffer, &length);
740 (PySequence_Check(
object) != 0) &&
741 (PyObject_HasAttrString(
object,
"__len__") != 0);
742 bool is_instance =
false;
744 const DCClass *dclass =
nullptr;
746 if (current_field !=
nullptr) {
748 if (class_param !=
nullptr) {
751 if (dclass->has_class_def()) {
752 PyObject *class_def = dclass->get_class_def();
753 is_instance = (PyObject_IsInstance(
object, dclass->get_class_def()) != 0);
754 Py_DECREF(class_def);
776 if (dclass !=
nullptr && (is_instance || !is_sequence)) {
779 pack_class_object(dclass,
object);
780 }
else if (is_sequence) {
784 int size = PySequence_Size(
object);
785 for (
int i = 0; i < size; ++i) {
786 PyObject *element = PySequence_GetItem(
object, i);
787 if (element !=
nullptr) {
788 pack_object(element);
791 std::cerr <<
"Unable to extract item " << i <<
" from sequence.\n";
799 strm <<
"Don't know how to pack object: "
800 << DCField::get_pystr(
object);
801 nassert_raise(strm.str());
817 PyObject *
object =
nullptr;
831 object = PyFloat_FromDouble(value);
838#if PY_MAJOR_VERSION >= 3
839 object = PyLong_FromLong(value);
841 object = PyInt_FromLong(value);
849#if PY_MAJOR_VERSION >= 3
850 object = PyLong_FromUnsignedLong(value);
852 if (value & 0x80000000) {
853 object = PyLong_FromUnsignedLong(value);
855 object = PyInt_FromLong(value);
864 object = PyLong_FromLongLong(value);
871 object = PyLong_FromUnsignedLongLong(value);
876#if PY_MAJOR_VERSION >= 3
880 object = PyBytes_FromStringAndSize(str.data(), str.size());
890#if PY_MAJOR_VERSION >= 3
891 object = PyUnicode_FromStringAndSize(str.data(), str.size());
892 if (
object ==
nullptr) {
893 nassert_raise(
"Unable to decode UTF-8 string; use blob type for binary data");
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);
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) {
1097enquote_string(ostream &out,
char quote_mark,
const string &str) {
1099 for (string::const_iterator pi = str.begin();
1102 if ((*pi) == quote_mark || (*pi) ==
'\\') {
1103 out <<
'\\' << (*pi);
1105 }
else if (!isprint(*pi) || (*pi) ==
'\t') {
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));
1146 if (_mode == M_pack || _mode == M_repack) {
1147 const char *data = _pack_data.
get_data();
1149 (data + _push_marker, _pack_data.
get_length() - _push_marker);
1151 }
else if (_mode == M_unpack) {
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;
1217pack_class_object(
const DCClass *dclass, PyObject *
object) {
1221 nassertv(field !=
nullptr);
1222 get_class_element(dclass,
object, field);
1234unpack_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);
1282set_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);
1348get_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)) {
This represents a class (or struct) object used as a parameter itself.
const DCClass * get_class() const
Returns the class object this parameter represents.
Defines a particular DistributedClass as read from an input .dc file.
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
bool has_constructor() const
Returns true if this class has a constructor method, false if it just uses the default constructor.
const std::string & get_name() const
Returns the name of this class.
A single field of a Distributed Class, either atomic or molecular.
const char * get_data() const
Returns the beginning of the data buffer.
char * take_data()
Returns the pointer to the beginning of the data buffer, and transfers ownership of the buffer to the...
char * get_rewrite_pointer(size_t position, size_t size)
Returns a pointer into the middle of the data at the indicated point.
void append_junk(size_t size)
Adds some uninitialized bytes to the end of the data.
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
size_t get_length() const
Returns the current length of the buffer.
void clear()
Empties the contents of the data (without necessarily freeing its allocated memory).
size_t get_begin(int n) const
Returns the beginning of the indicated field within the live data.
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...
const Entry & get_entry(int n) const
Returns the nth entry in the catalog.
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 release_live_catalog(const LiveCatalog *live_catalog) const
Releases the LiveCatalog object that was returned by an earlier call to 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 ...
This defines the internal interface for packing values into a DCField.
static void validate_uint_limits(unsigned int value, int num_bits, bool &range_error)
Confirms that the unsigned value fits within num_bits bits.
const DCPackerCatalog * get_catalog() const
Returns the DCPackerCatalog associated with this field, listing all of the nested fields by name.
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
int get_num_nested_fields() const
Returns the number of nested fields required by this field type.
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...
virtual int calc_num_nested_fields(size_t length_bytes) const
This flavor of get_num_nested_fields is used during unpacking.
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...
virtual bool validate_num_nested_fields(int num_nested_fields) const
After a number of fields have been packed via push() .
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
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...
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...
const DCPackerInterface * get_current_field() const
Returns the field that will be referenced by the next call to pack_*() or unpack_*().
void unpack_validate()
Internally unpacks the current numeric or string value and validates it against the type range limits...
void push()
Marks the beginning of a nested series of fields.
bool more_nested_fields() const
Returns true if there are more nested fields to pack or unpack in the current push sequence,...
std::string unpack_string()
Unpacks the current numeric or string value from the stream.
void clear_data()
Empties the data in the pack buffer and unpack buffer.
void pack_blob(const std::vector< unsigned char > &value)
Packs the indicated numeric or string value into the stream.
int unpack_int()
Unpacks the current numeric or string value from the stream.
void pack_uint(unsigned int value)
Packs the indicated numeric or string value into the stream.
std::vector< unsigned char > unpack_literal_value()
Returns the literal string that represents the packed value of the current field, and advances the fi...
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
void pack_int(int value)
Packs the indicated numeric or string value into the stream.
void begin_unpack(const DCPackerInterface *root)
Begins an unpacking session.
void begin_repack(const DCPackerInterface *root)
Begins a repacking session.
bool end_repack()
Finishes the repacking session.
DCPackType get_pack_type() const
Returns the type of value expected by the current field.
bool end_unpack()
Finishes the unpacking session.
bool has_nested_fields() const
Returns true if the current field has any nested fields (and thus expects a push() .
void pack_uint64(uint64_t value)
Packs the indicated numeric or string value into 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...
double unpack_double()
Unpacks the current numeric or string value from the stream.
void pop()
Marks the end of a nested series of fields.
bool had_pack_error() const
Returns true if there has been an packing error since the most recent call to begin(); in particular,...
bool end_pack()
Finishes a packing session.
void pack_int64(int64_t value)
Packs the indicated numeric or string value into the stream.
void unpack_skip()
Skips the current field without unpacking it and advances to the next field.
static void output_hex_string(std::ostream &out, const std::vector< unsigned char > &str)
Outputs the indicated string as a hex constant.
bool seek(const std::string &field_name)
Sets the current unpack (or repack) position to the named field.
void set_unpack_data(const std::vector< unsigned char > &data)
Sets up the unpack_data pointer.
bool parse_and_pack(const std::string &formatted_object)
Parses an object's value according to the DC file syntax (e.g.
void pack_default_value()
Adds the default value for the current element into the stream.
static void enquote_string(std::ostream &out, char quote_mark, const std::string &str)
Outputs the indicated string within quotation marks.
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....
void pack_double(double 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.
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...
unsigned int unpack_uint()
Unpacks the current numeric or string value from the stream.
uint64_t unpack_uint64()
Unpacks the current numeric or string value from the stream.
void pack_string(const std::string &value)
Packs the indicated numeric or string value into the stream.
This represents a switch object used as a parameter itself, which packs the appropriate fields of the...
const DCPackerInterface * apply_switch(const char *value_data, size_t length) const
Returns the DCPackerInterface that presents the alternative fields for the case indicated by the give...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.