mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
add switches
This commit is contained in:
parent
be06c52586
commit
803712f986
@ -26,6 +26,7 @@
|
||||
dcPackerInterface.h dcPackerInterface.I \
|
||||
dcParameter.h dcClassParameter.h dcArrayParameter.h dcSimpleParameter.h \
|
||||
dcNumericRange.h dcNumericRange.I \
|
||||
dcSwitch.h \
|
||||
dcTypedef.h \
|
||||
dcPython.h \
|
||||
dcbase.h dcindent.h hashGenerator.h \
|
||||
@ -42,6 +43,7 @@
|
||||
dcPackerInterface.cxx \
|
||||
dcParameter.cxx dcClassParameter.cxx \
|
||||
dcArrayParameter.cxx dcSimpleParameter.cxx \
|
||||
dcSwitch.cxx \
|
||||
dcTypedef.cxx \
|
||||
dcindent.cxx \
|
||||
hashGenerator.cxx primeNumberGenerator.cxx
|
||||
|
@ -40,6 +40,7 @@ DCArrayParameter(DCParameter *element_type, const DCUnsignedIntRange &size) :
|
||||
if (_array_size >= 0 && _element_type->has_fixed_byte_size()) {
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = _array_size * _element_type->get_fixed_byte_size();
|
||||
_has_fixed_structure = true;
|
||||
|
||||
} else {
|
||||
// We only need to store the length bytes if the array has a
|
||||
|
@ -317,7 +317,7 @@ write(ostream &out, bool brief, int indent_level) const {
|
||||
}
|
||||
|
||||
out << ";";
|
||||
if (!brief) {
|
||||
if (!brief && _number >= 0) {
|
||||
out << " // field " << _number;
|
||||
}
|
||||
out << "\n";
|
||||
@ -372,6 +372,9 @@ add_element(const DCAtomicField::ElementType &element) {
|
||||
_has_fixed_byte_size = element._param->has_fixed_byte_size();
|
||||
_fixed_byte_size += element._param->get_fixed_byte_size();
|
||||
}
|
||||
if (_has_fixed_structure) {
|
||||
_has_fixed_structure = element._param->has_fixed_structure();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -22,6 +22,41 @@
|
||||
#include "dcindent.h"
|
||||
#include "dcmsgtypes.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCClass::
|
||||
DCClass(const string &name, bool is_struct, bool bogus_class) :
|
||||
_name(name),
|
||||
_is_struct(is_struct),
|
||||
_bogus_class(bogus_class)
|
||||
{
|
||||
_number = -1;
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
_class_def = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCClass::
|
||||
~DCClass() {
|
||||
Fields::iterator fi;
|
||||
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
||||
delete (*fi);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
Py_XDECREF(_class_def);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::get_name
|
||||
// Access: Published
|
||||
@ -540,39 +575,6 @@ ai_format_generate(PyObject *distobj, int do_id,
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCClass::
|
||||
DCClass(const string &name, bool is_struct, bool bogus_class) :
|
||||
_name(name),
|
||||
_is_struct(is_struct),
|
||||
_bogus_class(bogus_class)
|
||||
{
|
||||
#ifdef HAVE_PYTHON
|
||||
_class_def = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCClass::
|
||||
~DCClass() {
|
||||
Fields::iterator fi;
|
||||
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
||||
delete (*fi);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
Py_XDECREF(_class_def);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::write
|
||||
// Access: Public, Virtual
|
||||
@ -599,7 +601,7 @@ write(ostream &out, bool brief, int indent_level) const {
|
||||
}
|
||||
|
||||
out << " {";
|
||||
if (!brief) {
|
||||
if (!brief && _number >= 0) {
|
||||
out << " // index " << _number;
|
||||
}
|
||||
out << "\n";
|
||||
|
@ -33,6 +33,10 @@ class DCParameter;
|
||||
// input .dc file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_DIRECT DCClass : public DCDeclaration {
|
||||
public:
|
||||
DCClass(const string &name, bool is_struct, bool bogus_class);
|
||||
~DCClass();
|
||||
|
||||
PUBLISHED:
|
||||
const string &get_name() const;
|
||||
int get_number() const;
|
||||
@ -76,9 +80,6 @@ PUBLISHED:
|
||||
#endif
|
||||
|
||||
public:
|
||||
DCClass(const string &name, bool is_struct, bool bogus_class);
|
||||
~DCClass();
|
||||
|
||||
virtual void write(ostream &out, bool brief, int indent_level) const;
|
||||
void generate_hash(HashGenerator &hashgen) const;
|
||||
|
||||
|
@ -40,10 +40,12 @@ DCClassParameter(DCClass *dclass) :
|
||||
// fields).
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = 0;
|
||||
_has_fixed_structure = true;
|
||||
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();
|
||||
_has_fixed_byte_size = _has_fixed_byte_size && field->has_fixed_byte_size();
|
||||
_fixed_byte_size += field->get_fixed_byte_size();
|
||||
_has_fixed_structure = _has_fixed_structure && field->has_fixed_structure();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,15 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCField::
|
||||
DCField(const string &name) : DCPackerInterface(name) {
|
||||
_number = 0;
|
||||
_number = -1;
|
||||
|
||||
_has_nested_fields = true;
|
||||
_num_nested_fields = 0;
|
||||
_pack_type = PT_field;
|
||||
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = 0;
|
||||
_has_fixed_structure = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -92,6 +94,16 @@ as_parameter() {
|
||||
return (DCParameter *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCField::as_switch
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCSwitch *DCField::
|
||||
as_switch() {
|
||||
return (DCSwitch *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCField::format_data
|
||||
// Access: Published
|
||||
|
@ -26,6 +26,7 @@
|
||||
class DCAtomicField;
|
||||
class DCMolecularField;
|
||||
class DCParameter;
|
||||
class DCSwitch;
|
||||
class HashGenerator;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -44,6 +45,7 @@ PUBLISHED:
|
||||
virtual DCAtomicField *as_atomic_field();
|
||||
virtual DCMolecularField *as_molecular_field();
|
||||
virtual DCParameter *as_parameter();
|
||||
virtual DCSwitch *as_switch();
|
||||
|
||||
string format_data(const string &packed_data);
|
||||
string parse_string(const string &formatted_string);
|
||||
|
@ -370,6 +370,16 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
|
||||
return KW_TYPEDEF;
|
||||
}
|
||||
|
||||
"switch" {
|
||||
accept();
|
||||
return KW_SWITCH;
|
||||
}
|
||||
|
||||
"case" {
|
||||
accept();
|
||||
return KW_CASE;
|
||||
}
|
||||
|
||||
"int8" {
|
||||
accept();
|
||||
return KW_INT8;
|
||||
|
@ -96,6 +96,9 @@ add_atomic(DCAtomicField *atomic) {
|
||||
_has_fixed_byte_size = atomic->has_fixed_byte_size();
|
||||
_fixed_byte_size += atomic->get_fixed_byte_size();
|
||||
}
|
||||
if (_has_fixed_structure) {
|
||||
_has_fixed_structure = atomic->has_fixed_structure();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -45,6 +45,12 @@ has_nested_fields() const {
|
||||
// The return value may be -1 to indicate that a
|
||||
// variable number of nested fields are accepted by this
|
||||
// field type (e.g. a variable-length array).
|
||||
//
|
||||
// Note that this method is unreliable to determine how
|
||||
// many fields you must traverse before you can call
|
||||
// pop(), since particularly in the presence of a
|
||||
// DCSwitch, it may change during traversal. Use
|
||||
// more_nested_fields() instead.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DCPacker::
|
||||
get_num_nested_fields() const {
|
||||
@ -63,6 +69,19 @@ more_nested_fields() const {
|
||||
return (_current_field != (DCPackerInterface *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPacker::get_current_parent
|
||||
// Access: Published
|
||||
// Description: Returns the field that we left in our last call to
|
||||
// push(): the owner of the current level of fields.
|
||||
// This may be NULL at the beginning of the pack
|
||||
// operation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const DCPackerInterface *DCPacker::
|
||||
get_current_parent() const {
|
||||
return _current_parent;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPacker::get_current_field
|
||||
// Access: Published
|
||||
@ -76,6 +95,24 @@ get_current_field() const {
|
||||
return _current_field;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPacker::get_last_switch
|
||||
// Access: Published
|
||||
// Description: Returns a pointer to the last DCSwitch instance that
|
||||
// we have passed by and selected one case of during the
|
||||
// pack/unpack process. Each time we encounter a new
|
||||
// DCSwitch and select a case, this will change state.
|
||||
//
|
||||
// This may be used to detect when a DCSwitch has been
|
||||
// selected. At the moment this changes state,
|
||||
// get_current_parent() will contain the particular
|
||||
// SwitchCase that was selected by the switch.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const DCSwitch *DCPacker::
|
||||
get_last_switch() const {
|
||||
return _last_switch;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPacker::get_pack_type
|
||||
// Access: Published
|
||||
@ -470,8 +507,16 @@ advance() {
|
||||
// call pop().
|
||||
_current_field = NULL;
|
||||
|
||||
} else if (_mode == M_unpack && _push_marker != 0 &&
|
||||
_unpack_p >= _push_marker) {
|
||||
// But if the parent is a switch record, we make a special case so
|
||||
// we can get the alternate fields.
|
||||
if (_current_parent != (DCPackerInterface *)NULL) {
|
||||
const DCSwitch *dswitch = ((DCPackerInterface *)_current_parent)->as_switch();
|
||||
if (dswitch != (DCSwitch *)NULL) {
|
||||
handle_switch(dswitch);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (_pop_marker != 0 && _unpack_p >= _pop_marker) {
|
||||
// Done with all the fields on this parent. The caller must now
|
||||
// call pop().
|
||||
_current_field = NULL;
|
||||
|
@ -17,6 +17,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dcPacker.h"
|
||||
#include "dcSwitch.h"
|
||||
#include "dcParserDefs.h"
|
||||
#include "dcLexerDefs.h"
|
||||
|
||||
@ -32,15 +33,11 @@ DCPacker() {
|
||||
_unpack_length = 0;
|
||||
_owns_unpack_data = false;
|
||||
_unpack_p = 0;
|
||||
_root = NULL;
|
||||
_catalog = NULL;
|
||||
_live_catalog = NULL;
|
||||
_current_field = NULL;
|
||||
_current_parent = NULL;
|
||||
_current_field_index = 0;
|
||||
_num_nested_fields = 0;
|
||||
_pack_error = false;
|
||||
_range_error = false;
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -272,14 +269,14 @@ seek(const string &field_name) {
|
||||
}
|
||||
nassertr(_catalog != (DCPackerCatalog *)NULL, false);
|
||||
|
||||
int entry_index = _catalog->find_entry_by_name(field_name);
|
||||
int entry_index = _live_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);
|
||||
const DCPackerCatalog::Entry &entry = _live_catalog->get_entry(entry_index);
|
||||
|
||||
// If we are seeking, we don't need to remember our current stack
|
||||
// position.
|
||||
@ -290,6 +287,13 @@ seek(const string &field_name) {
|
||||
_num_nested_fields = _current_parent->get_num_nested_fields();
|
||||
_unpack_p = _live_catalog->get_begin(entry_index);
|
||||
|
||||
// We don't really need _push_marker and _pop_marker now, except
|
||||
// that we should set _push_marker in case we have just seeked to
|
||||
// a switch parameter, and we should set _pop_marker to 0 just so
|
||||
// it won't get in the way.
|
||||
_push_marker = _unpack_p;
|
||||
_pop_marker = 0;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (_mode == M_repack) {
|
||||
@ -302,14 +306,24 @@ seek(const string &field_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int entry_index = _catalog->find_entry_by_name(field_name);
|
||||
int entry_index = _live_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);
|
||||
const DCPackerCatalog::Entry &entry = _live_catalog->get_entry(entry_index);
|
||||
|
||||
if (((DCPackerInterface *)entry._parent)->as_switch() != (DCSwitch *)NULL) {
|
||||
// If the parent is a DCSwitch, that can only mean that the
|
||||
// seeked field is a switch parameter. We can't support seeking
|
||||
// to a switch parameter and modifying it directly--what would
|
||||
// happen to all of the related fields? Instead, you'll have to
|
||||
// seek to the switch itself and repack the whole entity.
|
||||
_pack_error = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t begin = _live_catalog->get_begin(entry_index);
|
||||
if (begin < _unpack_p) {
|
||||
@ -337,9 +351,14 @@ seek(const string &field_name) {
|
||||
_current_field = entry._field;
|
||||
_current_parent = entry._parent;
|
||||
_current_field_index = entry._field_index;
|
||||
_num_nested_fields = 0; // this makes advance() stop after this field.
|
||||
_num_nested_fields = 1;
|
||||
_unpack_p = _live_catalog->get_end(entry_index);
|
||||
|
||||
// Set up push_marker and pop_marker so we won't try to advance
|
||||
// beyond this field.
|
||||
_push_marker = begin;
|
||||
_pop_marker = _live_catalog->get_end(entry_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -370,6 +389,7 @@ push() {
|
||||
element._current_parent = _current_parent;
|
||||
element._current_field_index = _current_field_index;
|
||||
element._push_marker = _push_marker;
|
||||
element._pop_marker = _pop_marker;
|
||||
_stack.push_back(element);
|
||||
_current_parent = _current_field;
|
||||
|
||||
@ -383,12 +403,14 @@ push() {
|
||||
// Reserve length_bytes for when we figure out what the length
|
||||
// is.
|
||||
_push_marker = _pack_data.get_length();
|
||||
_pop_marker = 0;
|
||||
_pack_data.append_junk(length_bytes);
|
||||
|
||||
} else if (_mode == M_unpack) {
|
||||
// Read length_bytes to determine the end of this nested
|
||||
// sequence.
|
||||
_push_marker = 0;
|
||||
_push_marker = _unpack_p;
|
||||
_pop_marker = 0;
|
||||
|
||||
if (length_bytes != 0) {
|
||||
if (_unpack_p + length_bytes > _unpack_length) {
|
||||
@ -400,13 +422,13 @@ push() {
|
||||
length = DCPackerInterface::do_unpack_uint32
|
||||
(_unpack_data + _unpack_p);
|
||||
_unpack_p += 4;
|
||||
_push_marker = _unpack_p + length;
|
||||
_pop_marker = _unpack_p + length;
|
||||
} else {
|
||||
length = DCPackerInterface::do_unpack_uint16
|
||||
(_unpack_data + _unpack_p);
|
||||
_unpack_p += 2;
|
||||
}
|
||||
_push_marker = _unpack_p + length;
|
||||
_pop_marker = _unpack_p + length;
|
||||
|
||||
// The explicit length trumps the number of nested fields
|
||||
// reported by get_num_nested_fields().
|
||||
@ -452,8 +474,8 @@ pop() {
|
||||
// Oops, didn't pack or unpack enough values.
|
||||
_pack_error = true;
|
||||
|
||||
} else if (_mode == M_unpack && _push_marker != 0 &&
|
||||
_unpack_p != _push_marker) {
|
||||
} else if (_mode == M_unpack && _pop_marker != 0 &&
|
||||
_unpack_p != _pop_marker) {
|
||||
// Didn't unpack the right number of values.
|
||||
_pack_error = true;
|
||||
}
|
||||
@ -488,6 +510,7 @@ pop() {
|
||||
_current_parent = _stack.back()._current_parent;
|
||||
_current_field_index = _stack.back()._current_field_index;
|
||||
_push_marker = _stack.back()._push_marker;
|
||||
_pop_marker = _stack.back()._pop_marker;
|
||||
_num_nested_fields = (_current_parent == NULL) ? 0 : _current_parent->get_num_nested_fields();
|
||||
_stack.pop_back();
|
||||
}
|
||||
@ -791,6 +814,7 @@ unpack_and_format(ostream &out) {
|
||||
break;
|
||||
|
||||
case PT_field:
|
||||
case PT_switch:
|
||||
out << '(';
|
||||
break;
|
||||
|
||||
@ -816,6 +840,7 @@ unpack_and_format(ostream &out) {
|
||||
break;
|
||||
|
||||
case PT_field:
|
||||
case PT_switch:
|
||||
out << ')';
|
||||
break;
|
||||
|
||||
@ -829,6 +854,54 @@ unpack_and_format(ostream &out) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPacker::handle_switch
|
||||
// Access: Private
|
||||
// Description: When we advance past the key field on a switch
|
||||
// record, we suddenly have more fields available--all
|
||||
// the appropriate alternate fields in the switch.
|
||||
//
|
||||
// This function is called when we detect this
|
||||
// condition; it switches the _current_parent to the
|
||||
// appropriate case of the switch record.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCPacker::
|
||||
handle_switch(const DCSwitch *dswitch) {
|
||||
// First, get the value from the key. This is either found in the
|
||||
// unpack or the pack data, depending on what mode we're in.
|
||||
const DCPackerInterface *new_parent = NULL;
|
||||
|
||||
if (_mode == M_pack || _mode == M_repack) {
|
||||
const char *data = _pack_data.get_data();
|
||||
new_parent = dswitch->apply_switch(data + _push_marker,
|
||||
_pack_data.get_length() - _push_marker);
|
||||
|
||||
} else if (_mode == M_unpack) {
|
||||
new_parent = dswitch->apply_switch(_unpack_data + _push_marker,
|
||||
_unpack_p - _push_marker);
|
||||
|
||||
}
|
||||
|
||||
if (new_parent == (DCPackerInterface *)NULL) {
|
||||
// This means an invalid value was packed for the key.
|
||||
_pack_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_last_switch = dswitch;
|
||||
|
||||
// Now substitute in the switch case for the previous parent (which
|
||||
// replaces the switch node itself). This will suddenly make a slew
|
||||
// of new fields appear.
|
||||
_current_parent = new_parent;
|
||||
_num_nested_fields = _current_parent->get_num_nested_fields();
|
||||
|
||||
if (_num_nested_fields < 0 ||
|
||||
_current_field_index < _num_nested_fields) {
|
||||
_current_field = _current_parent->get_nested_field(_current_field_index);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPacker::clear
|
||||
// Access: Private
|
||||
@ -842,6 +915,9 @@ clear() {
|
||||
_current_parent = NULL;
|
||||
_current_field_index = 0;
|
||||
_num_nested_fields = 0;
|
||||
_push_marker = 0;
|
||||
_pop_marker = 0;
|
||||
_last_switch = NULL;
|
||||
|
||||
if (_live_catalog != (DCPackerCatalog::LiveCatalog *)NULL) {
|
||||
_catalog->release_live_catalog(_live_catalog);
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "dcPackerCatalog.h"
|
||||
#include "dcPython.h"
|
||||
|
||||
class DCSwitch;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DCPacker
|
||||
// Description : This class can be used for packing a series of
|
||||
@ -64,7 +66,9 @@ PUBLISHED:
|
||||
INLINE int get_num_nested_fields() const;
|
||||
INLINE bool more_nested_fields() const;
|
||||
|
||||
INLINE const DCPackerInterface *get_current_parent() const;
|
||||
INLINE const DCPackerInterface *get_current_field() const;
|
||||
INLINE const DCSwitch *get_last_switch() const;
|
||||
INLINE DCPackType get_pack_type() const;
|
||||
|
||||
void push();
|
||||
@ -109,6 +113,7 @@ public:
|
||||
|
||||
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);
|
||||
@ -138,6 +143,7 @@ private:
|
||||
const DCPackerInterface *_current_parent;
|
||||
int _current_field_index;
|
||||
size_t _push_marker;
|
||||
size_t _pop_marker;
|
||||
};
|
||||
typedef pvector<StackElement> Stack;
|
||||
|
||||
@ -146,12 +152,17 @@ private:
|
||||
const DCPackerInterface *_current_parent;
|
||||
int _current_field_index;
|
||||
|
||||
// In pack mode, _push_marker marks the beginning of the push record
|
||||
// (so we can go back and write in the length later). In unpack
|
||||
// mode, it marks the end of the push record (so we know when we've
|
||||
// reached the end).
|
||||
// _push_marker marks the beginning of the push record (so we can go
|
||||
// back and write in the length later, or figure out the switch
|
||||
// parameter).
|
||||
size_t _push_marker;
|
||||
// _pop_marker is used in unpack mode with certain data structures
|
||||
// (like dynamic arrays) to mark the end of the push record (so we
|
||||
// know when we've reached the end). It is zero when it is not in
|
||||
// use.
|
||||
size_t _pop_marker;
|
||||
int _num_nested_fields;
|
||||
const DCSwitch *_last_switch;
|
||||
|
||||
bool _pack_error;
|
||||
bool _range_error;
|
||||
|
@ -42,6 +42,52 @@ get_end(int n) const {
|
||||
return _live_entries[n]._end;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::LiveCatalog::get_num_entries
|
||||
// Access: Public
|
||||
// Description: Returns the number of entries in the catalog.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DCPackerCatalog::LiveCatalog::
|
||||
get_num_entries() const {
|
||||
return _catalog->get_num_entries();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::LiveCatalog::get_entry
|
||||
// Access: Public
|
||||
// Description: Returns the nth entry in the catalog.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const DCPackerCatalog::Entry &DCPackerCatalog::LiveCatalog::
|
||||
get_entry(int n) const {
|
||||
return _catalog->get_entry(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::LiveCatalog::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::LiveCatalog::
|
||||
find_entry_by_name(const string &name) const {
|
||||
return _catalog->find_entry_by_name(name);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::LiveCatalog::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::LiveCatalog::
|
||||
find_entry_by_field(const DCPackerInterface *field) const {
|
||||
return _catalog->find_entry_by_field(field);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::get_num_entries
|
||||
// Access: Public
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "dcPackerCatalog.h"
|
||||
#include "dcPackerInterface.h"
|
||||
#include "dcPacker.h"
|
||||
#include "dcSwitch.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::Constructor
|
||||
@ -31,6 +32,22 @@ DCPackerCatalog(const DCPackerInterface *root) : _root(root) {
|
||||
_live_catalog = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: The copy constructor is used only internally, in
|
||||
// update_switch_fields().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCPackerCatalog::
|
||||
DCPackerCatalog(const DCPackerCatalog ©) :
|
||||
_root(copy._root),
|
||||
_entries(copy._entries),
|
||||
_entries_by_name(copy._entries_by_name),
|
||||
_entries_by_field(copy._entries_by_field)
|
||||
{
|
||||
_live_catalog = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::Destructor
|
||||
// Access: Private
|
||||
@ -42,6 +59,11 @@ DCPackerCatalog::
|
||||
if (_live_catalog != (LiveCatalog *)NULL) {
|
||||
delete _live_catalog;
|
||||
}
|
||||
|
||||
SwitchCatalogs::iterator si;
|
||||
for (si = _switch_catalogs.begin(); si != _switch_catalogs.end(); ++si) {
|
||||
delete (*si).second;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -95,11 +117,13 @@ find_entry_by_field(const DCPackerInterface *field) const {
|
||||
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 the previously-allocated live catalog; it will be the
|
||||
// same as this one since it's based on a fixed-length field.
|
||||
return _live_catalog;
|
||||
}
|
||||
|
||||
LiveCatalog *live_catalog = new LiveCatalog;
|
||||
live_catalog->_catalog = this;
|
||||
live_catalog->_live_entries.reserve(_entries.size());
|
||||
LiveCatalogEntry zero_entry;
|
||||
zero_entry._begin = 0;
|
||||
@ -110,13 +134,14 @@ get_live_catalog(const char *data, size_t length) const {
|
||||
|
||||
DCPacker packer;
|
||||
packer.begin_unpack(data, length, _root);
|
||||
r_fill_live_catalog(live_catalog, packer);
|
||||
const DCSwitch *last_switch = NULL;
|
||||
r_fill_live_catalog(live_catalog, packer, last_switch);
|
||||
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
|
||||
if (_root->has_fixed_structure()) {
|
||||
// If our root field has a fixed structure, 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;
|
||||
@ -165,6 +190,50 @@ add_entry(const string &name, const DCPackerInterface *field,
|
||||
_entries_by_field.insert(EntriesByField::value_type(field, entry_index));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::r_fill_catalog
|
||||
// Access: Private
|
||||
// Description: Called by DCPackerInterface to recursively fill up a
|
||||
// newly-allocated reference catalog. Also called by
|
||||
// update_switch_fields to append fields to a catalog
|
||||
// after a DCSwitch node is selected.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCPackerCatalog::
|
||||
r_fill_catalog(const string &name_prefix, const DCPackerInterface *field,
|
||||
const DCPackerInterface *parent, int field_index) {
|
||||
string next_name_prefix = name_prefix;
|
||||
|
||||
if (!field->get_name().empty()) {
|
||||
// Record this entry in the catalog.
|
||||
next_name_prefix += field->get_name();
|
||||
add_entry(next_name_prefix, field, parent, field_index);
|
||||
|
||||
next_name_prefix += ".";
|
||||
}
|
||||
|
||||
const DCSwitch *dswitch = ((DCPackerInterface *)field)->as_switch();
|
||||
if (dswitch != (DCSwitch *)NULL) {
|
||||
// If we come upon a DCSwitch while building the catalog, save the
|
||||
// name_prefix at this point so we'll have it again when we later
|
||||
// encounter the switch while unpacking a live record (and so we
|
||||
// can return to this point in the recursion from
|
||||
// update_switch_fields).
|
||||
_switch_prefixes[dswitch] = next_name_prefix;
|
||||
}
|
||||
|
||||
// Add any children.
|
||||
if (field->has_nested_fields()) {
|
||||
int num_nested = field->get_num_nested_fields();
|
||||
// It's ok if num_nested is -1.
|
||||
for (int i = 0; i < num_nested; i++) {
|
||||
DCPackerInterface *nested = field->get_nested_field(i);
|
||||
if (nested != (DCPackerInterface *)NULL) {
|
||||
r_fill_catalog(next_name_prefix, nested, field, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::r_fill_live_catalog
|
||||
// Access: Private
|
||||
@ -173,18 +242,20 @@ add_entry(const string &name, const DCPackerInterface *field,
|
||||
// appropriate offsets.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCPackerCatalog::
|
||||
r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const {
|
||||
r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer,
|
||||
const DCSwitch *&last_switch) const {
|
||||
const DCPackerInterface *current_field = packer.get_current_field();
|
||||
|
||||
int field_index = find_entry_by_field(current_field);
|
||||
int field_index = live_catalog->find_entry_by_field(current_field);
|
||||
if (field_index >= 0) {
|
||||
nassertv(field_index < (int)live_catalog->_live_entries.size());
|
||||
live_catalog->_live_entries[field_index]._begin = 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);
|
||||
r_fill_live_catalog(live_catalog, packer, last_switch);
|
||||
}
|
||||
packer.pop();
|
||||
|
||||
@ -195,4 +266,84 @@ r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer) const {
|
||||
if (field_index >= 0) {
|
||||
live_catalog->_live_entries[field_index]._end = packer.get_num_unpacked_bytes();
|
||||
}
|
||||
|
||||
if (last_switch != packer.get_last_switch()) {
|
||||
// We've just invoked a new DCSwitch. That means we must add the
|
||||
// new fields revealed by the switch to the reference catalog.
|
||||
last_switch = packer.get_last_switch();
|
||||
|
||||
const DCPackerInterface *switch_case = packer.get_current_parent();
|
||||
nassertv(switch_case != (DCPackerInterface *)NULL);
|
||||
const DCPackerCatalog *switch_catalog =
|
||||
live_catalog->_catalog->update_switch_fields(last_switch, switch_case);
|
||||
live_catalog->_catalog = switch_catalog;
|
||||
|
||||
// And we also have to expand the live catalog to hold the new
|
||||
// entries.
|
||||
LiveCatalogEntry zero_entry;
|
||||
zero_entry._begin = 0;
|
||||
zero_entry._end = 0;
|
||||
for (size_t i = live_catalog->_live_entries.size();
|
||||
i < switch_catalog->_entries.size();
|
||||
i++) {
|
||||
live_catalog->_live_entries.push_back(zero_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerCatalog::update_switch_fields
|
||||
// Access: Private
|
||||
// Description: Returns a new DCPackerCatalog that includes all of
|
||||
// the fields in this object, with the addition of the
|
||||
// fields named by switch_case.
|
||||
//
|
||||
// This is used to implement switches, which change the
|
||||
// set of fields they make available according to the
|
||||
// data in the record, and therefore present a different
|
||||
// catalog under different circumstances.
|
||||
//
|
||||
// This returned pointer is allocated one time for each
|
||||
// different switch_case instance; if a given same
|
||||
// switch_case is supplied twice, the same pointer is
|
||||
// returned both times. The ownership of the returned
|
||||
// pointer is kept by this object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const DCPackerCatalog *DCPackerCatalog::
|
||||
update_switch_fields(const DCSwitch *dswitch,
|
||||
const DCPackerInterface *switch_case) const {
|
||||
SwitchCatalogs::const_iterator si = _switch_catalogs.find(switch_case);
|
||||
if (si != _switch_catalogs.end()) {
|
||||
return (*si).second;
|
||||
}
|
||||
|
||||
// Look up the name_prefix will we use for all of the fields that
|
||||
// descend from this switch. This should be stored in this record
|
||||
// because we must have come across the DCSwitch when building the
|
||||
// catalog the first time.
|
||||
SwitchPrefixes::const_iterator pi = _switch_prefixes.find(dswitch);
|
||||
nassertr(pi != _switch_prefixes.end(), NULL);
|
||||
string name_prefix = (*pi).second;
|
||||
|
||||
// Start by creating a new DCPackerCatalog object that contains all
|
||||
// of the fields that this one contains.
|
||||
DCPackerCatalog *switch_catalog = new DCPackerCatalog(*this);
|
||||
|
||||
// Now record all of the fields of the switch case in the new
|
||||
// catalog. We start with the second field of the switch case,
|
||||
// since the first field will be the switch parameter itself, which
|
||||
// we would have already recorded the first time around.
|
||||
int num_nested = switch_case->get_num_nested_fields();
|
||||
for (int i = 1; i < num_nested; i++) {
|
||||
DCPackerInterface *nested = switch_case->get_nested_field(i);
|
||||
if (nested != (DCPackerInterface *)NULL) {
|
||||
switch_catalog->r_fill_catalog(name_prefix, nested, switch_case, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the newly-generated switch catalog in the record so the
|
||||
// same pointer can be returned in the future.
|
||||
((DCPackerCatalog *)this)->_switch_catalogs[switch_case] = switch_catalog;
|
||||
|
||||
return switch_catalog;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
class DCPackerInterface;
|
||||
class DCPacker;
|
||||
class DCSwitch;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DCPackerCatalog
|
||||
@ -35,6 +36,7 @@ class DCPacker;
|
||||
class EXPCL_DIRECT DCPackerCatalog {
|
||||
private:
|
||||
DCPackerCatalog(const DCPackerInterface *root);
|
||||
DCPackerCatalog(const DCPackerCatalog ©);
|
||||
~DCPackerCatalog();
|
||||
|
||||
public:
|
||||
@ -62,9 +64,16 @@ public:
|
||||
INLINE size_t get_begin(int n) const;
|
||||
INLINE size_t get_end(int n) const;
|
||||
|
||||
INLINE int get_num_entries() const;
|
||||
INLINE const Entry &get_entry(int n) const;
|
||||
INLINE int find_entry_by_name(const string &name) const;
|
||||
INLINE int find_entry_by_field(const DCPackerInterface *field) const;
|
||||
|
||||
private:
|
||||
typedef pvector<LiveCatalogEntry> LiveEntries;
|
||||
LiveEntries _live_entries;
|
||||
|
||||
const DCPackerCatalog *_catalog;
|
||||
friend class DCPackerCatalog;
|
||||
};
|
||||
|
||||
@ -75,11 +84,19 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
void r_fill_catalog(const string &name_prefix, const DCPackerInterface *field,
|
||||
const DCPackerInterface *parent, int field_index);
|
||||
void r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer,
|
||||
const DCSwitch *&last_switch) const;
|
||||
|
||||
const DCPackerCatalog *update_switch_fields(const DCSwitch *dswitch,
|
||||
const DCPackerInterface *switch_case) const;
|
||||
|
||||
|
||||
const DCPackerInterface *_root;
|
||||
LiveCatalog *_live_catalog;
|
||||
@ -93,6 +110,12 @@ private:
|
||||
typedef pmap<const DCPackerInterface *, int> EntriesByField;
|
||||
EntriesByField _entries_by_field;
|
||||
|
||||
typedef pmap<const DCPackerInterface *, DCPackerCatalog *> SwitchCatalogs;
|
||||
SwitchCatalogs _switch_catalogs;
|
||||
|
||||
typedef pmap<const DCSwitch *, string> SwitchPrefixes;
|
||||
SwitchPrefixes _switch_prefixes;
|
||||
|
||||
friend class DCPackerInterface;
|
||||
};
|
||||
|
||||
|
@ -60,6 +60,24 @@ get_fixed_byte_size() const {
|
||||
return _fixed_byte_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerInterface::has_fixed_structure
|
||||
// Access: Public
|
||||
// Description: Returns true if this field type always has the same
|
||||
// structure regardless of the data in the stream, or
|
||||
// false if its structure may vary. This is almost, but
|
||||
// not quite, the same thing as has_fixed_byte_size.
|
||||
// The difference is that a DCSwitch may have multiple
|
||||
// cases all with the same byte size, but they will
|
||||
// still (presumably) have different structures, in the
|
||||
// sense that the actual list of fields varies according
|
||||
// to the live data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool DCPackerInterface::
|
||||
has_fixed_structure() const {
|
||||
return _has_fixed_structure;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerInterface::get_num_length_bytes
|
||||
// Access: Public
|
||||
|
@ -30,6 +30,7 @@ DCPackerInterface(const string &name) :
|
||||
{
|
||||
_has_fixed_byte_size = false;
|
||||
_fixed_byte_size = 0;
|
||||
_has_fixed_structure = false;
|
||||
_num_length_bytes = 0;
|
||||
_has_nested_fields = false;
|
||||
_num_nested_fields = -1;
|
||||
@ -47,6 +48,7 @@ DCPackerInterface(const DCPackerInterface ©) :
|
||||
_name(copy._name),
|
||||
_has_fixed_byte_size(copy._has_fixed_byte_size),
|
||||
_fixed_byte_size(copy._fixed_byte_size),
|
||||
_has_fixed_structure(copy._has_fixed_structure),
|
||||
_num_length_bytes(copy._num_length_bytes),
|
||||
_has_nested_fields(copy._has_nested_fields),
|
||||
_num_nested_fields(copy._num_nested_fields),
|
||||
@ -67,6 +69,16 @@ DCPackerInterface::
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerInterface::as_switch
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCSwitch *DCPackerInterface::
|
||||
as_switch() {
|
||||
return (DCSwitch *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCPackerInterface::calc_num_nested_fields
|
||||
// Access: Public, Virtual
|
||||
@ -303,39 +315,7 @@ make_catalog() {
|
||||
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);
|
||||
_catalog->r_fill_catalog("", nested, this, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "dcbase.h"
|
||||
#include "dcSubatomicType.h"
|
||||
|
||||
class DCSwitch;
|
||||
class DCPackData;
|
||||
class DCPackerCatalog;
|
||||
|
||||
@ -48,6 +49,7 @@ enum DCPackType {
|
||||
PT_array,
|
||||
PT_field,
|
||||
PT_class,
|
||||
PT_switch,
|
||||
};
|
||||
END_PUBLISH
|
||||
|
||||
@ -70,10 +72,13 @@ public:
|
||||
PUBLISHED:
|
||||
INLINE const string &get_name() const;
|
||||
|
||||
virtual DCSwitch *as_switch();
|
||||
|
||||
public:
|
||||
INLINE void set_name(const string &name);
|
||||
INLINE bool has_fixed_byte_size() const;
|
||||
INLINE size_t get_fixed_byte_size() const;
|
||||
INLINE bool has_fixed_structure() const;
|
||||
INLINE size_t get_num_length_bytes() const;
|
||||
|
||||
INLINE bool has_nested_fields() const;
|
||||
@ -152,6 +157,7 @@ protected:
|
||||
string _name;
|
||||
bool _has_fixed_byte_size;
|
||||
size_t _fixed_byte_size;
|
||||
bool _has_fixed_structure;
|
||||
size_t _num_length_bytes;
|
||||
bool _has_nested_fields;
|
||||
int _num_nested_fields;
|
||||
@ -159,9 +165,6 @@ protected:
|
||||
|
||||
private:
|
||||
void make_catalog();
|
||||
void r_fill_catalog(DCPackerCatalog *catalog, const string &name_prefix,
|
||||
DCPackerInterface *parent, int field_index);
|
||||
|
||||
|
||||
DCPackerCatalog *_catalog;
|
||||
};
|
||||
|
@ -31,6 +31,7 @@ DCParameter::
|
||||
DCParameter() {
|
||||
_typedef = NULL;
|
||||
_has_fixed_byte_size = false;
|
||||
_has_fixed_structure = false;
|
||||
_num_nested_fields = -1;
|
||||
}
|
||||
|
||||
@ -139,9 +140,12 @@ output(ostream &out, bool brief) const {
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCParameter::
|
||||
write(ostream &out, bool brief, int indent_level) const {
|
||||
write(ostream &out, bool, int indent_level) const {
|
||||
// we must always output the name when the parameter occurs by
|
||||
// itself within a class, so we ignore brief and pass false up to
|
||||
// output().
|
||||
indent(out, indent_level);
|
||||
output(out, brief);
|
||||
output(out, false);
|
||||
out << ";\n";
|
||||
}
|
||||
|
||||
@ -168,4 +172,6 @@ output_typedef_name(ostream &out, const string &prename, const string &name,
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCParameter::
|
||||
generate_hash(HashGenerator &) const {
|
||||
// We specifically don't call up to DCField::generate_hash(), since
|
||||
// the parameter name is not actually significant to the hash.
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "dcParserDefs.h"
|
||||
#include "dcFile.h"
|
||||
#include "dcClass.h"
|
||||
#include "dcSwitch.h"
|
||||
#include "dcAtomicField.h"
|
||||
#include "dcMolecularField.h"
|
||||
#include "dcClassParameter.h"
|
||||
@ -27,6 +28,7 @@
|
||||
|
||||
static DCFile *dc_file = (DCFile *)NULL;
|
||||
static DCClass *current_class = (DCClass *)NULL;
|
||||
static DCSwitch *current_switch = (DCSwitch *)NULL;
|
||||
static DCAtomicField *current_atomic = (DCAtomicField *)NULL;
|
||||
static DCMolecularField *current_molecular = (DCMolecularField *)NULL;
|
||||
static DCAtomicField::ElementType atomic_element(new DCSimpleParameter(ST_invalid));
|
||||
@ -71,6 +73,8 @@ dc_cleanup_parser() {
|
||||
%token KW_FROM
|
||||
%token KW_IMPORT
|
||||
%token KW_TYPEDEF
|
||||
%token KW_SWITCH
|
||||
%token KW_CASE
|
||||
|
||||
%token KW_INT8
|
||||
%token KW_INT16
|
||||
@ -111,6 +115,11 @@ dc_cleanup_parser() {
|
||||
%type <u.flag> kw_struct_or_kw_dclass
|
||||
%type <u.dclass> dclass_name
|
||||
%type <u.atomic> atomic_name
|
||||
%type <u.field> dclass_field
|
||||
%type <u.field> switch_field
|
||||
%type <u.field> atomic_field
|
||||
%type <u.field> molecular_field
|
||||
%type <u.field> switch
|
||||
%type <u.subatomic> type_token
|
||||
%type <u.parameter> type_name
|
||||
%type <u.parameter> type_definition
|
||||
@ -120,6 +129,7 @@ dc_cleanup_parser() {
|
||||
%type <u.parameter> parameter_definition
|
||||
%type <str> import_identifier
|
||||
%type <str> slash_identifier
|
||||
%type <str> optional_name
|
||||
%type <u.real> number
|
||||
|
||||
%%
|
||||
@ -263,13 +273,7 @@ base_list:
|
||||
dclass_fields:
|
||||
empty
|
||||
| dclass_fields ';'
|
||||
| dclass_fields atomic_field
|
||||
| dclass_fields molecular_field
|
||||
| dclass_fields unnamed_parameter ';'
|
||||
{
|
||||
current_class->add_field($2);
|
||||
}
|
||||
| dclass_fields named_parameter
|
||||
| dclass_fields dclass_field
|
||||
{
|
||||
if (!current_class->add_field($2)) {
|
||||
yyerror("Duplicate field name: " + $2->get_name());
|
||||
@ -277,32 +281,30 @@ dclass_fields:
|
||||
}
|
||||
;
|
||||
|
||||
dclass_field:
|
||||
atomic_field
|
||||
| molecular_field
|
||||
| switch
|
||||
| unnamed_parameter ';'
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| named_parameter
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
atomic_field:
|
||||
IDENTIFIER '('
|
||||
{
|
||||
current_atomic = new DCAtomicField($1);
|
||||
if (!current_class->add_field(current_atomic)) {
|
||||
yyerror("Duplicate field name: " + current_atomic->get_name());
|
||||
}
|
||||
}
|
||||
parameter_list ')' atomic_flags
|
||||
;
|
||||
|
||||
atomic_name:
|
||||
IDENTIFIER
|
||||
{
|
||||
DCField *field = current_class->get_field_by_name($1);
|
||||
$$ = (DCAtomicField *)NULL;
|
||||
if (field == (DCField *)NULL) {
|
||||
yyerror("Unknown field: " + $1);
|
||||
} else {
|
||||
$$ = field->as_atomic_field();
|
||||
if ($$ == (DCAtomicField *)NULL) {
|
||||
yyerror("Not an atomic field: " + $1);
|
||||
}
|
||||
}
|
||||
$$ = current_atomic;
|
||||
}
|
||||
;
|
||||
;
|
||||
|
||||
parameter_list:
|
||||
empty
|
||||
@ -794,13 +796,29 @@ molecular_field:
|
||||
IDENTIFIER ':'
|
||||
{
|
||||
current_molecular = new DCMolecularField($1);
|
||||
if (!current_class->add_field(current_molecular)) {
|
||||
yyerror("Duplicate field name: " + current_molecular->get_name());
|
||||
}
|
||||
}
|
||||
molecular_atom_list
|
||||
{
|
||||
$$ = current_molecular;
|
||||
}
|
||||
;
|
||||
|
||||
atomic_name:
|
||||
IDENTIFIER
|
||||
{
|
||||
DCField *field = current_class->get_field_by_name($1);
|
||||
$$ = (DCAtomicField *)NULL;
|
||||
if (field == (DCField *)NULL) {
|
||||
yyerror("Unknown field: " + $1);
|
||||
} else {
|
||||
$$ = field->as_atomic_field();
|
||||
if ($$ == (DCAtomicField *)NULL) {
|
||||
yyerror("Not an atomic field: " + $1);
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
molecular_atom_list:
|
||||
atomic_name
|
||||
{
|
||||
@ -821,6 +839,70 @@ molecular_atom_list:
|
||||
}
|
||||
;
|
||||
|
||||
optional_name:
|
||||
empty
|
||||
{
|
||||
$$ = "";
|
||||
}
|
||||
| IDENTIFIER
|
||||
;
|
||||
|
||||
switch:
|
||||
KW_SWITCH optional_name '(' parameter ')' '{'
|
||||
{
|
||||
$$ = current_switch;
|
||||
current_switch = new DCSwitch($2, $4);
|
||||
}
|
||||
switch_fields '}'
|
||||
{
|
||||
$$ = current_switch;
|
||||
current_switch = (DCSwitch *)$<u.parameter>7;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
switch_fields:
|
||||
empty
|
||||
| switch_fields ';'
|
||||
| switch_fields switch_case
|
||||
| switch_fields switch_field
|
||||
{
|
||||
if (current_switch->get_num_cases() == 0) {
|
||||
yyerror("case declaration required before first element");
|
||||
} else if (!current_switch->add_field($2)) {
|
||||
yyerror("Duplicate field name: " + $2->get_name());
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
switch_case:
|
||||
KW_CASE
|
||||
{
|
||||
current_packer = &default_packer;
|
||||
current_packer->begin_pack(current_switch->get_switch_parameter());
|
||||
}
|
||||
parameter_value ':'
|
||||
{
|
||||
if (!current_packer->end_pack()) {
|
||||
yyerror("Invalid value for switch parameter");
|
||||
} else {
|
||||
current_switch->add_case(current_packer->get_string());
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
switch_field:
|
||||
switch
|
||||
| unnamed_parameter ';'
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| named_parameter
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
empty:
|
||||
;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
class DCFile;
|
||||
class DCClass;
|
||||
class DCField;
|
||||
class DCAtomicField;
|
||||
class DCParameter;
|
||||
class DCPacker;
|
||||
@ -48,6 +49,7 @@ public:
|
||||
double real;
|
||||
bool flag;
|
||||
DCClass *dclass;
|
||||
DCField *field;
|
||||
DCAtomicField *atomic;
|
||||
DCSubatomicType subatomic;
|
||||
DCParameter *parameter;
|
||||
|
@ -166,6 +166,7 @@ DCSimpleParameter(DCSubatomicType type, int divisor) :
|
||||
case ST_invalid:
|
||||
break;
|
||||
}
|
||||
_has_fixed_structure = _has_fixed_byte_size;
|
||||
|
||||
set_divisor(divisor);
|
||||
|
||||
@ -412,9 +413,11 @@ set_range(const DCDoubleRange &range) {
|
||||
_num_length_bytes = 0;
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = _uint_range.get_one_value();
|
||||
_has_fixed_structure = true;
|
||||
} else {
|
||||
_num_length_bytes = 2;
|
||||
_has_fixed_byte_size = false;
|
||||
_has_fixed_structure = false;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -431,9 +434,11 @@ set_range(const DCDoubleRange &range) {
|
||||
_num_length_bytes = 0;
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = _uint_range.get_one_value();
|
||||
_has_fixed_structure = true;
|
||||
} else {
|
||||
_num_length_bytes = 4;
|
||||
_has_fixed_byte_size = false;
|
||||
_has_fixed_structure = false;
|
||||
}
|
||||
break;
|
||||
|
||||
|
397
direct/src/dcparser/dcSwitch.cxx
Normal file
397
direct/src/dcparser/dcSwitch.cxx
Normal file
@ -0,0 +1,397 @@
|
||||
// Filename: dcSwitch.cxx
|
||||
// Created by: drose (23Jun04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "dcSwitch.h"
|
||||
#include "dcField.h"
|
||||
#include "dcindent.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::Constructor
|
||||
// Access: Public
|
||||
// Description: The switch_parameter must be recently allocated via
|
||||
// new; it will be deleted via delete when the switch
|
||||
// destructs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCSwitch::
|
||||
DCSwitch(const string &name, DCParameter *switch_parameter) :
|
||||
DCField(name),
|
||||
_switch_parameter(switch_parameter)
|
||||
{
|
||||
_has_fixed_byte_size = _switch_parameter->has_fixed_byte_size();
|
||||
_fixed_byte_size = _switch_parameter->get_fixed_byte_size();
|
||||
_has_fixed_structure = false;
|
||||
|
||||
// The DCSwitch presents just one nested field initially, which is
|
||||
// the switch parameter. When we pack or unpack that, the DCPacker
|
||||
// calls apply_switch(), which returns a new record that presents
|
||||
// the remaining nested fields.
|
||||
_has_nested_fields = true;
|
||||
_num_nested_fields = 1;
|
||||
|
||||
_pack_type = PT_switch;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCSwitch::
|
||||
~DCSwitch() {
|
||||
delete _switch_parameter;
|
||||
|
||||
Cases::iterator ci;
|
||||
for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
|
||||
const SwitchCase *dcase = (*ci);
|
||||
delete dcase;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::as_switch
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCSwitch *DCSwitch::
|
||||
as_switch() {
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_switch_parameter
|
||||
// Access: Published
|
||||
// Description: Returns the key parameter on which the switch is
|
||||
// based. The value of this parameter in the record
|
||||
// determines which one of the several cases within the
|
||||
// switch will be used.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCParameter *DCSwitch::
|
||||
get_switch_parameter() const {
|
||||
return _switch_parameter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_num_cases
|
||||
// Access: Published
|
||||
// Description: Returns the number of different cases within the
|
||||
// switch. The legal values for case_index range from 0
|
||||
// to get_num_cases() - 1.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DCSwitch::
|
||||
get_num_cases() const {
|
||||
return _cases.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_case_by_value
|
||||
// Access: Published
|
||||
// Description: Returns the index number of the case with the
|
||||
// indicated packed value, or -1 if no case has this
|
||||
// value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DCSwitch::
|
||||
get_case_by_value(const string &case_value) const {
|
||||
CasesByValue::const_iterator vi;
|
||||
vi = _cases_by_value.find(case_value);
|
||||
if (vi != _cases_by_value.end()) {
|
||||
return (*vi).second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_value
|
||||
// Access: Published
|
||||
// Description: Returns the packed value associated with the
|
||||
// indicated case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string DCSwitch::
|
||||
get_value(int case_index) const {
|
||||
nassertr(case_index >= 0 && case_index < (int)_cases.size(), string());
|
||||
return _cases[case_index]->_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_num_fields
|
||||
// Access: Published
|
||||
// Description: Returns the number of fields in the indicated case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DCSwitch::
|
||||
get_num_fields(int case_index) const {
|
||||
nassertr(case_index >= 0 && case_index < (int)_cases.size(), 0);
|
||||
return _cases[case_index]->_fields.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_num_fields
|
||||
// Access: Published
|
||||
// Description: Returns the nth field in the indicated case.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCField *DCSwitch::
|
||||
get_field(int case_index, int n) const {
|
||||
nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
|
||||
nassertr(n >= 0 && n < (int)_cases[case_index]->_fields.size(), NULL);
|
||||
return _cases[case_index]->_fields[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_field_by_name
|
||||
// Access: Published
|
||||
// Description: Returns the field with the given name from the
|
||||
// indicated case, or NULL if no field has this name.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCField *DCSwitch::
|
||||
get_field_by_name(int case_index, const string &name) const {
|
||||
nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
|
||||
|
||||
const FieldsByName &fields_by_name = _cases[case_index]->_fields_by_name;
|
||||
FieldsByName::const_iterator ni;
|
||||
ni = fields_by_name.find(name);
|
||||
if (ni != fields_by_name.end()) {
|
||||
return (*ni).second;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::get_nested_field
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the DCPackerInterface object that represents
|
||||
// the nth nested field. This may return NULL if there
|
||||
// is no such field (but it shouldn't do this if n is in
|
||||
// the range 0 <= n < get_num_nested_fields()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCPackerInterface *DCSwitch::
|
||||
get_nested_field(int) const {
|
||||
// The DCSwitch presents just one nested field initially, which is
|
||||
// the switch parameter. When we pack or unpack that, the DCPacker
|
||||
// calls apply_switch(), which returns a new record that presents
|
||||
// the remaining nested fields.
|
||||
return _switch_parameter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::add_case
|
||||
// Access: Public
|
||||
// Description: Adds a new case to the switch with the indicated
|
||||
// value, and returns the new case_index. If the value
|
||||
// has already been used for another case, returns -1.
|
||||
// This is normally called only by the parser.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DCSwitch::
|
||||
add_case(const string &value) {
|
||||
int case_index = (int)_cases.size();
|
||||
if (!_cases_by_value.insert(CasesByValue::value_type(value, case_index)).second) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SwitchCase *dcase = new SwitchCase(_name, value);
|
||||
dcase->add_field(_switch_parameter);
|
||||
_cases.push_back(dcase);
|
||||
return case_index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::add_field
|
||||
// Access: Public
|
||||
// Description: Adds a field to the case most recently added via
|
||||
// add_case(). Returns true if successful, false if the
|
||||
// field duplicates a field already named within this
|
||||
// case. It is an error to call this before calling
|
||||
// add_case(). This is normally called only by the
|
||||
// parser.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DCSwitch::
|
||||
add_field(DCField *field) {
|
||||
nassertr(!_cases.empty(), false);
|
||||
|
||||
if (!_cases.back()->add_field(field)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if we now have a fixed byte size for the overall switch.
|
||||
// This will be true only if all of the individual cases have the
|
||||
// same fixed byte size.
|
||||
_fixed_byte_size = _cases.back()->get_fixed_byte_size();
|
||||
|
||||
Cases::const_iterator ci;
|
||||
for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
|
||||
const SwitchCase *dcase = (*ci);
|
||||
if (!dcase->has_fixed_byte_size() ||
|
||||
dcase->get_fixed_byte_size() != _fixed_byte_size) {
|
||||
|
||||
// Nope, we have a variable byte size.
|
||||
_has_fixed_byte_size = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Sonofagun, we do have a fixed byte size.
|
||||
_has_fixed_byte_size = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::apply_switch
|
||||
// Access: Public
|
||||
// Description: Returns the DCPackerInterface that presents the
|
||||
// alternative fields for the case indicated by the
|
||||
// given packed value string, or NULL if the value
|
||||
// string does not match one of the expected cases.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const DCPackerInterface *DCSwitch::
|
||||
apply_switch(const char *value_data, size_t length) const {
|
||||
CasesByValue::const_iterator vi;
|
||||
vi = _cases_by_value.find(string(value_data, length));
|
||||
if (vi != _cases_by_value.end()) {
|
||||
return _cases[(*vi).second];
|
||||
}
|
||||
|
||||
// Invalid value.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::write
|
||||
// Access: Public, Virtual
|
||||
// Description: Generates a parseable description of the object to
|
||||
// the indicated output stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCSwitch::
|
||||
write(ostream &out, bool brief, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< "switch";
|
||||
if (!_name.empty()) {
|
||||
out << " " << _name;
|
||||
}
|
||||
out << " (";
|
||||
_switch_parameter->output(out, brief);
|
||||
out << ") {\n";
|
||||
|
||||
Cases::const_iterator ci;
|
||||
for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
|
||||
const SwitchCase *dcase = (*ci);
|
||||
indent(out, indent_level)
|
||||
<< "case " << _switch_parameter->format_data(dcase->_value) << ":\n";
|
||||
|
||||
Fields::const_iterator fi;
|
||||
if (!dcase->_fields.empty()) {
|
||||
fi = dcase->_fields.begin();
|
||||
++fi;
|
||||
while (fi != dcase->_fields.end()) {
|
||||
(*fi)->write(out, brief, indent_level + 2);
|
||||
++fi;
|
||||
}
|
||||
}
|
||||
}
|
||||
indent(out, indent_level)
|
||||
<< "};\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::generate_hash
|
||||
// Access: Public, Virtual
|
||||
// Description: Accumulates the properties of this switch into the
|
||||
// hash.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCSwitch::
|
||||
generate_hash(HashGenerator &hashgen) const {
|
||||
DCField::generate_hash(hashgen);
|
||||
|
||||
_switch_parameter->generate_hash(hashgen);
|
||||
|
||||
hashgen.add_int(_cases.size());
|
||||
Cases::const_iterator ci;
|
||||
for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
|
||||
const SwitchCase *dcase = (*ci);
|
||||
hashgen.add_string(dcase->_value);
|
||||
|
||||
hashgen.add_int(dcase->_fields.size());
|
||||
Fields::const_iterator fi;
|
||||
for (fi = dcase->_fields.begin(); fi != dcase->_fields.end(); ++fi) {
|
||||
(*fi)->generate_hash(hashgen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::SwitchCase::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCSwitch::SwitchCase::
|
||||
SwitchCase(const string &name, const string &value) :
|
||||
DCPackerInterface(name),
|
||||
_value(value)
|
||||
{
|
||||
_has_nested_fields = true;
|
||||
_num_nested_fields = 0;
|
||||
_pack_type = PT_switch;
|
||||
|
||||
_has_fixed_byte_size = true;
|
||||
_fixed_byte_size = 0;
|
||||
_has_fixed_structure = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::SwitchCase::get_nested_field
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns the DCPackerInterface object that represents
|
||||
// the nth nested field. This may return NULL if there
|
||||
// is no such field (but it shouldn't do this if n is in
|
||||
// the range 0 <= n < get_num_nested_fields()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCPackerInterface *DCSwitch::SwitchCase::
|
||||
get_nested_field(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_fields.size(), NULL);
|
||||
return _fields[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCSwitch::SwitchCase::add_field
|
||||
// Access: Public
|
||||
// Description: Adds a field to this case. Returns true if
|
||||
// successful, false if the field duplicates a field
|
||||
// already named within this case. This is normally
|
||||
// called only by the parser.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DCSwitch::SwitchCase::
|
||||
add_field(DCField *field) {
|
||||
bool inserted = _fields_by_name.insert
|
||||
(FieldsByName::value_type(field->get_name(), field)).second;
|
||||
|
||||
if (!inserted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_fields.push_back(field);
|
||||
|
||||
_num_nested_fields = (int)_fields.size();
|
||||
|
||||
// See if we still have a fixed byte size.
|
||||
if (_has_fixed_byte_size) {
|
||||
_has_fixed_byte_size = field->has_fixed_byte_size();
|
||||
_fixed_byte_size += field->get_fixed_byte_size();
|
||||
}
|
||||
if (_has_fixed_structure) {
|
||||
_has_fixed_structure = field->has_fixed_structure();
|
||||
}
|
||||
return true;
|
||||
}
|
86
direct/src/dcparser/dcSwitch.h
Normal file
86
direct/src/dcparser/dcSwitch.h
Normal file
@ -0,0 +1,86 @@
|
||||
// Filename: dcSwitch.h
|
||||
// Created by: drose (23Jun04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 DCSWITCH_H
|
||||
#define DCSWITCH_H
|
||||
|
||||
#include "dcbase.h"
|
||||
#include "dcField.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DCSwitch
|
||||
// Description : This represents a switch statement, which can appear
|
||||
// inside a class body and represents two or more
|
||||
// alternative unpacking schemes based on the first
|
||||
// field read.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_DIRECT DCSwitch : public DCField {
|
||||
public:
|
||||
DCSwitch(const string &name, DCParameter *switch_parameter);
|
||||
virtual ~DCSwitch();
|
||||
|
||||
PUBLISHED:
|
||||
virtual DCSwitch *as_switch();
|
||||
|
||||
DCParameter *get_switch_parameter() const;
|
||||
|
||||
int get_num_cases() const;
|
||||
int get_case_by_value(const string &case_value) const;
|
||||
|
||||
string get_value(int case_index) const;
|
||||
int get_num_fields(int case_index) const;
|
||||
DCField *get_field(int case_index, int n) const;
|
||||
DCField *get_field_by_name(int case_index, const string &name) const;
|
||||
|
||||
public:
|
||||
virtual DCPackerInterface *get_nested_field(int n) const;
|
||||
|
||||
int add_case(const string &value);
|
||||
bool add_field(DCField *field);
|
||||
|
||||
const DCPackerInterface *apply_switch(const char *value_data, size_t length) const;
|
||||
|
||||
virtual void write(ostream &out, bool brief, int indent_level) const;
|
||||
virtual void generate_hash(HashGenerator &hashgen) const;
|
||||
|
||||
private:
|
||||
DCParameter *_switch_parameter;
|
||||
|
||||
typedef pvector<DCField *> Fields;
|
||||
typedef pmap<string, DCField *> FieldsByName;
|
||||
|
||||
class SwitchCase : public DCPackerInterface {
|
||||
public:
|
||||
SwitchCase(const string &name, const string &value);
|
||||
virtual DCPackerInterface *get_nested_field(int n) const;
|
||||
|
||||
bool add_field(DCField *field);
|
||||
|
||||
string _value;
|
||||
Fields _fields;
|
||||
FieldsByName _fields_by_name;
|
||||
};
|
||||
|
||||
typedef pvector<SwitchCase *> Cases;
|
||||
Cases _cases;
|
||||
|
||||
typedef pmap<string, int> CasesByValue;
|
||||
CasesByValue _cases_by_value;
|
||||
};
|
||||
|
||||
#endif
|
@ -7,4 +7,5 @@
|
||||
#include "dcFile.cxx"
|
||||
#include "dcMolecularField.cxx"
|
||||
#include "dcSubatomicType.cxx"
|
||||
#include "dcSwitch.cxx"
|
||||
#include "dcTypedef.cxx"
|
||||
|
Loading…
x
Reference in New Issue
Block a user