Browse Source

python unpacking

David Rose 21 years ago
parent
commit
aff151835d

+ 0 - 41
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<PyObject *> &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

+ 0 - 6
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<PyObject *> &args, DatagramIterator &iterator) const;
-#endif
-
 public:
   // These members define the primary interface to the atomic field
   // definition as read from the file.

+ 3 - 3
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);
   }
 }

+ 55 - 10
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<PyObject *> 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 tuple;
+    return object;
+  }
+  
+  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;
+}

+ 3 - 5
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<PyObject *> &args, DatagramIterator &iterator) const=0;
-#endif
-
   friend class DCClass;
 };
 

+ 0 - 37
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<PyObject *> &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

+ 0 - 6
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<PyObject *> &args, DatagramIterator &iterator) const;
-#endif
-
 private:
   // These members define the primary interface to the molecular field
   // definition as read from the file.

+ 140 - 5
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);

+ 226 - 34
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

+ 37 - 7
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<StackElement> 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"

+ 62 - 5
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;
+}

+ 31 - 1
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

+ 2 - 2
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 {

+ 2 - 2
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 {

File diff suppressed because it is too large
+ 513 - 375
direct/src/dcparser/dcSimpleType.cxx


+ 10 - 11
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 &parameter_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;

+ 0 - 6
direct/src/dcparser/dcType.h

@@ -70,12 +70,6 @@ public:
   virtual void output(ostream &out, const string &parameter_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

Some files were not shown because too many files changed in this diff