From aff151835d64985d47a4c4791abd45cf4e5c58a6 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 17 Jun 2004 03:26:20 +0000 Subject: [PATCH] python unpacking --- direct/src/dcparser/dcAtomicField.cxx | 41 - direct/src/dcparser/dcAtomicField.h | 6 - direct/src/dcparser/dcClass.cxx | 6 +- direct/src/dcparser/dcField.cxx | 65 +- direct/src/dcparser/dcField.h | 8 +- direct/src/dcparser/dcMolecularField.cxx | 37 - direct/src/dcparser/dcMolecularField.h | 6 - direct/src/dcparser/dcPacker.I | 145 +++- direct/src/dcparser/dcPacker.cxx | 260 +++++- direct/src/dcparser/dcPacker.h | 44 +- direct/src/dcparser/dcPackerInterface.cxx | 67 +- direct/src/dcparser/dcPackerInterface.h | 32 +- direct/src/dcparser/dcParser.cxx.prebuilt | 4 +- direct/src/dcparser/dcParser.yxx | 4 +- direct/src/dcparser/dcSimpleType.cxx | 928 +++++++++++++--------- direct/src/dcparser/dcSimpleType.h | 21 +- direct/src/dcparser/dcType.h | 6 - 17 files changed, 1109 insertions(+), 571 deletions(-) diff --git a/direct/src/dcparser/dcAtomicField.cxx b/direct/src/dcparser/dcAtomicField.cxx index ebca8a1b8d..e1c1c0c66e 100644 --- a/direct/src/dcparser/dcAtomicField.cxx +++ b/direct/src/dcparser/dcAtomicField.cxx @@ -407,20 +407,6 @@ generate_hash(HashGenerator &hashgen) const { hashgen.add_int(_flags); } -//////////////////////////////////////////////////////////////////// -// Function: DCAtomicField::has_nested_fields -// Access: Public, Virtual -// Description: Returns true if this field type has any nested fields -// (and thus expects a push() .. pop() interface to the -// DCPacker), or false otherwise. If this returns true, -// get_num_nested_fields() may be called to determine -// how many nested fields are expected. -//////////////////////////////////////////////////////////////////// -bool DCAtomicField:: -has_nested_fields() const { - return true; -} - //////////////////////////////////////////////////////////////////// // Function: DCAtomicField::get_num_nested_fields // Access: Public, Virtual @@ -447,30 +433,3 @@ get_nested_field(int n) const { nassertr(n >= 0 && n < (int)_elements.size(), NULL); return _elements[n]._type; } - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: DCAtomicField::do_unpack_args -// Access: Public, Virtual -// Description: Unpacks the values from the datagram, beginning at -// the current point in the interator, into a vector of -// Python objects (each with its own reference count). -// Returns true if there are enough values in the -// datagram, false otherwise. -//////////////////////////////////////////////////////////////////// -bool DCAtomicField:: -do_unpack_args(pvector &args, DatagramIterator &iterator) const { - Elements::const_iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - const ElementType &element = (*ei); - PyObject *item = element._type->unpack_arg(iterator); - if (item == (PyObject *)NULL) { - // Ran out of datagram bytes. - return false; - } - args.push_back(item); - } - - return true; -} -#endif // HAVE_PYTHON diff --git a/direct/src/dcparser/dcAtomicField.h b/direct/src/dcparser/dcAtomicField.h index 4e70471638..bb323382db 100644 --- a/direct/src/dcparser/dcAtomicField.h +++ b/direct/src/dcparser/dcAtomicField.h @@ -64,15 +64,9 @@ public: virtual void write(ostream &out, bool brief, int indent_level) const; virtual void generate_hash(HashGenerator &hash) const; - virtual bool has_nested_fields() const; virtual int get_num_nested_fields() const; virtual DCPackerInterface *get_nested_field(int n) const; -public: -#ifdef HAVE_PYTHON - virtual bool do_unpack_args(pvector &args, DatagramIterator &iterator) const; -#endif - public: // These members define the primary interface to the atomic field // definition as read from the file. diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index cfd00a630e..71cee7e64d 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/direct/src/dcparser/dcClass.cxx @@ -239,7 +239,7 @@ receive_update(PyObject *distobj, DatagramIterator &iterator) const { void DCClass:: receive_update_broadcast_required(PyObject *distobj, DatagramIterator &iterator) const { int num_fields = get_num_inherited_fields(); - for (int i = 0; i < num_fields; i++) { + for (int i = 0; i < num_fields && !PyErr_Occurred(); i++) { DCField *field = get_inherited_field(i); DCAtomicField *atom = field->as_atomic_field(); if (atom != (DCAtomicField *)NULL && @@ -262,7 +262,7 @@ receive_update_broadcast_required(PyObject *distobj, DatagramIterator &iterator) void DCClass:: receive_update_all_required(PyObject *distobj, DatagramIterator &iterator) const { int num_fields = get_num_inherited_fields(); - for (int i = 0; i < num_fields; i++) { + for (int i = 0; i < num_fields && !PyErr_Occurred(); i++) { DCField *field = get_inherited_field(i); DCAtomicField *atom = field->as_atomic_field(); if (atom != (DCAtomicField *)NULL && atom->is_required()) { @@ -282,7 +282,7 @@ receive_update_all_required(PyObject *distobj, DatagramIterator &iterator) const void DCClass:: receive_update_other(PyObject *distobj, DatagramIterator &iterator) const { int num_fields = iterator.get_uint16(); - for (int i = 0; i < num_fields; i++) { + for (int i = 0; i < num_fields && !PyErr_Occurred(); i++) { receive_update(distobj, iterator); } } diff --git a/direct/src/dcparser/dcField.cxx b/direct/src/dcparser/dcField.cxx index be6c04b0a0..2106ef39c4 100644 --- a/direct/src/dcparser/dcField.cxx +++ b/direct/src/dcparser/dcField.cxx @@ -79,10 +79,17 @@ bool DCField:: pack_args(Datagram &datagram, PyObject *sequence) const { nassertr(PySequence_Check(sequence), false); DCPacker packer; - packer.begin(this); + packer.begin_pack(this); packer.pack_object(sequence); - if (packer.end()) { + if (packer.end_pack()) { datagram.append_data(packer.get_data(), packer.get_length()); + + /* + PyObject *str = PyObject_Str(sequence); + cerr << "pack " << get_name() << PyString_AsString(str) << "\n"; + Py_DECREF(str); + */ + return true; } @@ -113,16 +120,29 @@ pack_args(Datagram &datagram, PyObject *sequence) const { //////////////////////////////////////////////////////////////////// PyObject *DCField:: unpack_args(DatagramIterator &iterator) const { - pvector args; - bool enough_data = do_unpack_args(args, iterator); - nassertr(enough_data, NULL); + DCPacker packer; + packer.begin_unpack(iterator.get_remaining_bytes(), this); - PyObject *tuple = PyTuple_New(args.size()); - for (size_t i = 0; i < args.size(); i++) { - PyTuple_SET_ITEM(tuple, i, args[i]); + PyObject *object = packer.unpack_object(); + + if (packer.end_unpack()) { + // Successfully unpacked. + iterator.skip_bytes(packer.get_num_unpacked_bytes()); + + /* + PyObject *str = PyObject_Str(object); + cerr << "recv " << get_name() << PyString_AsString(str) << "\n"; + Py_DECREF(str); + */ + + return object; } - - return tuple; + + ostringstream strm; + strm << "Error unpacking field " << get_name(); + + nassert_raise(strm.str()); + return object; } #endif // HAVE_PYTHON @@ -146,6 +166,7 @@ receive_update(PyObject *distobj, DatagramIterator &iterator) const { Py_XDECREF(result); Py_DECREF(func); } + Py_DECREF(args); } #endif // HAVE_PYTHON @@ -225,3 +246,27 @@ generate_hash(HashGenerator &hashgen) const { // redundant. However, the field name is significant. hashgen.add_string(_name); } + +//////////////////////////////////////////////////////////////////// +// Function: DCField::has_nested_fields +// Access: Public, Virtual +// Description: Returns true if this field type has any nested fields +// (and thus expects a push() .. pop() interface to the +// DCPacker), or false otherwise. If this returns true, +// get_num_nested_fields() may be called to determine +// how many nested fields are expected. +//////////////////////////////////////////////////////////////////// +bool DCField:: +has_nested_fields() const { + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCField::get_pack_type +// Access: Public, Virtual +// Description: Returns the type of value expected by this field. +//////////////////////////////////////////////////////////////////// +DCPackType DCField:: +get_pack_type() const { + return PT_field; +} diff --git a/direct/src/dcparser/dcField.h b/direct/src/dcparser/dcField.h index 4dc541439e..a1f3fbd5cd 100644 --- a/direct/src/dcparser/dcField.h +++ b/direct/src/dcparser/dcField.h @@ -66,15 +66,13 @@ public: virtual void write(ostream &out, bool brief, int indent_level) const=0; virtual void generate_hash(HashGenerator &hash) const; + virtual bool has_nested_fields() const; + virtual DCPackType get_pack_type() const; + protected: int _number; string _name; -public: -#ifdef HAVE_PYTHON - virtual bool do_unpack_args(pvector &args, DatagramIterator &iterator) const=0; -#endif - friend class DCClass; }; diff --git a/direct/src/dcparser/dcMolecularField.cxx b/direct/src/dcparser/dcMolecularField.cxx index 830b2119ae..1e648d05b0 100644 --- a/direct/src/dcparser/dcMolecularField.cxx +++ b/direct/src/dcparser/dcMolecularField.cxx @@ -132,20 +132,6 @@ generate_hash(HashGenerator &hashgen) const { } } -//////////////////////////////////////////////////////////////////// -// Function: DCMolecularField::has_nested_fields -// Access: Public, Virtual -// Description: Returns true if this field type has any nested fields -// (and thus expects a push() .. pop() interface to the -// DCPacker), or false otherwise. If this returns true, -// get_num_nested_fields() may be called to determine -// how many nested fields are expected. -//////////////////////////////////////////////////////////////////// -bool DCMolecularField:: -has_nested_fields() const { - return true; -} - //////////////////////////////////////////////////////////////////// // Function: DCMolecularField::get_num_nested_fields // Access: Public, Virtual @@ -172,26 +158,3 @@ get_nested_field(int n) const { nassertr(n >= 0 && n < (int)_nested_fields.size(), NULL); return _nested_fields[n]; } - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: DCMolecularField::do_unpack_args -// Access: Public, Virtual -// Description: Unpacks the values from the datagram, beginning at -// the current point in the interator, into a vector of -// Python objects (each with its own reference count). -// Returns true if there are enough values in the -// datagram, false otherwise. -//////////////////////////////////////////////////////////////////// -bool DCMolecularField:: -do_unpack_args(pvector &args, DatagramIterator &iterator) const { - Fields::const_iterator fi; - for (fi = _fields.begin(); fi != _fields.end(); ++fi) { - if (!(*fi)->do_unpack_args(args, iterator)) { - return false; - } - } - - return true; -} -#endif // HAVE_PYTHON diff --git a/direct/src/dcparser/dcMolecularField.h b/direct/src/dcparser/dcMolecularField.h index a54ccbf4c6..bd7add5f9c 100644 --- a/direct/src/dcparser/dcMolecularField.h +++ b/direct/src/dcparser/dcMolecularField.h @@ -46,15 +46,9 @@ public: virtual void write(ostream &out, bool brief, int indent_level) const; virtual void generate_hash(HashGenerator &hash) const; - virtual bool has_nested_fields() const; virtual int get_num_nested_fields() const; virtual DCPackerInterface *get_nested_field(int n) const; -public: -#ifdef HAVE_PYTHON - virtual bool do_unpack_args(pvector &args, DatagramIterator &iterator) const; -#endif - private: // These members define the primary interface to the molecular field // definition as read from the file. diff --git a/direct/src/dcparser/dcPacker.I b/direct/src/dcparser/dcPacker.I index aeae8b8db2..c0d251f96c 100755 --- a/direct/src/dcparser/dcPacker.I +++ b/direct/src/dcparser/dcPacker.I @@ -51,18 +51,35 @@ get_num_nested_fields() const { return _num_nested_fields; } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::more_nested_fields +// Access: Published +// Description: Returns true if there are more nested fields to pack +// or unpack in the current push sequence, false if it +// is time to call pop(). +//////////////////////////////////////////////////////////////////// +INLINE bool DCPacker:: +more_nested_fields() const { + return (_current_field != (DCPackerInterface *)NULL); +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::get_pack_type // Access: Published // Description: Returns the type of value expected by the current -// field, or ST_invalid if it is not correct to call -// pack_value() at this point (e.g. the current field is -// an array, not the element of an array). +// field. See the enumerated type definition at the top +// of DCPackerInterface.h. If this returns one of +// PT_double, PT_int, PT_int64, or PT_string, then you +// should call the corresponding pack_double(), +// pack_int() function (or unpack_double(), +// unpack_int(), etc.) to transfer data. Otherwise, you +// should call push() and begin packing or unpacking the +// nested fields. //////////////////////////////////////////////////////////////////// -INLINE DCSubatomicType DCPacker:: +INLINE DCPackType DCPacker:: get_pack_type() const { if (_current_field == NULL) { - return ST_invalid; + return PT_invalid; } else { return _current_field->get_pack_type(); } @@ -76,6 +93,7 @@ get_pack_type() const { //////////////////////////////////////////////////////////////////// INLINE void DCPacker:: pack_double(double value) { + nassertv(_mode == M_pack); if (_current_field == NULL) { _pack_error = true; } else { @@ -94,6 +112,7 @@ pack_double(double value) { //////////////////////////////////////////////////////////////////// INLINE void DCPacker:: pack_int(int value) { + nassertv(_mode == M_pack); if (_current_field == NULL) { _pack_error = true; } else { @@ -112,6 +131,7 @@ pack_int(int value) { //////////////////////////////////////////////////////////////////// INLINE void DCPacker:: pack_int64(PN_int64 value) { + nassertv(_mode == M_pack); if (_current_field == NULL) { _pack_error = true; } else { @@ -130,6 +150,7 @@ pack_int64(PN_int64 value) { //////////////////////////////////////////////////////////////////// INLINE void DCPacker:: pack_string(const string &value) { + nassertv(_mode == M_pack); if (_current_field == NULL) { _pack_error = true; } else { @@ -149,6 +170,7 @@ pack_string(const string &value) { //////////////////////////////////////////////////////////////////// INLINE void DCPacker:: pack_literal_value(const string &value) { + nassertv(_mode == M_pack); if (_current_field == NULL) { _pack_error = true; } else { @@ -157,6 +179,98 @@ pack_literal_value(const string &value) { } } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_double +// Access: Published +// Description: Unpacks the current numeric or string value from the +// stream. +//////////////////////////////////////////////////////////////////// +INLINE double DCPacker:: +unpack_double() { + double value = 0.0; + nassertr(_mode == M_unpack, value); + if (_current_field == NULL) { + _pack_error = true; + + } else { + if (!_current_field->unpack_double(_unpack_data, _unpack_length, _unpack_p, value)) { + _pack_error = true; + } + advance(); + } + + return value; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_int +// Access: Published +// Description: Unpacks the current numeric or string value from the +// stream. +//////////////////////////////////////////////////////////////////// +INLINE int DCPacker:: +unpack_int() { + int value = 0; + nassertr(_mode == M_unpack, value); + if (_current_field == NULL) { + _pack_error = true; + + } else { + if (!_current_field->unpack_int(_unpack_data, _unpack_length, _unpack_p, value)) { + _pack_error = true; + } + advance(); + } + + return value; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_int64 +// Access: Published +// Description: Unpacks the current numeric or string value from the +// stream. +//////////////////////////////////////////////////////////////////// +INLINE PN_int64 DCPacker:: +unpack_int64() { + PN_int64 value = 0; + nassertr(_mode == M_unpack, value); + if (_current_field == NULL) { + _pack_error = true; + + } else { + if (!_current_field->unpack_int64(_unpack_data, _unpack_length, _unpack_p, value)) { + _pack_error = true; + } + advance(); + } + + return value; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_string +// Access: Published +// Description: Unpacks the current numeric or string value from the +// stream. +//////////////////////////////////////////////////////////////////// +INLINE string DCPacker:: +unpack_string() { + string value; + nassertr(_mode == M_unpack, value); + if (_current_field == NULL) { + _pack_error = true; + + } else { + if (!_current_field->unpack_string(_unpack_data, _unpack_length, _unpack_p, value)) { + _pack_error = true; + } + advance(); + } + + return value; +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::had_pack_error // Access: Published @@ -170,6 +284,21 @@ had_pack_error() const { return _pack_error; } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::get_num_unpacked_bytes +// Access: Published +// Description: Returns the number of bytes that have been unpacked +// so far, or after unpack_end(), the total number of +// bytes that were unpacked at all. This can be used to +// validate that all of the bytes in the buffer were +// actually unpacked (which is not otherwise considered +// an error). +//////////////////////////////////////////////////////////////////// +INLINE size_t DCPacker:: +get_num_unpacked_bytes() const { + return _unpack_p; +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::get_string // Access: Published @@ -222,6 +351,12 @@ advance() { // call pop(). _current_field = NULL; + } else if (_mode == M_unpack && _push_marker != 0 && + _unpack_p >= _push_marker) { + // Done with all the fields on this parent. The caller must now + // call pop(). + _current_field = NULL; + } else { // We have another field to advance to. _current_field = _current_parent->get_nested_field(_current_field_index); diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index 6100153cab..a33eb116a9 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/direct/src/dcparser/dcPacker.cxx @@ -25,6 +25,10 @@ //////////////////////////////////////////////////////////////////// DCPacker:: DCPacker() { + _mode = M_idle; + _unpack_data = NULL; + _unpack_length = 0; + _unpack_p = 0; _current_field = NULL; _current_parent = NULL; _current_field_index = 0; @@ -42,19 +46,17 @@ DCPacker:: } //////////////////////////////////////////////////////////////////// -// Function: DCPacker::begin +// Function: DCPacker::begin_pack // Access: Published // Description: Begins a packing session. The parameter is the DC // object that describes the packing format; it may be a // DCType or DCField. //////////////////////////////////////////////////////////////////// void DCPacker:: -begin(const DCPackerInterface *root) { - // If this assertion fails, we didn't match begin() up with end(). - nassertv(_stack.empty() && - _current_field == NULL && - _current_parent == NULL); +begin_pack(const DCPackerInterface *root) { + nassertv(_mode == M_idle); + _mode = M_pack; _pack_error = false; _pack_data.clear(); @@ -66,7 +68,7 @@ begin(const DCPackerInterface *root) { } //////////////////////////////////////////////////////////////////// -// Function: DCPacker::end +// Function: DCPacker::end_pack // Access: Published, Virtual // Description: Finishes a packing session. // @@ -74,7 +76,76 @@ begin(const DCPackerInterface *root) { // there has been some error during packing. //////////////////////////////////////////////////////////////////// bool DCPacker:: -end() { +end_pack() { + nassertr(_mode == M_pack, false); + + _mode = M_idle; + + if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) { + _pack_error = true; + _stack.clear(); + _current_field = NULL; + _current_parent = NULL; + _current_field_index = 0; + _num_nested_fields = 0; + } + + return !_pack_error; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::begin_unpack +// Access: Published +// Description: Begins an unpacking session. Unlike the other +// version of begin_unpack(), this version makes a copy +// of the data string. +//////////////////////////////////////////////////////////////////// +void DCPacker:: +begin_unpack(const string &data, const DCPackerInterface *root) { + _unpack_str = data; + begin_unpack(data.data(), data.length(), root); +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::begin_unpack +// Access: Public +// Description: Begins an unpacking session. The data pointer is +// used directly; the data buffer is not copied. +// Therefore, you must not delete or modify the data +// pointer until you call end_unpack(). +//////////////////////////////////////////////////////////////////// +void DCPacker:: +begin_unpack(const char *data, size_t length, + const DCPackerInterface *root) { + nassertv(_mode == M_idle); + + _mode = M_unpack; + _pack_error = false; + _unpack_data = data; + _unpack_length = length; + _unpack_p = 0; + + _stack.clear(); + _current_field = root; + _current_parent = NULL; + _current_field_index = 0; + _num_nested_fields = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::end_unpack +// Access: Published +// Description: Finishes the unpacking session. +// +// The return value is true on success, or false if +// there has been some error during unpacking. +//////////////////////////////////////////////////////////////////// +bool DCPacker:: +end_unpack() { + nassertr(_mode == M_unpack, false); + + _mode = M_idle; + if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) { _pack_error = true; _stack.clear(); @@ -105,14 +176,59 @@ push() { _pack_error = true; } else { - int num_nested_fields = _current_field->get_num_nested_fields(); StackElement element; element._current_parent = _current_parent; element._current_field_index = _current_field_index; - element._push_start = _push_start; + element._push_marker = _push_marker; _stack.push_back(element); - _current_parent = _current_field; + + + // Now deal with the length prefix that might or might not be + // before a sequence of nested fields. + int num_nested_fields = _current_parent->get_num_nested_fields(); + size_t length_bytes = _current_parent->get_length_bytes(); + + if (_mode == M_pack) { + // Reserve length_bytes for when we figure out what the length + // is. + _push_marker = _pack_data.get_length(); + _pack_data.append_junk(length_bytes); + + } else { // _mode == M_unpack + // Read length_bytes to determine the end of this nested + // sequence. + _push_marker = 0; + + if (length_bytes != 0) { + if (_unpack_p + length_bytes > _unpack_length) { + _pack_error = true; + + } else { + size_t length; + if (length_bytes == 4) { + length = ((size_t)(unsigned char)_unpack_data[_unpack_p + 0] | + ((size_t)(unsigned char)_unpack_data[_unpack_p + 1] << 8) | + ((size_t)(unsigned char)_unpack_data[_unpack_p + 2] << 16) | + ((size_t)(unsigned char)_unpack_data[_unpack_p + 3] << 24)); + _unpack_p += 4; + _push_marker = _unpack_p + length; + } else { + length = ((size_t)(unsigned char)_unpack_data[_unpack_p + 0] | + ((size_t)(unsigned char)_unpack_data[_unpack_p + 1] << 8)); + _unpack_p += 2; + } + _push_marker = _unpack_p + length; + + // The explicit length trumps the number of nested fields + // reported by get_num_nested_fields(). + num_nested_fields = _current_parent->get_num_nested_fields(length); + } + } + } + + + // Now point to the first field in the nested range. _num_nested_fields = num_nested_fields; _current_field_index = 0; @@ -123,12 +239,7 @@ push() { } else { _current_field = _current_parent->get_nested_field(_current_field_index); } - - // Reserve length_bytes for when we figure out what the length - // is. - _push_start = _pack_data.get_length(); - size_t length_bytes = _current_parent->get_length_bytes(); - _pack_data.append_junk(length_bytes); + } } @@ -145,7 +256,12 @@ push() { void DCPacker:: pop() { if (_current_field != NULL && _num_nested_fields >= 0) { - // Oops, didn't pack enough values. + // Oops, didn't pack or unpack enough values. + _pack_error = true; + + } else if (_mode == M_unpack && _push_marker != 0 && + _unpack_p != _push_marker) { + // Didn't unpack the right number of values. _pack_error = true; } @@ -154,28 +270,30 @@ pop() { _pack_error = true; } else { - size_t length_bytes = _current_parent->get_length_bytes(); - if (length_bytes != 0) { - // Now go back and fill in the length of the array. - char buffer[4]; - size_t length = _pack_data.get_length() - _push_start - length_bytes; - if (length_bytes == 4) { - buffer[0] = (char)(length & 0xff); - buffer[1] = (char)((length >> 8) & 0xff); - buffer[2] = (char)((length >> 16) & 0xff); - buffer[3] = (char)((length >> 24) & 0xff); - _pack_data.rewrite_data(_push_start, buffer, 4); - } else { - buffer[0] = (char)(length & 0xff); - buffer[1] = (char)((length >> 8) & 0xff); - _pack_data.rewrite_data(_push_start, buffer, 2); + if (_mode == M_pack) { + size_t length_bytes = _current_parent->get_length_bytes(); + if (length_bytes != 0) { + // Now go back and fill in the length of the array. + char buffer[4]; + size_t length = _pack_data.get_length() - _push_marker - length_bytes; + if (length_bytes == 4) { + buffer[0] = (char)(length & 0xff); + buffer[1] = (char)((length >> 8) & 0xff); + buffer[2] = (char)((length >> 16) & 0xff); + buffer[3] = (char)((length >> 24) & 0xff); + _pack_data.rewrite_data(_push_marker, buffer, 4); + } else { + buffer[0] = (char)(length & 0xff); + buffer[1] = (char)((length >> 8) & 0xff); + _pack_data.rewrite_data(_push_marker, buffer, 2); + } } } _current_field = _current_parent; _current_parent = _stack.back()._current_parent; _current_field_index = _stack.back()._current_field_index; - _push_start = _stack.back()._push_start; + _push_marker = _stack.back()._push_marker; _num_nested_fields = (_current_parent == NULL) ? 0 : _current_parent->get_num_nested_fields(); _stack.pop_back(); } @@ -195,6 +313,7 @@ pop() { //////////////////////////////////////////////////////////////////// void DCPacker:: pack_object(PyObject *object) { + nassertv(_mode == M_pack); PyObject *str = PyObject_Str(object); Py_DECREF(str); @@ -227,3 +346,76 @@ pack_object(PyObject *object) { } } #endif // HAVE_PYTHON + +#ifdef HAVE_PYTHON +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_object +// Access: Published +// Description: Unpacks a Python object of the appropriate type from +// the stream for the current field. This may be an +// integer or a string for a simple field object; if the +// current field represents a list of fields it will be +// a tuple. +//////////////////////////////////////////////////////////////////// +PyObject *DCPacker:: +unpack_object() { + PyObject *object = NULL; + + DCPackType pack_type = get_pack_type(); + + switch (pack_type) { + case PT_double: + { + double value = unpack_double(); + object = PyFloat_FromDouble(value); + } + break; + + case PT_int: + { + int value = unpack_int(); + object = PyInt_FromLong(value); + } + break; + + case PT_int64: + { + PN_int64 value = unpack_int64(); + object = PyLong_FromLongLong(value); + } + break; + + case PT_string: + { + string str = unpack_string(); + object = PyString_FromStringAndSize(str.data(), str.size()); + } + break; + + default: + { + // First, build up a list from the nested objects. + object = PyList_New(0); + + push(); + while (more_nested_fields()) { + PyObject *element = unpack_object(); + PyList_Append(object, element); + Py_DECREF(element); + } + pop(); + + if (pack_type != PT_array) { + // For these other kinds of objects, we'll convert the list + // into a tuple. + PyObject *tuple = PyList_AsTuple(object); + Py_DECREF(object); + object = tuple; + } + } + break; + } + + return object; +} +#endif // HAVE_PYTHON diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 4e6f776da1..c4e21c06ff 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -35,26 +35,42 @@ PUBLISHED: DCPacker(); ~DCPacker(); - void begin(const DCPackerInterface *root); - bool end(); + void begin_pack(const DCPackerInterface *root); + bool end_pack(); + +public: + void begin_unpack(const char *data, size_t length, + const DCPackerInterface *root); +PUBLISHED: + void begin_unpack(const string &data, const DCPackerInterface *root); + bool end_unpack(); INLINE bool has_nested_fields() const; INLINE int get_num_nested_fields() const; + INLINE bool more_nested_fields() const; + void push(); void pop(); - INLINE DCSubatomicType get_pack_type() const; + INLINE DCPackType get_pack_type() const; INLINE void pack_double(double value); INLINE void pack_int(int value); INLINE void pack_int64(PN_int64 value); INLINE void pack_string(const string &value); INLINE void pack_literal_value(const string &value); + INLINE double unpack_double(); + INLINE int unpack_int(); + INLINE PN_int64 unpack_int64(); + INLINE string unpack_string(); + #ifdef HAVE_PYTHON void pack_object(PyObject *object); + PyObject *unpack_object(); #endif INLINE bool had_pack_error() const; + INLINE size_t get_num_unpacked_bytes() const; INLINE string get_string() const; INLINE size_t get_length() const; @@ -65,13 +81,24 @@ private: INLINE void advance(); private: + enum Mode { + M_idle, + M_pack, + M_unpack, + }; + Mode _mode; + DCPackData _pack_data; + string _unpack_str; + const char *_unpack_data; + size_t _unpack_length; + size_t _unpack_p; class StackElement { public: const DCPackerInterface *_current_parent; int _current_field_index; - size_t _push_start; + size_t _push_marker; }; typedef pvector Stack; @@ -79,12 +106,15 @@ private: const DCPackerInterface *_current_field; const DCPackerInterface *_current_parent; int _current_field_index; - size_t _push_start; + + // In pack mode, _push_marker marks the beginning of the push record + // (so we can go back and write in the length later). In unpack + // mode, it marks the end of the push record (so we know when we've + // reached the end). + size_t _push_marker; int _num_nested_fields; bool _pack_error; - - friend class DCPackerInterface; }; #include "dcPacker.I" diff --git a/direct/src/dcparser/dcPackerInterface.cxx b/direct/src/dcparser/dcPackerInterface.cxx index 7b0fb126c4..2890225d08 100755 --- a/direct/src/dcparser/dcPackerInterface.cxx +++ b/direct/src/dcparser/dcPackerInterface.cxx @@ -54,6 +54,21 @@ get_num_nested_fields() const { return 0; } +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_num_nested_fields +// Access: Public, Virtual +// Description: This flavor of get_num_nested_fields is used during +// unpacking. It returns the number of nested fields to +// expect, given a certain length in bytes (as read from +// the get_length_bytes() stored in the stream on the +// pack). This will only be called if +// get_length_bytes() returns nonzero. +//////////////////////////////////////////////////////////////////// +int DCPackerInterface:: +get_num_nested_fields(size_t length_bytes) const { + return 0; +} + //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::get_nested_field // Access: Public, Virtual @@ -84,13 +99,11 @@ get_length_bytes() const { //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::get_pack_type // Access: Public, Virtual -// Description: Returns the type of value expected by this field, or -// ST_invalid if this field cannot accept simple value -// types. +// Description: Returns the type of value expected by this field. //////////////////////////////////////////////////////////////////// -DCSubatomicType DCPackerInterface:: +DCPackType DCPackerInterface:: get_pack_type() const { - return ST_invalid; + return PT_invalid; } //////////////////////////////////////////////////////////////////// @@ -136,3 +149,47 @@ bool DCPackerInterface:: pack_string(DCPackData &, const string &) const { return false; } + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::unpack_double +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCPackerInterface:: +unpack_double(const char *, size_t, size_t &, double &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::unpack_int +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCPackerInterface:: +unpack_int(const char *, size_t, size_t &, int &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::unpack_int64 +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCPackerInterface:: +unpack_int64(const char *, size_t, size_t &, PN_int64 &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::unpack_string +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCPackerInterface:: +unpack_string(const char *, size_t, size_t &, string &) const { + return false; +} diff --git a/direct/src/dcparser/dcPackerInterface.h b/direct/src/dcparser/dcPackerInterface.h index 0c2341d2ed..edf29871b7 100755 --- a/direct/src/dcparser/dcPackerInterface.h +++ b/direct/src/dcparser/dcPackerInterface.h @@ -24,6 +24,30 @@ class DCPackData; +BEGIN_PUBLISH +// This enumerated type is returned by get_pack_type() and represents +// the best choice for a subsequent call to pack_*() or unpack_*(). +enum DCPackType { + // This one should never be returned in a normal situation. + PT_invalid, + + // These PackTypes are all fundamental types, and should be packed + // (or unpacked) with the corresponding call to pack_double(), + // pack_int(), etc. + PT_double, + PT_int, + PT_int64, + PT_string, + + // The remaining PackTypes imply a need to call push() and pop(). + // They are all variants on the same thing: a list of nested fields, + // but the PackType provides a bit of a semantic context. + PT_array, + PT_field, + PT_struct, +}; +END_PUBLISH + //////////////////////////////////////////////////////////////////// // Class : DCPackerInterface // Description : This defines the internal interface for packing @@ -40,14 +64,20 @@ public: virtual bool has_nested_fields() const; virtual int get_num_nested_fields() const; + virtual int get_num_nested_fields(size_t length_bytes) const; virtual DCPackerInterface *get_nested_field(int n) const; virtual size_t get_length_bytes() const; - virtual DCSubatomicType get_pack_type() const; + virtual DCPackType get_pack_type() const; virtual bool pack_double(DCPackData &pack_data, double value) const; virtual bool pack_int(DCPackData &pack_data, int value) const; virtual bool pack_int64(DCPackData &pack_data, PN_int64 value) const; virtual bool pack_string(DCPackData &pack_data, const string &value) const; + + virtual bool unpack_double(const char *data, size_t length, size_t &p, double &value) const; + virtual bool unpack_int(const char *data, size_t length, size_t &p, int &value) const; + virtual bool unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const; + virtual bool unpack_string(const char *data, size_t length, size_t &p, string &value) const; }; #endif diff --git a/direct/src/dcparser/dcParser.cxx.prebuilt b/direct/src/dcparser/dcParser.cxx.prebuilt index 5bf53629fd..965bd4a7dd 100644 --- a/direct/src/dcparser/dcParser.cxx.prebuilt +++ b/direct/src/dcparser/dcParser.cxx.prebuilt @@ -1182,13 +1182,13 @@ case 38: case 39: #line 271 "dcParser.yxx" { - default_value_packer.begin(atomic_element._type); + default_value_packer.begin_pack(atomic_element._type); } break; case 40: #line 275 "dcParser.yxx" { - if (!default_value_packer.end()) { + if (!default_value_packer.end_pack()) { yyerror("Invalid default value for type"); } else { diff --git a/direct/src/dcparser/dcParser.yxx b/direct/src/dcparser/dcParser.yxx index e1ed3c97ec..b682e8bbf8 100644 --- a/direct/src/dcparser/dcParser.yxx +++ b/direct/src/dcparser/dcParser.yxx @@ -269,11 +269,11 @@ atomic_element_definition: } | atomic_element_definition '=' { - default_value_packer.begin(atomic_element._type); + default_value_packer.begin_pack(atomic_element._type); } default_value { - if (!default_value_packer.end()) { + if (!default_value_packer.end_pack()) { yyerror("Invalid default value for type"); } else { diff --git a/direct/src/dcparser/dcSimpleType.cxx b/direct/src/dcparser/dcSimpleType.cxx index 9de9c69bbd..3d35aeb722 100755 --- a/direct/src/dcparser/dcSimpleType.cxx +++ b/direct/src/dcparser/dcSimpleType.cxx @@ -38,38 +38,52 @@ DCSimpleType(DCSubatomicType type, int divisor) : // nested fields of the appropriate type. switch (_type) { case ST_int8array: + _pack_type = PT_array; _nested_type = ST_int8; _is_array = true; + _bytes_per_element = 1; break; case ST_int16array: + _pack_type = PT_array; _nested_type = ST_int16; _is_array = true; + _bytes_per_element = 2; break; case ST_int32array: + _pack_type = PT_array; _nested_type = ST_int32; _is_array = true; + _bytes_per_element = 4; break; case ST_uint8array: + _pack_type = PT_array; _nested_type = ST_uint8; _is_array = true; + _bytes_per_element = 1; break; case ST_uint16array: + _pack_type = PT_array; _nested_type = ST_uint16; _is_array = true; + _bytes_per_element = 2; break; case ST_uint32array: + _pack_type = PT_array; _nested_type = ST_uint32; _is_array = true; + _bytes_per_element = 4; break; case ST_uint32uint8array: + _pack_type = PT_array; _nested_type = ST_invalid; _is_array = true; + _bytes_per_element = 5; break; case ST_blob: @@ -78,13 +92,81 @@ DCSimpleType(DCSubatomicType type, int divisor) : // For these types, we will present an array interface as an array // of uint8, but we will also accept a set_value() with a string // parameter. + _pack_type = PT_string; _nested_type = ST_uint8; _is_array = true; + _bytes_per_element = 1; break; - default: + // The simple types can be packed directly. + case ST_int8: + _pack_type = PT_int; _nested_type = ST_invalid; _is_array = false; + _bytes_per_element = 0; + break; + + case ST_int16: + _pack_type = PT_int; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_int32: + _pack_type = PT_int; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_int64: + _pack_type = PT_int64; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_uint8: + _pack_type = PT_int; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_uint16: + _pack_type = PT_int; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_uint32: + _pack_type = PT_int; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_uint64: + _pack_type = PT_int64; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_float64: + _pack_type = PT_double; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; + break; + + case ST_invalid: + _pack_type = PT_invalid; + _nested_type = ST_invalid; + _is_array = false; + _bytes_per_element = 0; } if (_nested_type != ST_invalid) { @@ -155,6 +237,9 @@ get_divisor() const { void DCSimpleType:: set_divisor(int divisor) { _divisor = divisor; + if (_pack_type == PT_int || _pack_type == PT_int64) { + _pack_type = PT_double; + } } //////////////////////////////////////////////////////////////////// @@ -184,6 +269,24 @@ get_num_nested_fields() const { return _is_array ? -1 : 0; } +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleType::get_num_nested_fields +// Access: Public, Virtual +// Description: This flavor of get_num_nested_fields is used during +// unpacking. It returns the number of nested fields to +// expect, given a certain length in bytes (as read from +// the get_length_bytes() stored in the stream on the +// pack). This will only be called if +// get_length_bytes() returns nonzero. +//////////////////////////////////////////////////////////////////// +int DCSimpleType:: +get_num_nested_fields(size_t length_bytes) const { + if (_is_array) { + return length_bytes / _bytes_per_element; + } + return 0; +} + //////////////////////////////////////////////////////////////////// // Function: DCSimpleType::get_nested_field // Access: Public, Virtual @@ -214,13 +317,11 @@ get_length_bytes() const { //////////////////////////////////////////////////////////////////// // Function: DCSimpleType::get_pack_type // Access: Public, Virtual -// Description: Returns the type of value expected by this field, or -// ST_invalid if this field cannot accept simple value -// types. +// Description: Returns the type of value expected by this field. //////////////////////////////////////////////////////////////////// -DCSubatomicType DCSimpleType:: +DCPackType DCSimpleType:: get_pack_type() const { - return _type; + return _pack_type; } //////////////////////////////////////////////////////////////////// @@ -497,6 +598,427 @@ pack_string(DCPackData &pack_data, const string &value) const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleType::unpack_double +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCSimpleType:: +unpack_double(const char *data, size_t length, size_t &p, double &value) const { + switch (_type) { + case ST_int8: + if (p + 1 > length) { + return false; + } + value = (double)(int)(signed char)data[p]; + p++; + break; + + case ST_int16: + if (p + 2 > length) { + return false; + } + value = (double)(int)((unsigned int)(unsigned char)data[p] | + ((int)(signed char)data[p + 1] << 8)); + p += 2; + break; + + case ST_int32: + if (p + 4 > length) { + return false; + } + value = (double)(int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((int)(signed char)data[p + 3] << 24)); + p += 4; + break; + + case ST_int64: + if (p + 8 > length) { + return false; + } + value = (double)(PN_int64)((PN_uint64)(unsigned char)data[p] | + ((PN_uint64)(unsigned char)data[p + 1] << 8) | + ((PN_uint64)(unsigned char)data[p + 2] << 16) | + ((PN_uint64)(unsigned char)data[p + 3] << 24) | + ((PN_uint64)(unsigned char)data[p + 4] << 32) | + ((PN_uint64)(unsigned char)data[p + 5] << 40) | + ((PN_uint64)(unsigned char)data[p + 6] << 48) | + ((PN_int64)(signed char)data[p + 7] << 54)); + p += 8; + break; + + case ST_uint8: + if (p + 1 > length) { + return false; + } + value = (double)(unsigned int)(unsigned char)data[p]; + p++; + break; + + case ST_uint16: + if (p + 2 > length) { + return false; + } + value = (double)(unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8)); + p += 2; + break; + + case ST_uint32: + if (p + 4 > length) { + return false; + } + value = (double)(unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((unsigned int)(unsigned char)data[p + 3] << 24)); + p += 4; + break; + + case ST_uint64: + if (p + 8 > length) { + return false; + } + value = (double)(PN_uint64)((PN_uint64)(unsigned char)data[p] | + ((PN_uint64)(unsigned char)data[p + 1] << 8) | + ((PN_uint64)(unsigned char)data[p + 2] << 16) | + ((PN_uint64)(unsigned char)data[p + 3] << 24) | + ((PN_uint64)(unsigned char)data[p + 4] << 32) | + ((PN_uint64)(unsigned char)data[p + 5] << 40) | + ((PN_uint64)(unsigned char)data[p + 6] << 48) | + ((PN_uint64)(unsigned char)data[p + 7] << 54)); + p += 8; + break; + + case ST_float64: + if (p + 8 > length) { + return false; + } + { + double *real_value; +#ifdef WORDS_BIGENDIAN + char buffer[8]; + + // Reverse the byte ordering for big-endian machines. + for (size_t i = 0; i < 8; i++) { + buffer[i] = data[p + 7 - i]; + } + real_value = (double *)buffer; +#else + real_value = (double *)(data + p); +#endif // WORDS_BIGENDIAN + value = (*real_value); + } + p += 8; + break; + + default: + return false; + } + + if (_divisor != 1) { + value = value / _divisor; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleType::unpack_int +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCSimpleType:: +unpack_int(const char *data, size_t length, size_t &p, int &value) const { + switch (_type) { + case ST_int8: + if (p + 1 > length) { + return false; + } + value = (int)(signed char)data[p]; + p++; + break; + + case ST_int16: + if (p + 2 > length) { + return false; + } + value = (int)((unsigned int)(unsigned char)data[p] | + ((int)(signed char)data[p + 1] << 8)); + p += 2; + break; + + case ST_int32: + if (p + 4 > length) { + return false; + } + value = (int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((int)(signed char)data[p + 3] << 24)); + p += 4; + break; + + case ST_int64: + if (p + 8 > length) { + return false; + } + value = (int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((unsigned int)(unsigned char)data[p + 3] << 24)); + p += 8; + break; + + case ST_uint8: + if (p + 1 > length) { + return false; + } + value = (unsigned int)(unsigned char)data[p]; + p++; + break; + + case ST_uint16: + if (p + 2 > length) { + return false; + } + value = (unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8)); + p += 2; + break; + + case ST_uint32: + if (p + 4 > length) { + return false; + } + value = (unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((unsigned int)(unsigned char)data[p + 3] << 24)); + p += 4; + break; + + case ST_uint64: + if (p + 8 > length) { + return false; + } + value = (unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((unsigned int)(unsigned char)data[p + 3] << 24)); + p += 8; + break; + + case ST_float64: + if (p + 8 > length) { + return false; + } + { + double *real_value; +#ifdef WORDS_BIGENDIAN + char buffer[8]; + + // Reverse the byte ordering for big-endian machines. + for (size_t i = 0; i < 8; i++) { + buffer[i] = data[p + 7 - i]; + } + real_value = (double *)buffer; +#else + real_value = (double *)(data + p); +#endif // WORDS_BIGENDIAN + value = (int)(*real_value); + } + p += 8; + break; + + default: + return false; + } + + if (_divisor != 1) { + value = value / _divisor; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleType::unpack_int64 +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCSimpleType:: +unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const { + switch (_type) { + case ST_int8: + if (p + 1 > length) { + return false; + } + value = (int)(signed char)data[p]; + p++; + break; + + case ST_int16: + if (p + 2 > length) { + return false; + } + value = (int)((unsigned int)(unsigned char)data[p] | + ((int)(signed char)data[p + 1] << 8)); + p += 2; + break; + + case ST_int32: + if (p + 4 > length) { + return false; + } + value = (int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((int)(signed char)data[p + 3] << 24)); + p += 4; + break; + + case ST_int64: + if (p + 8 > length) { + return false; + } + value = (PN_int64)((PN_uint64)(unsigned char)data[p] | + ((PN_uint64)(unsigned char)data[p + 1] << 8) | + ((PN_uint64)(unsigned char)data[p + 2] << 16) | + ((PN_uint64)(unsigned char)data[p + 3] << 24) | + ((PN_uint64)(unsigned char)data[p + 4] << 32) | + ((PN_uint64)(unsigned char)data[p + 5] << 40) | + ((PN_uint64)(unsigned char)data[p + 6] << 48) | + ((PN_int64)(signed char)data[p + 7] << 54)); + p += 8; + break; + + case ST_uint8: + if (p + 1 > length) { + return false; + } + value = (unsigned int)(unsigned char)data[p]; + p++; + break; + + case ST_uint16: + if (p + 2 > length) { + return false; + } + value = (unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8)); + p += 2; + break; + + case ST_uint32: + if (p + 4 > length) { + return false; + } + value = (unsigned int)((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((unsigned int)(unsigned char)data[p + 3] << 24)); + p += 4; + break; + + case ST_uint64: + if (p + 8 > length) { + return false; + } + value = (PN_int64)((PN_uint64)(unsigned char)data[p] | + ((PN_uint64)(unsigned char)data[p + 1] << 8) | + ((PN_uint64)(unsigned char)data[p + 2] << 16) | + ((PN_uint64)(unsigned char)data[p + 3] << 24) | + ((PN_uint64)(unsigned char)data[p + 4] << 32) | + ((PN_uint64)(unsigned char)data[p + 5] << 40) | + ((PN_uint64)(unsigned char)data[p + 6] << 48) | + ((PN_uint64)(unsigned char)data[p + 7] << 54)); + p += 8; + break; + + case ST_float64: + if (p + 8 > length) { + return false; + } + { + double *real_value; +#ifdef WORDS_BIGENDIAN + char buffer[8]; + + // Reverse the byte ordering for big-endian machines. + for (size_t i = 0; i < 8; i++) { + buffer[i] = data[p + 7 - i]; + } + real_value = (double *)buffer; +#else + real_value = (double *)(data + p); +#endif // WORDS_BIGENDIAN + value = (PN_int64)(*real_value); + } + p += 8; + break; + + default: + return false; + } + + if (_divisor != 1) { + value = value / _divisor; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleType::unpack_string +// Access: Public, Virtual +// Description: Unpacks the current numeric or string value from the +// stream. Returns true on success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCSimpleType:: +unpack_string(const char *data, size_t length, size_t &p, string &value) const { + size_t string_length; + + switch (_type) { + case ST_string: + case ST_blob: + if (p + 2 > length) { + return false; + } + string_length = ((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8)); + p += 2; + break; + + case ST_blob32: + if (p + 4 > length) { + return false; + } + string_length = ((unsigned int)(unsigned char)data[p] | + ((unsigned int)(unsigned char)data[p + 1] << 8) | + ((unsigned int)(unsigned char)data[p + 2] << 16) | + ((unsigned int)(unsigned char)data[p + 3] << 24)); + p += 4; + break; + + default: + return false; + } + + if (p + string_length > length) { + return false; + } + value = string(data + p, string_length); + p += string_length; + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: DCSimpleType::output // Access: Public, Virtual @@ -562,390 +1084,6 @@ create_uint32uint8_type() { return _uint32uint8_type; } -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: DCSimpleType::pack_arg -// Access: Public, Virtual -// Description: Packs the Python object into the datagram, appending -// to the end of the datagram. -//////////////////////////////////////////////////////////////////// -void DCSimpleType:: -pack_arg(Datagram &datagram, PyObject *item) const { - do_pack_arg(datagram, item, _type); -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: DCSimpleType::unpack_arg -// Access: Public, Virtual -// Description: Unpacks a Python object from the datagram, beginning -// at the current point in the interator, and returns a -// new reference, or NULL if there was not enough data -// in the datagram. -//////////////////////////////////////////////////////////////////// -PyObject *DCSimpleType:: -unpack_arg(DatagramIterator &iterator) const { - return do_unpack_arg(iterator, _type); -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: DCSimpleType::do_pack_arg -// Access: Private -// Description: Packs the Python object into the datagram, appending -// to the end of the datagram. -//////////////////////////////////////////////////////////////////// -void DCSimpleType:: -do_pack_arg(Datagram &datagram, PyObject *item, DCSubatomicType type) const { - char *str; - int size; - - // Check for an array type. These are handled recursively. - DCSubatomicType array_subtype; - int num_bytes = 0; - switch (type) { - case ST_int16array: - array_subtype = ST_int16; - num_bytes = 2; - break; - - case ST_int32array: - array_subtype = ST_int32; - num_bytes = 4; - break; - - case ST_uint16array: - array_subtype = ST_uint16; - num_bytes = 2; - break; - - case ST_uint32array: - array_subtype = ST_uint32; - num_bytes = 4; - break; - - case ST_int8array: - array_subtype = ST_int8; - num_bytes = 1; - break; - - case ST_uint8array: - array_subtype = ST_uint8; - num_bytes = 1; - break; - - case ST_uint32uint8array: - array_subtype = ST_uint32; - num_bytes = 5; - break; - - default: - array_subtype = ST_invalid; - } - - if (array_subtype != ST_invalid) { - int size = PySequence_Size(item); - datagram.add_uint16(size * num_bytes); - if (type == ST_uint32uint8array) { - // This one is a special case: an array of tuples. - for (int i = 0; i < size; i++) { - PyObject *tuple = PySequence_GetItem(item, i); - do_pack_arg(datagram, PyTuple_GetItem(tuple, 0), ST_uint32); - do_pack_arg(datagram, PyTuple_GetItem(tuple, 1), ST_uint8); - Py_DECREF(tuple); - } - } else { - for (int i = 0; i < size; i++) { - PyObject *element = PySequence_GetItem(item, i); - do_pack_arg(datagram, element, array_subtype); - Py_DECREF(element); - } - } - - return; - } - - if (_divisor == 1) { - switch (type) { - case ST_int8: - datagram.add_int8(PyInt_AsLong(item)); - break; - - case ST_int16: - datagram.add_int16(PyInt_AsLong(item)); - break; - - case ST_int32: - datagram.add_int32(PyInt_AsLong(item)); - break; - - case ST_int64: - datagram.add_int64(PyLong_AsLongLong(item)); - break; - - case ST_uint8: - datagram.add_uint8(PyInt_AsLong(item)); - break; - - case ST_uint16: - datagram.add_uint16(PyInt_AsLong(item)); - break; - - case ST_uint32: - datagram.add_uint32(PyInt_AsLong(item)); - break; - - case ST_uint64: - datagram.add_uint64(PyLong_AsUnsignedLongLong(item)); - break; - - case ST_float64: - datagram.add_float64(PyFloat_AsDouble(item)); - break; - - case ST_string: - case ST_blob: - PyString_AsStringAndSize(item, &str, &size); - datagram.add_string(string(str, size)); - break; - - case ST_blob32: - PyString_AsStringAndSize(item, &str, &size); - datagram.add_string32(string(str, size)); - break; - - default: - break; - } - - } else { - switch (type) { - case ST_int8: - datagram.add_int8((PN_int8)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_int16: - datagram.add_int16((PN_int16)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_int32: - datagram.add_int32((PN_int32)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_int64: - datagram.add_int64((PN_int64)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_uint8: - datagram.add_uint8((PN_uint8)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_uint16: - datagram.add_uint16((PN_uint16)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_uint32: - datagram.add_uint32((PN_uint32)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_uint64: - datagram.add_uint64((PN_uint64)floor(PyFloat_AsDouble(item) * _divisor + 0.5)); - break; - - case ST_float64: - datagram.add_float64(PyFloat_AsDouble(item) * _divisor); - break; - - case ST_string: - case ST_blob: - PyString_AsStringAndSize(item, &str, &size); - datagram.add_string(string(str, size)); - break; - - case ST_blob32: - PyString_AsStringAndSize(item, &str, &size); - datagram.add_string32(string(str, size)); - break; - - default: - break; - } - } -} -#endif // HAVE_PYTHON - -#ifdef HAVE_PYTHON -//////////////////////////////////////////////////////////////////// -// Function: DCSimpleType::do_unpack_arg -// Access: Private -// Description: Unpacks a Python object from the datagram, beginning -// at the current point in the interator, and returns a -// new reference, or NULL if there was not enough data -// in the datagram. -//////////////////////////////////////////////////////////////////// -PyObject *DCSimpleType:: -do_unpack_arg(DatagramIterator &iterator, DCSubatomicType type) const { - string str; - - // Check for an array type. These are handled recursively. - DCSubatomicType array_subtype; - int num_bytes = 0; - switch (type) { - case ST_int16array: - array_subtype = ST_int16; - num_bytes = 2; - break; - - case ST_int32array: - array_subtype = ST_int32; - num_bytes = 4; - break; - - case ST_uint16array: - array_subtype = ST_uint16; - num_bytes = 2; - break; - - case ST_uint32array: - array_subtype = ST_uint32; - num_bytes = 4; - break; - - case ST_int8array: - array_subtype = ST_int8; - num_bytes = 1; - break; - - case ST_uint8array: - array_subtype = ST_uint8; - num_bytes = 1; - break; - - case ST_uint32uint8array: - array_subtype = ST_uint32; - num_bytes = 5; - break; - - default: - array_subtype = ST_invalid; - } - - if (array_subtype != ST_invalid) { - int size_bytes = iterator.get_uint16(); - int size = size_bytes / num_bytes; - nassertr(size * num_bytes == size_bytes, NULL); - - PyObject *list = PyList_New(size); - if (type == ST_uint32uint8array) { - // This one is a special case: an array of tuples. - for (int i = 0; i < size; i++) { - PyObject *a = do_unpack_arg(iterator, ST_uint32); - PyObject *b = do_unpack_arg(iterator, ST_uint8); - PyObject *tuple = PyTuple_New(2); - PyTuple_SET_ITEM(tuple, 0, a); - PyTuple_SET_ITEM(tuple, 1, b); - PyList_SET_ITEM(list, i, tuple); - } - } else { - for (int i = 0; i < size; i++) { - PyObject *element = do_unpack_arg(iterator, array_subtype); - PyList_SET_ITEM(list, i, element); - } - } - - return list; - } - - if (_divisor == 1) { - switch (type) { - case ST_int8: - return PyInt_FromLong(iterator.get_int8()); - - case ST_int16: - return PyInt_FromLong(iterator.get_int16()); - - case ST_int32: - return PyInt_FromLong(iterator.get_int32()); - - case ST_int64: - return PyLong_FromLongLong(iterator.get_int64()); - - case ST_uint8: - return PyInt_FromLong(iterator.get_uint8()); - - case ST_uint16: - return PyInt_FromLong(iterator.get_uint16()); - - case ST_uint32: - return PyInt_FromLong(iterator.get_uint32()); - - case ST_uint64: - return PyLong_FromUnsignedLongLong(iterator.get_uint64()); - - case ST_float64: - return PyFloat_FromDouble(iterator.get_float64()); - - case ST_string: - case ST_blob: - str = iterator.get_string(); - return PyString_FromStringAndSize(str.data(), str.size()); - - case ST_blob32: - str = iterator.get_string32(); - return PyString_FromStringAndSize(str.data(), str.size()); - - default: - return Py_BuildValue(""); - } - - } else { - switch (type) { - case ST_int8: - return PyFloat_FromDouble(iterator.get_int8() / (double)_divisor); - - case ST_int16: - return PyFloat_FromDouble(iterator.get_int16() / (double)_divisor); - - case ST_int32: - return PyFloat_FromDouble(iterator.get_int32() / (double)_divisor); - - case ST_int64: - return PyFloat_FromDouble(iterator.get_int64() / (double)_divisor); - - case ST_uint8: - return PyFloat_FromDouble(iterator.get_uint8() / (double)_divisor); - - case ST_uint16: - return PyFloat_FromDouble(iterator.get_uint16() / (double)_divisor); - - case ST_uint32: - return PyFloat_FromDouble(iterator.get_uint32() / (double)_divisor); - - case ST_uint64: - return PyFloat_FromDouble(iterator.get_uint64() / (double)_divisor); - - case ST_float64: - return PyFloat_FromDouble(iterator.get_float64() / (double)_divisor); - - case ST_string: - case ST_blob: - str = iterator.get_string(); - return PyString_FromStringAndSize(str.data(), str.size()); - - case ST_blob32: - str = iterator.get_string32(); - return PyString_FromStringAndSize(str.data(), str.size()); - - default: - return Py_BuildValue(""); - } - } -} -#endif // HAVE_PYTHON - - //////////////////////////////////////////////////////////////////// // Function: DCSimpleType::Uint32Uint8Type::Constructor // Access: Public @@ -998,3 +1136,13 @@ get_nested_field(int n) const { return NULL; } } + +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleType::Uint32Uint8Type::get_pack_type +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +DCPackType DCSimpleType::Uint32Uint8Type:: +get_pack_type() const { + return PT_struct; +} diff --git a/direct/src/dcparser/dcSimpleType.h b/direct/src/dcparser/dcSimpleType.h index a6762e4798..d39864ba04 100755 --- a/direct/src/dcparser/dcSimpleType.h +++ b/direct/src/dcparser/dcSimpleType.h @@ -47,15 +47,21 @@ PUBLISHED: public: virtual bool has_nested_fields() const; virtual int get_num_nested_fields() const; + virtual int get_num_nested_fields(size_t length_bytes) const; virtual DCPackerInterface *get_nested_field(int n) const; virtual size_t get_length_bytes() const; - virtual DCSubatomicType get_pack_type() const; + virtual DCPackType get_pack_type() const; virtual bool pack_double(DCPackData &pack_data, double value) const; virtual bool pack_int(DCPackData &pack_data, int value) const; virtual bool pack_int64(DCPackData &pack_data, PN_int64 value) const; virtual bool pack_string(DCPackData &pack_data, const string &value) const; + virtual bool unpack_double(const char *data, size_t length, size_t &p, double &value) const; + virtual bool unpack_int(const char *data, size_t length, size_t &p, int &value) const; + virtual bool unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const; + virtual bool unpack_string(const char *data, size_t length, size_t &p, string &value) const; + virtual void output(ostream &out, const string ¶meter_name, bool brief) const; virtual void generate_hash(HashGenerator &hash) const; @@ -64,23 +70,15 @@ private: static DCSimpleType *create_nested_field(DCSubatomicType type, int divisor); static DCPackerInterface *create_uint32uint8_type(); -#ifdef HAVE_PYTHON -public: - virtual void pack_arg(Datagram &datagram, PyObject *item) const; - virtual PyObject *unpack_arg(DatagramIterator &iterator) const; - -private: - void do_pack_arg(Datagram &datagram, PyObject *item, DCSubatomicType type) const; - PyObject *do_unpack_arg(DatagramIterator &iterator, DCSubatomicType type) const; -#endif // HAVE_PYTHON - private: DCSubatomicType _type; int _divisor; + DCPackType _pack_type; bool _is_array; DCSubatomicType _nested_type; DCPackerInterface *_nested_field; + size_t _bytes_per_element; // The rest of this is to maintain the static list of // DCPackerInterface objects for _nested_field, above. We allocate @@ -95,6 +93,7 @@ private: virtual bool has_nested_fields() const; virtual int get_num_nested_fields() const; virtual DCPackerInterface *get_nested_field(int n) const; + virtual DCPackType get_pack_type() const; DCSimpleType *_uint32_type; DCSimpleType *_uint8_type; diff --git a/direct/src/dcparser/dcType.h b/direct/src/dcparser/dcType.h index 2bf7e7a702..505aa374bf 100755 --- a/direct/src/dcparser/dcType.h +++ b/direct/src/dcparser/dcType.h @@ -70,12 +70,6 @@ public: virtual void output(ostream &out, const string ¶meter_name, bool brief) const=0; virtual void generate_hash(HashGenerator &hash) const; - -#ifdef HAVE_PYTHON - virtual void pack_arg(Datagram &datagram, PyObject *item) const=0; - virtual PyObject *unpack_arg(DatagramIterator &iterator) const=0; -#endif - }; #endif