Explorar o código

add unpack seeking

David Rose %!s(int64=21) %!d(string=hai) anos
pai
achega
d61f2fcfa4

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

@@ -22,6 +22,7 @@
      dcSubatomicType.h \
      dcPackData.h dcPackData.I \
      dcPacker.h dcPacker.I \
+     dcPackerCatalog.h dcPackerCatalog.I \
      dcPackerInterface.h dcPackerInterface.I \
      dcParameter.h dcClassParameter.h dcArrayParameter.h dcSimpleParameter.h \
      dcTypedef.h \
@@ -35,6 +36,7 @@
      dcMolecularField.cxx dcSubatomicType.cxx \
      dcPackData.cxx \
      dcPacker.cxx \
+     dcPackerCatalog.cxx \
      dcPackerInterface.cxx \
      dcParameter.cxx dcClassParameter.cxx \
      dcArrayParameter.cxx dcSimpleParameter.cxx \

+ 6 - 0
direct/src/dcparser/dcAtomicField.cxx

@@ -444,6 +444,12 @@ void DCAtomicField::
 add_element(const DCAtomicField::ElementType &element) {
   _elements.push_back(element);
   _num_nested_fields = (int)_elements.size();
+
+  // See if we still have a fixed byte size.
+  if (_has_fixed_byte_size) {
+    _has_fixed_byte_size = element._param->has_fixed_byte_size();
+    _fixed_byte_size += element._param->get_fixed_byte_size();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 1
direct/src/dcparser/dcClass.cxx

@@ -22,6 +22,16 @@
 #include "dcindent.h"
 #include "dcmsgtypes.h"
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCClass::get_name
+//       Access: Published
+//  Description: Returns the name of this class.
+////////////////////////////////////////////////////////////////////
+const string &DCClass::
+get_name() const {
+  return _name;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCClass::get_number
 //       Access: Published
@@ -628,7 +638,7 @@ ai_format_generate(PyObject *distobj, int do_id,
 ////////////////////////////////////////////////////////////////////
 DCClass::
 DCClass(const string &name, bool is_struct, bool bogus_class) : 
-  DCPackerInterface(name),
+  _name(name),
   _is_struct(is_struct),
   _bogus_class(bogus_class)
 {

+ 3 - 2
direct/src/dcparser/dcClass.h

@@ -21,7 +21,6 @@
 
 #include "dcbase.h"
 #include "dcField.h"
-#include "dcPackerInterface.h"
 #include "dcDeclaration.h"
 
 class HashGenerator;
@@ -32,8 +31,9 @@ class DCParameter;
 // Description : Defines a particular DistributedClass as read from an
 //               input .dc file.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_DIRECT DCClass : public DCPackerInterface, public DCDeclaration {
+class EXPCL_DIRECT DCClass : public DCDeclaration {
 PUBLISHED:
+  const string &get_name() const;
   int get_number() const;
 
   bool has_parent() const;
@@ -94,6 +94,7 @@ public:
   void set_number(int number);
 
 private:
+  string _name;
   bool _is_struct;
   bool _bogus_class;
   int _number;

+ 11 - 0
direct/src/dcparser/dcClassParameter.cxx

@@ -35,6 +35,17 @@ DCClassParameter(DCClass *dclass) :
   _num_fields = _dclass->get_num_inherited_fields();
   _num_nested_fields = _num_fields + _dclass->get_num_inherited_parameters();
   _pack_type = PT_class;
+
+  // If all of the nested fields have a fixed byte size, then so does
+  // the class (and its byte size is the sum of all of the nested
+  // fields).
+  _has_fixed_byte_size = true;
+  _fixed_byte_size = 0;
+  for (int i = 0; i < _num_nested_fields && _has_fixed_byte_size; i++) {
+    DCPackerInterface *field = get_nested_field(i);
+    _has_fixed_byte_size = field->has_fixed_byte_size();
+    _fixed_byte_size += field->get_fixed_byte_size();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 4 - 1
direct/src/dcparser/dcField.cxx

@@ -130,7 +130,7 @@ pack_args(Datagram &datagram, PyObject *sequence) const {
   PyObject *str = PyObject_Str(tuple);
   
   ostringstream strm;
-  strm << "Incorrect arguments to field: " << get_name()
+  strm << "Incorrect arguments or value too large on field: " << get_name()
        << PyString_AsString(str);
 
   Py_DECREF(str);
@@ -257,6 +257,9 @@ DCField(const string &name) : DCPackerInterface(name) {
   _has_nested_fields = true;
   _num_nested_fields = 0;
   _pack_type = PT_field;
+
+  _has_fixed_byte_size = true;
+  _fixed_byte_size = 0;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 10 - 1
direct/src/dcparser/dcMolecularField.cxx

@@ -75,7 +75,10 @@ DCMolecularField(const string &name) : DCField(name) {
 //  Description: Adds the indicated atomic field to the end of the
 //               list of atomic fields that make up the molecular
 //               field.  This is normally called only during parsing
-//               of the dc file.
+//               of the dc file.  The atomic field should be fully
+//               defined by this point; you should not modify the
+//               atomic field (e.g. by adding more elements) after
+//               adding it to a molecular field.
 ////////////////////////////////////////////////////////////////////
 void DCMolecularField::
 add_atomic(DCAtomicField *atomic) {
@@ -87,6 +90,12 @@ add_atomic(DCAtomicField *atomic) {
   }
 
   _num_nested_fields = _nested_fields.size();
+
+  // See if we still have a fixed byte size.
+  if (_has_fixed_byte_size) {
+    _has_fixed_byte_size = atomic->has_fixed_byte_size();
+    _fixed_byte_size += atomic->get_fixed_byte_size();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -63,6 +63,19 @@ more_nested_fields() const {
   return (_current_field != (DCPackerInterface *)NULL);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::get_current_field
+//       Access: Published
+//  Description: Returns the field that will be referenced by the next
+//               call to pack_*() or unpack_*().  This will be NULL if
+//               we have unpacked (or packed) all fields, or if it is
+//               time to call pop().
+////////////////////////////////////////////////////////////////////
+INLINE const DCPackerInterface *DCPacker::
+get_current_field() const {
+  return _current_field;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::get_pack_type
 //       Access: Published
@@ -355,6 +368,21 @@ unpack_string() {
   return value;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::unpack_literal_value
+//       Access: Published
+//  Description: Returns the literal string that represents the packed
+//               value of the current field, and advances the field
+//               pointer.
+////////////////////////////////////////////////////////////////////
+INLINE string DCPacker::
+unpack_literal_value() {
+  size_t start = _unpack_p;
+  unpack_skip();
+  nassertr(_unpack_p >= start, string());
+  return string(_unpack_data + start, _unpack_p - start);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::had_pack_error
 //       Access: Published

+ 136 - 16
direct/src/dcparser/dcPacker.cxx

@@ -31,6 +31,9 @@ DCPacker() {
   _unpack_data = NULL;
   _unpack_length = 0;
   _unpack_p = 0;
+  _root = NULL;
+  _catalog = NULL;
+  _live_catalog = NULL;
   _current_field = NULL;
   _current_parent = NULL;
   _current_field_index = 0;
@@ -45,6 +48,7 @@ DCPacker() {
 ////////////////////////////////////////////////////////////////////
 DCPacker::
 ~DCPacker() {
+  clear();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -62,7 +66,10 @@ begin_pack(const DCPackerInterface *root) {
   _pack_error = false;
   _pack_data.clear();
 
-  _stack.clear();
+  _root = root;
+  _catalog = NULL;
+  _live_catalog = NULL;
+
   _current_field = root;
   _current_parent = NULL;
   _current_field_index = 0;
@@ -85,13 +92,10 @@ end_pack() {
 
   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;
   }
 
+  clear();
+
   return !_pack_error;
 }
 
@@ -127,7 +131,10 @@ begin_unpack(const char *data, size_t length,
   _unpack_length = length;
   _unpack_p = 0;
 
-  _stack.clear();
+  _root = root;
+  _catalog = NULL;
+  _live_catalog = NULL;
+
   _current_field = root;
   _current_parent = NULL;
   _current_field_index = 0;
@@ -140,7 +147,8 @@ begin_unpack(const char *data, size_t length,
 //  Description: Finishes the unpacking session.
 //
 //               The return value is true on success, or false if
-//               there has been some error during unpacking.
+//               there has been some error during unpacking (or if all
+//               fields have not been unpacked).
 ////////////////////////////////////////////////////////////////////
 bool DCPacker::
 end_unpack() {
@@ -149,17 +157,69 @@ end_unpack() {
   _mode = M_idle;
 
   if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) {
-    _pack_error = true;
-    _stack.clear();
-    _current_field = NULL;
-    _current_parent = NULL;
-    _current_field_index = 0;
-    _num_nested_fields = 0;
+    // This happens if we have not unpacked all of the fields.
+    // However, this is not an error if we have called seek() during
+    // the unpack session (in which case the _catalog will be
+    // non-NULL).  On the other hand, if the catalog is still NULL,
+    // then we have never called seek() and it is an error not to
+    // unpack all values.
+    if (_catalog == (DCPackerCatalog *)NULL) {
+      _pack_error = true;
+    }
   }
 
+  clear();
+
   return !_pack_error;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::seek
+//       Access: Published
+//  Description: Sets the current unpack (or repack) position to the
+//               named field.  In unpack mode, the next call to
+//               unpack_*() or push() will begin to read the named
+//               field.  In repack mode, the next call to pack_*() or
+//               push() will modify the named field.
+//
+//               Returns true if successful, false if the field is not
+//               known (or if the packer is in an invalid mode).
+////////////////////////////////////////////////////////////////////
+bool DCPacker::
+seek(const string &field_name) {
+  if (_mode == M_unpack) {
+    if (_catalog == (DCPackerCatalog *)NULL) {
+      _catalog = _root->get_catalog();
+      _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
+    }
+    nassertr(_catalog != (DCPackerCatalog *)NULL, false);
+
+    int entry_index = _catalog->find_entry_by_name(field_name);
+    if (entry_index < 0) {
+      // The field was not known.
+      _pack_error = true;
+      return false;
+    }
+
+    const DCPackerCatalog::Entry &entry = _catalog->get_entry(entry_index);
+
+    // If we are seeking, we don't need to remember our current stack
+    // position.
+    _stack.clear();
+    _current_field = entry._field;
+    _current_parent = entry._parent;
+    _current_field_index = entry._field_index;
+    _num_nested_fields = _current_parent->get_num_nested_fields();
+    _unpack_p = _live_catalog->get_unpack_p(entry_index);
+
+    return true;
+  }
+
+  // Invalid mode.
+  _pack_error = true;
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::push
 //       Access: Published
@@ -281,10 +341,12 @@ pop() {
         size_t length = _pack_data.get_length() - _push_marker - length_bytes;
         if (length_bytes == 4) {
           DCPackerInterface::do_pack_uint32
-            (_pack_data.get_rewrite_pointer(_push_marker, 4), length);
+            (_pack_data.get_rewrite_pointer(_push_marker, 4), length, 
+             _pack_error);
         } else {
           DCPackerInterface::do_pack_uint16
-            (_pack_data.get_rewrite_pointer(_push_marker, 2), length);
+            (_pack_data.get_rewrite_pointer(_push_marker, 2), length,
+             _pack_error);
         }
       }
     }
@@ -300,6 +362,37 @@ pop() {
   advance();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::unpack_skip
+//       Access: Published
+//  Description: Skips the current field without unpacking it and
+//               advances to the next field.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+unpack_skip() {
+  nassertv(_mode == M_unpack);
+  if (_current_field == NULL) {
+    _pack_error = true;
+
+  } else if (_current_field->has_fixed_byte_size()) {
+    _unpack_p += _current_field->get_fixed_byte_size();
+    advance();
+
+  } else {
+    if (_current_field->unpack_skip(_unpack_data, _unpack_length, _unpack_p)) {
+      advance();
+
+    } else {
+      // If the single field couldn't be skipped, try skipping nested fields.
+      push();
+      while (more_nested_fields()) {
+        unpack_skip();
+      }
+      pop();
+    }
+  }
+}
+
 #ifdef HAVE_PYTHON
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::pack_object
@@ -363,6 +456,11 @@ unpack_object() {
   DCPackType pack_type = get_pack_type();
 
   switch (pack_type) {
+  case PT_invalid:
+    object = Py_None;
+    unpack_skip();
+    break;
+
   case PT_double:
     {
       double value = unpack_double();
@@ -566,3 +664,25 @@ unpack_and_format(ostream &out) {
     break;
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::clear
+//       Access: Private
+//  Description: Resets the data structures after a pack or unpack
+//               sequence.
+////////////////////////////////////////////////////////////////////
+void DCPacker::
+clear() {
+  _stack.clear();
+  _current_field = NULL;
+  _current_parent = NULL;
+  _current_field_index = 0;
+  _num_nested_fields = 0;
+
+  if (_live_catalog != (DCPackerCatalog::LiveCatalog *)NULL) {
+    _catalog->release_live_catalog(_live_catalog);
+    _live_catalog = NULL;
+  }
+  _catalog = NULL;
+  _root = NULL;
+}

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

@@ -23,6 +23,7 @@
 #include "dcPackerInterface.h"
 #include "dcSubatomicType.h"
 #include "dcPackData.h"
+#include "dcPackerCatalog.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : DCPacker
@@ -45,10 +46,13 @@ PUBLISHED:
   void begin_unpack(const string &data, const DCPackerInterface *root);
   bool end_unpack();
 
+  bool seek(const string &field_name);
+
   INLINE bool has_nested_fields() const;
   INLINE int get_num_nested_fields() const;
   INLINE bool more_nested_fields() const;
 
+  INLINE const DCPackerInterface *get_current_field() const;
   INLINE DCPackType get_pack_type() const;
 
   void push();
@@ -68,6 +72,8 @@ PUBLISHED:
   INLINE PN_int64 unpack_int64();
   INLINE PN_uint64 unpack_uint64();
   INLINE string unpack_string();
+  INLINE string unpack_literal_value();
+  void unpack_skip();
 
 #ifdef HAVE_PYTHON
   void pack_object(PyObject *object);
@@ -89,6 +95,7 @@ public:
 
 private:
   INLINE void advance();
+  void clear();
 
 private:
   enum Mode {
@@ -104,6 +111,10 @@ private:
   size_t _unpack_length;
   size_t _unpack_p;
 
+  const DCPackerInterface *_root;
+  const DCPackerCatalog *_catalog;
+  const DCPackerCatalog::LiveCatalog *_live_catalog;
+
   class StackElement {
   public:
     const DCPackerInterface *_current_parent;

+ 50 - 0
direct/src/dcparser/dcPackerCatalog.I

@@ -0,0 +1,50 @@
+// Filename: dcPackerCatalog.I
+// Created by:  drose (21Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: DCPackerCatalog::LiveCatalog::get_unpack_p
+//       Access: Public
+//  Description: Returns the beginning of the indicated field within
+//               the live data.
+////////////////////////////////////////////////////////////////////
+INLINE size_t DCPackerCatalog::LiveCatalog::
+get_unpack_p(int n) const {
+  nassertr(n >= 0 && n < (int)_live_entries.size(), 0);
+  return _live_entries[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::get_num_entries
+//       Access: Public
+//  Description: Returns the number of entries in the catalog.
+////////////////////////////////////////////////////////////////////
+INLINE int DCPackerCatalog::
+get_num_entries() const {
+  return _entries.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::get_entry
+//       Access: Public
+//  Description: Returns the nth entry in the catalog.
+////////////////////////////////////////////////////////////////////
+INLINE const DCPackerCatalog::Entry &DCPackerCatalog::
+get_entry(int n) const {
+  nassertr(n >= 0 && n < (int)_entries.size(), _entries[0]);
+  return _entries[n];
+}

+ 191 - 0
direct/src/dcparser/dcPackerCatalog.cxx

@@ -0,0 +1,191 @@
+// Filename: dcPackerCatalog.cxx
+// Created by:  drose (21Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "dcPackerCatalog.h"
+#include "dcPackerInterface.h"
+#include "dcPacker.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::Constructor
+//       Access: Private
+//  Description: The catalog is created only by
+//               DCPackerInterface::get_catalog().
+////////////////////////////////////////////////////////////////////
+DCPackerCatalog::
+DCPackerCatalog(const DCPackerInterface *root) : _root(root) {
+  _live_catalog = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::Destructor
+//       Access: Private
+//  Description: The catalog is destroyed only by
+//               ~DCPackerInterface().
+////////////////////////////////////////////////////////////////////
+DCPackerCatalog::
+~DCPackerCatalog() {
+  if (_live_catalog != (LiveCatalog *)NULL) {
+    delete _live_catalog;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::find_entry_by_name
+//       Access: Public
+//  Description: Returns the index number of the entry with the
+//               indicated name, or -1 if no entry has the indicated
+//               name.  The return value is suitable for passing to
+//               get_entry().
+////////////////////////////////////////////////////////////////////
+int DCPackerCatalog::
+find_entry_by_name(const string &name) const {
+  EntriesByName::const_iterator ni;
+  ni = _entries_by_name.find(name);
+  if (ni != _entries_by_name.end()) {
+    return (*ni).second;
+  }
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::find_entry_by_field
+//       Access: Public
+//  Description: Returns the index number of the entry with the
+//               indicated field, or -1 if no entry has the indicated
+//               field.  The return value is suitable for passing to
+//               get_entry().
+////////////////////////////////////////////////////////////////////
+int DCPackerCatalog::
+find_entry_by_field(const DCPackerInterface *field) const {
+  EntriesByField::const_iterator ni;
+  ni = _entries_by_field.find(field);
+  if (ni != _entries_by_field.end()) {
+    return (*ni).second;
+  }
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::get_live_catalog
+//       Access: Public
+//  Description: Returns a LiveCatalog object indicating the positions
+//               within the indicated data record of each field within
+//               the catalog.  If the catalog's fields are all
+//               fixed-width, this may return a statically-allocated
+//               LiveCatalog object that is the same for all data
+//               records; otherwise, it will allocate a new
+//               LiveCatalog object that must be freed with a later
+//               call to release_live_catalog().
+////////////////////////////////////////////////////////////////////
+const DCPackerCatalog::LiveCatalog *DCPackerCatalog::
+get_live_catalog(const char *data, size_t length) const {
+  if (_live_catalog != (LiveCatalog *)NULL) {
+    // Return the previously-allocated static catalog.
+    return _live_catalog;
+  }
+
+  LiveCatalog *live_catalog = new LiveCatalog;
+  live_catalog->_live_entries.reserve(_entries.size());
+  for (size_t i = 0; i < _entries.size(); i++) {
+    live_catalog->_live_entries.push_back(0);
+  }
+  
+  DCPacker packer;
+  packer.begin_unpack(data, length, _root);
+  r_fill_live_catalog(live_catalog, packer);
+  bool okflag = packer.end_unpack();
+
+  nassertr(okflag, live_catalog);
+
+  if (_root->has_fixed_byte_size()) {
+    // If our root field has a fixed byte size, then the live catalog
+    // will always be the same every time, so we might as well keep
+    // this one around as an optimization.
+    ((DCPackerCatalog *)this)->_live_catalog = live_catalog;
+  }
+
+  return live_catalog;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::release_live_catalog
+//       Access: Public
+//  Description: Releases the LiveCatalog object that was returned by
+//               an earlier call to get_live_catalog().  If this
+//               represents a newly-allocated live catalog, it will
+//               free it; otherwise, it will do nothing.
+//
+//               It is therefore always correct (and necessary) to
+//               match a call to get_live_catalog() with a later call
+//               to release_live_catalog().
+////////////////////////////////////////////////////////////////////
+void DCPackerCatalog::
+release_live_catalog(const DCPackerCatalog::LiveCatalog *live_catalog) const {
+  if (live_catalog != _live_catalog) {
+    delete (LiveCatalog *)live_catalog;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::add_entry
+//       Access: Private
+//  Description: Called only by DCPackerInterface::r_fill_catalog(),
+//               this adds a new entry to the catalog.
+////////////////////////////////////////////////////////////////////
+void DCPackerCatalog::
+add_entry(const string &name, const DCPackerInterface *field,
+          const DCPackerInterface *parent, int field_index) {
+  Entry entry;
+  entry._name = name;
+  entry._field = field;
+  entry._parent = parent;
+  entry._field_index = field_index;
+
+  int entry_index = (int)_entries.size();
+  _entries.push_back(entry);
+  _entries_by_name.insert(EntriesByName::value_type(name, entry_index));
+  _entries_by_field.insert(EntriesByField::value_type(field, entry_index));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::r_fill_live_catalog
+//       Access: Private
+//  Description: Recursively walks through all of the fields on the
+//               catalog and fills the live catalog with the
+//               appropriate offsets.
+////////////////////////////////////////////////////////////////////
+void DCPackerCatalog::
+r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const {
+  const DCPackerInterface *current_field = packer.get_current_field();
+
+  int field_index = find_entry_by_field(current_field);
+  if (field_index >= 0) {
+    live_catalog->_live_entries[field_index] = packer.get_num_unpacked_bytes();
+  }
+
+  if (packer.has_nested_fields() && packer.get_pack_type() != PT_string) {
+    packer.push();
+    while (packer.more_nested_fields()) {
+      r_fill_live_catalog(live_catalog, packer);
+    }
+    packer.pop();
+
+  } else {
+    packer.unpack_skip();
+  }
+}

+ 95 - 0
direct/src/dcparser/dcPackerCatalog.h

@@ -0,0 +1,95 @@
+// Filename: dcPackerCatalog.h
+// Created by:  drose (21Jun04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 DCPACKERCATALOG_H
+#define DCPACKERCATALOG_H
+
+#include "dcbase.h"
+
+class DCPackerInterface;
+class DCPacker;
+
+////////////////////////////////////////////////////////////////////
+//       Class : DCPackerCatalog
+// Description : This object contains the names of all of the nested
+//               fields available within a particular field.  It is
+//               created on demand when a catalog is first requested
+//               from a particular field; its ownership is retained by
+//               the field so it must not be deleted.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DIRECT DCPackerCatalog {
+private:
+  DCPackerCatalog(const DCPackerInterface *root);
+  ~DCPackerCatalog();
+
+public:
+  // The Entry class records the static catalog data: the name of each
+  // field and its relationship to its parent.
+  class Entry {
+  public:
+    string _name;
+    const DCPackerInterface *_field;
+    const DCPackerInterface *_parent;
+    int _field_index;
+  };
+
+  // The LiveCatalog class adds the dynamic catalog data: the actual
+  // location of each field within the data record.  This might be
+  // different for different data records (since some data fields have
+  // a dynamic length).
+  class LiveCatalog {
+  public:
+    INLINE size_t get_unpack_p(int n) const;
+
+  private:
+    typedef pvector<size_t> LiveEntries;
+    LiveEntries _live_entries;
+    friend class DCPackerCatalog;
+  };
+
+  INLINE int get_num_entries() const;
+  INLINE const Entry &get_entry(int n) const;
+  int find_entry_by_name(const string &name) const;
+  int find_entry_by_field(const DCPackerInterface *field) const;
+
+  const LiveCatalog *get_live_catalog(const char *data, size_t length) const;
+  void release_live_catalog(const LiveCatalog *live_catalog) const;
+    
+private:
+  void add_entry(const string &name, const DCPackerInterface *field,
+                 const DCPackerInterface *parent, int field_index);
+  void r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const;
+
+  const DCPackerInterface *_root;
+  LiveCatalog *_live_catalog;
+  
+  typedef pvector<Entry> Entries;
+  Entries _entries;
+
+  typedef pmap<string, int> EntriesByName;
+  EntriesByName _entries_by_name;
+
+  typedef pmap<const DCPackerInterface *, int> EntriesByField;
+  EntriesByField _entries_by_field;
+
+  friend class DCPackerInterface;
+};
+
+#include "dcPackerCatalog.I"
+
+#endif

+ 115 - 9
direct/src/dcparser/dcPackerInterface.I

@@ -17,14 +17,111 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_name
+//       Access: Published
+//  Description: Returns the name of this field, or empty string
+//               if the field is unnamed.
+////////////////////////////////////////////////////////////////////
+INLINE const string &DCPackerInterface::
+get_name() const {
+  return _name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::set_name
+//       Access: Public
+//  Description: Sets the name of this field.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPackerInterface::
+set_name(const string &name) {
+  _name = name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::has_fixed_byte_size
+//       Access: Public
+//  Description: Returns true if this field type always packs to the
+//               same number of bytes, false if it is variable.
+////////////////////////////////////////////////////////////////////
+INLINE bool DCPackerInterface::
+has_fixed_byte_size() const {
+  return _has_fixed_byte_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_fixed_byte_size
+//       Access: Public
+//  Description: If has_fixed_byte_size() returns true, this returns
+//               the number of bytes this field type will use.
+////////////////////////////////////////////////////////////////////
+INLINE size_t DCPackerInterface::
+get_fixed_byte_size() const {
+  return _fixed_byte_size;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_num_length_bytes
+//       Access: Public
+//  Description: Returns the number of bytes that should be written
+//               into the stream on a push() to record the number of
+//               bytes in the record up until the next pop().  This is
+//               only meaningful if _has_nested_fields is true.
+////////////////////////////////////////////////////////////////////
+INLINE size_t DCPackerInterface::
+get_num_length_bytes() const {
+  return _num_length_bytes;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::has_nested_fields
+//       Access: Public
+//  Description: Returns true if this field type has any nested fields
+//               (and thus expects a push() .. pop() interface to the
+//               DCPacker), or false otherwise.  If this returns true,
+//               get_num_nested_fields() may be called to determine
+//               how many nested fields are expected.
+////////////////////////////////////////////////////////////////////
+INLINE bool DCPackerInterface::
+has_nested_fields() const {
+  return _has_nested_fields;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_num_nested_fields
+//       Access: Public
+//  Description: Returns the number of nested fields required by this
+//               field type.  These may be array elements or structure
+//               elements.  The return value may be -1 to indicate the
+//               number of nested fields is variable.
+////////////////////////////////////////////////////////////////////
+INLINE int DCPackerInterface::
+get_num_nested_fields() const {
+  return _num_nested_fields;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_pack_type
+//       Access: Public
+//  Description: Returns the type of value expected by this field.
+////////////////////////////////////////////////////////////////////
+INLINE DCPackType DCPackerInterface::
+get_pack_type() const {
+  return _pack_type;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackerInterface::do_pack_int8
 //       Access: Public, Static
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_int8(char *buffer, int value) {
+do_pack_int8(char *buffer, int value, bool &pack_error) {
   buffer[0] = (char)(value & 0xff);
+  if ((abs(value) & ~0xff) != 0) {
+    pack_error = true;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -33,9 +130,12 @@ do_pack_int8(char *buffer, int value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_int16(char *buffer, int value) {
+do_pack_int16(char *buffer, int value, bool &pack_error) {
   buffer[0] = (char)(value & 0xff);
   buffer[1] = (char)((value >> 8) & 0xff);
+  if ((abs(value) & ~0xffff) != 0) {
+    pack_error = true;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -44,7 +144,7 @@ do_pack_int16(char *buffer, int value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_int32(char *buffer, int value) {
+do_pack_int32(char *buffer, int value, bool &) {
   buffer[0] = (char)(value & 0xff);
   buffer[1] = (char)((value >> 8) & 0xff);
   buffer[2] = (char)((value >> 16) & 0xff);
@@ -57,7 +157,7 @@ do_pack_int32(char *buffer, int value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_int64(char *buffer, PN_int64 value) {
+do_pack_int64(char *buffer, PN_int64 value, bool &) {
   buffer[0] = (char)(value & 0xff);
   buffer[1] = (char)((value >> 8) & 0xff);
   buffer[2] = (char)((value >> 16) & 0xff);
@@ -74,8 +174,11 @@ do_pack_int64(char *buffer, PN_int64 value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_uint8(char *buffer, unsigned int value) {
+do_pack_uint8(char *buffer, unsigned int value, bool &pack_error) {
   buffer[0] = (char)(value & 0xff);
+  if ((value & ~0xff) != 0) {
+    pack_error = true;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -84,9 +187,12 @@ do_pack_uint8(char *buffer, unsigned int value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_uint16(char *buffer, unsigned int value) {
+do_pack_uint16(char *buffer, unsigned int value, bool &pack_error) {
   buffer[0] = (char)(value & 0xff);
   buffer[1] = (char)((value >> 8) & 0xff);
+  if ((value & ~0xffff) != 0) {
+    pack_error = true;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -95,7 +201,7 @@ do_pack_uint16(char *buffer, unsigned int value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_uint32(char *buffer, unsigned int value) {
+do_pack_uint32(char *buffer, unsigned int value, bool &) {
   buffer[0] = (char)(value & 0xff);
   buffer[1] = (char)((value >> 8) & 0xff);
   buffer[2] = (char)((value >> 16) & 0xff);
@@ -108,7 +214,7 @@ do_pack_uint32(char *buffer, unsigned int value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_uint64(char *buffer, PN_uint64 value) {
+do_pack_uint64(char *buffer, PN_uint64 value, bool &) {
   buffer[0] = (char)(value & 0xff);
   buffer[1] = (char)((value >> 8) & 0xff);
   buffer[2] = (char)((value >> 16) & 0xff);
@@ -125,7 +231,7 @@ do_pack_uint64(char *buffer, PN_uint64 value) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackerInterface::
-do_pack_float64(char *buffer, double value) {
+do_pack_float64(char *buffer, double value, bool &) {
 #ifdef WORDS_BIGENDIAN
   // Reverse the byte ordering for big-endian machines.
   char *p = (char *)value;

+ 90 - 94
direct/src/dcparser/dcPackerInterface.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "dcPackerInterface.h"
+#include "dcPackerCatalog.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackerInterface::Constructor
@@ -33,6 +34,7 @@ DCPackerInterface(const string &name) :
   _has_nested_fields = false;
   _num_nested_fields = -1;
   _pack_type = PT_invalid;
+  _catalog = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -50,6 +52,7 @@ DCPackerInterface(const DCPackerInterface &copy) :
   _num_nested_fields(copy._num_nested_fields),
   _pack_type(copy._pack_type)
 {
+  _catalog = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -59,90 +62,9 @@ DCPackerInterface(const DCPackerInterface &copy) :
 ////////////////////////////////////////////////////////////////////
 DCPackerInterface::
 ~DCPackerInterface() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::get_name
-//       Access: Published
-//  Description: Returns the name of this field, or empty string
-//               if the field is unnamed.
-////////////////////////////////////////////////////////////////////
-const string &DCPackerInterface::
-get_name() const {
-  return _name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::set_name
-//       Access: Published
-//  Description: Sets the name of this field.
-////////////////////////////////////////////////////////////////////
-void DCPackerInterface::
-set_name(const string &name) {
-  _name = name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::has_fixed_byte_size
-//       Access: Public
-//  Description: Returns true if this field type always packs to the
-//               same number of bytes, false if it is variable.
-////////////////////////////////////////////////////////////////////
-bool DCPackerInterface::
-has_fixed_byte_size() const {
-  return _has_fixed_byte_size;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::get_fixed_byte_size
-//       Access: Public
-//  Description: If has_fixed_byte_size() returns true, this returns
-//               the number of bytes this field type will use.
-////////////////////////////////////////////////////////////////////
-size_t DCPackerInterface::
-get_fixed_byte_size() const {
-  return _fixed_byte_size;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::get_num_length_bytes
-//       Access: Public
-//  Description: Returns the number of bytes that should be written
-//               into the stream on a push() to record the number of
-//               bytes in the record up until the next pop().  This is
-//               only meaningful if _has_nested_fields is true.
-////////////////////////////////////////////////////////////////////
-size_t DCPackerInterface::
-get_num_length_bytes() const {
-  return _num_length_bytes;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::has_nested_fields
-//       Access: Public
-//  Description: Returns true if this field type has any nested fields
-//               (and thus expects a push() .. pop() interface to the
-//               DCPacker), or false otherwise.  If this returns true,
-//               get_num_nested_fields() may be called to determine
-//               how many nested fields are expected.
-////////////////////////////////////////////////////////////////////
-bool DCPackerInterface::
-has_nested_fields() const {
-  return _has_nested_fields;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::get_num_nested_fields
-//       Access: Public
-//  Description: Returns the number of nested fields required by this
-//               field type.  These may be array elements or structure
-//               elements.  The return value may be -1 to indicate the
-//               number of nested fields is variable.
-////////////////////////////////////////////////////////////////////
-int DCPackerInterface::
-get_num_nested_fields() const {
-  return _num_nested_fields;
+  if (_catalog != (DCPackerCatalog *)NULL) {
+    delete _catalog;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -173,16 +95,6 @@ get_nested_field(int n) const {
   return NULL;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DCPackerInterface::get_pack_type
-//       Access: Public
-//  Description: Returns the type of value expected by this field.
-////////////////////////////////////////////////////////////////////
-DCPackType DCPackerInterface::
-get_pack_type() const {
-  return _pack_type;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackerInterface::pack_double
 //       Access: Public, Virtual
@@ -314,3 +226,87 @@ bool DCPackerInterface::
 unpack_string(const char *, size_t, size_t &, string &) const {
   return false;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::unpack_skip
+//       Access: Public, Virtual
+//  Description: Increments p to the end of the current field without
+//               actually unpacking any data.  Returns true on
+//               success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCPackerInterface::
+unpack_skip(const char *, size_t, size_t &) const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::get_catalog
+//       Access: Public
+//  Description: Returns the DCPackerCatalog associated with this
+//               field, listing all of the nested fields by name.
+////////////////////////////////////////////////////////////////////
+const DCPackerCatalog *DCPackerInterface::
+get_catalog() const {
+  if (_catalog == (DCPackerCatalog *)NULL) {
+    ((DCPackerInterface *)this)->make_catalog();
+  }
+  return _catalog;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::make_catalog
+//       Access: Private
+//  Description: Called internally to create a new DCPackerCatalog
+//               object.
+////////////////////////////////////////////////////////////////////
+void DCPackerInterface::
+make_catalog() {
+  nassertv(_catalog == (DCPackerCatalog *)NULL);
+  _catalog = new DCPackerCatalog(this);
+
+  if (has_nested_fields()) {
+    int num_nested = get_num_nested_fields();
+    // num_nested might be -1, indicating there are a dynamic number
+    // of fields (e.g. an array).  But in that case, none of the
+    // fields will be named anyway, so we don't care about them, so
+    // it's ok that the following loop will not visit any fields.
+    for (int i = 0; i < num_nested; i++) {
+      DCPackerInterface *nested = get_nested_field(i);
+      if (nested != (DCPackerInterface *)NULL) {
+        nested->r_fill_catalog(_catalog, "", this, i);
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerInterface::r_fill_catalog
+//       Access: Private
+//  Description: Called internally to recursively fill up the new
+//               DCPackerCatalog object.
+////////////////////////////////////////////////////////////////////
+void DCPackerInterface::
+r_fill_catalog(DCPackerCatalog *catalog, const string &name_prefix,
+               DCPackerInterface *parent, int field_index) {
+  string next_name_prefix = name_prefix;
+
+  if (!get_name().empty()) {
+    // Record this entry in the catalog.
+    next_name_prefix += get_name();
+    catalog->add_entry(next_name_prefix, this, parent, field_index);
+
+    next_name_prefix += ".";
+  }
+
+  // Add any children.
+  if (has_nested_fields()) {
+    int num_nested = get_num_nested_fields();
+    // As above, it's ok if num_nested is -1.
+    for (int i = 0; i < num_nested; i++) {
+      DCPackerInterface *nested = get_nested_field(i);
+      if (nested != (DCPackerInterface *)NULL) {
+        nested->r_fill_catalog(catalog, next_name_prefix, this, i);
+      }
+    }
+  }
+}

+ 29 - 17
direct/src/dcparser/dcPackerInterface.h

@@ -23,6 +23,7 @@
 #include "dcSubatomicType.h"
 
 class DCPackData;
+class DCPackerCatalog;
 
 BEGIN_PUBLISH
 // This enumerated type is returned by get_pack_type() and represents
@@ -67,20 +68,20 @@ public:
   virtual ~DCPackerInterface();
 
 PUBLISHED:
-  const string &get_name() const;
-  void set_name(const string &name);
+  INLINE const string &get_name() const;
 
 public:
-  bool has_fixed_byte_size() const;
-  size_t get_fixed_byte_size() const;
-  size_t get_num_length_bytes() const;
+  INLINE void set_name(const string &name);
+  INLINE bool has_fixed_byte_size() const;
+  INLINE size_t get_fixed_byte_size() const;
+  INLINE size_t get_num_length_bytes() const;
 
-  bool has_nested_fields() const;
-  int get_num_nested_fields() const;
+  INLINE bool has_nested_fields() const;
+  INLINE int get_num_nested_fields() const;
   virtual int calc_num_nested_fields(size_t length_bytes) const;
   virtual DCPackerInterface *get_nested_field(int n) const;
 
-  DCPackType get_pack_type() const;
+  INLINE DCPackType get_pack_type() const;
 
   virtual bool pack_double(DCPackData &pack_data, double value) const;
   virtual bool pack_int(DCPackData &pack_data, int value) const;
@@ -95,19 +96,20 @@ public:
   virtual bool unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const;
   virtual bool unpack_uint64(const char *data, size_t length, size_t &p, PN_uint64 &value) const;
   virtual bool unpack_string(const char *data, size_t length, size_t &p, string &value) const;
+  virtual bool unpack_skip(const char *data, size_t length, size_t &p) const;
 
   // These are the low-level interfaces for packing and unpacking
   // numbers from a buffer.  You're responsible for making sure the
   // buffer has enough room, and for incrementing the pointer.
-  INLINE static void do_pack_int8(char *buffer, int value);
-  INLINE static void do_pack_int16(char *buffer, int value);
-  INLINE static void do_pack_int32(char *buffer, int value);
-  INLINE static void do_pack_int64(char *buffer, PN_int64 value);
-  INLINE static void do_pack_uint8(char *buffer, unsigned int value);
-  INLINE static void do_pack_uint16(char *buffer, unsigned int value);
-  INLINE static void do_pack_uint32(char *buffer, unsigned int value);
-  INLINE static void do_pack_uint64(char *buffer, PN_uint64 value);
-  INLINE static void do_pack_float64(char *buffer, double value);
+  INLINE static void do_pack_int8(char *buffer, int value, bool &pack_error);
+  INLINE static void do_pack_int16(char *buffer, int value, bool &pack_error);
+  INLINE static void do_pack_int32(char *buffer, int value, bool &pack_error);
+  INLINE static void do_pack_int64(char *buffer, PN_int64 value, bool &pack_error);
+  INLINE static void do_pack_uint8(char *buffer, unsigned int value, bool &pack_error);
+  INLINE static void do_pack_uint16(char *buffer, unsigned int value, bool &pack_error);
+  INLINE static void do_pack_uint32(char *buffer, unsigned int value, bool &pack_error);
+  INLINE static void do_pack_uint64(char *buffer, PN_uint64 value, bool &pack_error);
+  INLINE static void do_pack_float64(char *buffer, double value, bool &pack_error);
 
   INLINE static int do_unpack_int8(const char *buffer);
   INLINE static int do_unpack_int16(const char *buffer);
@@ -119,6 +121,8 @@ public:
   INLINE static PN_uint64 do_unpack_uint64(const char *buffer);
   INLINE static double do_unpack_float64(const char *buffer);
 
+  const DCPackerCatalog *get_catalog() const;
+
 protected:
   string _name;
   bool _has_fixed_byte_size;
@@ -127,6 +131,14 @@ protected:
   bool _has_nested_fields;
   int _num_nested_fields;
   DCPackType _pack_type;
+
+private:
+  void make_catalog();
+  void r_fill_catalog(DCPackerCatalog *catalog, const string &name_prefix,
+                      DCPackerInterface *parent, int field_index);
+                    
+
+  DCPackerCatalog *_catalog;
 };
 
 #include "dcPackerInterface.I"

+ 129 - 59
direct/src/dcparser/dcSimpleParameter.cxx

@@ -318,58 +318,59 @@ get_nested_field(int) const {
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 pack_double(DCPackData &pack_data, double value) const {
+  bool pack_error = false;
   double real_value = value * _divisor;
 
   switch (_type) {
   case ST_int8:
     do_pack_int8(pack_data.get_write_pointer(1), 
-               (int)floor(real_value + 0.5));
+                 (int)floor(real_value + 0.5), pack_error);
     break;
 
   case ST_int16:
     do_pack_int16(pack_data.get_write_pointer(2), 
-               (int)floor(real_value + 0.5));
+                  (int)floor(real_value + 0.5), pack_error);
     break;
-
+    
   case ST_int32:
     do_pack_int32(pack_data.get_write_pointer(4), 
-               (int)floor(real_value + 0.5));
+                  (int)floor(real_value + 0.5), pack_error);
     break;
-
+    
   case ST_int64:
     do_pack_int64(pack_data.get_write_pointer(8), 
-                (PN_int64)floor(real_value + 0.5));
+                  (PN_int64)floor(real_value + 0.5), pack_error);
     break;
-
+    
   case ST_uint8:
     do_pack_uint8(pack_data.get_write_pointer(1), 
-                (unsigned int)floor(real_value + 0.5));
+                  (unsigned int)floor(real_value + 0.5), pack_error);
     break;
-
+    
   case ST_uint16:
     do_pack_uint16(pack_data.get_write_pointer(2), 
-                (unsigned int)floor(real_value + 0.5));
+                   (unsigned int)floor(real_value + 0.5), pack_error);
     break;
-
+    
   case ST_uint32:
     do_pack_uint32(pack_data.get_write_pointer(4), 
-                (unsigned int)floor(real_value + 0.5));
+                   (unsigned int)floor(real_value + 0.5), pack_error);
     break;
-
+    
   case ST_uint64:
     do_pack_uint64(pack_data.get_write_pointer(8), 
-                (PN_uint64)floor(real_value + 0.5));
+                   (PN_uint64)floor(real_value + 0.5), pack_error);
     break;
 
   case ST_float64:
-    do_pack_float64(pack_data.get_write_pointer(8), real_value);
+    do_pack_float64(pack_data.get_write_pointer(8), real_value, pack_error);
     break;
 
   default:
     return false;
   }
 
-  return true;
+  return !pack_error;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -380,50 +381,51 @@ pack_double(DCPackData &pack_data, double value) const {
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 pack_int(DCPackData &pack_data, int value) const {
+  bool pack_error = false;
   int int_value = value * _divisor;
 
   switch (_type) {
   case ST_int8:
-    do_pack_int8(pack_data.get_write_pointer(1), int_value);
+    do_pack_int8(pack_data.get_write_pointer(1), int_value, pack_error);
     break;
 
   case ST_int16:
-    do_pack_int16(pack_data.get_write_pointer(2), int_value);
+    do_pack_int16(pack_data.get_write_pointer(2), int_value, pack_error);
     break;
 
   case ST_int32:
-    do_pack_int32(pack_data.get_write_pointer(4), int_value);
+    do_pack_int32(pack_data.get_write_pointer(4), int_value, pack_error);
     break;
 
   case ST_int64:
-    do_pack_int64(pack_data.get_write_pointer(8), int_value);
+    do_pack_int64(pack_data.get_write_pointer(8), int_value, pack_error);
     break;
 
   case ST_uint8:
-    do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value);
+    do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value, pack_error);
     break;
 
   case ST_uint16:
-    do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value);
+    do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value, pack_error);
     break;
 
   case ST_uint32:
-    do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value);
+    do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value, pack_error);
     break;
 
   case ST_uint64:
-    do_pack_uint64(pack_data.get_write_pointer(8), (unsigned int)int_value);
+    do_pack_uint64(pack_data.get_write_pointer(8), (unsigned int)int_value, pack_error);
     break;
 
   case ST_float64:
-    do_pack_float64(pack_data.get_write_pointer(8), int_value);
+    do_pack_float64(pack_data.get_write_pointer(8), int_value, pack_error);
     break;
 
   default:
     return false;
   }
 
-  return true;
+  return !pack_error;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -434,50 +436,51 @@ pack_int(DCPackData &pack_data, int value) const {
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 pack_uint(DCPackData &pack_data, unsigned int value) const {
+  bool pack_error = false;
   unsigned int int_value = value * _divisor;
 
   switch (_type) {
   case ST_int8:
-    do_pack_int8(pack_data.get_write_pointer(1), (int)int_value);
+    do_pack_int8(pack_data.get_write_pointer(1), (int)int_value, pack_error);
     break;
 
   case ST_int16:
-    do_pack_int16(pack_data.get_write_pointer(2), (int)int_value);
+    do_pack_int16(pack_data.get_write_pointer(2), (int)int_value, pack_error);
     break;
 
   case ST_int32:
-    do_pack_int32(pack_data.get_write_pointer(4), (int)int_value);
+    do_pack_int32(pack_data.get_write_pointer(4), (int)int_value, pack_error);
     break;
 
   case ST_int64:
-    do_pack_int64(pack_data.get_write_pointer(8), (int)int_value);
+    do_pack_int64(pack_data.get_write_pointer(8), (int)int_value, pack_error);
     break;
 
   case ST_uint8:
-    do_pack_uint8(pack_data.get_write_pointer(1), int_value);
+    do_pack_uint8(pack_data.get_write_pointer(1), int_value, pack_error);
     break;
 
   case ST_uint16:
-    do_pack_uint16(pack_data.get_write_pointer(2), int_value);
+    do_pack_uint16(pack_data.get_write_pointer(2), int_value, pack_error);
     break;
 
   case ST_uint32:
-    do_pack_uint32(pack_data.get_write_pointer(4), int_value);
+    do_pack_uint32(pack_data.get_write_pointer(4), int_value, pack_error);
     break;
 
   case ST_uint64:
-    do_pack_uint64(pack_data.get_write_pointer(8), int_value);
+    do_pack_uint64(pack_data.get_write_pointer(8), int_value, pack_error);
     break;
 
   case ST_float64:
-    do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
+    do_pack_float64(pack_data.get_write_pointer(8), (double)int_value, pack_error);
     break;
 
   default:
     return false;
   }
 
-  return true;
+  return !pack_error;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -488,50 +491,51 @@ pack_uint(DCPackData &pack_data, unsigned int value) const {
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 pack_int64(DCPackData &pack_data, PN_int64 value) const {
+  bool pack_error = false;
   PN_int64 int_value = value * _divisor;
 
   switch (_type) {
   case ST_int8:
-    do_pack_int8(pack_data.get_write_pointer(1), (int)int_value);
+    do_pack_int8(pack_data.get_write_pointer(1), (int)int_value, pack_error);
     break;
 
   case ST_int16:
-    do_pack_int16(pack_data.get_write_pointer(2), (int)int_value);
+    do_pack_int16(pack_data.get_write_pointer(2), (int)int_value, pack_error);
     break;
 
   case ST_int32:
-    do_pack_int32(pack_data.get_write_pointer(4), (int)int_value);
+    do_pack_int32(pack_data.get_write_pointer(4), (int)int_value, pack_error);
     break;
 
   case ST_int64:
-    do_pack_int64(pack_data.get_write_pointer(8), int_value);
+    do_pack_int64(pack_data.get_write_pointer(8), int_value, pack_error);
     break;
 
   case ST_uint8:
-    do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)(PN_uint64)int_value);
+    do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)(PN_uint64)int_value, pack_error);
     break;
 
   case ST_uint16:
-    do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)(PN_uint64)int_value);
+    do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)(PN_uint64)int_value, pack_error);
     break;
 
   case ST_uint32:
-    do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)(PN_uint64)int_value);
+    do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)(PN_uint64)int_value, pack_error);
     break;
 
   case ST_uint64:
-    do_pack_uint64(pack_data.get_write_pointer(8), (PN_uint64)int_value);
+    do_pack_uint64(pack_data.get_write_pointer(8), (PN_uint64)int_value, pack_error);
     break;
 
   case ST_float64:
-    do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
+    do_pack_float64(pack_data.get_write_pointer(8), (double)int_value, pack_error);
     break;
 
   default:
     return false;
   }
 
-  return true;
+  return !pack_error;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -542,50 +546,51 @@ pack_int64(DCPackData &pack_data, PN_int64 value) const {
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 pack_uint64(DCPackData &pack_data, PN_uint64 value) const {
+  bool pack_error = false;
   PN_uint64 int_value = value * _divisor;
 
   switch (_type) {
   case ST_int8:
-    do_pack_int8(pack_data.get_write_pointer(1), (int)(PN_int64)int_value);
+    do_pack_int8(pack_data.get_write_pointer(1), (int)(PN_int64)int_value, pack_error);
     break;
 
   case ST_int16:
-    do_pack_int16(pack_data.get_write_pointer(2), (int)(PN_int64)int_value);
+    do_pack_int16(pack_data.get_write_pointer(2), (int)(PN_int64)int_value, pack_error);
     break;
 
   case ST_int32:
-    do_pack_int32(pack_data.get_write_pointer(4), (int)(PN_int64)int_value);
+    do_pack_int32(pack_data.get_write_pointer(4), (int)(PN_int64)int_value, pack_error);
     break;
 
   case ST_int64:
-    do_pack_int64(pack_data.get_write_pointer(8), (PN_int64)int_value);
+    do_pack_int64(pack_data.get_write_pointer(8), (PN_int64)int_value, pack_error);
     break;
 
   case ST_uint8:
-    do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value);
+    do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value, pack_error);
     break;
 
   case ST_uint16:
-    do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value);
+    do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value, pack_error);
     break;
 
   case ST_uint32:
-    do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value);
+    do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value, pack_error);
     break;
 
   case ST_uint64:
-    do_pack_uint64(pack_data.get_write_pointer(8), int_value);
+    do_pack_uint64(pack_data.get_write_pointer(8), int_value, pack_error);
     break;
 
   case ST_float64:
-    do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
+    do_pack_float64(pack_data.get_write_pointer(8), (double)int_value, pack_error);
     break;
 
   default:
     return false;
   }
 
-  return true;
+  return !pack_error;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -596,15 +601,19 @@ pack_uint64(DCPackData &pack_data, PN_uint64 value) const {
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 pack_string(DCPackData &pack_data, const string &value) const {
+  bool pack_error = false;
+
   switch (_type) {
   case ST_string:
   case ST_blob:
-    do_pack_uint16(pack_data.get_write_pointer(2), value.length());
+    do_pack_uint16(pack_data.get_write_pointer(2), value.length(),
+                   pack_error);
     pack_data.append_data(value.data(), value.length());
     break;
 
   case ST_blob32:
-    do_pack_uint32(pack_data.get_write_pointer(4), value.length());
+    do_pack_uint32(pack_data.get_write_pointer(4), value.length(),
+                   pack_error);
     pack_data.append_data(value.data(), value.length());
     break;
 
@@ -612,7 +621,7 @@ pack_string(DCPackData &pack_data, const string &value) const {
     return false;
   }
 
-  return true;
+  return !pack_error;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1116,6 +1125,67 @@ unpack_string(const char *data, size_t length, size_t &p, string &value) const {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleParameter::unpack_skip
+//       Access: Public, Virtual
+//  Description: Increments p to the end of the current field without
+//               actually unpacking any data.  Returns true on
+//               success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleParameter::
+unpack_skip(const char *data, size_t length, size_t &p) const {
+  size_t string_length;
+
+  switch (_type) {
+  case ST_int8:
+  case ST_uint8:
+    p++;
+    break;
+
+  case ST_int16:
+  case ST_uint16:
+    p += 2;
+    break;
+
+  case ST_int32:
+  case ST_uint32:
+    p += 4;
+    break;
+
+  case ST_int64:
+  case ST_uint64:
+  case ST_float64:
+    p += 8;
+    break;
+
+  case ST_string:
+  case ST_blob:
+    if (p + 2 > length) {
+      return false;
+    }
+    string_length = do_unpack_uint16(data + p);
+    p += 2 + string_length;
+    break;
+
+  case ST_blob32:
+    if (p + 4 > length) {
+      return false;
+    }
+    string_length = do_unpack_uint32(data + p);
+    p += 4 + string_length;
+    break;
+
+  default:
+    return false;
+  }
+
+  if (p > length) {
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCSimpleParameter::output_instance
 //       Access: Public, Virtual

+ 1 - 0
direct/src/dcparser/dcSimpleParameter.h

@@ -64,6 +64,7 @@ public:
   virtual bool unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const;
   virtual bool unpack_uint64(const char *data, size_t length, size_t &p, PN_uint64 &value) const;
   virtual bool unpack_string(const char *data, size_t length, size_t &p, string &value) const;
+  virtual bool unpack_skip(const char *data, size_t length, size_t &p) const;
 
   virtual void output_instance(ostream &out, const string &prename, 
                                const string &name, const string &postname) const;

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

@@ -6,6 +6,7 @@
 #include "dcDeclaration.cxx"
 #include "dcPackData.cxx"
 #include "dcPacker.cxx"
+#include "dcPackerCatalog.cxx"
 #include "dcPackerInterface.cxx"
 #include "dcindent.cxx"