diff options
Diffstat (limited to 'TAO/tao/IIOP_Interpreter.cpp')
-rw-r--r-- | TAO/tao/IIOP_Interpreter.cpp | 1133 |
1 files changed, 1133 insertions, 0 deletions
diff --git a/TAO/tao/IIOP_Interpreter.cpp b/TAO/tao/IIOP_Interpreter.cpp new file mode 100644 index 00000000000..6baf82873c6 --- /dev/null +++ b/TAO/tao/IIOP_Interpreter.cpp @@ -0,0 +1,1133 @@ +// $ID: interp.cpp,v 1.21 1998/03/17 19:55:03 levine Exp $ + +// @(#)interp.cpp 1.4 95/11/04 +// Copyright 1994-1995 by Sun Microsystems Inc. +// All Rights Reserved + +#include "tao/corba.h" + +TAO_IIOP_Interpreter::Table_Element +TAO_IIOP_Interpreter::table_[CORBA::TC_KIND_COUNT] = +{ + { 0, 1, 0 }, // CORBA::tk_null + { 0, 1, 0 }, // CORBA::tk_void + + { 0, 1, 0, 0 }, // CORBA::tk_short + { 0, 1, 0, 0 }, // CORBA::tk_long + { 0, 1, 0, 0 }, // CORBA::tk_ushort + { 0, 1, 0, 0 }, // CORBA::tk_ulong + + { 0, 1, 0, 0 }, // CORBA::tk_float + { 0, 1, 0, 0 }, // CORBA::tk_double + + { 0, 1, 0, 0 }, // CORBA::tk_boolean + { 0, 1, 0, 0 }, // CORBA::tk_char + { 0, 1, 0, 0 }, // CORBA::tk_octet + { 0, 1, 0, 0 }, // CORBA::tk_any + + { 0, 1, 0, 0 }, // CORBA::tk_TypeCode + { 0, 1, 0, 0 }, // CORBA::tk_Principal + { 0, 1, 0, skip_encapsulation }, // CORBA::tk_objref + + { 0, 1, calc_struct_attributes, 0 }, // CORBA::tk_struct + { 0, 1, calc_union_attributes, 0 }, // CORBA::tk_union + + { 0, 1, 0, skip_encapsulation }, // CORBA::tk_enum + { 0, 1, 0, skip_long }, // CORBA::tk_string + { 0, 1, 0, skip_encapsulation }, // CORBA::tk_sequence + { 0, 1, calc_array_attributes, 0 }, // CORBA::tk_array + + // = Two TCKind values added in 94-11-7 + { 0, 1, calc_alias_attributes, 0 }, // CORBA::tk_alias + { 0, 1, calc_exception_attributes, 0 }, // CORBA::tk_except + + // = Five extended IDL data types, defined in Appendix A of 94-9-32 + // but here with different numeric TCKind codes. These types + // represent extensions to CORBA (specifically, to IDL) which are + // not yet standardized. + + { 0, 1, 0, 0 }, // CORBA::tk_longlong + { 0, 1, 0, 0 }, // CORBA::tk_ulonglong + { 0, 1, 0, 0 }, // CORBA::tk_longdouble + { 0, 1, 0, 0 }, // CORBA::tk_wchar + { 0, 1, 0, skip_long } // CORBA::tk_wstring +}; + +// Runtime initialization of the table above; note that this compiles +// down to a set of assignment statements, with the real work done by +// the C++ compiler when this file gets compiled. +// +// "Natural alignment" is a policy that the processor controls the +// alignment of data based on its type. There's variation; some CPUs +// have a maximum alignment requirement of two or four bytes, others +// have some type-specific exceptions to the normal "alignment == +// size" rule. +// +// "Fixed" alignment ignores data type when establishing alignment; +// not all processors support such policies, and those which do often +// pay a cost to do so (viz. RISC/CISC discussions). The primary +// example of an OS family that chose "fixed" alignment is Microsoft's +// x86 systems, which normally align on one byte boundaries to promote +// data space efficiency. +// +// NOTE: typical PC compiler options let you specify other alignments, +// but none are "natural". Also, they don't apply consistently to all +// data types. Change the "one byte" assumption with extreme caution! +// And make sure all header files (e.g. generated by an IDL compiler) +// make sure that alignment of IDL-defined data types is consistent +// (one byte). + + enum TCKIND + { + tk_null = 0, + tk_void = 1, + tk_short = 2, + tk_long = 3, + tk_ushort = 4, + tk_ulong = 5, + tk_float = 6, + tk_double = 7, + tk_boolean = 8, + tk_char = 9, + tk_octet = 10, + tk_any = 11, + tk_TypeCode = 12, + tk_Principal = 13, + tk_objref = 14, + tk_struct = 15, + tk_union = 16, + tk_enum = 17, + tk_string = 18, + tk_sequence = 19, + tk_array = 20, + tk_alias = 21, // 94-11-7 + tk_except = 22, // 94-11-7 + + // these five are OMG-IDL data type extensions + tk_longlong = 23, // 94-9-32 Appendix A (+ 2) + tk_ulonglong = 24, // 94-9-32 Appendix A (+ 2) + tk_longdouble = 25, // 94-9-32 Appendix A (+ 2) + tk_wchar = 26, // 94-9-32 Appendix A (+ 2) + tk_wstring = 27, // 94-9-32 Appendix A (+ 2) + + // This symbol is not defined by CORBA 2.0. It's used to speed up + // dispatch based on TCKind values, and lets many important ones + // just be table lookups. It must always be the last enum value!! + + TC_KIND_COUNT + }; + +#if defined (TAO_HAS_FIXED_BYTE_ALIGNMENT) + // Have a bogus one + #define declare_entry(x,t) struct align_struct_ ## t { } + + #define setup_entry(x,t) \ + { \ + TAO_IIOP_Interpreter::table_ [t].size_ = sizeof (x); \ + TAO_IIOP_Interpreter::table_ [t].alignment_ = 1; \ + } +#else /* ! TAO_HAS_FIXED_BYTE_ALIGNMENT */ + // unix, ACE_WIN32, VXWORKS, __Lynx__, at least + #define declare_entry(x,t) \ + struct align_struct_ ## t \ + { \ + x one; \ + char dummy [TAO_MAXIMUM_NATIVE_TYPE_SIZE + 1 - sizeof(x)]; \ + x two; \ + } + + #define setup_entry(x,t) \ + { \ + align_struct_ ## t align; \ + TAO_IIOP_Interpreter::table_ [t].size_ = sizeof (x); \ + TAO_IIOP_Interpreter::table_ [t].alignment_ = \ + (char *) &align.two - (char *) &align.one - TAO_MAXIMUM_NATIVE_TYPE_SIZE; \ + } +#endif /* ! TAO_HAS_FIXED_BYTE_ALIGNMENT */ + +// Fills in fixed size and alignment values. + +declare_entry (CORBA::Short, tk_short); +declare_entry (CORBA::Long, tk_long); +declare_entry (CORBA::UShort, tk_ushort); +declare_entry (CORBA::ULong, tk_ulong); + +declare_entry (CORBA::Float, tk_float); +declare_entry (CORBA::Double, tk_double); + +declare_entry (CORBA::Boolean, tk_boolean); +declare_entry (CORBA::Char, tk_char); +declare_entry (CORBA::Octet, tk_octet); +declare_entry (CORBA::Any, tk_any); + +declare_entry (CORBA::TypeCode_ptr, tk_TypeCode); +declare_entry (CORBA::Principal_ptr, tk_Principal); +declare_entry (CORBA::Object_ptr, tk_objref); + +declare_entry (CORBA::String, tk_string); +declare_entry (TAO_opaque, tk_sequence); + +declare_entry (CORBA::LongLong, tk_longlong); +declare_entry (CORBA::ULongLong, tk_ulonglong); +declare_entry (CORBA::LongDouble, tk_longdouble); +declare_entry (CORBA::WChar, tk_wchar); +declare_entry (CORBA::WString, tk_wstring); + +void +TAO_IIOP_Interpreter::init_table (void) +{ + setup_entry (CORBA::Short, tk_short); + setup_entry (CORBA::Long, tk_long); + setup_entry (CORBA::UShort, tk_ushort); + setup_entry (CORBA::ULong, tk_ulong); + + setup_entry (CORBA::Float, tk_float); + setup_entry (CORBA::Double, tk_double); + + setup_entry (CORBA::Boolean, tk_boolean); + setup_entry (CORBA::Char, tk_char); + setup_entry (CORBA::Octet, tk_octet); + setup_entry (CORBA::Any, tk_any); + + setup_entry (CORBA::TypeCode_ptr, tk_TypeCode); + setup_entry (CORBA::Principal_ptr, tk_Principal); + setup_entry (CORBA::Object_ptr, tk_objref); + + enum generic_enum {a, b, c, d}; + + // XXX workaround for G++ 2.6.3 bug + // setup_entry (generic_enum, CORBA::tk_enum); + TAO_IIOP_Interpreter::table_ [CORBA::tk_enum].size_ = + sizeof (generic_enum); + TAO_IIOP_Interpreter::table_ [CORBA::tk_enum].alignment_ = + sizeof (generic_enum); + + setup_entry (CORBA::String, tk_string); + setup_entry (TAO_opaque, tk_sequence); + + setup_entry (CORBA::LongLong, tk_longlong); + setup_entry (CORBA::ULongLong, tk_ulonglong); + setup_entry (CORBA::LongDouble, tk_longdouble); + setup_entry (CORBA::WChar, tk_wchar); + setup_entry (CORBA::WString, tk_wstring); +} + +#undef setup + +CORBA::Boolean +TAO_IIOP_Interpreter::skip_encapsulation (CDR *stream) +{ + return stream->skip_string (); +} + +CORBA::Boolean +TAO_IIOP_Interpreter::skip_long (CDR *stream) +{ + CORBA::ULong scratch; + + return stream->get_ulong (scratch); +} + +// For a given typecode, figure out its size and alignment needs. +// This version is used mostly when traversing other typecodes, and +// follows these rules: +// +// - Some typecodes are illegal (can't be nested inside others); +// - Indirections are allowed; +// - The whole typecode (including TCKind enum) is in the stream +// +// When the routine returns, the stream has skipped this TypeCode. +// +// "size" is returned, "alignment" is an 'out' parameter. If it is +// non-null, "tc" is initialized to hold the contents of the TypeCode; +// it depends on the contents of the original stream to be valid. +// +// XXX explore splitting apart returning the size/alignment data and +// the TypeCode initialization; union traversal would benefit a bit, +// but it would need more than that to make it as speedy as struct +// traversal. + +size_t +TAO_IIOP_Interpreter::calc_nested_size_and_alignment (CORBA::TypeCode_ptr tc, + CDR *original_stream, + size_t &alignment, + CORBA::Environment &env) +{ + // Get the "kind" ... if this is an indirection, this is a guess + // which will soon be updated. + CORBA::ULong temp; + CORBA::TCKind kind; + + if (original_stream->get_ulong (temp) == CORBA::B_FALSE) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + env.clear (); + kind = (CORBA::TCKind) temp; + + // Check for indirection, setting up the right CDR stream to use + // when getting the rest of the parameters. (We rely on the fact + // that indirections may not point to indirections.) + CDR indirected_stream; + CDR *stream; + + if (kind == ~0) + { + // Get indirection, sanity check it, set up new stream pointing + // there. + // + // XXX access to "real" size limit for this typecode and use it + // to check for errors before indirect and to limit the new + // stream's length. ULONG_MAX is too much! + + CORBA::Long offset; + if (!original_stream->get_long (offset) + || offset >= -8 + || ((-offset) & 0x03) != 0) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + // offset -= 4; // correct for get_long update + + // TODO Provide a method to get an encapsulation from a CDR + // stream. + indirected_stream.setup_indirection (*original_stream, offset); + stream = &indirected_stream; + + // Fetch indirected-to TCKind, deducing byte order. + + if (!indirected_stream.get_ulong (temp)) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + kind = (CORBA::TCKind) temp; + } + else + stream = original_stream; + + // Check for illegal TCKind enum values ... out of range, or which + // represent data values that can't be nested. (Some can't even + // exist freestanding!) + + if (kind >= CORBA::TC_KIND_COUNT + || kind <= CORBA::tk_void + || kind == CORBA::tk_except) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Use attribute calculator routine if it exists; these are needed + // only for variable-sized data types, with encapsulated parameter + // lists that affect the size and alignment of "top level" memory + // needed to hold an instance of this type. + + if (TAO_IIOP_Interpreter::table_[kind].calc_ != 0) + { + assert (TAO_IIOP_Interpreter::table_[kind].size_ == 0); + + // Pull encapsulation length out of the stream. + if (stream->get_ulong (temp) == CORBA::B_FALSE) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Initialize the TypeCode if requested + if (tc) + { + tc->kind_ = kind; + tc->buffer_ = stream->buffer (); + tc->length_ = temp; + } + + // Set up a separate stream for the parameters; it may easily + // have a different byte order, and this is as simple a way as + // any to ensure correctness. Then use the calculator routine + // to calculate size and alignment. + + CDR sub_encapsulation; + size_t size; + + assert (temp <= UINT_MAX); + sub_encapsulation.setup_encapsulation (stream->buffer(), temp); + size = TAO_IIOP_Interpreter::table_[kind].calc_ (&sub_encapsulation, alignment, env); + + // Check for garbage at end of parameter lists, or other cases + // where parameters and the size allocated to them don't jive. + + stream->rd_ptr (temp); + if (stream->buffer () != sub_encapsulation.buffer ()) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + return size; + } + assert (TAO_IIOP_Interpreter::table_[kind].size_ != 0); // fixed size data type + + // Reinitialize the TypeCode if requested; this consumes any + // TypeCode parameters in the stream. They only exist for TCKind + // values that have parameters, but which represent fixed-size data + // types in the binary representation: CORBA::tk_string, CORBA::tk_wstring, + // CORBA::tk_objref, CORBA::tk_enum, and CORBA::tk_sequence. + + if (tc) + { + CORBA::ULong len; + + tc->kind_ = kind; + switch (kind) + { + default: + assert (TAO_IIOP_Interpreter::table_[kind].skipper_ == 0); + break; + + case CORBA::tk_string: + case CORBA::tk_wstring: + if (stream->get_ulong (len) == CORBA::B_FALSE) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + tc->length_ = len; + break; + + case CORBA::tk_enum: + case CORBA::tk_objref: + case CORBA::tk_sequence: + if (stream->get_ulong (len) == CORBA::B_FALSE) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + tc->length_ = len; + + assert (len < UINT_MAX); + tc->buffer_ = stream->buffer (); + stream->rd_ptr (len); + break; + } + + // Otherwise, consume any parameters without stuffing them into + // a temporary TypeCode. + } + else if (TAO_IIOP_Interpreter::table_[kind].skipper_ != 0 + && TAO_IIOP_Interpreter::table_[kind].skipper_ (stream) == CORBA::B_FALSE) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Return statically known values. + alignment = TAO_IIOP_Interpreter::table_[kind].alignment_; + return TAO_IIOP_Interpreter::table_[kind].size_; +} + +// Given typecode bytes for a structure (or exception), figure out its +// alignment and size; return size, alignment is an 'out' parameter. +// Only "CORBA::tk_struct" (or "CORBA::tk_except") has been taken out of the stream +// parameter holding the bytes. +// +// We use a one-pass algorithm, calculating size and inter-element +// padding while recording the strongest alignment restriction. Then +// we correct the size to account for tail-padding. +// +// This routine recognizes that exceptions are just structs with some +// additional information. Different environments may differ in what +// that additional information is, so this routine may need to be +// taught about compiler-specific representation of that additional +// "RTTI" data. + +size_t +TAO_IIOP_Interpreter::calc_struct_and_except_attributes (CDR *stream, + size_t &alignment, + CORBA::Boolean is_exception, + CORBA::Environment &env) +{ + CORBA::ULong members; + size_t size; + + // Exceptions are like structs, with key additions (all of which + // might need to be be applied to structures!): vtable, typecode, + // and refcount. The size must include these "hidden" members. + // + // NOTE: in environments with "true" C++ exceptions, there may need + // to be a slot for additional "RTTI" information; maybe it is part + // of the vtable, or maybe not. Or, that information (needed to + // determine which 'catch' clauses apply) may only be provided by + // the compiler to the runtime support for the "throw" statement. + + if (is_exception) + { + size = sizeof (CORBA::Exception); + alignment = TAO_IIOP_Interpreter::table_[CORBA::tk_TypeCode].alignment_; + } + else + { + alignment = 1; + size = 0; + } + + // skip rest of header (type ID and name) and collect the number of + // struct members + + if (!stream->skip_string () + || !stream->skip_string () + || !stream->get_ulong (members)) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // iterate over all the members, skipping their names and looking + // only at type data. + + for ( ; members != 0; members--) { + size_t member_size; + size_t member_alignment; + + // Skip name of the member. + if (!stream->skip_string ()) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Get size and alignment of the member, accounting for + // indirection and the various kinds of parameter encoding. + + member_size = calc_nested_size_and_alignment (0, + stream, + member_alignment, + env); + if (env.exception () != 0) + return 0; + + // Round up the struct size to handle member alignment (by adding + // internal padding), then update the current size to handle the + // member's size. + + size = (size_t) align_binary (size, member_alignment); + size += member_size; + + // Finally update the overall structure alignment requirement, if + // this element must be more strongly aligned. + + if (member_alignment > alignment) + alignment = member_alignment; + }; + + // Round up the structure size to match its overall alignment. This + // adds tail padding, if needed. + return (size_t) align_binary (size, alignment); +} + +// Calculate size and alignment for a structure. + +size_t +TAO_IIOP_Interpreter::calc_struct_attributes (CDR *stream, + size_t &alignment, + CORBA::Environment &env) +{ + return calc_struct_and_except_attributes (stream, + alignment, + CORBA::B_FALSE, + env); +} + +// Calculate size and alignment for an exception. + +size_t +TAO_IIOP_Interpreter::calc_exception_attributes (CDR *stream, + size_t &alignment, + CORBA::Environment &env) +{ + return calc_struct_and_except_attributes (stream, + alignment, + CORBA::B_TRUE, + env); +} + +// Calculate and return sizes for both parts of a union, as needed by +// other code. Return value is the overall size. The padded size of +// the discriminant is needed to traverse the two values separately. +// Unfortunately that is not quite practical to do with a single pass +// over the typecode: the inter-element padding changes depending on +// the strictest alignment required by _any_ arm of the union. + +size_t +TAO_IIOP_Interpreter::calc_key_union_attributes (CDR *stream, + size_t &overall_alignment, + size_t &discrim_size_with_pad, + CORBA::Environment &env) +{ + CORBA::ULong members; + CORBA::ULong temp; + size_t discrim_size; + size_t value_alignment; + size_t value_size; + + overall_alignment = value_alignment = 1; + value_size = discrim_size_with_pad = 0; + + // Skip initial optional members (type ID and name). + + if (!stream->skip_string () // type ID + || !stream->skip_string ()) + { // typedef name + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Calculate discriminant size and alignment: it's the first member + // of the "struct" representing the union. We detect illegal + // discriminant kinds a bit later. + + CORBA::TypeCode discrim_tc (CORBA::tk_void); + + discrim_size = calc_nested_size_and_alignment (&discrim_tc, + stream, + overall_alignment, + env); + if (env.exception () != 0) + return 0; + + // skip "default used" indicator, and save "member count" + + if (!stream->get_ulong (temp) // default used + || !stream->get_ulong (members)) + { // member count + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // iterate over the tuples for all the members; all we care about is + // their types, which can affect either alignment or padding + // requirement for the union part of the construct. + + for ( ; members != 0; members--) { + size_t member_size, member_alignment; + + // Skip member label; its size varies with discriminant type, but + // here we don't care about its content. This is where illegal + // discriminant kinds are detected. + // + // NOTE: This modifies 94-9-32 Appendix A to stipulate that + // "long long" values are not legal as discriminants. + + switch (discrim_tc.kind_) + { + case CORBA::tk_short: + case CORBA::tk_ushort: + case CORBA::tk_wchar: + { + CORBA::Short s; + + if (!stream->get_short (s)) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + } + break; + + case CORBA::tk_long: + case CORBA::tk_ulong: + case CORBA::tk_enum: + { + CORBA::Long l; + + if (!stream->get_long (l)) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + } + break; + + case CORBA::tk_boolean: + case CORBA::tk_char: + { + CORBA::Char c; + + if (!stream->get_byte (c)) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + } + break; + + default: + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // We also don't care about any member name. + + if (!stream->skip_string ()) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Get the member size and alignment. + + member_size = calc_nested_size_and_alignment (0, + stream, + member_alignment, + env); + if (env.exception () != 0) + return 0; + + // Save the largest member and alignment. They don't need to be + // changed in sync -- e.g. "long double" size is larger than its + // alignment restriction on SPARC, x86, and some m68k platforms. + if (member_size > value_size) + value_size = member_size; + if (member_alignment > value_alignment) + value_alignment = member_alignment; + } + + // Round up the discriminator's size to include padding it needs in + // order to be followed by the value. + discrim_size_with_pad = (size_t) align_binary (discrim_size, + value_alignment); + + // Now calculate the overall size of the structure, which is the + // discriminator, inter-element padding, value, and tail padding. + // We know all of those except tail padding, which is a function of + // the overall alignment. (Ensures that arrays of these can be + // safely allocated and accessed!) + + if (value_alignment > overall_alignment) + overall_alignment = value_alignment; + + return (size_t) align_binary (discrim_size_with_pad + value_size, + overall_alignment); +} + +// Calculate size and alignment for a CORBA discriminated union. +// +// Note that this is really a two-element structure. The first +// element is the discriminator; the second is the value. All normal +// structure padding/alignment rules apply. In particular, all arms +// of the union have the same initial address (adequately aligned for +// any of the members). + +size_t +TAO_IIOP_Interpreter::calc_union_attributes (CDR *stream, + size_t &alignment, + CORBA::Environment &env) +{ + size_t scratch; + + return calc_key_union_attributes (stream, alignment, scratch, env); +} + +// Calculate size and alignment for a typedeffed type. + +size_t +TAO_IIOP_Interpreter::calc_alias_attributes (CDR *stream, + size_t &alignment, + CORBA::Environment &env) +{ + // Skip type ID and name in the parameter stream + + if (!stream->skip_string () // type ID + || !stream->skip_string ()) // typedef name + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // The typedef is identical to the type for which it stands. + return calc_nested_size_and_alignment (0, stream, alignment, env); +} + +// Calculate size and alignment of an array. (All such arrays are +// described as single dimensional, even though the IDL definition may +// specify a multidimensional array ... such arrays are treated as +// nested single dimensional arrays.) + +size_t +TAO_IIOP_Interpreter::calc_array_attributes (CDR *stream, + size_t &alignment, + CORBA::Environment &env) +{ + size_t member_size; + CORBA::ULong member_count; + + // get size and alignment of the array member + + member_size = calc_nested_size_and_alignment (0, stream, alignment, env); + if (env.exception () != 0) + return 0; + + // Get and check count of members. + + if (stream->get_ulong (member_count) == CORBA::B_FALSE + || member_count > UINT_MAX) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return 0; + } + + // Array size is a function only of member number and count + return member_size * (size_t) member_count; +} + +// Visit each of the elements of a structure. + +CORBA::TypeCode::traverse_status +TAO_IIOP_Interpreter::struct_traverse (CDR *stream, + const void *value1, + const void *value2, + CORBA::TypeCode::traverse_status (_FAR *visit) + (CORBA::TypeCode_ptr tc, + const void *value1, + const void *value2, + void *context, + CORBA::Environment &env), + void *context, + CORBA::Environment &env) +{ + // Skip over the type ID and type name in the parameters, then get + // the number of members. + CORBA::ULong members; + + if (!stream->skip_string () // type ID + || !stream->skip_string () // type name + || !stream->get_ulong (members)) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return CORBA::TypeCode::TRAVERSE_STOP; + } + + // Visit each member of the structure/exception. The initial + // pointer(s) point at the first values to visit. For structs we + // could avoid the inter-member padding ... not for the case of + // exceptions. No big deal. + // + // NOTE: For last element, could turn visit() call into something + // subject to compiler's tail call optimization and thus save a + // stack frame. + + CORBA::TypeCode::traverse_status retval; + + for (retval = CORBA::TypeCode::TRAVERSE_CONTINUE; + members != 0 && retval == CORBA::TypeCode::TRAVERSE_CONTINUE; + members--) + { + CORBA::TypeCode member_tc (CORBA::tk_null); + size_t size; + size_t alignment; + + // Skip the member's name in the parameter list. + + if (!stream->skip_string ()) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return CORBA::TypeCode::TRAVERSE_STOP; + } + + // Get the member's size, alignment, and a temporary TypeCode, + // skipping that TypeCode in the stream as we do so. + // + // This accounts for all variations: different or nonexistent + // parameter lists, errors such as out-of-range TCKind values or + // nested exceptions, and indirected typecodes. + + size = calc_nested_size_and_alignment (&member_tc, + stream, + alignment, + env); + if (env.exception () != 0) + return CORBA::TypeCode::TRAVERSE_STOP; + + // Pad the value pointers to account for the alignment + // requirements of this member, then visit. + + value1 = ptr_align_binary ((const u_char *) value1, alignment); + value2 = ptr_align_binary ((const u_char *) value2, alignment); + + retval = visit (&member_tc, value1, value2, context, env); + + // Update 'value' pointers to account for the size of the values + // just visited. + value1 = size + (char *)value1; + value2 = size + (char *)value2; + + if (env.exception () != 0) + retval = CORBA::TypeCode::TRAVERSE_STOP; + } + + return retval; +} + +// Cast the discriminant values to the right type and compare them. + +CORBA::Boolean +TAO_IIOP_Interpreter::match_value (CORBA::TCKind kind, + CDR *tc_stream, + const void *value, + CORBA::Environment &env) +{ + CORBA::Boolean retval = CORBA::B_FALSE; + + switch (kind) + { + case CORBA::tk_short: + case CORBA::tk_ushort: + { + CORBA::UShort discrim; + + if (tc_stream->get_ushort (discrim) != CORBA::B_FALSE) + retval = (discrim == *(CORBA::UShort *)value); + else + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + break; + + case CORBA::tk_long: + case CORBA::tk_ulong: + { + CORBA::ULong discrim; + + if (tc_stream->get_ulong (discrim) != CORBA::B_FALSE) + retval = (discrim == *(CORBA::ULong *)value); + else + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + break; + + case CORBA::tk_enum: + { + CORBA::ULong discrim; + + if (tc_stream->get_ulong (discrim) != CORBA::B_FALSE) + retval = (discrim == *(unsigned *)value); + else + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + break; + + case CORBA::tk_boolean: + { + CORBA::Boolean discrim; + + if (tc_stream->get_boolean (discrim) != CORBA::B_FALSE) + retval = (discrim == *(CORBA::Boolean *)value); + else + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + break; + + case CORBA::tk_char: + { + CORBA::Char discrim; + + if (tc_stream->get_char (discrim) != CORBA::B_FALSE) + retval = (discrim == *(CORBA::Char *)value); + else + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + break; + + case CORBA::tk_wchar: + { + CORBA::WChar discrim; + + if (tc_stream->get_wchar (discrim) != CORBA::B_FALSE) + retval = (discrim == *(CORBA::WChar *)value); + else + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + break; + + default: + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + } + + return retval; +} + +// Visit the two elements of the union: the discrminant, and then any +// specific value as indicated by the discriminant of value1. + +CORBA::TypeCode::traverse_status +TAO_IIOP_Interpreter::union_traverse (CDR *stream, + const void *value1, + const void *value2, + CORBA::TypeCode::traverse_status (_FAR *visit) + (CORBA::TypeCode_ptr tc, + const void *value1, + const void *value2, + void *context, + CORBA::Environment &env), + void *context, + CORBA::Environment &env) +{ + size_t discrim_size_with_pad; + + // Figure out size of discriminant plus padding, used to adjust + // value pointers later. This can't be calculated without looking + // at all branches of the union ... forcing union traversal to be a + // two-pass algorithm, unless/until some data gets squirreled away. + { + // TODO provide a method to "copy" the CDR stream... + CDR temp_cdr (*stream); + size_t scratch; + + (void) calc_key_union_attributes (&temp_cdr, + scratch, + discrim_size_with_pad, + env); + } + if (env.exception() != 0) + return CORBA::TypeCode::TRAVERSE_STOP; + + // Skip the optional type ID and type name. + if (!stream->skip_string () // type ID, hidden + || !stream->skip_string ()) + { // typedef name + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return CORBA::TypeCode::TRAVERSE_STOP; + } + + // Get and skip the discriminant's TypeCode. This allow for + // indirection (e.g. a complex enum discriminant). We use that + // TypeCode to visit the discriminant. + // + // We know the kind is legal and the TypeCode is valid because this + // repeats work we did earlier -- so checks are omitted. + + CORBA::TypeCode discrim_tc (CORBA::tk_null); + + size_t scratch; + + (void) calc_nested_size_and_alignment (&discrim_tc, + stream, + scratch, + env); + if (visit (&discrim_tc, + value1, + value2, + context, + env) == CORBA::TypeCode::TRAVERSE_STOP) + return CORBA::TypeCode::TRAVERSE_STOP; + + // Adjust the pointers to point to the other member of the union; + // this ensures alignment for any of the values. Save the pointer + // to the discriminant though; we need it to find out which member + // to visit! + + const void *discrim_ptr = value1; + + value1 = discrim_size_with_pad + (char *) value1; + value2 = discrim_size_with_pad + (char *) value2; + + // Get the flag that tells if there's a "default" arm in this union, + // then the number of members in the union. + + CORBA::Long default_used = 0; + CORBA::ULong member_count; + + if (!stream->get_long (default_used)) + { + // default used + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return CORBA::TypeCode::TRAVERSE_STOP; + } + + if (!stream->get_ulong (member_count)) + { // member count + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return CORBA::TypeCode::TRAVERSE_STOP; + } + + // Scan to find the tuple whose value matches the discriminator. + // + // While we're scanning, record any default arm's information. If + // we can't find a match for the discriminant value, that arm will + // be used later. + + char *default_tc_ptr = 0; + size_t default_tc_len = 0; + + while (member_count-- != 0) + { + // Test to see if the discriminant value matches the one in the + // TypeCode; this skips the the discriminant value in this CDR + // stream. + + CORBA::Boolean discrim_matched; + + discrim_matched = match_value (discrim_tc.kind_, + stream, + discrim_ptr, + env); + if (env.exception () != 0) + return CORBA::TypeCode::TRAVERSE_STOP; + + // Skip the name of the member; we never care about it. + + if (!stream->skip_string ()) + { + env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); + return CORBA::TypeCode::TRAVERSE_STOP; + } + + // If this is the default member, remember where its typecode + // data is stored; we'll use it later. + + if (default_used >= 0 && default_used-- == 0) + { + default_tc_ptr = stream->buffer (); + default_tc_len = stream->length (); + } + + // Get the TypeCode for this member. + // + // XXX we really don't care about size and alignment this time, + // only that we initialize the TypeCode. + + CORBA::TypeCode tc (CORBA::tk_null); + size_t scratch; + + (void) calc_nested_size_and_alignment (&tc, stream, scratch, env); + if (env.exception () != 0) + return CORBA::TypeCode::TRAVERSE_STOP; + + // If we matched, visit the member and return. + if (discrim_matched) + return visit (&tc, value1, value2, context, env); + } + + // If we get here, it means any default arm should be used. We know + // at least the basic sanity checks passed; we don't repeat. + + if (default_tc_ptr) + { + CDR temp_str; + temp_str.setup_encapsulation (default_tc_ptr, + default_tc_len); + // Get and use the TypeCode. + // + // XXX we really don't care about size and alignment this time, + // only that we initialize the TypeCode. + + size_t scratch; + CORBA::TypeCode tc (CORBA::tk_null); + + (void) calc_nested_size_and_alignment (&tc, &temp_str, scratch, env); + return visit (&tc, value1, value2, context, env); + } + return CORBA::TypeCode::TRAVERSE_CONTINUE; +} + |