From 28a42d68b65d70965f9c9804907dffde73ef14af Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 22 Jun 2004 03:18:01 +0000 Subject: [PATCH] begin_repack --- direct/src/dcparser/dcPackData.I | 25 ++++ direct/src/dcparser/dcPackData.h | 1 + direct/src/dcparser/dcPacker.I | 14 +-- direct/src/dcparser/dcPacker.cxx | 158 ++++++++++++++++++++++-- direct/src/dcparser/dcPacker.h | 11 ++ direct/src/dcparser/dcPackerCatalog.I | 20 ++- direct/src/dcparser/dcPackerCatalog.cxx | 11 +- direct/src/dcparser/dcPackerCatalog.h | 10 +- 8 files changed, 229 insertions(+), 21 deletions(-) diff --git a/direct/src/dcparser/dcPackData.I b/direct/src/dcparser/dcPackData.I index f447ff87bb..2f733949b2 100755 --- a/direct/src/dcparser/dcPackData.I +++ b/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; +} diff --git a/direct/src/dcparser/dcPackData.h b/direct/src/dcparser/dcPackData.h index 14bc9921a3..41abe12615 100755 --- a/direct/src/dcparser/dcPackData.h +++ b/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); diff --git a/direct/src/dcparser/dcPacker.I b/direct/src/dcparser/dcPacker.I index 9ecbd83483..ca349f62ac 100755 --- a/direct/src/dcparser/dcPacker.I +++ b/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 { diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index 8fda7af74c..5d7ce72eb6 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/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; } diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index ce61eaa256..027f17a595 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/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; diff --git a/direct/src/dcparser/dcPackerCatalog.I b/direct/src/dcparser/dcPackerCatalog.I index 5f7c0844fa..5f8dedbef6 100644 --- a/direct/src/dcparser/dcPackerCatalog.I +++ b/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]; + 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]._end; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcPackerCatalog.cxx b/direct/src/dcparser/dcPackerCatalog.cxx index ac1f1cff52..829d3838ee 100644 --- a/direct/src/dcparser/dcPackerCatalog.cxx +++ b/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(); + } } diff --git a/direct/src/dcparser/dcPackerCatalog.h b/direct/src/dcparser/dcPackerCatalog.h index 51f485fcf2..7d9be397d5 100644 --- a/direct/src/dcparser/dcPackerCatalog.h +++ b/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 LiveEntries; + typedef pvector LiveEntries; LiveEntries _live_entries; friend class DCPackerCatalog; };