begin_repack
This commit is contained in:
parent
151636950d
commit
28a42d68b6
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue