Browse Source

begin_repack

David Rose 21 years ago
parent
commit
28a42d68b6

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

@@ -139,6 +139,8 @@ get_length() const {
 //       Access: Public
 //  Description: Returns the beginning of the data buffer.  The buffer
 //               is not null-terminated, but see also get_string().
+//               This may (or may not) return NULL if the buffer is
+//               empty.
 //
 //               This may be used in conjunction with get_length() to
 //               copy all of the bytes out of the buffer.
@@ -147,3 +149,26 @@ INLINE const char *DCPackData::
 get_data() const {
   return _buffer;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackData::take_data
+//       Access: Public
+//  Description: Returns the pointer to the beginning of the data
+//               buffer, and transfers ownership of the buffer to the
+//               caller.  The caller is now responsible for ultimately
+//               freeing the returned pointer with delete[], if it is
+//               non-NULL.  This may (or may not) return NULL if the
+//               buffer is empty.
+//
+//               This also empties the DCPackData structure.
+////////////////////////////////////////////////////////////////////
+INLINE char *DCPackData::
+take_data() {
+  char *data = _buffer;
+
+  _buffer = NULL;
+  _allocated_size = 0;
+  _used_length = 0;
+
+  return data;
+}

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

@@ -43,6 +43,7 @@ PUBLISHED:
   INLINE size_t get_length() const;
 public:
   INLINE const char *get_data() const;
+  INLINE char *take_data();
 
 private:
   void set_used_length(size_t size);

+ 7 - 7
direct/src/dcparser/dcPacker.I

@@ -106,7 +106,7 @@ get_pack_type() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_double(double value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {
@@ -125,7 +125,7 @@ pack_double(double value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_int(int value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {
@@ -144,7 +144,7 @@ pack_int(int value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_uint(unsigned int value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {
@@ -163,7 +163,7 @@ pack_uint(unsigned int value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_int64(PN_int64 value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {
@@ -182,7 +182,7 @@ pack_int64(PN_int64 value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_uint64(PN_uint64 value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {
@@ -201,7 +201,7 @@ pack_uint64(PN_uint64 value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_string(const string &value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {
@@ -221,7 +221,7 @@ pack_string(const string &value) {
 ////////////////////////////////////////////////////////////////////
 INLINE void DCPacker::
 pack_literal_value(const string &value) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   if (_current_field == NULL) {
     _pack_error = true;
   } else {

+ 151 - 7
direct/src/dcparser/dcPacker.cxx

@@ -30,6 +30,7 @@ DCPacker() {
   _mode = M_idle;
   _unpack_data = NULL;
   _unpack_length = 0;
+  _owns_unpack_data = false;
   _unpack_p = 0;
   _root = NULL;
   _catalog = NULL;
@@ -127,8 +128,7 @@ begin_unpack(const char *data, size_t length,
   
   _mode = M_unpack;
   _pack_error = false;
-  _unpack_data = data;
-  _unpack_length = length;
+  set_unpack_data(data, length, false);
   _unpack_p = 0;
 
   _root = root;
@@ -173,6 +173,80 @@ end_unpack() {
   return !_pack_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().
+//
+//               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.
+////////////////////////////////////////////////////////////////////
+void DCPacker::
+begin_repack(const char *data, size_t length,
+             const DCPackerInterface *root) {
+  nassertv(_mode == M_idle);
+  
+  _mode = M_repack;
+  _pack_error = false;
+  set_unpack_data(data, length, false);
+  _unpack_p = 0;
+
+  // In repack mode, we immediately get the catalog, since we know
+  // we'll need it.
+  _root = root;
+  _catalog = _root->get_catalog();
+  _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
+
+  // We don't begin at the first field in repack mode.  Instead, you
+  // must explicitly call seek().
+  _current_field = NULL;
+  _current_parent = NULL;
+  _current_field_index = 0;
+  _num_nested_fields = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPacker::end_repack
+//       Access: Published
+//  Description: Finishes the repacking session.
+//
+//               The return value is true on success, or false if
+//               there has been some error during repacking (or if all
+//               fields have not been repacked).
+////////////////////////////////////////////////////////////////////
+bool DCPacker::
+end_repack() {
+  nassertr(_mode == M_repack, false);
+
+  // Put the rest of the data onto the pack stream.
+  _pack_data.append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
+  
+  _mode = M_idle;
+  clear();
+
+  return !_pack_error;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCPacker::seek
 //       Access: Published
@@ -210,7 +284,57 @@ seek(const string &field_name) {
     _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);
+    _unpack_p = _live_catalog->get_begin(entry_index);
+
+    return true;
+
+  } else if (_mode == M_repack) {
+    nassertr(_catalog != (DCPackerCatalog *)NULL, false);
+
+    if (!_stack.empty() || _current_field != (DCPackerInterface *)NULL) {
+      // It is an error to reseek while the stack is nonempty--that
+      // means we haven't finished packing the current field.
+      _pack_error = true;
+      return 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);
+
+    size_t begin = _live_catalog->get_begin(entry_index);
+    if (begin < _unpack_p) {
+      // Whoops, we are seeking fields out-of-order.  That means we
+      // need to write the entire record and start again. 
+      _pack_data.append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
+      size_t length = _pack_data.get_length();
+      char *buffer = _pack_data.take_data();
+      set_unpack_data(buffer, length, true);
+      _unpack_p = 0;
+
+      _catalog->release_live_catalog(_live_catalog);
+      _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
+
+      begin = _live_catalog->get_begin(entry_index);
+    }
+
+    // Now copy the bytes from _unpack_p to begin from the
+    // _unpack_data to the _pack_data.  These are the bytes we just
+    // skipped over with the call to seek().
+    _pack_data.append_data(_unpack_data + _unpack_p, begin - _unpack_p);
+
+    // And set the packer up to pack the indicated field (but no
+    // subsequent fields).
+    _current_field = entry._field;
+    _current_parent = entry._parent;
+    _current_field_index = entry._field_index;
+    _num_nested_fields = 0;  // this makes advance() stop after this field.
+    _unpack_p = _live_catalog->get_end(entry_index);
 
     return true;
   }
@@ -251,13 +375,13 @@ push() {
     int num_nested_fields = _current_parent->get_num_nested_fields();
     size_t length_bytes = _current_parent->get_num_length_bytes();
     
-    if (_mode == M_pack) {
+    if (_mode == M_pack || _mode == M_repack) {
       // Reserve length_bytes for when we figure out what the length
       // is.
       _push_marker = _pack_data.get_length();
       _pack_data.append_junk(length_bytes);
 
-    } else { // _mode == M_unpack
+    } else if (_mode == M_unpack) {
       // Read length_bytes to determine the end of this nested
       // sequence.
       _push_marker = 0;
@@ -289,6 +413,8 @@ push() {
           }
         }
       }
+    } else {
+      _pack_error = true;
     }
 
 
@@ -334,7 +460,7 @@ pop() {
     _pack_error = true;
 
   } else {
-    if (_mode == M_pack) {
+    if (_mode == M_pack || _mode == M_repack) {
       size_t length_bytes = _current_parent->get_num_length_bytes();
       if (length_bytes != 0) {
         // Now go back and fill in the length of the array.
@@ -405,7 +531,7 @@ unpack_skip() {
 ////////////////////////////////////////////////////////////////////
 void DCPacker::
 pack_object(PyObject *object) {
-  nassertv(_mode == M_pack);
+  nassertv(_mode == M_pack || _mode == M_repack);
   PyObject *str = PyObject_Str(object);
   Py_DECREF(str);
 
@@ -685,4 +811,22 @@ 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;
 }

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

@@ -46,6 +46,13 @@ PUBLISHED:
   void begin_unpack(const string &data, 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);
+  bool end_repack();
+
   bool seek(const string &field_name);
 
   INLINE bool has_nested_fields() const;
@@ -96,12 +103,15 @@ public:
 private:
   INLINE void advance();
   void clear();
+  void set_unpack_data(const char *unpack_data, size_t unpack_length, 
+                       bool owns_unpack_data);
 
 private:
   enum Mode {
     M_idle,
     M_pack,
     M_unpack,
+    M_repack,
   };
   Mode _mode;
 
@@ -109,6 +119,7 @@ private:
   string _unpack_str;
   const char *_unpack_data;
   size_t _unpack_length;
+  bool _owns_unpack_data;
   size_t _unpack_p;
 
   const DCPackerInterface *_root;

+ 17 - 3
direct/src/dcparser/dcPackerCatalog.I

@@ -16,16 +16,30 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
 ////////////////////////////////////////////////////////////////////
-//     Function: DCPackerCatalog::LiveCatalog::get_unpack_p
+//     Function: DCPackerCatalog::LiveCatalog::get_begin
 //       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 {
+get_begin(int n) const {
+  nassertr(n >= 0 && n < (int)_live_entries.size(), 0);
+  return _live_entries[n]._begin;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCPackerCatalog::LiveCatalog::get_end
+//       Access: Public
+//  Description: Returns the end of the indicated field (the byte
+//               position of the first following field) within the
+//               live data.
+////////////////////////////////////////////////////////////////////
+INLINE size_t DCPackerCatalog::LiveCatalog::
+get_end(int n) const {
   nassertr(n >= 0 && n < (int)_live_entries.size(), 0);
-  return _live_entries[n];
+  return _live_entries[n]._end;
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -101,8 +101,11 @@ get_live_catalog(const char *data, size_t length) const {
 
   LiveCatalog *live_catalog = new LiveCatalog;
   live_catalog->_live_entries.reserve(_entries.size());
+  LiveCatalogEntry zero_entry;
+  zero_entry._begin = 0;
+  zero_entry._end = 0;
   for (size_t i = 0; i < _entries.size(); i++) {
-    live_catalog->_live_entries.push_back(0);
+    live_catalog->_live_entries.push_back(zero_entry);
   }
   
   DCPacker packer;
@@ -175,7 +178,7 @@ r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const {
 
   int field_index = find_entry_by_field(current_field);
   if (field_index >= 0) {
-    live_catalog->_live_entries[field_index] = packer.get_num_unpacked_bytes();
+    live_catalog->_live_entries[field_index]._begin = packer.get_num_unpacked_bytes();
   }
 
   if (packer.has_nested_fields() && packer.get_pack_type() != PT_string) {
@@ -188,4 +191,8 @@ r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const {
   } else {
     packer.unpack_skip();
   }
+
+  if (field_index >= 0) {
+    live_catalog->_live_entries[field_index]._end = packer.get_num_unpacked_bytes();
+  }
 }

+ 8 - 2
direct/src/dcparser/dcPackerCatalog.h

@@ -52,12 +52,18 @@ public:
   // 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 LiveCatalogEntry {
+  public:
+    size_t _begin;
+    size_t _end;
+  };
   class LiveCatalog {
   public:
-    INLINE size_t get_unpack_p(int n) const;
+    INLINE size_t get_begin(int n) const;
+    INLINE size_t get_end(int n) const;
 
   private:
-    typedef pvector<size_t> LiveEntries;
+    typedef pvector<LiveCatalogEntry> LiveEntries;
     LiveEntries _live_entries;
     friend class DCPackerCatalog;
   };