17 #include "dcParserDefs.h"
18 #include "dcLexerDefs.h"
19 #include "dcClassParameter.h"
20 #include "dcSwitchParameter.h"
27 DCPacker::StackElement *DCPacker::StackElement::_deleted_chain = NULL;
28 int DCPacker::StackElement::_num_ever_allocated = 0;
40 _owns_unpack_data =
false;
77 nassertv(_mode == M_idle);
88 _current_field = root;
89 _current_parent = NULL;
90 _current_field_index = 0;
91 _num_nested_fields = 0;
104 nassertr(_mode == M_pack,
false);
108 if (_stack != NULL || _current_field != NULL || _current_parent != NULL) {
126 nassertv(_mode == M_idle);
128 char *buffer =
new char[data.length()];
129 memcpy(buffer, data.data(), data.length());
142 bool owns_unpack_data) {
143 nassertv(_mode == M_idle);
145 if (_owns_unpack_data) {
146 delete[] _unpack_data;
148 _unpack_data = unpack_data;
149 _unpack_length = unpack_length;
150 _owns_unpack_data = owns_unpack_data;
169 nassertv(_mode == M_idle);
170 nassertv(_unpack_data != NULL);
173 _parse_error =
false;
175 _range_error =
false;
179 _live_catalog = NULL;
181 _current_field = root;
182 _current_parent = NULL;
183 _current_field_index = 0;
184 _num_nested_fields = 0;
198 nassertr(_mode == M_unpack,
false);
202 if (_stack != NULL || _current_field != NULL || _current_parent != NULL) {
239 nassertv(_mode == M_idle);
240 nassertv(_unpack_data != NULL);
241 nassertv(_unpack_p == 0);
244 _parse_error =
false;
246 _range_error =
false;
254 if (_live_catalog == NULL) {
260 _current_field = NULL;
261 _current_parent = NULL;
262 _current_field_index = 0;
263 _num_nested_fields = 0;
277 nassertr(_mode == M_repack,
false);
280 _pack_data.
append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
301 seek(
const string &field_name) {
307 if (_live_catalog == NULL) {
313 if (seek_index < 0) {
319 return seek(seek_index);
341 if (_live_catalog == NULL) {
346 if (_mode == M_unpack) {
352 _current_field = entry._field;
353 _current_parent = entry._parent;
354 _current_field_index = entry._field_index;
356 _unpack_p = _live_catalog->
get_begin(seek_index);
362 _push_marker = _unpack_p;
367 }
else if (_mode == M_repack) {
370 if (_stack != NULL || _current_field != NULL) {
388 size_t begin = _live_catalog->
get_begin(seek_index);
389 if (begin < _unpack_p) {
392 _pack_data.
append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
401 if (_live_catalog == NULL) {
406 begin = _live_catalog->
get_begin(seek_index);
412 _pack_data.
append_data(_unpack_data + _unpack_p, begin - _unpack_p);
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);
424 _push_marker = begin;
425 _pop_marker = _live_catalog->
get_end(seek_index);
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;
460 _current_parent = _current_field;
468 if (_mode == M_pack || _mode == M_repack) {
475 }
else if (_mode == M_unpack) {
478 _push_marker = _unpack_p;
481 if (length_bytes != 0) {
482 if (_unpack_p + length_bytes > _unpack_length) {
487 if (length_bytes == 4) {
488 length = DCPackerInterface::do_unpack_uint32
489 (_unpack_data + _unpack_p);
492 length = DCPackerInterface::do_unpack_uint16
493 (_unpack_data + _unpack_p);
496 _pop_marker = _unpack_p + length;
501 num_nested_fields = 0;
513 _num_nested_fields = num_nested_fields;
514 _current_field_index = 0;
516 if (_num_nested_fields >= 0 &&
517 _current_field_index >= _num_nested_fields) {
518 _current_field = NULL;
538 if (_current_field != NULL && _num_nested_fields >= 0) {
542 }
else if (_mode == M_unpack && _pop_marker != 0 &&
543 _unpack_p != _pop_marker) {
548 if (_stack == NULL) {
558 if (_mode == M_pack || _mode == M_repack) {
560 if (length_bytes != 0) {
562 size_t length = _pack_data.
get_length() - _push_marker - length_bytes;
563 if (length_bytes == 4) {
564 DCPackerInterface::do_pack_uint32
568 DCPackerInterface::do_pack_uint16
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;
581 StackElement *next = _stack->_next;
598 nassertv(_mode == M_pack || _mode == M_repack);
599 if (_current_field == NULL) {
627 nassertv(_mode == M_unpack);
628 if (_current_field == NULL) {
632 if (_current_field->
unpack_validate(_unpack_data, _unpack_length, _unpack_p,
633 _pack_error, _range_error)) {
656 nassertv(_mode == M_unpack);
657 if (_current_field == NULL) {
661 if (_current_field->
unpack_skip(_unpack_data, _unpack_length, _unpack_p,
687 pack_object(PyObject *
object) {
688 nassertv(_mode == M_pack || _mode == M_repack);
697 if(PyLong_Check(
object))
702 #if PY_MAJOR_VERSION < 3
703 else if (PyInt_Check(
object))
711 if(PyLong_Check(
object))
716 #if PY_MAJOR_VERSION < 3
717 else if(PyInt_Check(
object))
719 PyObject *obj1 = PyNumber_Long(
object);
720 pack_int(PyLong_AsUnsignedLongLong(obj1));
727 if(PyLong_Check(
object))
732 #if PY_MAJOR_VERSION < 3
733 else if (PyInt_Check(
object))
741 if(PyLong_Check(
object))
743 pack_uint(PyLong_AsUnsignedLong(
object));
746 #if PY_MAJOR_VERSION < 3
747 else if (PyInt_Check(
object))
749 PyObject *obj1 = PyNumber_Long(
object);
759 if (PyLong_Check(
object)) {
761 #if PY_MAJOR_VERSION < 3
762 }
else if (PyInt_Check(
object)) {
765 }
else if (PyFloat_Check(
object)) {
767 }
else if (PyLong_Check(
object)) {
769 #if PY_MAJOR_VERSION >= 3
770 }
else if (PyUnicode_Check(
object)) {
773 buffer = PyUnicode_AsUTF8AndSize(
object, &length);
777 }
else if (PyBytes_Check(
object)) {
780 PyBytes_AsStringAndSize(
object, &buffer, &length);
785 }
else if (PyString_Check(
object) || PyUnicode_Check(
object)) {
788 PyString_AsStringAndSize(
object, &buffer, &length);
798 (PySequence_Check(
object) != 0) &&
799 (PyObject_HasAttrString(
object,
"__len__") != 0);
800 bool is_instance =
false;
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);
834 if (dclass != (
DCClass *)NULL && (is_instance || !is_sequence)) {
838 pack_class_object(dclass,
object);
839 }
else if (is_sequence) {
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);
850 cerr <<
"Unable to extract item " << i <<
" from sequence.\n";
859 strm <<
"Don't know how to pack object: "
860 << DCField::get_pystr(
object);
861 nassert_raise(strm.str());
866 #endif // HAVE_PYTHON
880 PyObject *
object = NULL;
894 object = PyFloat_FromDouble(value);
901 #if PY_MAJOR_VERSION >= 3
902 object = PyLong_FromLong(value);
904 object = PyInt_FromLong(value);
912 #if PY_MAJOR_VERSION >= 3
913 object = PyLong_FromLong(value);
915 if (value & 0x80000000) {
916 object = PyLong_FromUnsignedLong(value);
918 object = PyInt_FromLong(value);
927 object = PyLong_FromLongLong(value);
934 object = PyLong_FromUnsignedLongLong(value);
939 #if PY_MAJOR_VERSION >= 3
943 object = PyBytes_FromStringAndSize(str.data(), str.size());
953 #if PY_MAJOR_VERSION >= 3
954 object = PyUnicode_FromStringAndSize(str.data(), str.size());
956 object = PyString_FromStringAndSize(str.data(), str.size());
966 if (dclass->has_class_def()) {
970 object = unpack_class_object(dclass);
971 if (
object == (PyObject *)NULL) {
972 cerr <<
"Unable to construct object of class "
987 object = PyList_New(0);
991 PyObject *element = unpack_object();
992 PyList_Append(
object, element);
997 if (pack_type != PT_array) {
1000 PyObject *tuple = PyList_AsTuple(
object);
1008 nassertr(
object != (PyObject *)NULL, NULL);
1011 #endif // HAVE_PYTHON
1023 istringstream strm(formatted_object);
1036 dc_init_parser_parameter_value(in,
"parse_and_pack", *
this);
1038 dc_cleanup_parser();
1040 bool parse_error = (dc_error_count() != 0);
1042 _parse_error =
true;
1045 return !parse_error;
1075 const DCField *field = _current_field->as_field();
1076 if (field != (
DCField *)NULL &&
1082 switch (pack_type) {
1117 switch (pack_type) {
1143 switch (pack_type) {
1171 for (string::const_iterator pi = str.begin();
1174 if ((*pi) == quote_mark || (*pi) ==
'\\') {
1175 out <<
'\\' << (*pi);
1177 }
else if (!isprint(*pi)) {
1179 sprintf(buffer,
"%02x", (
unsigned char)(*pi));
1180 out <<
"\\x" << buffer;
1197 for (string::const_iterator pi = str.begin();
1201 sprintf(buffer,
"%02x", (
unsigned char)(*pi));
1208 // Function: DCPacker::handle_switch
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.
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.
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.
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);
1229 }
else if (_mode == M_unpack) {
1230 new_parent = switch_parameter->apply_switch
1231 (_unpack_data + _push_marker, _unpack_p - _push_marker);
1236 _range_error =
true;
1240 _last_switch = switch_parameter;
1245 _current_parent = new_parent;
1248 if (_num_nested_fields < 0 ||
1249 _current_field_index < _num_nested_fields) {
1263 _current_field = NULL;
1264 _current_parent = NULL;
1265 _current_field_index = 0;
1266 _num_nested_fields = 0;
1269 _last_switch = NULL;
1273 _live_catalog = NULL;
1286 while (_stack != (StackElement *)NULL) {
1287 StackElement *next = _stack->_next;
1302 pack_class_object(
const DCClass *dclass, PyObject *
object) {
1306 nassertv(field != (
DCField *)NULL);
1307 get_class_element(dclass,
object, field);
1311 #endif // HAVE_PYTHON
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);
1326 PyObject *
object = NULL;
1331 object = PyObject_CallObject(class_def, NULL);
1332 if (
object == (PyObject *)NULL) {
1341 nassertr(field != (
DCField *)NULL,
object);
1344 set_class_element(class_def,
object, field);
1347 if (
object == (PyObject *)NULL) {
1353 nassertr(field != (
DCField *)NULL,
object);
1355 set_class_element(class_def,
object, field);
1361 #endif // HAVE_PYTHON
1372 set_class_element(PyObject *class_def, PyObject *&
object,
1374 string field_name = field->
get_name();
1377 if (field_name.empty()) {
1378 switch (pack_type) {
1387 nassertv(field != (
DCField *)NULL);
1388 nassertv(
object != (PyObject *)NULL);
1389 set_class_element(class_def,
object, field);
1404 PyObject *element = unpack_object();
1406 if (pack_type == PT_field) {
1407 if (
object == (PyObject *)NULL) {
1410 object = PyObject_CallObject(class_def, element);
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);
1424 nassertv(
object != (PyObject *)NULL);
1425 PyObject_SetAttrString(
object, (
char *)field_name.c_str(), element);
1431 #endif // HAVE_PYTHON
1442 get_class_element(
const DCClass *dclass, PyObject *
object,
1444 string field_name = field->
get_name();
1447 if (field_name.empty()) {
1448 switch (pack_type) {
1457 nassertv(field != (
DCField *)NULL);
1458 get_class_element(dclass,
object, field);
1473 if (!dclass->pack_required_field(*
this,
object, field)) {
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_*().
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...
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 DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
bool end_repack()
Finishes the repacking session.
const string & get_name() const
Returns the name of this class.
void pack_int64(PN_int64 value)
Packs the indicated numeric or string value into the stream.
bool has_nested_fields() const
Returns true if the current field has any nested fields (and thus expects a push() ...
bool parse_and_pack(const string &formatted_object)
Parses an object's value according to the DC file syntax (e.g.
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).
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...
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.
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.
Defines a particular DistributedClass as read from an input .dc file.
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...
void pack_uint(unsigned int value)
Packs the indicated numeric or string value into the stream.
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.
double unpack_double()
Unpacks the current numeric or string value from the stream.
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
Represents the type specification for a single parameter within a field specification.
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.
void pack_default_value()
Adds the default value for the current element into the stream.
static void output_hex_string(ostream &out, const string &str)
Outputs the indicated string as a hex constant.
string unpack_literal_value()
Returns the literal string that represents the packed value of the current field, and advances the fi...
void push()
Marks the beginning of a nested series of fields.
void pack_string(const string &value)
Packs the indicated numeric or string value into the stream.
size_t get_length() const
Returns the current length of the buffer.
char * take_data()
Returns the pointer to the beginning of the data buffer, and transfers ownership of the buffer to the...
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...
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.
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
int unpack_int()
Unpacks the current numeric or string value from the stream.
PN_uint64 unpack_uint64()
Unpacks the current numeric or string value from the stream.
static void enquote_string(ostream &out, char quote_mark, const string &str)
Outputs the indicated string within quotation marks.
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.
char * get_rewrite_pointer(size_t position, size_t size)
Returns a pointer into the middle of the data at the indicated point.
bool more_nested_fields() const
Returns true if there are more nested fields to pack or unpack in the current push sequence...
string unpack_string()
Unpacks the current numeric or string value from the stream.
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...
const char * get_data() const
Returns the beginning of the data buffer.
bool end_pack()
Finishes a packing session.
void set_unpack_data(const string &data)
Sets up the unpack_data pointer.
PN_int64 unpack_int64()
Unpacks the current numeric or string value from the stream.
void pack_double(double value)
Packs the indicated numeric or string value into the stream.
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.
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...
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_uint64(PN_uint64 value)
Packs the indicated numeric or string value into the stream.
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...