From 6845758d2bbacc181bdbf6c08666baa0600176fa Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 25 Jun 2004 00:39:33 +0000 Subject: [PATCH] unpack to python object --- direct/src/dcparser/dcClass.cxx | 13 +++ direct/src/dcparser/dcClass.h | 1 + direct/src/dcparser/dcField.cxx | 10 ++ direct/src/dcparser/dcField.h | 1 + direct/src/dcparser/dcPacker.cxx | 123 ++++++++++++++++++++++ direct/src/dcparser/dcPacker.h | 6 ++ direct/src/dcparser/dcPackerCatalog.cxx | 5 +- direct/src/dcparser/dcPackerInterface.cxx | 20 ++++ direct/src/dcparser/dcPackerInterface.h | 4 + 9 files changed, 182 insertions(+), 1 deletion(-) diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index 92f53415b4..51a25b6fb2 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/direct/src/dcparser/dcClass.cxx @@ -223,6 +223,19 @@ is_bogus_class() const { return _bogus_class; } +#ifdef HAVE_PYTHON +//////////////////////////////////////////////////////////////////// +// Function: DCClass::has_class_def +// Access: Published +// Description: Returns true if the DCClass object has an associated +// Python class definition, false otherwise. +//////////////////////////////////////////////////////////////////// +bool DCClass:: +has_class_def() const { + return (_class_def != NULL); +} +#endif // HAVE_PYTHON + #ifdef HAVE_PYTHON //////////////////////////////////////////////////////////////////// // Function: DCClass::set_class_def diff --git a/direct/src/dcparser/dcClass.h b/direct/src/dcparser/dcClass.h index 32022999d9..6cd17e2a7f 100644 --- a/direct/src/dcparser/dcClass.h +++ b/direct/src/dcparser/dcClass.h @@ -55,6 +55,7 @@ PUBLISHED: bool is_bogus_class() const; #ifdef HAVE_PYTHON + bool has_class_def() const; void set_class_def(PyObject *class_def); PyObject *get_class_def() const; diff --git a/direct/src/dcparser/dcField.cxx b/direct/src/dcparser/dcField.cxx index d3655ae050..c0880463aa 100644 --- a/direct/src/dcparser/dcField.cxx +++ b/direct/src/dcparser/dcField.cxx @@ -60,6 +60,16 @@ get_number() const { return _number; } +//////////////////////////////////////////////////////////////////// +// Function: DCField::as_field +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +DCField *DCField:: +as_field() { + return this; +} + //////////////////////////////////////////////////////////////////// // Function: DCField::as_atomic_field // Access: Published, Virtual diff --git a/direct/src/dcparser/dcField.h b/direct/src/dcparser/dcField.h index 480f29995c..f4415533c8 100644 --- a/direct/src/dcparser/dcField.h +++ b/direct/src/dcparser/dcField.h @@ -42,6 +42,7 @@ public: PUBLISHED: int get_number() const; + virtual DCField *as_field(); virtual DCAtomicField *as_atomic_field(); virtual DCMolecularField *as_molecular_field(); virtual DCParameter *as_parameter(); diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index 0c8f6bb419..2014716e18 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/direct/src/dcparser/dcPacker.cxx @@ -20,6 +20,8 @@ #include "dcSwitch.h" #include "dcParserDefs.h" #include "dcLexerDefs.h" +#include "dcClassParameter.h" +#include "dcClass.h" //////////////////////////////////////////////////////////////////// // Function: DCPacker::Constructor @@ -217,6 +219,9 @@ begin_repack(const char *data, size_t length, _root = root; _catalog = _root->get_catalog(); _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length); + if (_live_catalog == NULL) { + _pack_error = true; + } // We don't begin at the first field in repack mode. Instead, you // must explicitly call seek(). @@ -268,6 +273,10 @@ seek(const string &field_name) { _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length); } nassertr(_catalog != (DCPackerCatalog *)NULL, false); + if (_live_catalog == NULL) { + _pack_error = true; + return false; + } int entry_index = _live_catalog->find_entry_by_name(field_name); if (entry_index < 0) { @@ -305,6 +314,10 @@ seek(const string &field_name) { _pack_error = true; return false; } + if (_live_catalog == NULL) { + _pack_error = true; + return false; + } int entry_index = _live_catalog->find_entry_by_name(field_name); if (entry_index < 0) { @@ -338,6 +351,11 @@ seek(const string &field_name) { _catalog->release_live_catalog(_live_catalog); _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length); + if (_live_catalog == NULL) { + _pack_error = true; + return false; + } + begin = _live_catalog->get_begin(entry_index); } @@ -696,6 +714,22 @@ unpack_object() { } break; + case PT_class: + { + const DCClassParameter *class_param = ((DCPackerInterface *)get_current_field())->as_class_parameter(); + if (class_param != (DCClassParameter *)NULL) { + DCClass *dclass = class_param->get_class(); + if (dclass->has_class_def()) { + // If we know what kind of class object this is and it has a + // valid constructor, create the class object instead of + // just a tuple. + object = unpack_class_object(dclass); + break; + } + } + } + // If we don't know what kind of class object it is, or it doesn't + // have a constructor, fall through and make a tuple. default: { // First, build up a list from the nested objects. @@ -994,3 +1028,92 @@ set_unpack_data(const char *unpack_data, size_t unpack_length, _unpack_length = unpack_length; _owns_unpack_data = owns_unpack_data; } + +#ifdef HAVE_PYTHON +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::unpack_class_object +// Access: Private +// Description: Given that the current element is a ClassParameter +// for a Python class for which we have a valid +// constructor, unpack it and fill in its values. +//////////////////////////////////////////////////////////////////// +PyObject *DCPacker:: +unpack_class_object(DCClass *dclass) { + PyObject *class_def = dclass->get_class_def(); + nassertr(class_def != (PyObject *)NULL, NULL); + + PyObject *object = PyObject_CallObject(class_def, NULL); + if (object == (PyObject *)NULL) { + return NULL; + } + + push(); + while (more_nested_fields()) { + const DCField *field = ((DCPackerInterface *)get_current_field())->as_field(); + nassertr(field != (DCField *)NULL, object); + + set_class_element(object, field); + } + pop(); + + return object; +} +#endif // HAVE_PYTHON + + +#ifdef HAVE_PYTHON +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::set_class_element +// Access: Private +// Description: Unpacks the current element and stuffs it on the +// Python class object in whatever way is appopriate. +//////////////////////////////////////////////////////////////////// +void DCPacker:: +set_class_element(PyObject *object, const DCField *field) { + string field_name = field->get_name(); + DCPackType pack_type = get_pack_type(); + + if (field_name.empty()) { + switch (pack_type) { + case PT_class: + case PT_switch: + // If the field has no name, but it is one of these container + // objects, we want to unpack its nested objects directly into + // the class. + push(); + while (more_nested_fields()) { + const DCField *field = ((DCPackerInterface *)get_current_field())->as_field(); + nassertv(field != (DCField *)NULL); + set_class_element(object, field); + } + pop(); + break; + + default: + // Otherwise, we just skip over the field. + unpack_skip(); + } + + } else { + // If the field does have a name, we will want to store it on the + // class, either by calling a method (for a PT_field pack_type) or + // by setting a value (for any other kind of pack_type). + + PyObject *element = unpack_object(); + + if (pack_type == PT_field) { + PyObject *func = PyObject_GetAttrString(object, (char *)field_name.c_str()); + if (func != (PyObject *)NULL) { + PyObject *result = PyObject_CallObject(func, element); + Py_XDECREF(result); + } + Py_DECREF(func); + + } else { + PyObject_SetAttrString(object, (char *)field_name.c_str(), element); + } + + Py_DECREF(element); + } +} +#endif // HAVE_PYTHON diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 25597caaa3..125a927b00 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -26,6 +26,7 @@ #include "dcPackerCatalog.h" #include "dcPython.h" +class DCClass; class DCSwitch; //////////////////////////////////////////////////////////////////// @@ -134,6 +135,11 @@ private: 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); + void set_class_element(PyObject *object, const DCField *field); +#endif + private: enum Mode { M_idle, diff --git a/direct/src/dcparser/dcPackerCatalog.cxx b/direct/src/dcparser/dcPackerCatalog.cxx index ea0e031aee..c4bf6c62e4 100644 --- a/direct/src/dcparser/dcPackerCatalog.cxx +++ b/direct/src/dcparser/dcPackerCatalog.cxx @@ -138,7 +138,10 @@ get_live_catalog(const char *data, size_t length) const { r_fill_live_catalog(live_catalog, packer, last_switch); bool okflag = packer.end_unpack(); - nassertr(okflag, live_catalog); + if (!okflag) { + delete live_catalog; + return NULL; + } if (_root->has_fixed_structure()) { // If our root field has a fixed structure, then the live catalog diff --git a/direct/src/dcparser/dcPackerInterface.cxx b/direct/src/dcparser/dcPackerInterface.cxx index aac933df43..5c5dac71df 100755 --- a/direct/src/dcparser/dcPackerInterface.cxx +++ b/direct/src/dcparser/dcPackerInterface.cxx @@ -69,6 +69,16 @@ DCPackerInterface:: } } +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::as_field +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +DCField *DCPackerInterface:: +as_field() { + return (DCField *)NULL; +} + //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::as_switch // Access: Published, Virtual @@ -79,6 +89,16 @@ as_switch() { return (DCSwitch *)NULL; } +//////////////////////////////////////////////////////////////////// +// Function: DCPackerInterface::as_class_parameter +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +DCClassParameter *DCPackerInterface:: +as_class_parameter() { + return (DCClassParameter *)NULL; +} + //////////////////////////////////////////////////////////////////// // Function: DCPackerInterface::calc_num_nested_fields // Access: Public, Virtual diff --git a/direct/src/dcparser/dcPackerInterface.h b/direct/src/dcparser/dcPackerInterface.h index ffab344dfb..2fb1f7e4a6 100755 --- a/direct/src/dcparser/dcPackerInterface.h +++ b/direct/src/dcparser/dcPackerInterface.h @@ -22,7 +22,9 @@ #include "dcbase.h" #include "dcSubatomicType.h" +class DCField; class DCSwitch; +class DCClassParameter; class DCPackData; class DCPackerCatalog; @@ -74,7 +76,9 @@ public: PUBLISHED: INLINE const string &get_name() const; + virtual DCField *as_field(); virtual DCSwitch *as_switch(); + virtual DCClassParameter *as_class_parameter(); public: INLINE void set_name(const string &name);