From 4b15c13cc03f6cbd457d571f0f312339770d299a Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 25 Jun 2004 21:22:16 +0000 Subject: [PATCH] allow serial pack/unpack sessions --- direct/src/dcparser/dcAtomicField.cxx | 3 +- direct/src/dcparser/dcClass.cxx | 93 +++-- direct/src/dcparser/dcClass.h | 15 +- direct/src/dcparser/dcField.cxx | 69 ++-- direct/src/dcparser/dcField.h | 11 +- direct/src/dcparser/dcPackData.I | 10 +- direct/src/dcparser/dcPackData.h | 2 + direct/src/dcparser/dcPacker.I | 471 +++++++++++++++++++++++- direct/src/dcparser/dcPacker.cxx | 129 +++---- direct/src/dcparser/dcPacker.h | 62 +++- direct/src/dcparser/dcPackerCatalog.cxx | 3 +- 11 files changed, 701 insertions(+), 167 deletions(-) diff --git a/direct/src/dcparser/dcAtomicField.cxx b/direct/src/dcparser/dcAtomicField.cxx index 512eb34c84..f43c117f2e 100644 --- a/direct/src/dcparser/dcAtomicField.cxx +++ b/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(); } diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index 51a25b6fb2..617f226361 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/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 diff --git a/direct/src/dcparser/dcClass.h b/direct/src/dcparser/dcClass.h index 6cd17e2a7f..368b06cd7f 100644 --- a/direct/src/dcparser/dcClass.h +++ b/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, diff --git a/direct/src/dcparser/dcField.cxx b/direct/src/dcparser/dcField.cxx index c0880463aa..4c84abdf07 100644 --- a/direct/src/dcparser/dcField.cxx +++ b/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 diff --git a/direct/src/dcparser/dcField.h b/direct/src/dcparser/dcField.h index f4415533c8..d4763ab40d 100644 --- a/direct/src/dcparser/dcField.h +++ b/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: diff --git a/direct/src/dcparser/dcPackData.I b/direct/src/dcparser/dcPackData.I index 2f733949b2..4d5653d05b 100755 --- a/direct/src/dcparser/dcPackData.I +++ b/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. //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcPackData.h b/direct/src/dcparser/dcPackData.h index 41abe12615..4aa8ba9e33 100755 --- a/direct/src/dcparser/dcPackData.h +++ b/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: diff --git a/direct/src/dcparser/dcPacker.I b/direct/src/dcparser/dcPacker.I index ae19fdf929..e675bb73d9 100755 --- a/direct/src/dcparser/dcPacker.I +++ b/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 diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index 2014716e18..7d58adc405 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/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. // -// 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. +// Unlike begin_pack() or begin_unpack() you may not +// concatenate the results of multiple begin_repack() +// sessions in one buffer. +// +// 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 diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 125a927b00..8cb89a221f 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/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; diff --git a/direct/src/dcparser/dcPackerCatalog.cxx b/direct/src/dcparser/dcPackerCatalog.cxx index c4bf6c62e4..c1401ed708 100644 --- a/direct/src/dcparser/dcPackerCatalog.cxx +++ b/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();