begin_repack

This commit is contained in:
David Rose 2004-06-22 03:18:01 +00:00
parent 151636950d
commit 28a42d68b6
8 changed files with 229 additions and 21 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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 {

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
////////////////////////////////////////////////////////////////////

View File

@ -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();
}
}

View File

@ -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;
};