Browse Source

allow serial pack/unpack sessions

David Rose 21 years ago
parent
commit
4b15c13cc0

+ 2 - 1
direct/src/dcparser/dcAtomicField.cxx

@@ -459,7 +459,8 @@ output(ostream &out, bool brief) const {
   if (!brief && _has_default_value) {
     out << " = ";
     DCPacker packer;
-    packer.begin_unpack(_default_value, _param);
+    packer.set_unpack_data(_default_value);
+    packer.begin_unpack(_param);
     packer.unpack_and_format(out);
     packer.end_unpack();
   }

+ 58 - 35
direct/src/dcparser/dcClass.cxx

@@ -275,16 +275,21 @@ get_class_def() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: DCClass::receive_update
 //       Access: Published
-//  Description: Extracts the update message out of the datagram and
+//  Description: Extracts the update message out of the packer and
 //               applies it to the indicated object by calling the
 //               appropriate method.
 ////////////////////////////////////////////////////////////////////
 void DCClass::
-receive_update(PyObject *distobj, DatagramIterator &iterator) const {
-  int field_id = iterator.get_uint16();
+receive_update(PyObject *distobj, DatagramIterator &di) const {
+  DCPacker packer;
+  packer.set_unpack_data(di.get_remaining_bytes());
+
+  int field_id = packer.raw_unpack_uint16();
   DCField *field = get_inherited_field(field_id);
   nassertv_always(field != NULL);
-  field->receive_update(distobj, iterator);
+  field->receive_update(packer, distobj);
+
+  di.skip_bytes(packer.get_num_unpacked_bytes());
 }
 #endif  // HAVE_PYTHON
 
@@ -298,16 +303,21 @@ receive_update(PyObject *distobj, DatagramIterator &iterator) const {
 //               atomic fields that are marked "broadcast required".
 ////////////////////////////////////////////////////////////////////
 void DCClass::
-receive_update_broadcast_required(PyObject *distobj, DatagramIterator &iterator) const {
+receive_update_broadcast_required(PyObject *distobj, DatagramIterator &di) const {
+  DCPacker packer;
+  packer.set_unpack_data(di.get_remaining_bytes());
+
   int num_fields = get_num_inherited_fields();
   for (int i = 0; i < num_fields && !PyErr_Occurred(); i++) {
     DCField *field = get_inherited_field(i);
     DCAtomicField *atom = field->as_atomic_field();
     if (atom != (DCAtomicField *)NULL &&
         atom->is_required() && atom->is_broadcast()) {
-      atom->receive_update(distobj, iterator);
+      atom->receive_update(packer, distobj);
     }
   }
+
+  di.skip_bytes(packer.get_num_unpacked_bytes());
 }
 #endif  // HAVE_PYTHON
 
@@ -321,15 +331,20 @@ receive_update_broadcast_required(PyObject *distobj, DatagramIterator &iterator)
 //               marked "required", whether they are broadcast or not.
 ////////////////////////////////////////////////////////////////////
 void DCClass::
-receive_update_all_required(PyObject *distobj, DatagramIterator &iterator) const {
+receive_update_all_required(PyObject *distobj, DatagramIterator &di) const {
+  DCPacker packer;
+  packer.set_unpack_data(di.get_remaining_bytes());
+
   int num_fields = get_num_inherited_fields();
   for (int i = 0; i < num_fields && !PyErr_Occurred(); i++) {
     DCField *field = get_inherited_field(i);
     DCAtomicField *atom = field->as_atomic_field();
     if (atom != (DCAtomicField *)NULL && atom->is_required()) {
-      atom->receive_update(distobj, iterator);
+      atom->receive_update(packer, distobj);
     }
   }
+
+  di.skip_bytes(packer.get_num_unpacked_bytes());
 }
 #endif  // HAVE_PYTHON
 
@@ -341,10 +356,10 @@ receive_update_all_required(PyObject *distobj, DatagramIterator &iterator) const
 //               fields that are broadcast in one chunk.
 ////////////////////////////////////////////////////////////////////
 void DCClass::
-receive_update_other(PyObject *distobj, DatagramIterator &iterator) const {
-  int num_fields = iterator.get_uint16();
+receive_update_other(PyObject *distobj, DatagramIterator &di) const {
+  int num_fields = di.get_uint16();
   for (int i = 0; i < num_fields && !PyErr_Occurred(); i++) {
-    receive_update(distobj, iterator);
+    receive_update(distobj, di);
   }
 }
 #endif  // HAVE_PYTHON
@@ -359,8 +374,12 @@ receive_update_other(PyObject *distobj, DatagramIterator &iterator) const {
 void DCClass::
 direct_update(PyObject *distobj, const string &field_name, 
               const string &value_blob) {
-  Datagram datagram(value_blob);
-  direct_update(distobj, field_name, datagram);
+  DCField *field = get_field_by_name(field_name);
+  nassertv_always(field != NULL);
+
+  DCPacker packer;
+  packer.set_unpack_data(value_blob);
+  field->receive_update(packer, distobj);
 }
 #endif  // HAVE_PYTHON
 
@@ -374,10 +393,7 @@ direct_update(PyObject *distobj, const string &field_name,
 void DCClass::
 direct_update(PyObject *distobj, const string &field_name, 
               const Datagram &datagram) {
-  DCField *field = get_field_by_name(field_name);
-  nassertv_always(field != NULL);
-  DatagramIterator iterator(datagram);
-  field->receive_update(distobj, iterator);
+  direct_update(distobj, field_name, datagram.get_message());
 }
 #endif  // HAVE_PYTHON
 
@@ -387,7 +403,7 @@ direct_update(PyObject *distobj, const string &field_name,
 //       Access: Published
 //  Description: Looks up the current value of the indicated field by
 //               calling the appropriate get*() function, then packs
-//               that value into the datagram.  This field is
+//               that value into the packer.  This field is
 //               presumably either a required field or a specified
 //               optional field, and we are building up a datagram for
 //               the generate-with-required message.
@@ -395,7 +411,7 @@ direct_update(PyObject *distobj, const string &field_name,
 //               Returns true on success, false on failure.
 ////////////////////////////////////////////////////////////////////
 bool DCClass::
-pack_required_field(Datagram &dg, PyObject *distobj, DCField *field) const {
+pack_required_field(DCPacker &packer, PyObject *distobj, DCField *field) const {
   DCAtomicField *atom = field->as_atomic_field();
   if (atom == (DCAtomicField *)NULL) {
     ostringstream strm;
@@ -461,7 +477,7 @@ pack_required_field(Datagram &dg, PyObject *distobj, DCField *field) const {
   }        
   
   // Now pack the arguments into the datagram.
-  bool pack_ok = atom->pack_args(dg, result);
+  bool pack_ok = atom->pack_args(packer, result);
   Py_DECREF(result);
 
   return pack_ok;
@@ -487,7 +503,10 @@ client_format_update(const string &field_name, int do_id,
     nassert_raise(strm.str());
     return Datagram();
   }
-  return field->client_format_update(do_id, args);
+
+  DCPacker packer;
+  field->client_format_update(packer, do_id, args);
+  return Datagram(packer.get_data(), packer.get_length());
 }
 #endif  // HAVE_PYTHON
 
@@ -510,7 +529,10 @@ ai_format_update(const string &field_name, int do_id,
     nassert_raise(strm.str());
     return Datagram();
   }
-  return field->ai_format_update(do_id, to_id, from_id, args);
+
+  DCPacker packer;
+  field->ai_format_update(packer, do_id, to_id, from_id, args);
+  return Datagram(packer.get_data(), packer.get_length());
 }
 #endif  // HAVE_PYTHON
 
@@ -530,22 +552,23 @@ Datagram DCClass::
 ai_format_generate(PyObject *distobj, int do_id, 
                    int zone_id, int district_id, int from_channel_id,
                    PyObject *optional_fields) const {
-  Datagram dg;
-  dg.add_uint32(district_id);
-  dg.add_uint32(from_channel_id);
-  dg.add_uint8('A');
+  DCPacker packer;
+
+  packer.raw_pack_uint32(district_id);
+  packer.raw_pack_uint32(from_channel_id);
+  packer.raw_pack_uint8('A');
 
   bool has_optional_fields = (PyObject_IsTrue(optional_fields) != 0);
 
   if (has_optional_fields) {
-    dg.add_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER);
+    packer.raw_pack_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER);
   } else {
-    dg.add_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED);
+    packer.raw_pack_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED);
   }
 
-  dg.add_uint32(zone_id);
-  dg.add_uint16(_number);
-  dg.add_uint32(do_id);
+  packer.raw_pack_uint32(zone_id);
+  packer.raw_pack_uint16(_number);
+  packer.raw_pack_uint32(do_id);
 
   // Specify all of the required fields.
   int num_fields = get_num_inherited_fields();
@@ -553,7 +576,7 @@ ai_format_generate(PyObject *distobj, int do_id,
     DCField *field = get_inherited_field(i);
     DCAtomicField *atom = field->as_atomic_field();
     if (atom != (DCAtomicField *)NULL && atom->is_required()) {
-      if (!pack_required_field(dg, distobj, atom)) {
+      if (!pack_required_field(packer, distobj, atom)) {
         return Datagram();
       }
     }
@@ -562,7 +585,7 @@ ai_format_generate(PyObject *distobj, int do_id,
   // Also specify the optional fields.
   if (has_optional_fields) {
     int num_optional_fields = PySequence_Size(optional_fields);
-    dg.add_uint16(num_optional_fields);
+    packer.raw_pack_uint16(num_optional_fields);
 
     for (int i = 0; i < num_optional_fields; i++) {
       PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
@@ -578,13 +601,13 @@ ai_format_generate(PyObject *distobj, int do_id,
         return Datagram();
       }
 
-      if (!pack_required_field(dg, distobj, field)) {
+      if (!pack_required_field(packer, distobj, field)) {
         return Datagram();
       }
     }
   }
 
-  return dg;
+  return Datagram(packer.get_data(), packer.get_length());
 }
 #endif  // HAVE_PYTHON
 

+ 8 - 7
direct/src/dcparser/dcClass.h

@@ -59,20 +59,21 @@ PUBLISHED:
   void set_class_def(PyObject *class_def);
   PyObject *get_class_def() const;
 
-  void receive_update(PyObject *distobj, DatagramIterator &iterator) const;
-  void receive_update_broadcast_required(PyObject *distobj, DatagramIterator &iterator) const;
-  void receive_update_all_required(PyObject *distobj, DatagramIterator &iterator) const;
-  void receive_update_other(PyObject *distobj, DatagramIterator &iterator) const;
+  void receive_update(PyObject *distobj, DatagramIterator &di) const;
+  void receive_update_broadcast_required(PyObject *distobj, DatagramIterator &di) const;
+  void receive_update_all_required(PyObject *distobj, DatagramIterator &di) const;
+  void receive_update_other(PyObject *distobj, DatagramIterator &di) const;
+
   void direct_update(PyObject *distobj, const string &field_name, 
                      const string &value_blob);
   void direct_update(PyObject *distobj, const string &field_name, 
                      const Datagram &datagram);
-  bool pack_required_field(Datagram &dg, PyObject *distobj, 
+  bool pack_required_field(DCPacker &packer, PyObject *distobj, 
                            DCField *field) const;
 
 
-  Datagram client_format_update(const string &field_name, int do_id, 
-                                PyObject *args) const;
+  Datagram client_format_update(const string &field_name,
+                                int do_id, PyObject *args) const;
   Datagram ai_format_update(const string &field_name, int do_id, 
                             int to_id, int from_id, PyObject *args) const;
   Datagram ai_format_generate(PyObject *distobj, int do_id, int zone_id,

+ 30 - 39
direct/src/dcparser/dcField.cxx

@@ -124,7 +124,8 @@ as_switch() {
 string DCField::
 format_data(const string &packed_data) {
   DCPacker packer;
-  packer.begin_unpack(packed_data, this);
+  packer.set_unpack_data(packed_data);
+  packer.begin_unpack(this);
   string result = packer.unpack_and_format();
   if (!packer.end_unpack()) {
     return string();
@@ -168,7 +169,8 @@ parse_string(const string &formatted_string) {
 bool DCField::
 validate_ranges(const string &packed_data) const {
   DCPacker packer;
-  packer.begin_unpack(packed_data, this);
+  packer.set_unpack_data(packed_data);
+  packer.begin_unpack(this);
   packer.unpack_validate();
   if (!packer.end_unpack()) {
     return false;
@@ -182,18 +184,15 @@ validate_ranges(const string &packed_data) const {
 //     Function: DCField::pack_args
 //       Access: Published
 //  Description: Packs the Python arguments from the indicated tuple
-//               into the datagram, appending to the end of the
-//               datagram.  Returns true on success, false on failure.
+//               into the packer.  Returns true on success, false on
+//               failure.
 ////////////////////////////////////////////////////////////////////
 bool DCField::
-pack_args(Datagram &datagram, PyObject *sequence) const {
+pack_args(DCPacker &packer, PyObject *sequence) const {
   nassertr(PySequence_Check(sequence), false);
-  DCPacker packer;
   packer.begin_pack(this);
   packer.pack_object(sequence);
   if (packer.end_pack()) {
-    datagram.append_data(packer.get_data(), packer.get_length());
-
     /*
     PyObject *str = PyObject_Str(sequence);
     cerr << "pack " << get_name() << PyString_AsString(str) << "\n";
@@ -227,24 +226,20 @@ pack_args(Datagram &datagram, PyObject *sequence) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: DCField::unpack_args
 //       Access: Published
-//  Description: Unpacks the values from the datagram, beginning at
-//               the current point in the interator, into a Python
+//  Description: Unpacks the values from the packer, beginning at
+//               the current point in the unpack_buffer, into a Python
 //               tuple and returns the tuple.  If there are remaining
-//               bytes in the datagram, they are ignored (but the
-//               iterator is left at the first unread byte).
+//               bytes in the unpack buffer, they are ignored (but the
+//               packer is left at the first unread byte).
 ////////////////////////////////////////////////////////////////////
 PyObject *DCField::
-unpack_args(DatagramIterator &iterator) const {
-  DCPacker packer;
-  string data = iterator.get_remaining_bytes();
-  packer.begin_unpack(data, this);
+unpack_args(DCPacker &packer) const {
+  packer.begin_unpack(this);
 
   PyObject *object = packer.unpack_object();
 
   if (packer.end_unpack()) {
     // Successfully unpacked.
-    iterator.skip_bytes(packer.get_num_unpacked_bytes());
-
     /*
     PyObject *str = PyObject_Str(object);
     cerr << "recv " << get_name() << PyString_AsString(str) << "\n";
@@ -283,8 +278,8 @@ unpack_args(DatagramIterator &iterator) const {
 //               appropriate method.
 ////////////////////////////////////////////////////////////////////
 void DCField::
-receive_update(PyObject *distobj, DatagramIterator &iterator) const {
-  PyObject *args = unpack_args(iterator);
+receive_update(DCPacker &packer, PyObject *distobj) const {
+  PyObject *args = unpack_args(packer);
 
   if (PyObject_HasAttrString(distobj, (char *)_name.c_str())) {
     PyObject *func = PyObject_GetAttrString(distobj, (char *)_name.c_str());
@@ -307,14 +302,12 @@ receive_update(PyObject *distobj, DatagramIterator &iterator) const {
 //               to send an update for the indicated distributed
 //               object from the client.
 ////////////////////////////////////////////////////////////////////
-Datagram DCField::
-client_format_update(int do_id, PyObject *args) const {
-  Datagram dg;
-  dg.add_uint16(CLIENT_OBJECT_UPDATE_FIELD);
-  dg.add_uint32(do_id);
-  dg.add_uint16(_number);
-  pack_args(dg, args);
-  return dg;
+void DCField::
+client_format_update(DCPacker &packer, int do_id, PyObject *args) const {
+  packer.raw_pack_uint16(CLIENT_OBJECT_UPDATE_FIELD);
+  packer.raw_pack_uint32(do_id);
+  packer.raw_pack_uint16(_number);
+  pack_args(packer, args);
 }
 #endif  // HAVE_PYTHON
 
@@ -326,17 +319,15 @@ client_format_update(int do_id, PyObject *args) const {
 //               to send an update for the indicated distributed
 //               object from the AI.
 ////////////////////////////////////////////////////////////////////
-Datagram DCField::
-ai_format_update(int do_id, int to_id, int from_id, PyObject *args) const {
-  Datagram dg;
-  dg.add_uint32(to_id);
-  dg.add_uint32(from_id);
-  dg.add_uint8('A');
-  dg.add_uint16(STATESERVER_OBJECT_UPDATE_FIELD);
-  dg.add_uint32(do_id);
-  dg.add_uint16(_number);
-  pack_args(dg, args);
-  return dg;
+void DCField::
+ai_format_update(DCPacker &packer, int do_id, int to_id, int from_id, PyObject *args) const {
+  packer.raw_pack_uint32(to_id);
+  packer.raw_pack_uint32(from_id);
+  packer.raw_pack_uint8('A');
+  packer.raw_pack_uint16(STATESERVER_OBJECT_UPDATE_FIELD);
+  packer.raw_pack_uint32(do_id);
+  packer.raw_pack_uint16(_number);
+  pack_args(packer, args);
 }
 #endif  // HAVE_PYTHON
 

+ 6 - 5
direct/src/dcparser/dcField.h

@@ -23,6 +23,7 @@
 #include "dcPackerInterface.h"
 #include "dcPython.h"
 
+class DCPacker;
 class DCAtomicField;
 class DCMolecularField;
 class DCParameter;
@@ -54,13 +55,13 @@ PUBLISHED:
   bool validate_ranges(const string &packed_data) const;
 
 #ifdef HAVE_PYTHON
-  bool pack_args(Datagram &datagram, PyObject *sequence) const;
-  PyObject *unpack_args(DatagramIterator &iterator) const;
+  bool pack_args(DCPacker &packer, PyObject *sequence) const;
+  PyObject *unpack_args(DCPacker &packer) const;
 
-  void receive_update(PyObject *distobj, DatagramIterator &iterator) const;
+  void receive_update(DCPacker &packer, PyObject *distobj) const;
 
-  Datagram client_format_update(int do_id, PyObject *args) const;
-  Datagram ai_format_update(int do_id, int to_id, int from_id, PyObject *args) const;
+  void client_format_update(DCPacker &packer, int do_id, PyObject *args) const;
+  void ai_format_update(DCPacker &packer, int do_id, int to_id, int from_id, PyObject *args) const;
 #endif 
 
 public:

+ 5 - 5
direct/src/dcparser/dcPackData.I

@@ -54,7 +54,7 @@ clear() {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackData::append_data
-//       Access: Published
+//       Access: Public
 //  Description: Adds the indicated bytes to the end of the data.
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackData::
@@ -65,7 +65,7 @@ append_data(const char *buffer, size_t size) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackData::get_write_pointer
-//       Access: Published
+//       Access: Public
 //  Description: Adds the indicated number of bytes to the end of the
 //               data without initializing them, and returns a pointer
 //               to the beginning of the new data.
@@ -78,7 +78,7 @@ get_write_pointer(size_t size) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackData::append_junk
-//       Access: Published
+//       Access: Public
 //  Description: Adds some uninitialized bytes to the end of the data.
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPackData::
@@ -88,7 +88,7 @@ append_junk(size_t size) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackData::rewrite_data
-//       Access: Published
+//       Access: Public
 //  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.
@@ -101,7 +101,7 @@ rewrite_data(size_t position, const char *buffer, size_t size) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPackData::get_rewrite_pointer
-//       Access: Published
+//       Access: Public
 //  Description: Returns a pointer into the middle of the data at the
 //               indicated point.
 ////////////////////////////////////////////////////////////////////

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

@@ -33,12 +33,14 @@ PUBLISHED:
 
   INLINE void clear();
 
+public:
   INLINE void append_data(const char *buffer, size_t size);
   INLINE char *get_write_pointer(size_t size);
   INLINE void append_junk(size_t size);
   INLINE void rewrite_data(size_t position, const char *buffer, size_t size);
   INLINE char *get_rewrite_pointer(size_t position, size_t size);
 
+PUBLISHED:
   INLINE string get_string() const;
   INLINE size_t get_length() const;
 public:

+ 470 - 1
direct/src/dcparser/dcPacker.I

@@ -17,9 +17,28 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::clear_data
+//       Access: Published
+//  Description: Empties the data in the pack buffer and unpack
+//               buffer.  This should be called between calls to
+//               begin_pack(), unless you want to concatenate all of
+//               the pack results together.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+clear_data() {
+  _pack_data.clear();
+
+  if (_owns_unpack_data) {
+    delete[] _unpack_data;
+    _owns_unpack_data = false;
+  }
+  _unpack_data = NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::has_nested_fields
-//       Access: Public, Virtual
+//       Access: Published
 //  Description: Returns true if the current field has any nested
 //               fields (and thus expects a push() .. pop()
 //               interface), or false otherwise.  If this returns
@@ -621,6 +640,456 @@ get_data() const {
   return _pack_data.get_data();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::append_data
+//       Access: Public
+//  Description: Adds the indicated bytes to the end of the data.
+//               This may only be called between packing sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+append_data(const char *buffer, size_t size) {
+  nassertv(_mode == M_idle);
+  _pack_data.append_data(buffer, size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::get_write_pointer
+//       Access: Public
+//  Description: Adds the indicated number of bytes to the end of the
+//               data without initializing them, and returns a pointer
+//               to the beginning of the new data.  This may only be
+//               called between packing sessions.
+////////////////////////////////////////////////////////////////////
+INLINE char *DCPacker::
+get_write_pointer(size_t size) {
+  nassertr(_mode == M_idle, NULL);
+  return _pack_data.get_write_pointer(size);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_int8
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_int8(int value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_int8(_pack_data.get_write_pointer(1), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_int16
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_int16(int value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_int16(_pack_data.get_write_pointer(2), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_int32
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_int32(int value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_int32(_pack_data.get_write_pointer(4), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_int64
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_int64(PN_int64 value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_int64(_pack_data.get_write_pointer(8), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_uint8
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_uint8(unsigned int value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_uint8(_pack_data.get_write_pointer(1), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_uint16
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_uint16(unsigned int value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_uint16(_pack_data.get_write_pointer(2), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_uint32
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_uint32(unsigned int value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_uint32(_pack_data.get_write_pointer(4), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_uint64
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_uint64(PN_uint64 value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_uint64(_pack_data.get_write_pointer(8), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_float64
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_float64(double value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_float64(_pack_data.get_write_pointer(8), value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_pack_string
+//       Access: Published
+//  Description: Packs the data into the buffer between packing
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_pack_string(const string &value) {
+  nassertv(_mode == M_idle);
+  DCPackerInterface::do_pack_uint16(_pack_data.get_write_pointer(2), value.length());
+  _pack_data.append_data(value.data(), value.length());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int8
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE int DCPacker::
+raw_unpack_int8() {
+  int value = 0;
+  raw_unpack_int8(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int16
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE int DCPacker::
+raw_unpack_int16() {
+  int value = 0;
+  raw_unpack_int16(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int32
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE int DCPacker::
+raw_unpack_int32() {
+  int value = 0;
+  raw_unpack_int32(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int64
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE PN_int64 DCPacker::
+raw_unpack_int64() {
+  PN_int64 value = 0;
+  raw_unpack_int64(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int8
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_int8(int &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 1 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_int8(_unpack_data + _unpack_p);
+  _unpack_p++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int16
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_int16(int &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 2 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_int16(_unpack_data + _unpack_p);
+  _unpack_p += 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int32
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_int32(int &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 4 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_int32(_unpack_data + _unpack_p);
+  _unpack_p += 4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint8
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned int DCPacker::
+raw_unpack_uint8() {
+  unsigned int value = 0;
+  raw_unpack_uint8(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint16
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned int DCPacker::
+raw_unpack_uint16() {
+  unsigned int value = 0;
+  raw_unpack_uint16(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint32
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE unsigned int DCPacker::
+raw_unpack_uint32() {
+  unsigned int value = 0;
+  raw_unpack_uint32(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint64
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE PN_uint64 DCPacker::
+raw_unpack_uint64() {
+  PN_uint64 value = 0;
+  raw_unpack_uint64(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_float64
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE double DCPacker::
+raw_unpack_float64() {
+  double value = 0;
+  raw_unpack_float64(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_string
+//       Access: Published
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE string DCPacker::
+raw_unpack_string() {
+  string value;
+  raw_unpack_string(value);
+  return value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_int64
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_int64(PN_int64 &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 8 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_int64(_unpack_data + _unpack_p);
+  _unpack_p += 8;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint8
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_uint8(unsigned int &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 1 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_uint8(_unpack_data + _unpack_p);
+  _unpack_p++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint16
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_uint16(unsigned int &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 2 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_uint16(_unpack_data + _unpack_p);
+  _unpack_p += 2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint32
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_uint32(unsigned int &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 4 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_uint32(_unpack_data + _unpack_p);
+  _unpack_p += 4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_uint64
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_uint64(PN_uint64 &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 8 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_uint64(_unpack_data + _unpack_p);
+  _unpack_p += 8;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_float64
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_float64(double &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  if (_unpack_p + 8 > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+  value = DCPackerInterface::do_unpack_float64(_unpack_data + _unpack_p);
+  _unpack_p += 8;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::raw_unpack_string
+//       Access: Public
+//  Description: Unpacks the data from the buffer between unpacking
+//               sessions.
+////////////////////////////////////////////////////////////////////
+INLINE void DCPacker::
+raw_unpack_string(string &value) {
+  nassertv(_mode == M_idle && _unpack_data != NULL);
+  unsigned int string_length = raw_unpack_uint16();
+
+  if (_unpack_p + string_length > _unpack_length) {
+    _pack_error = true;
+    return;
+  }
+
+  value.assign(_unpack_data + _unpack_p, string_length);
+  _unpack_p += string_length;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::advance
 //       Access: Private

+ 67 - 62
direct/src/dcparser/dcPacker.cxx

@@ -49,6 +49,7 @@ DCPacker() {
 ////////////////////////////////////////////////////////////////////
 DCPacker::
 ~DCPacker() {
+  clear_data();
   clear();
 }
 
@@ -58,6 +59,12 @@ DCPacker::
 //  Description: Begins a packing session.  The parameter is the DC
 //               object that describes the packing format; it may be a
 //               DCParameter or DCField.
+//
+//               Unless you call clear_data() between sessions,
+//               multiple packing sessions will be concatenated
+//               together into the same buffer.  If you wish to add
+//               bytes to the buffer between packing sessions, use
+//               append_data() or get_write_pointer().
 ////////////////////////////////////////////////////////////////////
 void DCPacker::
 begin_pack(const DCPackerInterface *root) {
@@ -66,7 +73,6 @@ begin_pack(const DCPackerInterface *root) {
   _mode = M_pack;
   _pack_error = false;
   _range_error = false;
-  _pack_data.clear();
 
   _root = root;
   _catalog = NULL;
@@ -102,36 +108,63 @@ end_pack() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DCPacker::begin_unpack
-//       Access: Published
-//  Description: Begins an unpacking session.  Unlike the other
-//               version of begin_unpack(), this version makes a copy
-//               of the data string.
+//     Function: DCPacker::set_unpack_data
+//       Access: Public
+//  Description: Sets up the unpack_data pointer.  You may call this
+//               before calling the version of begin_unpack() that
+//               takes only one parameter.
 ////////////////////////////////////////////////////////////////////
 void DCPacker::
-begin_unpack(const string &data, const DCPackerInterface *root) {
-  _unpack_str = data;
-  begin_unpack(_unpack_str.data(), _unpack_str.length(), root);
+set_unpack_data(const string &data) {
+  nassertv(_mode == M_idle);
+
+  char *buffer = new char[data.length()];
+  memcpy(buffer, data.data(), data.length());
+  set_unpack_data(buffer, data.length(), true);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::set_unpack_data
+//       Access: Public
+//  Description: Sets up the unpack_data pointer.  You may call this
+//               before calling the version of begin_unpack() that
+//               takes only one parameter.
+////////////////////////////////////////////////////////////////////
+void DCPacker::
+set_unpack_data(const char *unpack_data, size_t unpack_length, 
+                bool owns_unpack_data) {
+  nassertv(_mode == M_idle);
+
+  if (_owns_unpack_data) {
+    delete[] _unpack_data;
+  }
+  _unpack_data = unpack_data;
+  _unpack_length = unpack_length;
+  _owns_unpack_data = owns_unpack_data;
+  _unpack_p = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::begin_unpack
 //       Access: Public
-//  Description: Begins an unpacking session.  The data pointer is
-//               used directly; the data buffer is not copied.
-//               Therefore, you must not delete or modify the data
-//               pointer until you call end_unpack().
+//  Description: Begins an unpacking session.  You must have
+//               previously called set_unpack_data() to specify a
+//               buffer to unpack.
+//
+//               If there was data left in the buffer after a previous
+//               begin_unpack() .. end_unpack() session, the new
+//               session will resume from the current point.  This
+//               method may be used, therefore, to unpack a sequence
+//               of objects from the same buffer.
 ////////////////////////////////////////////////////////////////////
 void DCPacker::
-begin_unpack(const char *data, size_t length,
-             const DCPackerInterface *root) {
+begin_unpack(const DCPackerInterface *root) {
   nassertv(_mode == M_idle);
+  nassertv(_unpack_data != NULL);
   
   _mode = M_unpack;
   _pack_error = false;
   _range_error = false;
-  set_unpack_data(data, length, false);
-  _unpack_p = 0;
 
   _root = root;
   _catalog = NULL;
@@ -175,44 +208,34 @@ end_unpack() {
   return !_pack_error && !_range_error;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DCPacker::begin_repack
-//       Access: Published
-//  Description: Begins an repacking session.  Unlike the other
-//               version of begin_repack(), this version makes a copy
-//               of the data string.
-////////////////////////////////////////////////////////////////////
-void DCPacker::
-begin_repack(const string &data, const DCPackerInterface *root) {
-  _unpack_str = data;
-  begin_repack(_unpack_str.data(), _unpack_str.length(), root);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::begin_repack
 //       Access: Public
-//  Description: Begins an repacking session.  The data pointer is
-//               used directly; the data buffer is not copied.
-//               Therefore, you must not delete or modify the data
-//               pointer until you call end_repack().
+//  Description: Begins a repacking session.  You must have previously
+//               called set_unpack_data() to specify a buffer to
+//               unpack.
+//
+//               Unlike begin_pack() or begin_unpack() you may not
+//               concatenate the results of multiple begin_repack()
+//               sessions in one buffer.
 //
-//               When repacking, unlike in packing or unpacking modes,
-//               you may not walk through the fields from beginning to
-//               end, or even pack two consecutive fields at once.
-//               Instead, you must call seek() for each field you wish
-//               to modify and pack only that one field; then call
-//               seek() again to modify another field.
+//               Also, unlike in packing or unpacking modes, you may
+//               not walk through the fields from beginning to end, or
+//               even pack two consecutive fields at once.  Instead,
+//               you must call seek() for each field you wish to
+//               modify and pack only that one field; then call seek()
+//               again to modify another field.
 ////////////////////////////////////////////////////////////////////
 void DCPacker::
-begin_repack(const char *data, size_t length,
-             const DCPackerInterface *root) {
+begin_repack(const DCPackerInterface *root) {
   nassertv(_mode == M_idle);
+  nassertv(_unpack_data != NULL);
+  nassertv(_unpack_p == 0);
   
   _mode = M_repack;
   _pack_error = false;
   _range_error = false;
-  set_unpack_data(data, length, false);
-  _unpack_p = 0;
+  _pack_data.clear();
 
   // In repack mode, we immediately get the catalog, since we know
   // we'll need it.
@@ -1009,24 +1032,6 @@ clear() {
   }
   _catalog = NULL;
   _root = NULL;
-
-  set_unpack_data(NULL, 0, false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: DCPacker::set_unpack_data
-//       Access: Private
-//  Description: Sets up the unpack_data pointer.
-////////////////////////////////////////////////////////////////////
-void DCPacker::
-set_unpack_data(const char *unpack_data, size_t unpack_length, 
-                bool owns_unpack_data) {
-  if (_owns_unpack_data) {
-    delete[] _unpack_data;
-  }
-  _unpack_data = unpack_data;
-  _unpack_length = unpack_length;
-  _owns_unpack_data = owns_unpack_data;
 }
 
 #ifdef HAVE_PYTHON

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

@@ -44,21 +44,21 @@ PUBLISHED:
   DCPacker();
   ~DCPacker();
 
+  INLINE void clear_data();
+
   void begin_pack(const DCPackerInterface *root);
   bool end_pack();
 
+  void set_unpack_data(const string &data);
 public:
-  void begin_unpack(const char *data, size_t length,
-                    const DCPackerInterface *root);
+  void set_unpack_data(const char *unpack_data, size_t unpack_length, 
+                       bool owns_unpack_data);
+
 PUBLISHED:
-  void begin_unpack(const string &data, const DCPackerInterface *root);
+  void begin_unpack(const DCPackerInterface *root);
   bool end_unpack();
 
-public:
-  void begin_repack(const char *data, size_t length,
-                    const DCPackerInterface *root);
-PUBLISHED:
-  void begin_repack(const string &data, const DCPackerInterface *root);
+  void begin_repack(const DCPackerInterface *root);
   bool end_repack();
 
   bool seek(const string &field_name);
@@ -125,6 +125,49 @@ PUBLISHED:
 public:
   INLINE const char *get_data() const;
 
+  INLINE void append_data(const char *buffer, size_t size);
+  INLINE char *get_write_pointer(size_t size);
+
+PUBLISHED:
+  // The following methods are used only for packing (or unpacking)
+  // raw data into the buffer between packing sessions (e.g. between
+  // calls to end_pack() and the next begin_pack()).
+
+  INLINE void raw_pack_int8(int value);
+  INLINE void raw_pack_int16(int value);
+  INLINE void raw_pack_int32(int value);
+  INLINE void raw_pack_int64(PN_int64 value);
+  INLINE void raw_pack_uint8(unsigned int value);
+  INLINE void raw_pack_uint16(unsigned int value);
+  INLINE void raw_pack_uint32(unsigned int value);
+  INLINE void raw_pack_uint64(PN_uint64 value);
+  INLINE void raw_pack_float64(double value);
+  INLINE void raw_pack_string(const string &value);
+
+  INLINE int raw_unpack_int8();
+  INLINE int raw_unpack_int16();
+  INLINE int raw_unpack_int32();
+  INLINE PN_int64 raw_unpack_int64();
+  INLINE unsigned int raw_unpack_uint8();
+  INLINE unsigned int raw_unpack_uint16();
+  INLINE unsigned int raw_unpack_uint32();
+  INLINE PN_uint64 raw_unpack_uint64();
+  INLINE double raw_unpack_float64();
+  INLINE string raw_unpack_string();
+
+public:
+  INLINE void raw_unpack_int8(int &value);
+  INLINE void raw_unpack_int16(int &value);
+  INLINE void raw_unpack_int32(int &value);
+  INLINE void raw_unpack_int64(PN_int64 &value);
+  INLINE void raw_unpack_uint8(unsigned int &value);
+  INLINE void raw_unpack_uint16(unsigned int &value);
+  INLINE void raw_unpack_uint32(unsigned int &value);
+  INLINE void raw_unpack_uint64(PN_uint64 &value);
+  INLINE void raw_unpack_float64(double &value);
+  INLINE void raw_unpack_string(string &value);
+
+public:
   static void enquote_string(ostream &out, char quote_mark, const string &str);
   static void output_hex_string(ostream &out, const string &str);
 
@@ -132,8 +175,6 @@ private:
   INLINE void advance();
   void handle_switch(const DCSwitch *dswitch);
   void clear();
-  void set_unpack_data(const char *unpack_data, size_t unpack_length, 
-                       bool owns_unpack_data);
 
 #ifdef HAVE_PYTHON
   PyObject *unpack_class_object(DCClass *dclass);
@@ -150,7 +191,6 @@ private:
   Mode _mode;
 
   DCPackData _pack_data;
-  string _unpack_str;
   const char *_unpack_data;
   size_t _unpack_length;
   bool _owns_unpack_data;

+ 2 - 1
direct/src/dcparser/dcPackerCatalog.cxx

@@ -133,7 +133,8 @@ get_live_catalog(const char *data, size_t length) const {
   }
   
   DCPacker packer;
-  packer.begin_unpack(data, length, _root);
+  packer.set_unpack_data(data, length, false);
+  packer.begin_unpack(_root);
   const DCSwitch *last_switch = NULL;
   r_fill_live_catalog(live_catalog, packer, last_switch);
   bool okflag = packer.end_unpack();