Browse Source

introducing complex dc types

David Rose 21 years ago
parent
commit
9ccac55523

+ 12 - 2
direct/src/dcparser/Sources.pp

@@ -17,12 +17,22 @@
   #define SOURCES \
   #define SOURCES \
      dcAtomicField.h dcClass.h dcField.h dcFile.h dcLexer.lxx  \
      dcAtomicField.h dcClass.h dcField.h dcFile.h dcLexer.lxx  \
      dcLexerDefs.h dcMolecularField.h dcParser.yxx dcParserDefs.h  \
      dcLexerDefs.h dcMolecularField.h dcParser.yxx dcParserDefs.h  \
-     dcSubatomicType.h dcbase.h dcindent.h hashGenerator.h  \
+     dcSubatomicType.h \
+     dcPackData.h dcPackData.I \
+     dcPacker.h dcPacker.I \
+     dcPackerInterface.h \
+     dcType.h dcSimpleType.h \
+     dcbase.h dcindent.h hashGenerator.h  \
      primeNumberGenerator.h  
      primeNumberGenerator.h  
 
 
   #define INCLUDED_SOURCES \
   #define INCLUDED_SOURCES \
      dcAtomicField.cxx dcClass.cxx dcField.cxx dcFile.cxx \
      dcAtomicField.cxx dcClass.cxx dcField.cxx dcFile.cxx \
-     dcMolecularField.cxx dcSubatomicType.cxx dcindent.cxx  \
+     dcMolecularField.cxx dcSubatomicType.cxx \
+     dcPackData.cxx \
+     dcPacker.cxx \
+     dcPackerInterface.cxx \
+     dcType.cxx dcSimpleType.cxx \
+     dcindent.cxx  \
      hashGenerator.cxx primeNumberGenerator.cxx 
      hashGenerator.cxx primeNumberGenerator.cxx 
 
 
   #define IGATESCAN all
   #define IGATESCAN all

+ 88 - 717
direct/src/dcparser/dcAtomicField.cxx

@@ -19,195 +19,70 @@
 #include "dcAtomicField.h"
 #include "dcAtomicField.h"
 #include "hashGenerator.h"
 #include "hashGenerator.h"
 #include "dcindent.h"
 #include "dcindent.h"
+#include "dcSimpleType.h"
 
 
 #include <math.h>
 #include <math.h>
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DCAtomicField::ElementType::Constructor
 //     Function: DCAtomicField::ElementType::Constructor
 //       Access: Public
 //       Access: Public
-//  Description:
+//  Description: The type parameter should be a newly-allocated DCType
+//               object; it will eventually be freed with delete when
+//               this object destructs.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 DCAtomicField::ElementType::
 DCAtomicField::ElementType::
