From d61f2fcfa49ecf067abb1eb1f892df2c73378a42 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 21 Jun 2004 23:51:59 +0000 Subject: [PATCH] add unpack seeking --- direct/src/dcparser/Sources.pp | 2 + direct/src/dcparser/dcAtomicField.cxx | 6 + direct/src/dcparser/dcClass.cxx | 12 +- direct/src/dcparser/dcClass.h | 5 +- direct/src/dcparser/dcClassParameter.cxx | 11 ++ direct/src/dcparser/dcField.cxx | 5 +- direct/src/dcparser/dcMolecularField.cxx | 11 +- direct/src/dcparser/dcPacker.I | 28 +++ direct/src/dcparser/dcPacker.cxx | 152 ++++++++++++++-- direct/src/dcparser/dcPacker.h | 11 ++ direct/src/dcparser/dcPackerCatalog.I | 50 +++++ direct/src/dcparser/dcPackerCatalog.cxx | 191 ++++++++++++++++++++ direct/src/dcparser/dcPackerCatalog.h | 95 ++++++++++ direct/src/dcparser/dcPackerInterface.I | 124 ++++++++++++- direct/src/dcparser/dcPackerInterface.cxx | 184 +++++++++---------- direct/src/dcparser/dcPackerInterface.h | 46 +++-- direct/src/dcparser/dcSimpleParameter.cxx | 188 +++++++++++++------ direct/src/dcparser/dcSimpleParameter.h | 1 + direct/src/dcparser/dcparser_composite1.cxx | 1 + 19 files changed, 923 insertions(+), 200 deletions(-) create mode 100644 direct/src/dcparser/dcPackerCatalog.I create mode 100644 direct/src/dcparser/dcPackerCatalog.cxx create mode 100644 direct/src/dcparser/dcPackerCatalog.h diff --git a/direct/src/dcparser/Sources.pp b/direct/src/dcparser/Sources.pp index 5cf286ec16..3e1fedce34 100644 --- a/direct/src/dcparser/Sources.pp +++ b/direct/src/dcparser/Sources.pp @@ -22,6 +22,7 @@ dcSubatomicType.h \ dcPackData.h dcPackData.I \ dcPacker.h dcPacker.I \ + dcPackerCatalog.h dcPackerCatalog.I \ dcPackerInterface.h dcPackerInterface.I \ dcParameter.h dcClassParameter.h dcArrayParameter.h dcSimpleParameter.h \ dcTypedef.h \ @@ -35,6 +36,7 @@ dcMolecularField.cxx dcSubatomicType.cxx \ dcPackData.cxx \ dcPacker.cxx \ + dcPackerCatalog.cxx \ dcPackerInterface.cxx \ dcParameter.cxx dcClassParameter.cxx \ dcArrayParameter.cxx dcSimpleParameter.cxx \ diff --git a/direct/src/dcparser/dcAtomicField.cxx b/direct/src/dcparser/dcAtomicField.cxx index b1385c4399..aecbe2a49b 100644 --- a/direct/src/dcparser/dcAtomicField.cxx +++ b/direct/src/dcparser/dcAtomicField.cxx @@ -444,6 +444,12 @@ void DCAtomicField:: add_element(const DCAtomicField::ElementType &element) { _elements.push_back(element); _num_nested_fields = (int)_elements.size(); + + // See if we still have a fixed byte size. + if (_has_fixed_byte_size) { + _has_fixed_byte_size = element._param->has_fixed_byte_size(); + _fixed_byte_size += element._param->get_fixed_byte_size(); + } } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index 75ff704bfd..309581cb83 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/direct/src/dcparser/dcClass.cxx @@ -22,6 +22,16 @@ #include "dcindent.h" #include "dcmsgtypes.h" +//////////////////////////////////////////////////////////////////// +// Function: DCClass::get_name +// Access: Published +// Description: Returns the name of this class. +//////////////////////////////////////////////////////////////////// +const string &DCClass:: +get_name() const { + return _name; +} + //////////////////////////////////////////////////////////////////// // Function: DCClass::get_number // Access: Published @@ -628,7 +638,7 @@ ai_format_generate(PyObject *distobj, int do_id, //////////////////////////////////////////////////////////////////// DCClass:: DCClass(const string &name, bool is_struct, bool bogus_class) : - DCPackerInterface(name), + _name(name), _is_struct(is_struct), _bogus_class(bogus_class) { diff --git a/direct/src/dcparser/dcClass.h b/direct/src/dcparser/dcClass.h index f66258eb6d..0d1b20d146 100644 --- a/direct/src/dcparser/dcClass.h +++ b/direct/src/dcparser/dcClass.h @@ -21,7 +21,6 @@ #include "dcbase.h" #include "dcField.h" -#include "dcPackerInterface.h" #include "dcDeclaration.h" class HashGenerator; @@ -32,8 +31,9 @@ class DCParameter; // Description : Defines a particular DistributedClass as read from an // input .dc file. //////////////////////////////////////////////////////////////////// -class EXPCL_DIRECT DCClass : public DCPackerInterface, public DCDeclaration { +class EXPCL_DIRECT DCClass : public DCDeclaration { PUBLISHED: + const string &get_name() const; int get_number() const; bool has_parent() const; @@ -94,6 +94,7 @@ public: void set_number(int number); private: + string _name; bool _is_struct; bool _bogus_class; int _number; diff --git a/direct/src/dcparser/dcClassParameter.cxx b/direct/src/dcparser/dcClassParameter.cxx index 1840c46caa..781d9f96a6 100644 --- a/direct/src/dcparser/dcClassParameter.cxx +++ b/direct/src/dcparser/dcClassParameter.cxx @@ -35,6 +35,17 @@ DCClassParameter(DCClass *dclass) : _num_fields = _dclass->get_num_inherited_fields(); _num_nested_fields = _num_fields + _dclass->get_num_inherited_parameters(); _pack_type = PT_class; + + // If all of the nested fields have a fixed byte size, then so does + // the class (and its byte size is the sum of all of the nested + // fields). + _has_fixed_byte_size = true; + _fixed_byte_size = 0; + for (int i = 0; i < _num_nested_fields && _has_fixed_byte_size; i++) { + DCPackerInterface *field = get_nested_field(i); + _has_fixed_byte_size = field->has_fixed_byte_size(); + _fixed_byte_size += field->get_fixed_byte_size(); + } } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcField.cxx b/direct/src/dcparser/dcField.cxx index dba12f1454..365bc413d1 100644 --- a/direct/src/dcparser/dcField.cxx +++ b/direct/src/dcparser/dcField.cxx @@ -130,7 +130,7 @@ pack_args(Datagram &datagram, PyObject *sequence) const { PyObject *str = PyObject_Str(tuple); ostringstream strm; - strm << "Incorrect arguments to field: " << get_name() + strm << "Incorrect arguments or value too large on field: " << get_name() << PyString_AsString(str); Py_DECREF(str); @@ -257,6 +257,9 @@ DCField(const string &name) : DCPackerInterface(name) { _has_nested_fields = true; _num_nested_fields = 0; _pack_type = PT_field; + + _has_fixed_byte_size = true; + _fixed_byte_size = 0; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcMolecularField.cxx b/direct/src/dcparser/dcMolecularField.cxx index 1812030c5a..62fee1e7db 100644 --- a/direct/src/dcparser/dcMolecularField.cxx +++ b/direct/src/dcparser/dcMolecularField.cxx @@ -75,7 +75,10 @@ DCMolecularField(const string &name) : DCField(name) { // Description: Adds the indicated atomic field to the end of the // list of atomic fields that make up the molecular // field. This is normally called only during parsing -// of the dc file. +// of the dc file. The atomic field should be fully +// defined by this point; you should not modify the +// atomic field (e.g. by adding more elements) after +// adding it to a molecular field. //////////////////////////////////////////////////////////////////// void DCMolecularField:: add_atomic(DCAtomicField *atomic) { @@ -87,6 +90,12 @@ add_atomic(DCAtomicField *atomic) { } _num_nested_fields = _nested_fields.size(); + + // See if we still have a fixed byte size. + if (_has_fixed_byte_size) { + _has_fixed_byte_size = atomic->has_fixed_byte_size(); + _fixed_byte_size += atomic->get_fixed_byte_size(); + } } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcPacker.I b/direct/src/dcparser/dcPacker.I index 2ec2b45e8c..9ecbd83483 100755 --- a/direct/src/dcparser/dcPacker.I +++ b/direct/src/dcparser/dcPacker.I @@ -63,6 +63,19 @@ more_nested_fields() const { return (_current_field != (DCPackerInterface *)NULL); } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::get_current_field +// Access: Published +// Description: Returns the field that will be referenced by the next +// call to pack_*() or unpack_*(). This will be NULL if +// we have unpacked (or packed) all fields, or if it is +// time to call pop(). +//////////////////////////////////////////////////////////////////// +INLINE const DCPackerInterface *DCPacker:: +get_current_field() const { + return _current_field; +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::get_pack_type // Access: Published @@ -355,6 +368,21 @@ unpack_string() { return value; } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_literal_value +// Access: Published +// Description: Returns the literal string that represents the packed +// value of the current field, and advances the field +// pointer. +//////////////////////////////////////////////////////////////////// +INLINE string DCPacker:: +unpack_literal_value() { + size_t start = _unpack_p; + unpack_skip(); + nassertr(_unpack_p >= start, string()); + return string(_unpack_data + start, _unpack_p - start); +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::had_pack_error // Access: Published diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index bc54f8111e..8fda7af74c 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/direct/src/dcparser/dcPacker.cxx @@ -31,6 +31,9 @@ DCPacker() { _unpack_data = NULL; _unpack_length = 0; _unpack_p = 0; + _root = NULL; + _catalog = NULL; + _live_catalog = NULL; _current_field = NULL; _current_parent = NULL; _current_field_index = 0; @@ -45,6 +48,7 @@ DCPacker() { //////////////////////////////////////////////////////////////////// DCPacker:: ~DCPacker() { + clear(); } //////////////////////////////////////////////////////////////////// @@ -62,7 +66,10 @@ begin_pack(const DCPackerInterface *root) { _pack_error = false; _pack_data.clear(); - _stack.clear(); + _root = root; + _catalog = NULL; + _live_catalog = NULL; + _current_field = root; _current_parent = NULL; _current_field_index = 0; @@ -85,13 +92,10 @@ end_pack() { if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) { _pack_error = true; - _stack.clear(); - _current_field = NULL; - _current_parent = NULL; - _current_field_index = 0; - _num_nested_fields = 0; } + clear(); + return !_pack_error; } @@ -127,7 +131,10 @@ begin_unpack(const char *data, size_t length, _unpack_length = length; _unpack_p = 0; - _stack.clear(); + _root = root; + _catalog = NULL; + _live_catalog = NULL; + _current_field = root; _current_parent = NULL; _current_field_index = 0; @@ -140,7 +147,8 @@ begin_unpack(const char *data, size_t length, // Description: Finishes the unpacking session. // // The return value is true on success, or false if -// there has been some error during unpacking. +// there has been some error during unpacking (or if all +// fields have not been unpacked). //////////////////////////////////////////////////////////////////// bool DCPacker:: end_unpack() { @@ -149,17 +157,69 @@ end_unpack() { _mode = M_idle; if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) { - _pack_error = true; - _stack.clear(); - _current_field = NULL; - _current_parent = NULL; - _current_field_index = 0; - _num_nested_fields = 0; + // This happens if we have not unpacked all of the fields. + // However, this is not an error if we have called seek() during + // the unpack session (in which case the _catalog will be + // non-NULL). On the other hand, if the catalog is still NULL, + // then we have never called seek() and it is an error not to + // unpack all values. + if (_catalog == (DCPackerCatalog *)NULL) { + _pack_error = true; + } } + clear(); + return !_pack_error; } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::seek +// Access: Published +// Description: Sets the current unpack (or repack) position to the +// named field. In unpack mode, the next call to +// unpack_*() or push() will begin to read the named +// field. In repack mode, the next call to pack_*() or +// push() will modify the named field. +// +// Returns true if successful, false if the field is not +// known (or if the packer is in an invalid mode). +//////////////////////////////////////////////////////////////////// +bool DCPacker:: +seek(const string &field_name) { + if (_mode == M_unpack) { + if (_catalog == (DCPackerCatalog *)NULL) { + _catalog = _root->get_catalog(); + _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length); + } + nassertr(_catalog != (DCPackerCatalog *)NULL, 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); + + // If we are seeking, we don't need to remember our current stack + // position. + _stack.clear(); + _current_field = entry._field; + _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); + + return true; + } + + // Invalid mode. + _pack_error = true; + return false; +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::push // Access: Published @@ -281,10 +341,12 @@ pop() { size_t length = _pack_data.get_length() - _push_marker - length_bytes; if (length_bytes == 4) { DCPackerInterface::do_pack_uint32 - (_pack_data.get_rewrite_pointer(_push_marker, 4), length); + (_pack_data.get_rewrite_pointer(_push_marker, 4), length, + _pack_error); } else { DCPackerInterface::do_pack_uint16 - (_pack_data.get_rewrite_pointer(_push_marker, 2), length); + (_pack_data.get_rewrite_pointer(_push_marker, 2), length, + _pack_error); } } } @@ -300,6 +362,37 @@ pop() { advance(); } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_skip +// Access: Published +// Description: Skips the current field without unpacking it and +// advances to the next field. +//////////////////////////////////////////////////////////////////// +INLINE void DCPacker:: +unpack_skip() { + nassertv(_mode == M_unpack); + if (_current_field == NULL) { + _pack_error = true; + + } else if (_current_field->has_fixed_byte_size()) { + _unpack_p += _current_field->get_fixed_byte_size(); + advance(); + + } else { + if (_current_field->unpack_skip(_unpack_data, _unpack_length, _unpack_p)) { + advance(); + + } else { + // If the single field couldn't be skipped, try skipping nested fields. + push(); + while (more_nested_fields()) { + unpack_skip(); + } + pop(); + } + } +} + #ifdef HAVE_PYTHON //////////////////////////////////////////////////////////////////// // Function: DCPacker::pack_object @@ -363,6 +456,11 @@ unpack_object() { DCPackType pack_type = get_pack_type(); switch (pack_type) { + case PT_invalid: + object = Py_None; + unpack_skip(); + break; + case PT_double: { double value = unpack_double(); @@ -566,3 +664,25 @@ unpack_and_format(ostream &out) { break; } } + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::clear +// Access: Private +// Description: Resets the data structures after a pack or unpack +// sequence. +//////////////////////////////////////////////////////////////////// +void DCPacker:: +clear() { + _stack.clear(); + _current_field = NULL; + _current_parent = NULL; + _current_field_index = 0; + _num_nested_fields = 0; + + if (_live_catalog != (DCPackerCatalog::LiveCatalog *)NULL) { + _catalog->release_live_catalog(_live_catalog); + _live_catalog = NULL; + } + _catalog = NULL; + _root = NULL; +} diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 62f98c0d74..ce61eaa256 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -23,6 +23,7 @@ #include "dcPackerInterface.h" #include "dcSubatomicType.h" #include "dcPackData.h" +#include "dcPackerCatalog.h" //////////////////////////////////////////////////////////////////// // Class : DCPacker @@ -45,10 +46,13 @@ PUBLISHED: void begin_unpack(const string &data, const DCPackerInterface *root); bool end_unpack(); + bool seek(const string &field_name); + INLINE bool has_nested_fields() const; INLINE int get_num_nested_fields() const; INLINE bool more_nested_fields() const; + INLINE const DCPackerInterface *get_current_field() const; INLINE DCPackType get_pack_type() const; void push(); @@ -68,6 +72,8 @@ PUBLISHED: INLINE PN_int64 unpack_int64(); INLINE PN_uint64 unpack_uint64(); INLINE string unpack_string(); + INLINE string unpack_literal_value(); + void unpack_skip(); #ifdef HAVE_PYTHON void pack_object(PyObject *object); @@ -89,6 +95,7 @@ public: private: INLINE void advance(); + void clear(); private: enum Mode { @@ -104,6 +111,10 @@ private: size_t _unpack_length; size_t _unpack_p; + const DCPackerInterface *_root; + const DCPackerCatalog *_catalog; + const DCPackerCatalog::LiveCatalog *_live_catalog; + class StackElement { public: const DCPackerInterface *_current_parent; diff --git a/direct/src/dcparser/dcPackerCatalog.I b/direct/src/dcparser/dcPackerCatalog.I new file mode 100644 index 0000000000..5f7c0844fa --- /dev/null +++ b/direct/src/dcparser/dcPackerCatalog.I @@ -0,0 +1,50 @@ +// Filename: dcPackerCatalog.I +// Created by: drose (21Jun04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::LiveCatalog::get_unpack_p +// 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 { + nassertr(n >= 0 && n < (int)_live_entries.size(), 0); + return _live_entries[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::get_num_entries +// Access: Public +// Description: Returns the number of entries in the catalog. +//////////////////////////////////////////////////////////////////// +INLINE int DCPackerCatalog:: +get_num_entries() const { + return _entries.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::get_entry +// Access: Public +// Description: Returns the nth entry in the catalog. +//////////////////////////////////////////////////////////////////// +INLINE const DCPackerCatalog::Entry &DCPackerCatalog:: +get_entry(int n) const { + nassertr(n >= 0 && n < (int)_entries.size(), _entries[0]); + return _entries[n]; +} diff --git a/direct/src/dcparser/dcPackerCatalog.cxx b/direct/src/dcparser/dcPackerCatalog.cxx new file mode 100644 index 0000000000..ac1f1cff52 --- /dev/null +++ b/direct/src/dcparser/dcPackerCatalog.cxx @@ -0,0 +1,191 @@ +// Filename: dcPackerCatalog.cxx +// Created by: drose (21Jun04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "dcPackerCatalog.h" +#include "dcPackerInterface.h" +#include "dcPacker.h" + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::Constructor +// Access: Private +// Description: The catalog is created only by +// DCPackerInterface::get_catalog(). +//////////////////////////////////////////////////////////////////// +DCPackerCatalog:: +DCPackerCatalog(const DCPackerInterface *root) : _root(root) { + _live_catalog = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::Destructor +// Access: Private +// Description: The catalog is destroyed only by +// ~DCPackerInterface(). +//////////////////////////////////////////////////////////////////// +DCPackerCatalog:: +~DCPackerCatalog() { + if (_live_catalog != (LiveCatalog *)NULL) { + delete _live_catalog; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::find_entry_by_name +// Access: Public +// Description: Returns the index number of the entry with the +// indicated name, or -1 if no entry has the indicated +// name. The return value is suitable for passing to +// get_entry(). +//////////////////////////////////////////////////////////////////// +int DCPackerCatalog:: +find_entry_by_name(const string &name) const { + EntriesByName::const_iterator ni; + ni = _entries_by_name.find(name); + if (ni != _entries_by_name.end()) { + return (*ni).second; + } + return -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::find_entry_by_field +// Access: Public +// Description: Returns the index number of the entry with the +// indicated field, or -1 if no entry has the indicated +// field. The return value is suitable for passing to +// get_entry(). +//////////////////////////////////////////////////////////////////// +int DCPackerCatalog:: +find_entry_by_field(const DCPackerInterface *field) const { + EntriesByField::const_iterator ni; + ni = _entries_by_field.find(field); + if (ni != _entries_by_field.end()) { + return (*ni).second; + } + return -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::get_live_catalog +// Access: Public +// Description: Returns a LiveCatalog object indicating the positions +// within the indicated data record of each field within +// the catalog. If the catalog's fields are all +// fixed-width, this may return a statically-allocated +// LiveCatalog object that is the same for all data +// records; otherwise, it will allocate a new +// LiveCatalog object that must be freed with a later +// call to release_live_catalog(). +//////////////////////////////////////////////////////////////////// +const DCPackerCatalog::LiveCatalog *DCPackerCatalog:: +get_live_catalog(const char *data, size_t length) const { + if (_live_catalog != (LiveCatalog *)NULL) { + // Return the previously-allocated static catalog. + return _live_catalog; + } + + LiveCatalog *live_catalog = new LiveCatalog; + live_catalog->_live_entries.reserve(_entries.size()); + for (size_t i = 0; i < _entries.size(); i++) { + live_catalog->_live_entries.push_back(0); + } + + DCPacker packer; + packer.begin_unpack(data, length, _root); + r_fill_live_catalog(live_catalog, packer); + bool okflag = packer.end_unpack(); + + nassertr(okflag, live_catalog); + + if (_root->has_fixed_byte_size()) { + // If our root field has a fixed byte size, then the live catalog + // will always be the same every time, so we might as well keep + // this one around as an optimization. + ((DCPackerCatalog *)this)->_live_catalog = live_catalog; + } + + return live_catalog; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::release_live_catalog +// Access: Public +// Description: Releases the LiveCatalog object that was returned by +// an earlier call to get_live_catalog(). If this +// represents a newly-allocated live catalog, it will +// free it; otherwise, it will do nothing. +// +// It is therefore always correct (and necessary) to +// match a call to get_live_catalog() with a later call +// to release_live_catalog(). +//////////////////////////////////////////////////////////////////// +void DCPackerCatalog:: +release_live_catalog(const DCPackerCatalog::LiveCatalog *live_catalog) const { + if (live_catalog != _live_catalog) { + delete (LiveCatalog *)live_catalog; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::add_entry +// Access: Private +// Description: Called only by DCPackerInterface::r_fill_catalog(), +// this adds a new entry to the catalog. +//////////////////////////////////////////////////////////////////// +void DCPackerCatalog:: +add_entry(const string &name, const DCPackerInterface *field, + const DCPackerInterface *parent, int field_index) { + Entry entry; + entry._name = name; + entry._field = field; + entry._parent = parent; + entry._field_index = field_index; + + int entry_index = (int)_entries.size(); + _entries.push_back(entry); + _entries_by_name.insert(EntriesByName::value_type(name, entry_index)); + _entries_by_field.insert(EntriesByField::value_type(field, entry_index)); +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerCatalog::r_fill_live_catalog +// Access: Private +// Description: Recursively walks through all of the fields on the +// catalog and fills the live catalog with the +// appropriate offsets. +//////////////////////////////////////////////////////////////////// +void DCPackerCatalog:: +r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const { + const DCPackerInterface *current_field = packer.get_current_field(); + + int field_index = find_entry_by_field(current_field); + if (field_index >= 0) { + live_catalog->_live_entries[field_index] = packer.get_num_unpacked_bytes(); + } + + if (packer.has_nested_fields() && packer.get_pack_type() != PT_string) { + packer.push(); + while (packer.more_nested_fields()) { + r_fill_live_catalog(live_catalog, packer); + } + packer.pop(); + + } else { + packer.unpack_skip(); + } +} diff --git a/direct/src/dcparser/dcPackerCatalog.h b/direct/src/dcparser/dcPackerCatalog.h new file mode 100644 index 0000000000..51f485fcf2 --- /dev/null +++ b/direct/src/dcparser/dcPackerCatalog.h @@ -0,0 +1,95 @@ +// Filename: dcPackerCatalog.h +// Created by: drose (21Jun04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DCPACKERCATALOG_H +#define DCPACKERCATALOG_H + +#include "dcbase.h" + +class DCPackerInterface; +class DCPacker; + +//////////////////////////////////////////////////////////////////// +// Class : DCPackerCatalog +// Description : This object contains the names of all of the nested +// fields available within a particular field. It is +// created on demand when a catalog is first requested +// from a particular field; its ownership is retained by +// the field so it must not be deleted. +//////////////////////////////////////////////////////////////////// +class EXPCL_DIRECT DCPackerCatalog { +private: + DCPackerCatalog(const DCPackerInterface *root); + ~DCPackerCatalog(); + +public: + // The Entry class records the static catalog data: the name of each + // field and its relationship to its parent. + class Entry { + public: + string _name; + const DCPackerInterface *_field; + const DCPackerInterface *_parent; + int _field_index; + }; + + // The LiveCatalog class adds the dynamic catalog data: the actual + // 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 LiveCatalog { + public: + INLINE size_t get_unpack_p(int n) const; + + private: + typedef pvector LiveEntries; + LiveEntries _live_entries; + friend class DCPackerCatalog; + }; + + INLINE int get_num_entries() const; + INLINE const Entry &get_entry(int n) const; + int find_entry_by_name(const string &name) const; + int find_entry_by_field(const DCPackerInterface *field) const; + + const LiveCatalog *get_live_catalog(const char *data, size_t length) const; + void release_live_catalog(const LiveCatalog *live_catalog) const; + +private: + void add_entry(const string &name, const DCPackerInterface *field, + const DCPackerInterface *parent, int field_index); + void r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const; + + const DCPackerInterface *_root; + LiveCatalog *_live_catalog; + + typedef pvector Entries; + Entries _entries; + + typedef pmap EntriesByName; + EntriesByName _entries_by_name; + + typedef pmap EntriesByField; + EntriesByField _entries_by_field; + + friend class DCPackerInterface; +}; + +#include "dcPackerCatalog.I" + +#endif diff --git a/direct/src/dcparser/dcPackerInterface.I b/direct/src/dcparser/dcPackerInterface.I index 891ac1866e..c4f7e08c40 100644 --- a/direct/src/dcparser/dcPackerInterface.I +++ b/direct/src/dcparser/dcPackerInterface.I @@ -17,14 +17,111 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_name +// Access: Published +// Description: Returns the name of this field, or empty string +// if the field is unnamed. +//////////////////////////////////////////////////////////////////// +INLINE const string &DCPackerInterface:: +get_name() const { + return _name; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::set_name +// Access: Public +// Description: Sets the name of this field. +//////////////////////////////////////////////////////////////////// +INLINE void DCPackerInterface:: +set_name(const string &name) { + _name = name; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::has_fixed_byte_size +// Access: Public +// Description: Returns true if this field type always packs to the +// same number of bytes, false if it is variable. +//////////////////////////////////////////////////////////////////// +INLINE bool DCPackerInterface:: +has_fixed_byte_size() const { + return _has_fixed_byte_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_fixed_byte_size +// Access: Public +// Description: If has_fixed_byte_size() returns true, this returns +// the number of bytes this field type will use. +//////////////////////////////////////////////////////////////////// +INLINE size_t DCPackerInterface:: +get_fixed_byte_size() const { + return _fixed_byte_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_num_length_bytes +// Access: Public +// Description: Returns the number of bytes that should be written +// into the stream on a push() to record the number of +// bytes in the record up until the next pop(). This is +// only meaningful if _has_nested_fields is true. +//////////////////////////////////////////////////////////////////// +INLINE size_t DCPackerInterface:: +get_num_length_bytes() const { + return _num_length_bytes; +} + + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::has_nested_fields +// Access: Public +// Description: Returns true if this field type has any nested fields +// (and thus expects a push() .. pop() interface to the +// DCPacker), or false otherwise. If this returns true, +// get_num_nested_fields() may be called to determine +// how many nested fields are expected. +//////////////////////////////////////////////////////////////////// +INLINE bool DCPackerInterface:: +has_nested_fields() const { + return _has_nested_fields; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_num_nested_fields +// Access: Public +// Description: Returns the number of nested fields required by this +// field type. These may be array elements or structure +// elements. The return value may be -1 to indicate the +// number of nested fields is variable. +//////////////////////////////////////////////////////////////////// +INLINE int DCPackerInterface:: +get_num_nested_fields() const { + return _num_nested_fields; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_pack_type +// Access: Public +// Description: Returns the type of value expected by this field. +//////////////////////////////////////////////////////////////////// +INLINE DCPackType DCPackerInterface:: +get_pack_type() const { + return _pack_type; +} + //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::do_pack_int8 // Access: Public, Static // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_int8(char *buffer, int value) { +do_pack_int8(char *buffer, int value, bool &pack_error) { buffer[0] = (char)(value & 0xff); + if ((abs(value) & ~0xff) != 0) { + pack_error = true; + } } //////////////////////////////////////////////////////////////////// @@ -33,9 +130,12 @@ do_pack_int8(char *buffer, int value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_int16(char *buffer, int value) { +do_pack_int16(char *buffer, int value, bool &pack_error) { buffer[0] = (char)(value & 0xff); buffer[1] = (char)((value >> 8) & 0xff); + if ((abs(value) & ~0xffff) != 0) { + pack_error = true; + } } //////////////////////////////////////////////////////////////////// @@ -44,7 +144,7 @@ do_pack_int16(char *buffer, int value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_int32(char *buffer, int value) { +do_pack_int32(char *buffer, int value, bool &) { buffer[0] = (char)(value & 0xff); buffer[1] = (char)((value >> 8) & 0xff); buffer[2] = (char)((value >> 16) & 0xff); @@ -57,7 +157,7 @@ do_pack_int32(char *buffer, int value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_int64(char *buffer, PN_int64 value) { +do_pack_int64(char *buffer, PN_int64 value, bool &) { buffer[0] = (char)(value & 0xff); buffer[1] = (char)((value >> 8) & 0xff); buffer[2] = (char)((value >> 16) & 0xff); @@ -74,8 +174,11 @@ do_pack_int64(char *buffer, PN_int64 value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_uint8(char *buffer, unsigned int value) { +do_pack_uint8(char *buffer, unsigned int value, bool &pack_error) { buffer[0] = (char)(value & 0xff); + if ((value & ~0xff) != 0) { + pack_error = true; + } } //////////////////////////////////////////////////////////////////// @@ -84,9 +187,12 @@ do_pack_uint8(char *buffer, unsigned int value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_uint16(char *buffer, unsigned int value) { +do_pack_uint16(char *buffer, unsigned int value, bool &pack_error) { buffer[0] = (char)(value & 0xff); buffer[1] = (char)((value >> 8) & 0xff); + if ((value & ~0xffff) != 0) { + pack_error = true; + } } //////////////////////////////////////////////////////////////////// @@ -95,7 +201,7 @@ do_pack_uint16(char *buffer, unsigned int value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_uint32(char *buffer, unsigned int value) { +do_pack_uint32(char *buffer, unsigned int value, bool &) { buffer[0] = (char)(value & 0xff); buffer[1] = (char)((value >> 8) & 0xff); buffer[2] = (char)((value >> 16) & 0xff); @@ -108,7 +214,7 @@ do_pack_uint32(char *buffer, unsigned int value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_uint64(char *buffer, PN_uint64 value) { +do_pack_uint64(char *buffer, PN_uint64 value, bool &) { buffer[0] = (char)(value & 0xff); buffer[1] = (char)((value >> 8) & 0xff); buffer[2] = (char)((value >> 16) & 0xff); @@ -125,7 +231,7 @@ do_pack_uint64(char *buffer, PN_uint64 value) { // Description: //////////////////////////////////////////////////////////////////// INLINE void DCPackerInterface:: -do_pack_float64(char *buffer, double value) { +do_pack_float64(char *buffer, double value, bool &) { #ifdef WORDS_BIGENDIAN // Reverse the byte ordering for big-endian machines. char *p = (char *)value; diff --git a/direct/src/dcparser/dcPackerInterface.cxx b/direct/src/dcparser/dcPackerInterface.cxx index f131caec6d..5344b5df26 100755 --- a/direct/src/dcparser/dcPackerInterface.cxx +++ b/direct/src/dcparser/dcPackerInterface.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "dcPackerInterface.h" +#include "dcPackerCatalog.h" //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::Constructor @@ -33,6 +34,7 @@ DCPackerInterface(const string &name) : _has_nested_fields = false; _num_nested_fields = -1; _pack_type = PT_invalid; + _catalog = NULL; } //////////////////////////////////////////////////////////////////// @@ -50,6 +52,7 @@ DCPackerInterface(const DCPackerInterface ©) : _num_nested_fields(copy._num_nested_fields), _pack_type(copy._pack_type) { + _catalog = NULL; } //////////////////////////////////////////////////////////////////// @@ -59,90 +62,9 @@ DCPackerInterface(const DCPackerInterface ©) : //////////////////////////////////////////////////////////////////// DCPackerInterface:: ~DCPackerInterface() { -} - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::get_name -// Access: Published -// Description: Returns the name of this field, or empty string -// if the field is unnamed. -//////////////////////////////////////////////////////////////////// -const string &DCPackerInterface:: -get_name() const { - return _name; -} - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::set_name -// Access: Published -// Description: Sets the name of this field. -//////////////////////////////////////////////////////////////////// -void DCPackerInterface:: -set_name(const string &name) { - _name = name; -} - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::has_fixed_byte_size -// Access: Public -// Description: Returns true if this field type always packs to the -// same number of bytes, false if it is variable. -//////////////////////////////////////////////////////////////////// -bool DCPackerInterface:: -has_fixed_byte_size() const { - return _has_fixed_byte_size; -} - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::get_fixed_byte_size -// Access: Public -// Description: If has_fixed_byte_size() returns true, this returns -// the number of bytes this field type will use. -//////////////////////////////////////////////////////////////////// -size_t DCPackerInterface:: -get_fixed_byte_size() const { - return _fixed_byte_size; -} - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::get_num_length_bytes -// Access: Public -// Description: Returns the number of bytes that should be written -// into the stream on a push() to record the number of -// bytes in the record up until the next pop(). This is -// only meaningful if _has_nested_fields is true. -//////////////////////////////////////////////////////////////////// -size_t DCPackerInterface:: -get_num_length_bytes() const { - return _num_length_bytes; -} - - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::has_nested_fields -// Access: Public -// Description: Returns true if this field type has any nested fields -// (and thus expects a push() .. pop() interface to the -// DCPacker), or false otherwise. If this returns true, -// get_num_nested_fields() may be called to determine -// how many nested fields are expected. -//////////////////////////////////////////////////////////////////// -bool DCPackerInterface:: -has_nested_fields() const { - return _has_nested_fields; -} - -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::get_num_nested_fields -// Access: Public -// Description: Returns the number of nested fields required by this -// field type. These may be array elements or structure -// elements. The return value may be -1 to indicate the -// number of nested fields is variable. -//////////////////////////////////////////////////////////////////// -int DCPackerInterface:: -get_num_nested_fields() const { - return _num_nested_fields; + if (_catalog != (DCPackerCatalog *)NULL) { + delete _catalog; + } } //////////////////////////////////////////////////////////////////// @@ -173,16 +95,6 @@ get_nested_field(int n) const { return NULL; } -//////////////////////////////////////////////////////////////////// -// Function: DCPackerInterface::get_pack_type -// Access: Public -// Description: Returns the type of value expected by this field. -//////////////////////////////////////////////////////////////////// -DCPackType DCPackerInterface:: -get_pack_type() const { - return _pack_type; -} - //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::pack_double // Access: Public, Virtual @@ -314,3 +226,87 @@ bool DCPackerInterface:: unpack_string(const char *, size_t, size_t &, string &) const { return false; } + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::unpack_skip +// Access: Public, Virtual +// Description: Increments p to the end of the current field without +// actually unpacking any data. Returns true on +// success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCPackerInterface:: +unpack_skip(const char *, size_t, size_t &) const { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::get_catalog +// Access: Public +// Description: Returns the DCPackerCatalog associated with this +// field, listing all of the nested fields by name. +//////////////////////////////////////////////////////////////////// +const DCPackerCatalog *DCPackerInterface:: +get_catalog() const { + if (_catalog == (DCPackerCatalog *)NULL) { + ((DCPackerInterface *)this)->make_catalog(); + } + return _catalog; +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::make_catalog +// Access: Private +// Description: Called internally to create a new DCPackerCatalog +// object. +//////////////////////////////////////////////////////////////////// +void DCPackerInterface:: +make_catalog() { + nassertv(_catalog == (DCPackerCatalog *)NULL); + _catalog = new DCPackerCatalog(this); + + if (has_nested_fields()) { + int num_nested = get_num_nested_fields(); + // num_nested might be -1, indicating there are a dynamic number + // of fields (e.g. an array). But in that case, none of the + // fields will be named anyway, so we don't care about them, so + // it's ok that the following loop will not visit any fields. + for (int i = 0; i < num_nested; i++) { + DCPackerInterface *nested = get_nested_field(i); + if (nested != (DCPackerInterface *)NULL) { + nested->r_fill_catalog(_catalog, "", this, i); + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::r_fill_catalog +// Access: Private +// Description: Called internally to recursively fill up the new +// DCPackerCatalog object. +//////////////////////////////////////////////////////////////////// +void DCPackerInterface:: +r_fill_catalog(DCPackerCatalog *catalog, const string &name_prefix, + DCPackerInterface *parent, int field_index) { + string next_name_prefix = name_prefix; + + if (!get_name().empty()) { + // Record this entry in the catalog. + next_name_prefix += get_name(); + catalog->add_entry(next_name_prefix, this, parent, field_index); + + next_name_prefix += "."; + } + + // Add any children. + if (has_nested_fields()) { + int num_nested = get_num_nested_fields(); + // As above, it's ok if num_nested is -1. + for (int i = 0; i < num_nested; i++) { + DCPackerInterface *nested = get_nested_field(i); + if (nested != (DCPackerInterface *)NULL) { + nested->r_fill_catalog(catalog, next_name_prefix, this, i); + } + } + } +} diff --git a/direct/src/dcparser/dcPackerInterface.h b/direct/src/dcparser/dcPackerInterface.h index 572ec99e15..ea903c06b7 100755 --- a/direct/src/dcparser/dcPackerInterface.h +++ b/direct/src/dcparser/dcPackerInterface.h @@ -23,6 +23,7 @@ #include "dcSubatomicType.h" class DCPackData; +class DCPackerCatalog; BEGIN_PUBLISH // This enumerated type is returned by get_pack_type() and represents @@ -67,20 +68,20 @@ public: virtual ~DCPackerInterface(); PUBLISHED: - const string &get_name() const; - void set_name(const string &name); + INLINE const string &get_name() const; public: - bool has_fixed_byte_size() const; - size_t get_fixed_byte_size() const; - size_t get_num_length_bytes() const; + INLINE void set_name(const string &name); + INLINE bool has_fixed_byte_size() const; + INLINE size_t get_fixed_byte_size() const; + INLINE size_t get_num_length_bytes() const; - bool has_nested_fields() const; - int get_num_nested_fields() const; + INLINE bool has_nested_fields() const; + INLINE int get_num_nested_fields() const; virtual int calc_num_nested_fields(size_t length_bytes) const; virtual DCPackerInterface *get_nested_field(int n) const; - DCPackType get_pack_type() const; + INLINE DCPackType get_pack_type() const; virtual bool pack_double(DCPackData &pack_data, double value) const; virtual bool pack_int(DCPackData &pack_data, int value) const; @@ -95,19 +96,20 @@ public: virtual bool unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const; virtual bool unpack_uint64(const char *data, size_t length, size_t &p, PN_uint64 &value) const; virtual bool unpack_string(const char *data, size_t length, size_t &p, string &value) const; + virtual bool unpack_skip(const char *data, size_t length, size_t &p) const; // These are the low-level interfaces for packing and unpacking // numbers from a buffer. You're responsible for making sure the // buffer has enough room, and for incrementing the pointer. - INLINE static void do_pack_int8(char *buffer, int value); - INLINE static void do_pack_int16(char *buffer, int value); - INLINE static void do_pack_int32(char *buffer, int value); - INLINE static void do_pack_int64(char *buffer, PN_int64 value); - INLINE static void do_pack_uint8(char *buffer, unsigned int value); - INLINE static void do_pack_uint16(char *buffer, unsigned int value); - INLINE static void do_pack_uint32(char *buffer, unsigned int value); - INLINE static void do_pack_uint64(char *buffer, PN_uint64 value); - INLINE static void do_pack_float64(char *buffer, double value); + INLINE static void do_pack_int8(char *buffer, int value, bool &pack_error); + INLINE static void do_pack_int16(char *buffer, int value, bool &pack_error); + INLINE static void do_pack_int32(char *buffer, int value, bool &pack_error); + INLINE static void do_pack_int64(char *buffer, PN_int64 value, bool &pack_error); + INLINE static void do_pack_uint8(char *buffer, unsigned int value, bool &pack_error); + INLINE static void do_pack_uint16(char *buffer, unsigned int value, bool &pack_error); + INLINE static void do_pack_uint32(char *buffer, unsigned int value, bool &pack_error); + INLINE static void do_pack_uint64(char *buffer, PN_uint64 value, bool &pack_error); + INLINE static void do_pack_float64(char *buffer, double value, bool &pack_error); INLINE static int do_unpack_int8(const char *buffer); INLINE static int do_unpack_int16(const char *buffer); @@ -119,6 +121,8 @@ public: INLINE static PN_uint64 do_unpack_uint64(const char *buffer); INLINE static double do_unpack_float64(const char *buffer); + const DCPackerCatalog *get_catalog() const; + protected: string _name; bool _has_fixed_byte_size; @@ -127,6 +131,14 @@ protected: bool _has_nested_fields; int _num_nested_fields; DCPackType _pack_type; + +private: + void make_catalog(); + void r_fill_catalog(DCPackerCatalog *catalog, const string &name_prefix, + DCPackerInterface *parent, int field_index); + + + DCPackerCatalog *_catalog; }; #include "dcPackerInterface.I" diff --git a/direct/src/dcparser/dcSimpleParameter.cxx b/direct/src/dcparser/dcSimpleParameter.cxx index 1ba1bfed7c..0cb64c0478 100644 --- a/direct/src/dcparser/dcSimpleParameter.cxx +++ b/direct/src/dcparser/dcSimpleParameter.cxx @@ -318,58 +318,59 @@ get_nested_field(int) const { //////////////////////////////////////////////////////////////////// bool DCSimpleParameter:: pack_double(DCPackData &pack_data, double value) const { + bool pack_error = false; double real_value = value * _divisor; switch (_type) { case ST_int8: do_pack_int8(pack_data.get_write_pointer(1), - (int)floor(real_value + 0.5)); + (int)floor(real_value + 0.5), pack_error); break; case ST_int16: do_pack_int16(pack_data.get_write_pointer(2), - (int)floor(real_value + 0.5)); + (int)floor(real_value + 0.5), pack_error); break; - + case ST_int32: do_pack_int32(pack_data.get_write_pointer(4), - (int)floor(real_value + 0.5)); + (int)floor(real_value + 0.5), pack_error); break; - + case ST_int64: do_pack_int64(pack_data.get_write_pointer(8), - (PN_int64)floor(real_value + 0.5)); + (PN_int64)floor(real_value + 0.5), pack_error); break; - + case ST_uint8: do_pack_uint8(pack_data.get_write_pointer(1), - (unsigned int)floor(real_value + 0.5)); + (unsigned int)floor(real_value + 0.5), pack_error); break; - + case ST_uint16: do_pack_uint16(pack_data.get_write_pointer(2), - (unsigned int)floor(real_value + 0.5)); + (unsigned int)floor(real_value + 0.5), pack_error); break; - + case ST_uint32: do_pack_uint32(pack_data.get_write_pointer(4), - (unsigned int)floor(real_value + 0.5)); + (unsigned int)floor(real_value + 0.5), pack_error); break; - + case ST_uint64: do_pack_uint64(pack_data.get_write_pointer(8), - (PN_uint64)floor(real_value + 0.5)); + (PN_uint64)floor(real_value + 0.5), pack_error); break; case ST_float64: - do_pack_float64(pack_data.get_write_pointer(8), real_value); + do_pack_float64(pack_data.get_write_pointer(8), real_value, pack_error); break; default: return false; } - return true; + return !pack_error; } //////////////////////////////////////////////////////////////////// @@ -380,50 +381,51 @@ pack_double(DCPackData &pack_data, double value) const { //////////////////////////////////////////////////////////////////// bool DCSimpleParameter:: pack_int(DCPackData &pack_data, int value) const { + bool pack_error = false; int int_value = value * _divisor; switch (_type) { case ST_int8: - do_pack_int8(pack_data.get_write_pointer(1), int_value); + do_pack_int8(pack_data.get_write_pointer(1), int_value, pack_error); break; case ST_int16: - do_pack_int16(pack_data.get_write_pointer(2), int_value); + do_pack_int16(pack_data.get_write_pointer(2), int_value, pack_error); break; case ST_int32: - do_pack_int32(pack_data.get_write_pointer(4), int_value); + do_pack_int32(pack_data.get_write_pointer(4), int_value, pack_error); break; case ST_int64: - do_pack_int64(pack_data.get_write_pointer(8), int_value); + do_pack_int64(pack_data.get_write_pointer(8), int_value, pack_error); break; case ST_uint8: - do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value); + do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value, pack_error); break; case ST_uint16: - do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value); + do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value, pack_error); break; case ST_uint32: - do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value); + do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value, pack_error); break; case ST_uint64: - do_pack_uint64(pack_data.get_write_pointer(8), (unsigned int)int_value); + do_pack_uint64(pack_data.get_write_pointer(8), (unsigned int)int_value, pack_error); break; case ST_float64: - do_pack_float64(pack_data.get_write_pointer(8), int_value); + do_pack_float64(pack_data.get_write_pointer(8), int_value, pack_error); break; default: return false; } - return true; + return !pack_error; } //////////////////////////////////////////////////////////////////// @@ -434,50 +436,51 @@ pack_int(DCPackData &pack_data, int value) const { //////////////////////////////////////////////////////////////////// bool DCSimpleParameter:: pack_uint(DCPackData &pack_data, unsigned int value) const { + bool pack_error = false; unsigned int int_value = value * _divisor; switch (_type) { case ST_int8: - do_pack_int8(pack_data.get_write_pointer(1), (int)int_value); + do_pack_int8(pack_data.get_write_pointer(1), (int)int_value, pack_error); break; case ST_int16: - do_pack_int16(pack_data.get_write_pointer(2), (int)int_value); + do_pack_int16(pack_data.get_write_pointer(2), (int)int_value, pack_error); break; case ST_int32: - do_pack_int32(pack_data.get_write_pointer(4), (int)int_value); + do_pack_int32(pack_data.get_write_pointer(4), (int)int_value, pack_error); break; case ST_int64: - do_pack_int64(pack_data.get_write_pointer(8), (int)int_value); + do_pack_int64(pack_data.get_write_pointer(8), (int)int_value, pack_error); break; case ST_uint8: - do_pack_uint8(pack_data.get_write_pointer(1), int_value); + do_pack_uint8(pack_data.get_write_pointer(1), int_value, pack_error); break; case ST_uint16: - do_pack_uint16(pack_data.get_write_pointer(2), int_value); + do_pack_uint16(pack_data.get_write_pointer(2), int_value, pack_error); break; case ST_uint32: - do_pack_uint32(pack_data.get_write_pointer(4), int_value); + do_pack_uint32(pack_data.get_write_pointer(4), int_value, pack_error); break; case ST_uint64: - do_pack_uint64(pack_data.get_write_pointer(8), int_value); + do_pack_uint64(pack_data.get_write_pointer(8), int_value, pack_error); break; case ST_float64: - do_pack_float64(pack_data.get_write_pointer(8), (double)int_value); + do_pack_float64(pack_data.get_write_pointer(8), (double)int_value, pack_error); break; default: return false; } - return true; + return !pack_error; } //////////////////////////////////////////////////////////////////// @@ -488,50 +491,51 @@ pack_uint(DCPackData &pack_data, unsigned int value) const { //////////////////////////////////////////////////////////////////// bool DCSimpleParameter:: pack_int64(DCPackData &pack_data, PN_int64 value) const { + bool pack_error = false; PN_int64 int_value = value * _divisor; switch (_type) { case ST_int8: - do_pack_int8(pack_data.get_write_pointer(1), (int)int_value); + do_pack_int8(pack_data.get_write_pointer(1), (int)int_value, pack_error); break; case ST_int16: - do_pack_int16(pack_data.get_write_pointer(2), (int)int_value); + do_pack_int16(pack_data.get_write_pointer(2), (int)int_value, pack_error); break; case ST_int32: - do_pack_int32(pack_data.get_write_pointer(4), (int)int_value); + do_pack_int32(pack_data.get_write_pointer(4), (int)int_value, pack_error); break; case ST_int64: - do_pack_int64(pack_data.get_write_pointer(8), int_value); + do_pack_int64(pack_data.get_write_pointer(8), int_value, pack_error); break; case ST_uint8: - do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)(PN_uint64)int_value); + do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)(PN_uint64)int_value, pack_error); break; case ST_uint16: - do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)(PN_uint64)int_value); + do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)(PN_uint64)int_value, pack_error); break; case ST_uint32: - do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)(PN_uint64)int_value); + do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)(PN_uint64)int_value, pack_error); break; case ST_uint64: - do_pack_uint64(pack_data.get_write_pointer(8), (PN_uint64)int_value); + do_pack_uint64(pack_data.get_write_pointer(8), (PN_uint64)int_value, pack_error); break; case ST_float64: - do_pack_float64(pack_data.get_write_pointer(8), (double)int_value); + do_pack_float64(pack_data.get_write_pointer(8), (double)int_value, pack_error); break; default: return false; } - return true; + return !pack_error; } //////////////////////////////////////////////////////////////////// @@ -542,50 +546,51 @@ pack_int64(DCPackData &pack_data, PN_int64 value) const { //////////////////////////////////////////////////////////////////// bool DCSimpleParameter:: pack_uint64(DCPackData &pack_data, PN_uint64 value) const { + bool pack_error = false; PN_uint64 int_value = value * _divisor; switch (_type) { case ST_int8: - do_pack_int8(pack_data.get_write_pointer(1), (int)(PN_int64)int_value); + do_pack_int8(pack_data.get_write_pointer(1), (int)(PN_int64)int_value, pack_error); break; case ST_int16: - do_pack_int16(pack_data.get_write_pointer(2), (int)(PN_int64)int_value); + do_pack_int16(pack_data.get_write_pointer(2), (int)(PN_int64)int_value, pack_error); break; case ST_int32: - do_pack_int32(pack_data.get_write_pointer(4), (int)(PN_int64)int_value); + do_pack_int32(pack_data.get_write_pointer(4), (int)(PN_int64)int_value, pack_error); break; case ST_int64: - do_pack_int64(pack_data.get_write_pointer(8), (PN_int64)int_value); + do_pack_int64(pack_data.get_write_pointer(8), (PN_int64)int_value, pack_error); break; case ST_uint8: - do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value); + do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value, pack_error); break; case ST_uint16: - do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value); + do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value, pack_error); break; case ST_uint32: - do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value); + do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value, pack_error); break; case ST_uint64: - do_pack_uint64(pack_data.get_write_pointer(8), int_value); + do_pack_uint64(pack_data.get_write_pointer(8), int_value, pack_error); break; case ST_float64: - do_pack_float64(pack_data.get_write_pointer(8), (double)int_value); + do_pack_float64(pack_data.get_write_pointer(8), (double)int_value, pack_error); break; default: return false; } - return true; + return !pack_error; } //////////////////////////////////////////////////////////////////// @@ -596,15 +601,19 @@ pack_uint64(DCPackData &pack_data, PN_uint64 value) const { //////////////////////////////////////////////////////////////////// bool DCSimpleParameter:: pack_string(DCPackData &pack_data, const string &value) const { + bool pack_error = false; + switch (_type) { case ST_string: case ST_blob: - do_pack_uint16(pack_data.get_write_pointer(2), value.length()); + do_pack_uint16(pack_data.get_write_pointer(2), value.length(), + pack_error); pack_data.append_data(value.data(), value.length()); break; case ST_blob32: - do_pack_uint32(pack_data.get_write_pointer(4), value.length()); + do_pack_uint32(pack_data.get_write_pointer(4), value.length(), + pack_error); pack_data.append_data(value.data(), value.length()); break; @@ -612,7 +621,7 @@ pack_string(DCPackData &pack_data, const string &value) const { return false; } - return true; + return !pack_error; } //////////////////////////////////////////////////////////////////// @@ -1116,6 +1125,67 @@ unpack_string(const char *data, size_t length, size_t &p, string &value) const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: DCSimpleParameter::unpack_skip +// Access: Public, Virtual +// Description: Increments p to the end of the current field without +// actually unpacking any data. Returns true on +// success, false on failure. +//////////////////////////////////////////////////////////////////// +bool DCSimpleParameter:: +unpack_skip(const char *data, size_t length, size_t &p) const { + size_t string_length; + + switch (_type) { + case ST_int8: + case ST_uint8: + p++; + break; + + case ST_int16: + case ST_uint16: + p += 2; + break; + + case ST_int32: + case ST_uint32: + p += 4; + break; + + case ST_int64: + case ST_uint64: + case ST_float64: + p += 8; + break; + + case ST_string: + case ST_blob: + if (p + 2 > length) { + return false; + } + string_length = do_unpack_uint16(data + p); + p += 2 + string_length; + break; + + case ST_blob32: + if (p + 4 > length) { + return false; + } + string_length = do_unpack_uint32(data + p); + p += 4 + string_length; + break; + + default: + return false; + } + + if (p > length) { + return false; + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: DCSimpleParameter::output_instance // Access: Public, Virtual diff --git a/direct/src/dcparser/dcSimpleParameter.h b/direct/src/dcparser/dcSimpleParameter.h index aa9358b307..eab6191848 100644 --- a/direct/src/dcparser/dcSimpleParameter.h +++ b/direct/src/dcparser/dcSimpleParameter.h @@ -64,6 +64,7 @@ public: virtual bool unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value) const; virtual bool unpack_uint64(const char *data, size_t length, size_t &p, PN_uint64 &value) const; virtual bool unpack_string(const char *data, size_t length, size_t &p, string &value) const; + virtual bool unpack_skip(const char *data, size_t length, size_t &p) const; virtual void output_instance(ostream &out, const string &prename, const string &name, const string &postname) const; diff --git a/direct/src/dcparser/dcparser_composite1.cxx b/direct/src/dcparser/dcparser_composite1.cxx index 2b992aadfd..f18f90d13d 100644 --- a/direct/src/dcparser/dcparser_composite1.cxx +++ b/direct/src/dcparser/dcparser_composite1.cxx @@ -6,6 +6,7 @@ #include "dcDeclaration.cxx" #include "dcPackData.cxx" #include "dcPacker.cxx" +#include "dcPackerCatalog.cxx" #include "dcPackerInterface.cxx" #include "dcindent.cxx"