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...