-ElementType() {
-  _type = ST_invalid;
-  _divisor = 1;
+ElementType(DCType *type) {
+  _type = type;
   _has_default_value = false;
   _has_default_value = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::set_default_value
-//       Access: Public
-//  Description: Stores the indicated value as the default value for
-//               this element.
-//
-//               Returns true if the element type reasonably accepts a
-//               default value of numeric type, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-set_default_value(double num) {
-  switch (_type) {
-    // Only fields of these types accept numbers.
-  case ST_int8:
-  case ST_int16:
-  case ST_int32:
-  case ST_uint8:
-  case ST_uint16:
-  case ST_uint32:
-  case ST_float64:
-    break;
-
-  default:
-    return false;
-  }
-
-  string formatted;
-  if (!format_default_value(num, formatted)) {
-    return false;
-  }
-
-  _default_value = formatted;
-  _has_default_value = true;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::set_default_value
-//       Access: Public
-//  Description: Stores the indicated value as the default value for
-//               this element.
-//
-//               Returns true if the element type reasonably accepts a
-//               default value of string type, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-set_default_value(const string &str) {
-  if (_type != ST_string && _type != ST_blob && _type != ST_blob32) {
-    // Only fields of type string or blob accept quoted strings.
-    return false;
-  }
-
-  _default_value = str;
-  _has_default_value = true;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::set_default_value_literal
-//       Access: Public
-//  Description: Explicitly sets the default value to the given
-//               pre-formatted string.
-////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-set_default_value_literal(const string &str) {
-  _default_value = str;
-  _has_default_value = true;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::add_default_value
+//     Function: DCAtomicField::ElementType::Copy Constructor
 //       Access: Public
 //       Access: Public
-//  Description: Appends the indicated value as the next array element
-//               value for the default value for this type.
-//
-//               Returns true if the element type reasonably accepts a
-//               default value of numeric type, false otherwise.
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-add_default_value(double num) {
-  string formatted;
-  if (!format_default_value(num, formatted)) {
-    return false;
-  }
-
-  _default_value += formatted;
-  return true;
+DCAtomicField::ElementType::
+ElementType(const DCAtomicField::ElementType &copy) :
+  _type(copy._type->make_copy()),
+  _name(copy._name),
+  _default_value(copy._default_value),
+  _has_default_value(copy._has_default_value)
+{
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::add_default_value
+//     Function: DCAtomicField::ElementType::Copy Assignment Operator
 //       Access: Public
 //       Access: Public
-//  Description: Appends the indicated value as the next array element
-//               value for the default value for this type.
-//
-//               Returns true if the element type reasonably accepts a
-//               default value of numeric type, false otherwise.
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-add_default_value(const string &str) {
-  string formatted;
-  if (!format_default_value(str, formatted)) {
-    return false;
-  }
-
-  _default_value += formatted;
-  return true;
+void DCAtomicField::ElementType::
+operator = (const DCAtomicField::ElementType &copy) {
+  delete _type;
+  _type = copy._type->make_copy();
+  _name = copy._name;
+  _default_value = copy._default_value;
+  _has_default_value = copy._has_default_value;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::add_default_value_literal
+//     Function: DCAtomicField::ElementType::Destructor
 //       Access: Public
 //       Access: Public
-//  Description: Appends the indicated value as the next array element
-//               value for the default value for this type.
-//
-//               Returns true if the element type reasonably accepts a
-//               default value of numeric type, false otherwise.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-add_default_value_literal(const string &str) {
-  if (_type != ST_blob && _type != ST_blob32) {
-    // Only blobs can have literal hex strings nested within arrays.
-    return false;
-  }
-
-  _default_value += str;
-  return true;
+DCAtomicField::ElementType::
+~ElementType() {
+  delete _type;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::end_array
+//     Function: DCAtomicField::ElementType::set_default_value
 //       Access: Public
 //       Access: Public
-//  Description: Called by the parser after a number of calls to
-//               add_default_value(), to indicate the array has been
-//               completed.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-end_array() {
-  switch (_type) {
-  case ST_int8array:
-  case ST_int16array:
-  case ST_int32array:
-  case ST_uint8array:
-  case ST_uint16array:
-  case ST_uint32array:
-  case ST_blob:
-  case ST_blob32:
-    // These types accept arrays.
-    return true;
-
-  case ST_uint32uint8array:
-    {
-      // In this special case type, we collapse every other 32-bit
-      // value down to an 8-bit value after formatting.
-      string new_value;
-      size_t p = 0;
-      while (p < _default_value.size()) {
-        // We should have at least 8 bytes for each two elements.  If
-        // we don't, maybe the user gave us an odd number of elements.
-        if (p + 8 > _default_value.size()) {
-          return false;
-        }
-        new_value += _default_value.substr(p, 5);
-        p += 8;
-      }
-
-      _default_value = new_value;
-      return true;
-    }
-
-  default:
-    return false;
-  }
+void DCAtomicField::ElementType::
+set_default_value(const string &default_value) {
+  _default_value = default_value;
+  _has_default_value = true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -217,513 +92,16 @@ end_array() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void DCAtomicField::ElementType::
 void DCAtomicField::ElementType::
 output(ostream &out, bool brief) const {
 output(ostream &out, bool brief) const {
-  out << _type;
-  if (_divisor != 1) {
-    out << " / " << _divisor;
-  }
-  if (!brief) {
-    if (!_name.empty()) {
-      out << " " << _name;
-    }
-    if (_has_default_value) {
-      out << " = <" << hex;
-      string::const_iterator si;
-      for (si = _default_value.begin(); si != _default_value.end(); ++si) {
-        out << setw(2) << setfill('0') << (int)(unsigned char)(*si);
-      }
-      out << dec << ">";
-    }
-  }
-}
-
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::pack_arg
-//       Access: Public
-//  Description: Packs the Python object into the datagram, appending
-//               to the end of the datagram.
-////////////////////////////////////////////////////////////////////
-void DCAtomicField::ElementType::
-pack_arg(Datagram &datagram, PyObject *item, DCSubatomicType type) const {
-  char *str;
-  int size;
-
-  if (type == ST_invalid) {
-    type = _type;
-  }
-
-  // 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);
-        pack_arg(datagram, PyTuple_GetItem(tuple, 0), ST_uint32);
-        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);
-        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: DCAtomicField::ElementType::unpack_arg
-//       Access: Public
-//  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 *DCAtomicField::ElementType::
-unpack_arg(DatagramIterator &iterator, DCSubatomicType type) const {
-  string str;
-
-  if (type == ST_invalid) {
-    type = _type;
-  }
-
-  // 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 = unpack_arg(iterator, ST_uint32);
-        PyObject *b = 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 = 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: DCAtomicField::ElementType::format_default_value
-//       Access: Private
-//  Description: Formats the indicated default value to a sequence of
-//               bytes, according to the element type.  Returns true
-//               if the element type reasonably accepts a number,
-//               false otherwise.
-////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-format_default_value(double num, string &formatted) const {
-  double real_value = num * _divisor;
-  int int_value = (int)floor(real_value + 0.5);
-
-  switch (_type) {
-  case ST_int8:
-  case ST_uint8:
-  case ST_int8array:
-  case ST_uint8array:
-  case ST_blob:
-  case ST_blob32:
-    formatted = string(1, (char)(int_value & 0xff));
-    break;
-
-  case ST_int16:
-  case ST_uint16:
-  case ST_int16array:
-  case ST_uint16array:
-    formatted =
-      string(1, (char)(int_value & 0xff)) +
-      string(1, (char)((int_value >> 8) & 0xff));
-    break;
-
-  case ST_int32:
-  case ST_uint32:
-  case ST_int32array:
-  case ST_uint32array:
-  case ST_uint32uint8array:
-    formatted =
-      string(1, (char)(int_value & 0xff)) +
-      string(1, (char)((int_value >> 8) & 0xff)) +
-      string(1, (char)((int_value >> 16) & 0xff)) +
-      string(1, (char)((int_value >> 24) & 0xff));
-    break;
-
-  case ST_int64:
-    // We don't fully support default values for int64.  The
-    // high-order 32 bits cannot be specified.
-    formatted =
-      string(1, (char)(int_value & 0xff)) +
-      string(1, (char)((int_value >> 8) & 0xff)) +
-      string(1, (char)((int_value >> 16) & 0xff)) +
-      string(1, (char)((int_value >> 24) & 0xff)) +
-      ((int_value & 0x80000000) != 0 ? string(4, '\xff') : string(4, '\0'));
-    break;
-
-  case ST_uint64:
-    // We don't fully support default values for int64.  The
-    // high-order 32 bits cannot be specified.
-    formatted =
-      string(1, (char)(int_value & 0xff)) +
-      string(1, (char)((int_value >> 8) & 0xff)) +
-      string(1, (char)((int_value >> 16) & 0xff)) +
-      string(1, (char)((int_value >> 24) & 0xff)) +
-      string(4, '\0');
-    break;
-
-  case ST_float64:
-    // This may not be fully portable.
-    formatted = string((char *)&real_value, 8);
-#ifdef WORDS_BIGENDIAN
-    {
-      // Reverse the byte ordering for big-endian machines.
-      string str;
-      str.reserve(8);
-
-      int length = str.length();
-      for (size_t i = 0; i < 8; i++) {
-        str += formatted[length - 1 - i];
-      }
-      formatted = str;
-    }
-#endif
-    break;
-
-  case ST_string:
-    // It doesn't make sense to assign a numeric default value to a
-    // string.
-    return false;
+  _type->output(out, _name, brief);
 
 
-  case ST_invalid:
-    break;
-  }
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::ElementType::format_default_value
-//       Access: Private
-//  Description: Formats the indicated default value to a sequence of
-//               bytes, according to the element type.  Returns true
-//               if the element type reasonably accepts a string,
-//               false otherwise.
-////////////////////////////////////////////////////////////////////
-bool DCAtomicField::ElementType::
-format_default_value(const string &str, string &formatted) const {
-  switch (_type) {
-  case ST_string:
-  case ST_blob:
-  case ST_blob32:
-    {
-      int length = str.length();
-      formatted =
-        string(1, (char)(length & 0xff)) +
-        string(1, (char)((length >> 8) & 0xff)) +
-        str;
+  if (!brief && _has_default_value) {
+    out << " = <" << hex;
+    string::const_iterator si;
+    for (si = _default_value.begin(); si != _default_value.end(); ++si) {
+      out << setw(2) << setfill('0') << (int)(unsigned char)(*si);
     }
     }
-    break;
-
-  default:
-    // It doesn't make sense to assign a string default to a number.
-    return false;
+    out << dec << ">";
   }
   }
-
-  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -741,7 +119,8 @@ as_atomic_field() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DCAtomicField::get_num_elements
 //     Function: DCAtomicField::get_num_elements
 //       Access: Public
 //       Access: Public
-//  Description: Returns the number of elements of the atomic field.
+//  Description: Returns the number of elements (parameters) of the
+//               atomic field.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int DCAtomicField::
 int DCAtomicField::
 get_num_elements() const {
 get_num_elements() const {
@@ -751,12 +130,12 @@ get_num_elements() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DCAtomicField::get_element_type
 //     Function: DCAtomicField::get_element_type
 //       Access: Public
 //       Access: Public
-//  Description: Returns the numeric type of the nth element of the
-//               field.
+//  Description: Returns the type object describing the type of the
+//               nth element (parameter).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-DCSubatomicType DCAtomicField::
-get_element_type(int n) const {
-  nassertr(n >= 0 && n < (int)_elements.size(), ST_invalid);
+DCType *DCAtomicField::
+get_element_type_obj(int n) const {
+  nassertr(n >= 0 && n < (int)_elements.size(), NULL);
   return _elements[n]._type;
   return _elements[n]._type;
 }
 }
 
 
@@ -774,21 +153,6 @@ get_element_name(int n) const {
   return _elements[n]._name;
   return _elements[n]._name;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DCAtomicField::get_element_divisor
-//       Access: Public
-//  Description: Returns the divisor associated with the nth element
-//               of the field.  This implements an implicit
-//               fixed-point system; floating-point values are to be
-//               multiplied by this value before encoding into a
-//               packet, and divided by this number after decoding.
-////////////////////////////////////////////////////////////////////
-int DCAtomicField::
-get_element_divisor(int n) const {
-  nassertr(n >= 0 && n < (int)_elements.size(), 1);
-  return _elements[n]._divisor;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DCAtomicField::get_element_default
 //     Function: DCAtomicField::get_element_default
 //       Access: Public
 //       Access: Public
@@ -807,34 +171,7 @@ get_element_default(int n) const {
   nassertr(has_element_default(n), string());
   nassertr(has_element_default(n), string());
   nassertr(n >= 0 && n < (int)_elements.size(), string());
   nassertr(n >= 0 && n < (int)_elements.size(), string());
 
 
-  string default_value = _elements[n]._default_value;
-
-  switch (_elements[n]._type) {
-  case ST_int8array:
-  case ST_int16array:
-  case ST_int32array:
-  case ST_uint8array:
-  case ST_uint16array:
-  case ST_uint32array:
-  case ST_uint32uint8array:
-  case ST_blob:
-  case ST_blob32:
-  case ST_string:
-    // These array types also want an implicit length.
-    {
-      int length = default_value.length();
-      default_value =
-        string(1, (char)(length & 0xff)) +
-        string(1, (char)((length >> 8) & 0xff)) +
-        default_value;
-    }
-    break;
-
-  default:
-    break;
-  }
-
-  return default_value;
+  return _elements[n]._default_value;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -849,6 +186,41 @@ has_element_default(int n) const {
   return _elements[n]._has_default_value;
   return _elements[n]._has_default_value;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCAtomicField::get_element_type
+//       Access: Public
+//  Description: Returns the numeric type of the nth element of the
+//               field.  This method is deprecated; use
+//               get_element_type_obj() instead.
+////////////////////////////////////////////////////////////////////
+DCSubatomicType DCAtomicField::
+get_element_type(int n) const {
+  nassertr(n >= 0 && n < (int)_elements.size(), ST_invalid);
+  DCSimpleType *simple_type = _elements[n]._type->as_simple_type();
+  nassertr(simple_type != (DCSimpleType *)NULL, ST_invalid);
+  return simple_type->get_type();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCAtomicField::get_element_divisor
+//       Access: Public
+//  Description: Returns the divisor associated with the nth element
+//               of the field.  This implements an implicit
+//               fixed-point system; floating-point values are to be
+//               multiplied by this value before encoding into a
+//               packet, and divided by this number after decoding.
+//
+//               This method is deprecated; use get_element_type_obj()
+//               instead.
+////////////////////////////////////////////////////////////////////
+int DCAtomicField::
+get_element_divisor(int n) const {
+  nassertr(n >= 0 && n < (int)_elements.size(), 1);
+  DCSimpleType *simple_type = _elements[n]._type->as_simple_type();
+  nassertr(simple_type != (DCSimpleType *)NULL, 1);
+  return simple_type->get_divisor();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DCAtomicField::is_required
 //     Function: DCAtomicField::is_required
 //       Access: Public
 //       Access: Public
@@ -1030,8 +402,7 @@ generate_hash(HashGenerator &hashgen) const {
   Elements::const_iterator ei;
   Elements::const_iterator ei;
   for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
   for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
     const ElementType &element = (*ei);
     const ElementType &element = (*ei);
-    hashgen.add_int(element._type);
-    hashgen.add_int(element._divisor);
+    element._type->generate_hash(hashgen);
   }
   }
   hashgen.add_int(_flags);
   hashgen.add_int(_flags);
 }
 }
@@ -1060,7 +431,7 @@ do_pack_args(Datagram &datagram, PyObject *tuple, int &index) const {
     }
     }
     PyObject *item = PySequence_GetItem(tuple, index);
     PyObject *item = PySequence_GetItem(tuple, index);
     index++;
     index++;
-    element.pack_arg(datagram, item);
+    element._type->pack_arg(datagram, item);
     Py_DECREF(item);
     Py_DECREF(item);
   }
   }
 
 
@@ -1083,7 +454,7 @@ do_unpack_args(pvector<PyObject *> &args, DatagramIterator &iterator) const {
   Elements::const_iterator ei;
   Elements::const_iterator ei;
   for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
   for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
     const ElementType &element = (*ei);
     const ElementType &element = (*ei);
-    PyObject *item = element.unpack_arg(iterator);
+    PyObject *item = element._type->unpack_arg(iterator);
     if (item == (PyObject *)NULL) {
     if (item == (PyObject *)NULL) {
       // Ran out of datagram bytes.
       // Ran out of datagram bytes.
       return false;
       return false;

+ 13 - 21
direct/src/dcparser/dcAtomicField.h

@@ -22,6 +22,7 @@
 #include "dcbase.h"
 #include "dcbase.h"
 #include "dcField.h"
 #include "dcField.h"
 #include "dcSubatomicType.h"
 #include "dcSubatomicType.h"
+#include "dcType.h"
 
 
 // Must use math.h instead of cmath.h so this can compile outside of
 // Must use math.h instead of cmath.h so this can compile outside of
 // Panda.
 // Panda.
@@ -39,12 +40,15 @@ PUBLISHED:
   virtual DCAtomicField *as_atomic_field();
   virtual DCAtomicField *as_atomic_field();
 
 
   int get_num_elements() const;
   int get_num_elements() const;
-  DCSubatomicType get_element_type(int n) const;
+  DCType *get_element_type_obj(int n) const;
   string get_element_name(int n) const;
   string get_element_name(int n) const;
-  int get_element_divisor(int n) const;
   string get_element_default(int n) const;
   string get_element_default(int n) const;
   bool has_element_default(int n) const;
   bool has_element_default(int n) const;
 
 
+  // These two methods are deprecated and will be removed soon.
+  DCSubatomicType get_element_type(int n) const;
+  int get_element_divisor(int n) const;
+
   bool is_required() const;
   bool is_required() const;
   bool is_broadcast() const;
   bool is_broadcast() const;
   bool is_p2p() const;
   bool is_p2p() const;
@@ -71,32 +75,19 @@ public:
   // definition as read from the file.
   // definition as read from the file.
   class ElementType {
   class ElementType {
   public:
   public:
-    ElementType();
-    bool set_default_value(double num);
-    bool set_default_value(const string &str);
-    bool set_default_value_literal(const string &str);
+    ElementType(DCType *type);
+    ElementType(const ElementType &copy);
+    void operator = (const ElementType &copy);
+    ~ElementType();
 
 
-    bool add_default_value(double num);
-    bool add_default_value(const string &str);
-    bool add_default_value_literal(const string &str);
-    bool end_array();
+    void set_default_value(const string &default_value);
 
 
     void output(ostream &out, bool brief) const;
     void output(ostream &out, bool brief) const;
 
 
-#ifdef HAVE_PYTHON
-    void pack_arg(Datagram &datagram, PyObject *item, DCSubatomicType = ST_invalid) const;
-    PyObject *unpack_arg(DatagramIterator &iterator, DCSubatomicType = ST_invalid) const;
-#endif
-
-    DCSubatomicType _type;
+    DCType *_type;
     string _name;
     string _name;
-    int _divisor;
     string _default_value;
     string _default_value;
     bool _has_default_value;
     bool _has_default_value;
-
-  private:
-    bool format_default_value(double num, string &formatted) const;
-    bool format_default_value(const string &str, string &formatted) const;
   };
   };
 
 
   typedef pvector<ElementType> Elements;
   typedef pvector<ElementType> Elements;
@@ -115,6 +106,7 @@ public:
   };
   };
 
 
   int _flags;  // A bitmask union of any of the above values.
   int _flags;  // A bitmask union of any of the above values.
+  size_t _pack_index;
 };
 };
 
 
 #endif
 #endif

+ 2 - 1
direct/src/dcparser/dcField.h

@@ -20,6 +20,7 @@
 #define DCFIELD_H
 #define DCFIELD_H
 
 
 #include "dcbase.h"
 #include "dcbase.h"
+#include "dcPackerInterface.h"
 
 
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
 
 
@@ -41,7 +42,7 @@ class HashGenerator;
 // Description : A single field of a Distributed Class, either atomic
 // Description : A single field of a Distributed Class, either atomic
 //               or molecular.
 //               or molecular.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_DIRECT DCField {
+class EXPCL_DIRECT DCField : public DCPackerInterface {
 PUBLISHED:
 PUBLISHED:
   int get_number() const;
   int get_number() const;
   const string &get_name() const;
   const string &get_name() const;

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

@@ -54,6 +54,12 @@ public:
   // definition as read from the file.
   // definition as read from the file.
   typedef pvector<DCAtomicField *> Fields;
   typedef pvector<DCAtomicField *> Fields;
   Fields _fields;
   Fields _fields;
+
+private:
+  DCType *get_next_pack_element();
+
+  size_t _pack_field_index;
+  size_t _pack_element_index;
 };
 };
 
 
 #endif
 #endif

+ 124 - 0
direct/src/dcparser/dcPackData.I

@@ -0,0 +1,124 @@
+// Filename: dcPackData.I
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DCPackData::
+DCPackData() {
+  _buffer = NULL;
+  _allocated_size = 0;
+  _used_length = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE DCPackData::
+~DCPackData() {
+  if (_buffer != (const char *)NULL) {
+    delete[] _buffer;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::clear
+//       Access: Published
+//  Description: Empties the contents of the data (without necessarily
+//               freeing its allocated memory).
+////////////////////////////////////////////////////////////////////
+INLINE void DCPackData::
+clear() {
+  _used_length = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::append_data
+//       Access: Published
+//  Description: Adds the indicated bytes to the end of the data.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPackData::
+append_data(const char *buffer, size_t size) {
+  set_used_length(_used_length + size);
+  memcpy(_buffer + _used_length - size, buffer, size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::append_junk
+//       Access: Published
+//  Description: Adds some uninitialized bytes to the end of the data.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPackData::
+append_junk(size_t size) {
+  set_used_length(_used_length + size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::rewrite_data
+//       Access: Published
+//  Description: Changes the data at the indicated position to the
+//               given value.  It is an error if there are not at
+//               least position + size bytes in the data.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPackData::
+rewrite_data(size_t position, const char *buffer, size_t size) {
+  nassertv(position + size <= _used_length);
+  memcpy(_buffer + position, buffer, size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::get_string
+//       Access: Published
+//  Description: Returns the data buffer as a string.  Also see
+//               get_data().
+////////////////////////////////////////////////////////////////////
+INLINE string DCPackData::
+get_string() const {
+  return string(_buffer, _used_length);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::get_length
+//       Access: Published
+//  Description: Returns the current length of the buffer.  This is
+//               the number of useful bytes stored in the buffer, not
+//               the amount of memory it takes up.
+////////////////////////////////////////////////////////////////////
+INLINE size_t DCPackData::
+get_length() const {
+  return _used_length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::get_data
+//       Access: Public
+//  Description: Returns the beginning of the data buffer.  The buffer
+//               is not null-terminated, but see also get_string().
+//
+//               This may be used in conjunction with get_length() to
+//               copy all of the bytes out of the buffer.
+////////////////////////////////////////////////////////////////////
+INLINE const char *DCPackData::
+get_data() const {
+  return _buffer;
+}

+ 45 - 0
direct/src/dcparser/dcPackData.cxx

@@ -0,0 +1,45 @@
+// Filename: dcPackData.cxx
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "dcPackData.h"
+
+static const size_t extra_size = 50;
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::set_used_length
+//       Access: Private
+//  Description: Ensures that the buffer has at least size bytes, and
+//               sets the _used_length to the indicated values; grows
+//               the buffer if it does not.
+////////////////////////////////////////////////////////////////////
+void DCPackData::
+set_used_length(size_t size) {
+  if (size > _allocated_size) {
+    _allocated_size = size * size + extra_size;
+    char *new_buf = new char[_allocated_size];
+    if (_used_length > 0) {
+      memcpy(new_buf, _buffer, _used_length);
+    }
+    if (_buffer != NULL) {
+      delete[] _buffer;
+    }
+    _buffer = new_buf;
+  }
+
+  _used_length = size;
+}

+ 56 - 0
direct/src/dcparser/dcPackData.h

@@ -0,0 +1,56 @@
+// Filename: dcPackData.h
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DCPACKDATA_H
+#define DCPACKDATA_H
+
+#include "dcbase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : DCPackData
+// Description : This is a block of data that receives the results of
+//               DCPacker.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT DCPackData {
+PUBLISHED:
+  INLINE DCPackData();
+  INLINE ~DCPackData();
+
+  INLINE void clear();
+
+  INLINE void append_data(const char *buffer, size_t size);
+  INLINE void append_junk(size_t size);
+  INLINE void rewrite_data(size_t position, const char *buffer, size_t size);
+
+  INLINE string get_string() const;
+  INLINE size_t get_length() const;
+public:
+  INLINE const char *get_data() const;
+
+private:
+  void set_used_length(size_t size);
+
+private:
+  char *_buffer;
+  size_t _allocated_size;
+  size_t _used_length;
+};
+
+#include "dcPackData.I"
+
+#endif

+ 212 - 0
direct/src/dcparser/dcPacker.I

@@ -0,0 +1,212 @@
+// Filename: dcPacker.I
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::get_num_nested_fields
+//       Access: Published
+//  Description: Returns the number of nested fields associated with
+//               the current field.  If this returns nonzero, it will
+//               be necessary to call push(), followed by pack_value()
+//               the indicated number of times, followed by pop().
+//
+//               The return value may also be -1 to indicate that a
+//               variable number of nested fields are accepted by this
+//               field type (e.g. a variable-length array).
+////////////////////////////////////////////////////////////////////
+INLINE int DCPacker::
+get_num_nested_fields() const {
+  return _num_nested_fields;
+}
+
+////////////////////////////////////////////////////////////////////
+//     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).
+////////////////////////////////////////////////////////////////////
+INLINE DCSubatomicType DCPacker::
+get_pack_type() const {
+  if (_current_field == NULL) {
+    return ST_invalid;
+  } else {
+    return _current_field->get_pack_type();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::pack_value
+//       Access: Published
+//  Description: Packs the indicated numeric or string value into the
+//               stream.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+pack_value(double value) {
+  if (_current_field == NULL) {
+    _pack_error = true;
+  } else {
+    if (!_current_field->pack_value(_pack_data, value)) {
+      _pack_error = true;
+    }
+    advance();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::pack_value
+//       Access: Published
+//  Description: Packs the indicated numeric or string value into the
+//               stream.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+pack_value(int value) {
+  if (_current_field == NULL) {
+    _pack_error = true;
+  } else {
+    if (!_current_field->pack_value(_pack_data, value)) {
+      _pack_error = true;
+    }
+    advance();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::pack_value
+//       Access: Published
+//  Description: Packs the indicated numeric or string value into the
+//               stream.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+pack_value(PN_int64 value) {
+  if (_current_field == NULL) {
+    _pack_error = true;
+  } else {
+    if (!_current_field->pack_value(_pack_data, value)) {
+      _pack_error = true;
+    }
+    advance();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::pack_value
+//       Access: Published
+//  Description: Packs the indicated numeric or string value into the
+//               stream.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+pack_value(const string &value) {
+  if (_current_field == NULL) {
+    _pack_error = true;
+  } else {
+    if (!_current_field->pack_value(_pack_data, value)) {
+      _pack_error = true;
+    }
+    advance();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::pack_literal_value
+//       Access: Published
+//  Description: Adds the indicated string value into the stream,
+//               representing a single pre-packed field element, or a
+//               whole group of field elements at once.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+pack_literal_value(const string &value) {
+  if (_current_field == NULL) {
+    _pack_error = true;
+  } else {
+    _pack_data.append_data(value.data(), value.length());
+    advance();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::had_pack_error
+//       Access: Published
+//  Description: Returns true if there has been an error in packing
+//               since the most recent call to begin().  It is
+//               most useful to call this after end() to validate
+//               the entire packing run.
+////////////////////////////////////////////////////////////////////
+INLINE bool DCPacker::
+had_pack_error() const {
+  return _pack_error;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::get_string
+//       Access: Published
+//  Description: Returns the packed data buffer as a string.  Also see
+//               get_data().
+////////////////////////////////////////////////////////////////////
+INLINE string DCPacker::
+get_string() const {
+  return _pack_data.get_string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::get_length
+//       Access: Published
+//  Description: Returns the current length of the buffer.  This is
+//               the number of useful bytes stored in the buffer, not
+//               the amount of memory it takes up.
+////////////////////////////////////////////////////////////////////
+INLINE size_t DCPacker::
+get_length() const {
+  return _pack_data.get_length();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::get_data
+//       Access: Public
+//  Description: Returns the beginning of the data buffer.  The buffer
+//               is not null-terminated, but see also get_string().
+//
+//               This may be used in conjunction with get_length() to
+//               copy all of the bytes out of the buffer.
+////////////////////////////////////////////////////////////////////
+INLINE const char *DCPacker::
+get_data() const {
+  return _pack_data.get_data();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::advance
+//       Access: Private
+//  Description: Advances to the next field after a call to
+//               pack_value() or pop().
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+advance() {
+  if (_num_nested_fields >= 0 &&
+      _current_field_index >= _num_nested_fields) {
+    // 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_index++;
+    _current_field = _current_parent->get_nested_field(_current_field_index);
+  }
+}

+ 182 - 0
direct/src/dcparser/dcPacker.cxx

@@ -0,0 +1,182 @@
+// Filename: dcPacker.cxx
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "dcPacker.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCPacker::
+DCPacker() {
+  _current_field = NULL;
+  _current_parent = NULL;
+  _current_field_index = 0;
+  _num_nested_fields = 0;
+  _pack_error = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCPacker::
+~DCPacker() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::begin
+//       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(DCPackerInterface *root) {
+  // If this assertion fails, we didn't match begin() up with end().
+  nassertv(_stack.empty() && 
+           _current_field == NULL &&
+           _current_parent == NULL);
+  
+  _pack_error = false;
+  _pack_data.clear();
+
+  _stack.clear();
+  _current_field = root;
+  _current_parent = NULL;
+  _current_field_index = 0;
+  _num_nested_fields = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::end
+//       Access: Published, Virtual
+//  Description: Finishes a packing session.
+//
+//               The return value is true on success, or false if
+//               there has been some error during packing.
+////////////////////////////////////////////////////////////////////
+bool DCPacker::
+end() {
+  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::push
+//       Access: Published
+//  Description: Marks the beginning of a nested series of fields.
+//
+//               This must be called before filling the elements of an
+//               array or the individual fields in a structure field.
+//               It must also be balanced by a matching pop().
+//
+//               It is necessary to use push() / pop() if and only if
+//               get_num_nested_fields() returns nonzero.
+////////////////////////////////////////////////////////////////////
+void DCPacker::
+push() {
+  if (_current_field == NULL) {
+    _pack_error = true;
+
+  } else {
+    int num_nested_fields = _current_field->get_num_nested_fields();
+    if (num_nested_fields == 0) {
+      _pack_error = true;
+
+    } else {
+      StackElement element;
+      element._current_parent = _current_parent;
+      element._current_field_index = _current_field_index;
+      element._push_start = _push_start;
+      _stack.push_back(element);
+
+      _current_parent = _current_field;
+      _current_field_index = 0;
+      _current_field = _current_parent->get_nested_field(0);
+      _num_nested_fields = num_nested_fields;
+
+      // 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);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::pop
+//       Access: Published
+//  Description: Marks the end of a nested series of fields.
+//
+//               This must be called to match a previous push() only
+//               after all the expected number of nested fields have
+//               been packed.  It is an error to call it too early, or
+//               too late.
+////////////////////////////////////////////////////////////////////
+void DCPacker::
+pop() {
+  if (_current_field != NULL && _num_nested_fields >= 0) {
+    // Oops, didn't pack enough values.
+    _pack_error = true;
+  }
+
+  if (_stack.empty()) {
+    // Unbalanced 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);
+      }
+    }
+
+    _current_field = _current_parent;
+    _current_parent = _stack.back()._current_parent;
+    _current_field_index = _stack.back()._current_field_index;
+    _push_start = _stack.back()._push_start;
+    _num_nested_fields = (_current_parent == NULL) ? 0 : _current_parent->get_num_nested_fields();
+    _stack.pop_back();
+  }
+
+  advance();
+}

+ 87 - 0
direct/src/dcparser/dcPacker.h

@@ -0,0 +1,87 @@
+// Filename: dcPacker.h
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DCPACKER_H
+#define DCPACKER_H
+
+#include "dcbase.h"
+#include "dcPackerInterface.h"
+#include "dcSubatomicType.h"
+#include "dcPackData.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : DCPacker
+// Description : This class can be used for packing a series of
+//               numeric and string data into a binary stream,
+//               according to the DC specification.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT DCPacker {
+PUBLISHED:
+  DCPacker();
+  ~DCPacker();
+
+  void begin(DCPackerInterface *root);
+  bool end();
+
+  INLINE int get_num_nested_fields() const;
+  void push();
+  void pop();
+
+  INLINE DCSubatomicType get_pack_type() const;
+  INLINE void pack_value(double value);
+  INLINE void pack_value(int value);
+  INLINE void pack_value(PN_int64 value);
+  INLINE void pack_value(const string &value);
+  INLINE void pack_literal_value(const string &value);
+
+  INLINE bool had_pack_error() const;
+
+  INLINE string get_string() const;
+  INLINE size_t get_length() const;
+public:
+  INLINE const char *get_data() const;
+
+private:
+  INLINE void advance();
+
+private:
+  DCPackData _pack_data;
+
+  class StackElement {
+  public:
+    DCPackerInterface *_current_parent;
+    int _current_field_index;
+    size_t _push_start;
+  };
+  typedef vector<StackElement> Stack;
+
+  Stack _stack;
+  DCPackerInterface *_current_field;
+  DCPackerInterface *_current_parent;
+  int _current_field_index;
+  size_t _push_start;
+  int _num_nested_fields;
+
+  bool _pack_error;
+
+  friend class DCPackerInterface;
+};
+
+#include "dcPacker.I"
+
+#endif

+ 126 - 0
direct/src/dcparser/dcPackerInterface.cxx

@@ -0,0 +1,126 @@
+// Filename: dcPackerInterface.cxx
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "dcPackerInterface.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCPackerInterface::
+~DCPackerInterface() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_num_nested_fields
+//       Access: Public, Virtual
+//  Description: Returns the number of nested fields required by this
+//               field type.  These may be array elements or structure
+//               elements.  The return value should be 0 if the field
+//               type does not have any nested fields.  It may also be
+//               -1 to indicate the number of nested fields is
+//               variable.
+////////////////////////////////////////////////////////////////////
+int DCPackerInterface::
+get_num_nested_fields() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_nested_field
+//       Access: Public, Virtual
+//  Description: Returns the DCPackerInterface object that represents
+//               the nth nested field.  This may return NULL if there
+//               is no such field (but it shouldn't do this if n is in
+//               the range 0 <= n < get_num_nested_fields()).
+////////////////////////////////////////////////////////////////////
+DCPackerInterface *DCPackerInterface::
+get_nested_field(int n) const {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_length_bytes
+//       Access: Public, Virtual
+//  Description: If get_num_nested_fields() returns non-zero, this
+//               should return either 0, 2, or 4, indicating the
+//               number of bytes this field's data should be prefixed
+//               with to record its length.  This is respected by
+//               push() and pop().
+////////////////////////////////////////////////////////////////////
+size_t DCPackerInterface::
+get_length_bytes() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     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.
+////////////////////////////////////////////////////////////////////
+DCSubatomicType DCPackerInterface::
+get_pack_type() const {
+  return ST_invalid;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::pack_value
+//       Access: Public, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCPackerInterface::
+pack_value(DCPackData &, double) const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::pack_value
+//       Access: Public, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCPackerInterface::
+pack_value(DCPackData &, int) const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::pack_value
+//       Access: Public, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCPackerInterface::
+pack_value(DCPackData &, PN_int64) const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::pack_value
+//       Access: Public, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCPackerInterface::
+pack_value(DCPackData &, const string &) const {
+  return false;
+}

+ 52 - 0
direct/src/dcparser/dcPackerInterface.h

@@ -0,0 +1,52 @@
+// Filename: dcPackerInterface.h
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DCPACKERINTERFACE_H
+#define DCPACKERINTERFACE_H
+
+#include "dcbase.h"
+#include "dcSubatomicType.h"
+
+class DCPackData;
+
+////////////////////////////////////////////////////////////////////
+//       Class : DCPackerInterface
+// Description : This defines the internal interface for packing
+//               values into a DCField.  The various different DC
+//               objects inherit from this.  
+//
+//               Normally these methods are called only by the
+//               DCPacker object; the user wouldn't normally call
+//               these directly.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT DCPackerInterface {
+public:
+  virtual ~DCPackerInterface();
+
+  virtual int get_num_nested_fields() const;
+  virtual DCPackerInterface *get_nested_field(int n) const;
+  virtual size_t get_length_bytes() const;
+
+  virtual DCSubatomicType get_pack_type() const;
+  virtual bool pack_value(DCPackData &pack_data, double value) const;
+  virtual bool pack_value(DCPackData &pack_data, int value) const;
+  virtual bool pack_value(DCPackData &pack_data, PN_int64 value) const;
+  virtual bool pack_value(DCPackData &pack_data, const string &value) const;
+};
+
+#endif

+ 52 - 73
direct/src/dcparser/dcParser.yxx

@@ -10,6 +10,8 @@
 #include "dcClass.h"
 #include "dcClass.h"
 #include "dcAtomicField.h"
 #include "dcAtomicField.h"
 #include "dcMolecularField.h"
 #include "dcMolecularField.h"
+#include "dcSimpleType.h"
+#include "dcPacker.h"
 
 
 // Because our token type contains objects of type string, which
 // Because our token type contains objects of type string, which
 // require correct copy construction (and not simply memcpying), we
 // require correct copy construction (and not simply memcpying), we
@@ -23,7 +25,8 @@ static DCFile *dc_file = (DCFile *)NULL;
 static DCClass *current_class = (DCClass *)NULL;
 static DCClass *current_class = (DCClass *)NULL;
 static DCAtomicField *current_atomic = (DCAtomicField *)NULL;
 static DCAtomicField *current_atomic = (DCAtomicField *)NULL;
 static DCMolecularField *current_molecular = (DCMolecularField *)NULL;
 static DCMolecularField *current_molecular = (DCMolecularField *)NULL;
-static DCAtomicField::ElementType atomic_element;
+static DCAtomicField::ElementType atomic_element(new DCSimpleType(ST_invalid));
+static DCPacker default_value_packer;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // Defining the interface to the parser.
 // Defining the interface to the parser.
@@ -241,8 +244,7 @@ nonempty_parameter_list:
 atomic_element:
 atomic_element:
         type_token 
         type_token 
 {
 {
-  atomic_element = DCAtomicField::ElementType();
-  atomic_element._type = $1;
+  atomic_element = DCAtomicField::ElementType(new DCSimpleType($1));
 }
 }
         atomic_element_definition
         atomic_element_definition
 {
 {
@@ -254,114 +256,91 @@ atomic_element_definition:
         empty
         empty
         | atomic_element_definition '/' INTEGER
         | atomic_element_definition '/' INTEGER
 {
 {
-  atomic_element._divisor = $3;
+  if (atomic_element._type->as_simple_type() == NULL) {
+    yyerror("Invalid divisor on complex type");
+
+  } else {
+    atomic_element._type->as_simple_type()->set_divisor($3);
+  }
 }
 }
         | atomic_element_definition IDENTIFIER
         | atomic_element_definition IDENTIFIER
 {
 {
   atomic_element._name = $2;
   atomic_element._name = $2;
 }
 }
-        | atomic_element_definition '=' INTEGER
-{
-  if (!atomic_element.set_default_value($3)) {
-    yyerror("Invalid default value: " + $<str>3);
-  }
-}
-        | atomic_element_definition '=' REAL
-{
-  if (!atomic_element.set_default_value($3)) {
-    yyerror("Invalid default value: " + $<str>3);
-  }
-}
-        | atomic_element_definition '=' STRING
+        | atomic_element_definition '='
 {
 {
-  if (!atomic_element.set_default_value($3)) {
-    yyerror("Invalid default value: \"" + $3 + "\"");
-  }
+  default_value_packer.begin(atomic_element._type);
 }
 }
-        | atomic_element_definition '=' HEX_STRING
+	default_value
 {
 {
-  if (!atomic_element.set_default_value_literal($3)) {
-    yyerror("Invalid default hex string value");
-  }
-}
-        | atomic_element_definition '=' '{' default_array '}'
-{
-  if (!atomic_element.end_array()) {
-    yyerror("Array default value inappropriate");
+  if (!default_value_packer.end()) {
+    yyerror("Invalid default value for type");
+
   } else {
   } else {
-    atomic_element._has_default_value = true;
+    atomic_element.set_default_value(default_value_packer.get_string());
   }
   }
 }
 }
-        ;
-
-default_array:
-        empty
-        | default_array_def maybe_comma
-        ;
-
-maybe_comma:
-        empty
-        | ','
-        ;
-
-default_array_def:
-        default_array_element
-        | default_array_def ',' default_array_element
-        ;
+	;
 
 
-default_array_element:
-        INTEGER
+default_value:
+	INTEGER
 {
 {
-  if (!atomic_element.add_default_value($1)) {
-    yyerror("Invalid default value: " + $<str>1);
-  }
+  default_value_packer.pack_value($1);
 }
 }
         | REAL
         | REAL
 {
 {
-  if (!atomic_element.add_default_value($1)) {
-    yyerror("Invalid default value: " + $<str>1);
-  }
+  default_value_packer.pack_value($1);
 }
 }
         | STRING
         | STRING
 {
 {
-  if (!atomic_element.add_default_value($1)) {
-    yyerror("Invalid default value: " + $<str>1);
-  }
+  default_value_packer.pack_value($1);
 }
 }
         | HEX_STRING
         | HEX_STRING
 {
 {
-  if (!atomic_element.add_default_value_literal($1)) {
-    yyerror("Invalid hex literal in default array");
-  }
+  default_value_packer.pack_literal_value($1);
+}
+        | '{' 
+{
+  default_value_packer.push();
+}
+        default_array '}'
+{
+  default_value_packer.pop();
 }
 }
         | INTEGER '*' INTEGER
         | INTEGER '*' INTEGER
 {
 {
   for (int i = 0; i < $3; i++) {
   for (int i = 0; i < $3; i++) {
-    if (!atomic_element.add_default_value($1)) {
-      yyerror("Invalid default value: " + $<str>1);
-      break;
-    }
+    default_value_packer.pack_value($1);
   }
   }
 }
 }
         | REAL '*' INTEGER
         | REAL '*' INTEGER
 {
 {
   for (int i = 0; i < $3; i++) {
   for (int i = 0; i < $3; i++) {
-    if (!atomic_element.add_default_value($1)) {
-      yyerror("Invalid default value: " + $<str>1);
-      break;
-    }
+    default_value_packer.pack_value($1);
   }
   }
 }
 }
         | HEX_STRING '*' INTEGER
         | HEX_STRING '*' INTEGER
 {
 {
   for (int i = 0; i < $3; i++) {
   for (int i = 0; i < $3; i++) {
-    if (!atomic_element.add_default_value_literal($1)) {
-      yyerror("Invalid hex literal in default array");
-      break;
-    }
+    default_value_packer.pack_literal_value($1);
   }
   }
 }
 }
-        ;  
+        ;
+
+default_array:
+        empty
+        | default_array_def maybe_comma
+        ;
+
+maybe_comma:
+        empty
+        | ','
+        ;
+
+default_array_def:
+        default_value
+        | default_array_def ',' default_value
+        ;
 
 
 type_token:
 type_token:
         KW_INT8
         KW_INT8

+ 978 - 0
direct/src/dcparser/dcSimpleType.cxx

@@ -0,0 +1,978 @@
+// Filename: dcSimpleType.cxx
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "dcSimpleType.h"
+#include "dcPackData.h"
+#include "hashGenerator.h"
+
+DCSimpleType::NestedFieldMap DCSimpleType::_nested_field_map;
+DCSimpleType::Uint32Uint8Type *DCSimpleType::_uint32uint8_type = NULL;
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCSimpleType::
+DCSimpleType(DCSubatomicType type, int divisor) :
+  _type(type),
+  _divisor(divisor)
+{
+  // Check for one of the built-in array types.  For these types, we
+  // must present a packing interface that has a variable number of
+  // nested fields of the appropriate type.
+  switch (_type) {
+  case ST_int8array:
+    _nested_type = ST_int8;
+    _is_array = true;
+    break;
+
+  case ST_int16array:
+    _nested_type = ST_int16;
+    _is_array = true;
+    break;
+
+  case ST_int32array:
+    _nested_type = ST_int32;
+    _is_array = true;
+    break;
+
+  case ST_uint8array:
+    _nested_type = ST_uint8;
+    _is_array = true;
+    break;
+
+  case ST_uint16array:
+    _nested_type = ST_uint16;
+    _is_array = true;
+    break;
+
+  case ST_uint32array:
+    _nested_type = ST_uint32;
+    _is_array = true;
+    break;
+
+  case ST_uint32uint8array:
+    _nested_type = ST_invalid;
+    _is_array = true;
+    break;
+
+  case ST_blob:
+  case ST_blob32:
+  case ST_string: 
+    // 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.
+    _nested_type = ST_uint8;
+    _is_array = true;
+    break;
+
+  default:
+    _nested_type = ST_invalid;
+    _is_array = false;
+  }
+
+  if (_nested_type != ST_invalid) {
+    _nested_field = create_nested_field(_nested_type, _divisor);
+
+  } else if (_type == ST_uint32uint8array) {
+    // This one is a special case.  We must create a special nested
+    // type that accepts a uint32 followed by a uint8 for each
+    // element.
+    _nested_field = create_uint32uint8_type();
+
+  } else {
+    _nested_field = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::as_simple_type
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCSimpleType *DCSimpleType::
+as_simple_type() {
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::make_copy
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCType *DCSimpleType::
+make_copy() const {
+  return new DCSimpleType(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::get_type
+//       Access: Published
+//  Description: Returns the particular subatomic type represented by
+//               this instance.
+////////////////////////////////////////////////////////////////////
+DCSubatomicType DCSimpleType::
+get_type() const {
+  return _type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::get_divisor
+//       Access: Published
+//  Description: Returns the divisor associated with this type.  This
+//               is 1 by default, but if this is other than one it
+//               represents the scale to apply when packing and
+//               unpacking numeric values (to store fixed-point values
+//               in an integer field).  It is only meaningful for
+//               numeric-type fields.
+////////////////////////////////////////////////////////////////////
+int DCSimpleType::
+get_divisor() const {
+  return _divisor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::set_divisor
+//       Access: Published
+//  Description: See get_divisor().
+////////////////////////////////////////////////////////////////////
+void DCSimpleType::
+set_divisor(int divisor) {
+  _divisor = divisor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::get_num_nested_fields
+//       Access: Public, Virtual
+//  Description: Returns the number of nested fields required by this
+//               field type.  These may be array elements or structure
+//               elements.  The return value should be 0 if the field
+//               type does not have any nested fields.  It may also be
+//               -1 to indicate the number of nested fields is
+//               variable.
+////////////////////////////////////////////////////////////////////
+int DCSimpleType::
+get_num_nested_fields() const {
+  return _is_array ? -1 : 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::get_nested_field
+//       Access: Public, Virtual
+//  Description: Returns the DCPackerInterface object that represents
+//               the nth nested field.  This may return NULL if there
+//               is no such field (but it shouldn't do this if n is in
+//               the range 0 <= n < get_num_nested_fields()).
+////////////////////////////////////////////////////////////////////
+DCPackerInterface *DCSimpleType::
+get_nested_field(int n) const {
+  return _nested_field;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::get_length_bytes
+//       Access: Public, Virtual
+//  Description: If get_num_nested_fields() returns non-zero, this
+//               should return either 0, 2, or 4, indicating the
+//               number of bytes this field's data should be prefixed
+//               with to record its length.  This is respected by
+//               push() and pop().
+////////////////////////////////////////////////////////////////////
+size_t DCSimpleType::
+get_length_bytes() const {
+  return _type == ST_blob32 ? 4 : 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     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.
+////////////////////////////////////////////////////////////////////
+DCSubatomicType DCSimpleType::
+get_pack_type() const {
+  return _type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::pack_value
+//       Access: Published, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleType::
+pack_value(DCPackData &pack_data, double value) const {
+  double real_value = value * _divisor;
+  int int_value = (int)floor(real_value + 0.5);
+
+  char buffer[8];
+
+  switch (_type) {
+  case ST_int8:
+  case ST_uint8:
+    buffer[0] = (char)(int_value & 0xff);
+    pack_data.append_data(buffer, 1);
+    break;
+
+  case ST_int16:
+  case ST_uint16:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    pack_data.append_data(buffer, 2);
+    break;
+
+  case ST_int32:
+  case ST_uint32:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    buffer[2] = (char)((int_value >> 16) & 0xff);
+    buffer[3] = (char)((int_value >> 24) & 0xff);
+    pack_data.append_data(buffer, 4);
+    break;
+
+  case ST_int64:
+  case ST_uint64:
+    {
+      PN_int64 int64_value = (PN_int64)floor(real_value + 0.5);
+      buffer[0] = (char)(int64_value & 0xff);
+      buffer[1] = (char)((int64_value >> 8) & 0xff);
+      buffer[2] = (char)((int64_value >> 16) & 0xff);
+      buffer[3] = (char)((int64_value >> 24) & 0xff);
+      buffer[4] = (char)((int64_value >> 32) & 0xff);
+      buffer[5] = (char)((int64_value >> 40) & 0xff);
+      buffer[6] = (char)((int64_value >> 48) & 0xff);
+      buffer[7] = (char)((int64_value >> 56) & 0xff);
+      pack_data.append_data(buffer, 8);
+    }
+    break;
+
+  case ST_float64:
+#ifdef WORDS_BIGENDIAN
+    {
+      // Reverse the byte ordering for big-endian machines.
+      char *p = (char *)real_value;
+      for (size_t i = 0; i < 8; i++) {
+        buffer[i] = p[7 - i];
+      }
+    }
+#else
+    memcpy(buffer, &real_value, 8);
+#endif
+    pack_data.append_data(buffer, 8);
+    break;
+
+  default:
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::pack_value
+//       Access: Published, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleType::
+pack_value(DCPackData &pack_data, int value) const {
+  int int_value = value * _divisor;
+
+  char buffer[8];
+
+  switch (_type) {
+  case ST_int8:
+  case ST_uint8:
+    buffer[0] = (char)(int_value & 0xff);
+    pack_data.append_data(buffer, 1);
+    break;
+
+  case ST_int16:
+  case ST_uint16:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    pack_data.append_data(buffer, 2);
+    break;
+
+  case ST_int32:
+  case ST_uint32:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    buffer[2] = (char)((int_value >> 16) & 0xff);
+    buffer[3] = (char)((int_value >> 24) & 0xff);
+    pack_data.append_data(buffer, 4);
+    break;
+
+  case ST_int64:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    buffer[2] = (char)((int_value >> 16) & 0xff);
+    buffer[3] = (char)((int_value >> 24) & 0xff);
+    if ((int_value & 0x80000000) != 0) {
+      buffer[4] = buffer[5] = buffer[6] = buffer[7] = (char)0xff;
+    } else {
+      buffer[4] = buffer[5] = buffer[6] = buffer[7] = (char)0;
+    }
+    pack_data.append_data(buffer, 8);
+    break;
+
+  case ST_uint64:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    buffer[2] = (char)((int_value >> 16) & 0xff);
+    buffer[3] = (char)((int_value >> 24) & 0xff);
+    buffer[4] = buffer[5] = buffer[6] = buffer[7] = (char)0;
+    pack_data.append_data(buffer, 8);
+    break;
+
+  case ST_float64:
+#ifdef WORDS_BIGENDIAN
+    {
+      // Reverse the byte ordering for big-endian machines.
+      double real_value = int_value;
+      char *p = (char *)real_value;
+      for (size_t i = 0; i < 8; i++) {
+        buffer[i] = p[7 - i];
+      }
+    }
+#else
+    {
+      double real_value = int_value;
+      memcpy(buffer, &real_value, 8);
+    }
+#endif
+    pack_data.append_data(buffer, 8);
+    break;
+
+  default:
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::pack_value
+//       Access: Published, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleType::
+pack_value(DCPackData &pack_data, PN_int64 value) const {
+  PN_int64 int_value = value * _divisor;
+
+  char buffer[8];
+
+  switch (_type) {
+  case ST_int8:
+  case ST_uint8:
+    buffer[0] = (char)(int_value & 0xff);
+    pack_data.append_data(buffer, 1);
+    break;
+
+  case ST_int16:
+  case ST_uint16:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    pack_data.append_data(buffer, 2);
+    break;
+
+  case ST_int32:
+  case ST_uint32:
+    buffer[0] = (char)(int_value & 0xff);
+    buffer[1] = (char)((int_value >> 8) & 0xff);
+    buffer[2] = (char)((int_value >> 16) & 0xff);
+    buffer[3] = (char)((int_value >> 24) & 0xff);
+    pack_data.append_data(buffer, 4);
+    break;
+
+  case ST_int64:
+  case ST_uint64:
+    {
+      buffer[0] = (char)(int_value & 0xff);
+      buffer[1] = (char)((int_value >> 8) & 0xff);
+      buffer[2] = (char)((int_value >> 16) & 0xff);
+      buffer[3] = (char)((int_value >> 24) & 0xff);
+      buffer[4] = (char)((int_value >> 32) & 0xff);
+      buffer[5] = (char)((int_value >> 40) & 0xff);
+      buffer[6] = (char)((int_value >> 48) & 0xff);
+      buffer[7] = (char)((int_value >> 56) & 0xff);
+      pack_data.append_data(buffer, 8);
+    }
+    break;
+
+  case ST_float64:
+#ifdef WORDS_BIGENDIAN
+    {
+      // Reverse the byte ordering for big-endian machines.
+      double real_value = int_value;
+      char *p = (char *)real_value;
+      for (size_t i = 0; i < 8; i++) {
+        buffer[i] = p[7 - i];
+      }
+    }
+#else
+    {
+      double real_value = int_value;
+      memcpy(buffer, &real_value, 8);
+    }
+#endif
+    pack_data.append_data(buffer, 8);
+    break;
+
+  default:
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::pack_value
+//       Access: Published, Virtual
+//  Description: Packs the indicated numeric or string value into the
+//               stream.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleType::
+pack_value(DCPackData &pack_data, const string &value) const {
+  char buffer[4];
+
+  switch (_type) {
+  case ST_string:
+  case ST_blob:
+    {
+      int length = value.length();
+      buffer[0] = (char)(length & 0xff);
+      buffer[1] = (char)((length >> 8) & 0xff);
+      pack_data.append_data(buffer, 2);
+      pack_data.append_data(value.data(), length);
+    }
+    break;
+
+  case ST_blob32:
+    {
+      int length = value.length();
+      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.append_data(buffer, 4);
+      pack_data.append_data(value.data(), length);
+    }
+    break;
+
+  default:
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void DCSimpleType::
+output(ostream &out, const string &parameter_name, bool brief) const {
+  out << _type;
+  if (_divisor != 1) {
+    out << " / " << _divisor;
+  }
+  if (!brief && !parameter_name.empty()) {
+    out << " " << parameter_name;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::generate_hash
+//       Access: Public, Virtual
+//  Description: Accumulates the properties of this type into the
+//               hash.
+////////////////////////////////////////////////////////////////////
+void DCSimpleType::
+generate_hash(HashGenerator &hashgen) const {
+  DCType::generate_hash(hashgen);
+
+  hashgen.add_int(_type);
+  hashgen.add_int(_divisor);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::create_nested_field
+//       Access: Private, Static
+//  Description: Creates the one instance of the DCSimpleType
+//               corresponding to this combination of type and divisor
+//               if it is not already created.
+////////////////////////////////////////////////////////////////////
+DCSimpleType *DCSimpleType::
+create_nested_field(DCSubatomicType type, int divisor) {
+  DivisorMap divisor_map = _nested_field_map[type];
+  DivisorMap::iterator di;
+  di = divisor_map.find(divisor);
+  if (di != divisor_map.end()) {
+    return (*di).second;
+  }
+
+  DCSimpleType *nested_field = new DCSimpleType(type, divisor);
+  divisor_map[divisor] = nested_field;
+  return nested_field;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::create_uint32uint8_type
+//       Access: Private, Static
+//  Description: Creates the one instance of the Uint32Uint8Type
+//               object if it is not already created.
+////////////////////////////////////////////////////////////////////
+DCPackerInterface *DCSimpleType::
+create_uint32uint8_type() {
+  if (_uint32uint8_type == NULL) {
+    _uint32uint8_type = new Uint32Uint8Type;
+  }
+  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
+//  Description: This special packer interface is provided just to
+//               implement uint32uint8array, which is a special kind
+//               of array that consists of nested pairs of (uint32,
+//               uint8) values.
+////////////////////////////////////////////////////////////////////
+DCSimpleType::Uint32Uint8Type::
+Uint32Uint8Type() {
+  _uint32_type = new DCSimpleType(ST_uint32);
+  _uint8_type = new DCSimpleType(ST_uint8);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::Uint32Uint8Type::get_num_nested_fields
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int DCSimpleType::Uint32Uint8Type::
+get_num_nested_fields() const {
+  return 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleType::Uint32Uint8Type::get_nested_field
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCPackerInterface *DCSimpleType::Uint32Uint8Type::
+get_nested_field(int n) const {
+  switch (n) {
+  case 0:
+    return _uint32_type;
+
+  case 1:
+    return _uint8_type;
+
+  default:
+    return NULL;
+  }
+}

+ 104 - 0
direct/src/dcparser/dcSimpleType.h

@@ -0,0 +1,104 @@
+// Filename: dcSimpleType.h
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DCSIMPLETYPE_H
+#define DCSIMPLETYPE_H
+
+#include "dcbase.h"
+#include "dcType.h"
+#include "dcSubatomicType.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : DCSimpleType
+// Description : This is the most fundamental kind of parameter type:
+//               a single number or string, one of the DCSubatomicType
+//               elements.  It may also optionally have a divisor,
+//               which is meaningful only for the numeric type
+//               elements (and represents a fixed-point numeric
+//               convention).
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT DCSimpleType : public DCType {
+public:
+  DCSimpleType(DCSubatomicType type, int divisor = 1);
+
+PUBLISHED:
+  virtual DCSimpleType *as_simple_type();
+  virtual DCType *make_copy() const;
+
+  DCSubatomicType get_type() const;
+  int get_divisor() const;
+  void set_divisor(int divisor);
+
+public:
+  virtual int get_num_nested_fields() const;
+  virtual DCPackerInterface *get_nested_field(int n) const;
+  virtual size_t get_length_bytes() const;
+
+  virtual DCSubatomicType get_pack_type() const;
+  virtual bool pack_value(DCPackData &pack_data, double value) const;
+  virtual bool pack_value(DCPackData &pack_data, int value) const;
+  virtual bool pack_value(DCPackData &pack_data, PN_int64 value) const;
+  virtual bool pack_value(DCPackData &pack_data, const string &value) const;
+
+  virtual void output(ostream &out, const string &parameter_name, 
+                      bool brief) const;
+  virtual void generate_hash(HashGenerator &hash) const;
+
+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;
+
+  bool _is_array;
+  DCSubatomicType _nested_type;
+  DCPackerInterface *_nested_field;
+
+  // The rest of this is to maintain the static list of
+  // DCPackerInterface objects for _nested_field, above.  We allocate
+  // each possible object once, and don't delete it.
+  typedef map<int, DCSimpleType *> DivisorMap;
+  typedef map<DCSubatomicType, DivisorMap> NestedFieldMap;
+  static NestedFieldMap _nested_field_map;
+
+  class Uint32Uint8Type : public DCPackerInterface {
+  public:
+    Uint32Uint8Type();
+    virtual int get_num_nested_fields() const;
+    virtual DCPackerInterface *get_nested_field(int n) const;
+
+    DCSimpleType *_uint32_type;
+    DCSimpleType *_uint8_type;
+  };
+
+  static Uint32Uint8Type *_uint32uint8_type;
+};
+
+#endif

+ 103 - 0
direct/src/dcparser/dcType.cxx

@@ -0,0 +1,103 @@
+// Filename: dcType.cxx
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "dcType.h"
+#include "hashGenerator.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::Constructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+DCType::
+DCType() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+DCType::
+~DCType() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::get_name
+//       Access: Published, Virtual
+//  Description: Returns a string that uniquely describes this type.
+////////////////////////////////////////////////////////////////////
+string DCType::
+get_name() const {
+  // The default get_name() implementation simply returns the result
+  // of output().
+  ostringstream result;
+  output(result, "", true);
+  return result.str();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::as_simple_type
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCSimpleType *DCType::
+as_simple_type() {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::as_class_type
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCClassType *DCType::
+as_class_type() {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::as_array_type
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCArrayType *DCType::
+as_array_type() {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::as_typedef_type
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+DCTypedefType *DCType::
+as_typedef_type() {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCType::generate_hash
+//       Access: Public, Virtual
+//  Description: Accumulates the properties of this type into the
+//               hash.
+////////////////////////////////////////////////////////////////////
+void DCType::
+generate_hash(HashGenerator &) const {
+}

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

@@ -0,0 +1,69 @@
+// Filename: dcType.h
+// Created by:  drose (15Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DCTYPE_H
+#define DCTYPE_H
+
+#include "dcbase.h"
+#include "dcPackerInterface.h"
+
+class DCSimpleType;
+class DCClassType;
+class DCArrayType;
+class DCTypedefType;
+
+////////////////////////////////////////////////////////////////////
+//       Class : DCType
+// Description : Represents the type specification for a single
+//               parameter within a field specification.  This may be
+//               a simple type, or it may be a class or an array
+//               reference.
+//
+//               This may also be a typedef reference to another type,
+//               which has the same properties as the referenced type,
+//               but a different name.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT DCType : public DCPackerInterface {
+protected:
+  DCType();
+public:
+  virtual ~DCType();
+
+PUBLISHED:
+  virtual string get_name() const;
+
+  virtual DCSimpleType *as_simple_type();
+  virtual DCClassType *as_class_type();
+  virtual DCArrayType *as_array_type();
+  virtual DCTypedefType *as_typedef_type();
+
+  virtual DCType *make_copy() const=0;
+
+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

+ 11 - 0
direct/src/dcparser/dcbase.h

@@ -49,6 +49,7 @@
 #include <iostream>
 #include <iostream>
 #include <fstream>
 #include <fstream>
 #include <iomanip>
 #include <iomanip>
+#include <sstream>
 
 
 #include <string>
 #include <string>
 #include <assert.h>
 #include <assert.h>
@@ -65,6 +66,8 @@
 
 
 using namespace std;
 using namespace std;
 
 
+#define INLINE inline
+
 // These symbols are used within the Panda environment for exporting
 // These symbols are used within the Panda environment for exporting
 // classes and functions to the scripting language.  They're largely
 // classes and functions to the scripting language.  They're largely
 // meaningless if we're not compiling within Panda.
 // meaningless if we're not compiling within Panda.
@@ -99,6 +102,14 @@ typedef string Filename;
 #define pvector vector
 #define pvector vector
 #define pmap map
 #define pmap map
 
 
+#ifdef WIN32
+typedef __int64 PN_int64;
+typedef unsigned __int64 PN_uint64;
+#else
+typedef long long PN_int64;
+typedef unsigned long long PN_uint64;
+#endif
+
 #endif  // WITHIN_PANDA
 #endif  // WITHIN_PANDA
 
 
 #endif  // DCBASE_H
 #endif  // DCBASE_H

+ 3 - 0
direct/src/dcparser/dcparser_composite1.cxx

@@ -3,4 +3,7 @@
 #include "hashGenerator.cxx"
 #include "hashGenerator.cxx"
 #include "dcAtomicField.cxx"
 #include "dcAtomicField.cxx"
 #include "dcClass.cxx"
 #include "dcClass.cxx"
+#include "dcPackData.cxx"
+#include "dcPacker.cxx"
+#include "dcPackerInterface.cxx"
 
 

+ 2 - 0
direct/src/dcparser/dcparser_composite2.cxx

@@ -1,4 +1,6 @@
 
 
+#include "dcType.cxx"
+#include "dcSimpleType.cxx"
 #include "dcField.cxx"
 #include "dcField.cxx"
 #include "dcFile.cxx"
 #include "dcFile.cxx"
 #include "dcMolecularField.cxx"
 #include "dcMolecularField.cxx"