// $Id$ // @(#)interp.cpp 1.4 95/11/04 // Copyright 1994-1995 by Sun Microsystems Inc. // All Rights Reserved // We need to include Sequence.h and Sequence_T.h before the // CDR_Interpreter to workaround a Greenhills (1.8.8 and 1.8.9) // compiler bug. #include "tao/Sequence.h" #include "tao/Sequence_T.h" #include "tao/CDR_Interpreter.h" #include "tao/Any.h" #include "tao/varout.h" #include "tao/CDR.h" #include "tao/Typecode.h" #include "tao/Environment.h" #include "tao/Union.h" ACE_RCSID(tao, CDR_Interpreter, "$Id$") TAO_CDR_Interpreter::Table_Element TAO_CDR_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 #if defined (TAO_NO_COPY_OCTET_SEQUENCES) { 0, 1, calc_seq_attributes, 0 }, // CORBA::tk_sequence #else { 0, 1, 0, skip_encapsulation }, // CORBA::tk_sequence #endif { 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_CDR_Interpreter::table_ [t].size_ = sizeof (x); \ TAO_CDR_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_CDR_Interpreter::table_ [t].size_ = sizeof (x); \ TAO_CDR_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 (TAO_Object_Field_T, tk_objref); declare_entry (CORBA::String, tk_string); #if !defined (TAO_NO_COPY_OCTET_SEQUENCES) declare_entry (TAO_opaque, tk_sequence); #endif 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_CDR_Interpreter::init (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); setup_entry (TAO_Object_Field_T, 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_CDR_Interpreter::table_ [CORBA::tk_enum].size_ = sizeof (generic_enum); TAO_CDR_Interpreter::table_ [CORBA::tk_enum].alignment_ = sizeof (generic_enum); setup_entry (CORBA::String, tk_string); #if !defined (TAO_NO_COPY_OCTET_SEQUENCES) setup_entry (TAO_opaque, tk_sequence); #endif /* defined (TAO_NO_COPY_OCTET_SEQUENCES) */ 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_CDR_Interpreter::skip_encapsulation (TAO_InputCDR *stream) { return stream->skip_string (); } CORBA::Boolean TAO_CDR_Interpreter::skip_long (TAO_InputCDR *stream) { CORBA::ULong scratch; return stream->read_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_CDR_Interpreter::calc_nested_size_and_alignment_i (CORBA::TypeCode_ptr tc, TAO_InputCDR *stream, CORBA::TCKind kind, size_t &alignment, CORBA::Environment &env) { CORBA::ULong temp; // Just a temporary to retrieve CORBA::TCKind variables as ULong's // 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_CDR_Interpreter::table_[kind].calc_ != 0) { assert (TAO_CDR_Interpreter::table_[kind].size_ == 0); // Pull encapsulation length out of the stream. if (stream->read_ulong (temp) == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } // Initialize the TypeCode if requested if (tc) { tc->kind_ = kind; tc->buffer_ = stream->rd_ptr (); 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. assert (temp <= UINT_MAX); TAO_InputCDR nested (*stream, temp); if (nested.good_bit () == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } size_t size = TAO_CDR_Interpreter::table_[kind].calc_ (&nested, alignment, env); if (env.exception () != 0) { return 0; } // Check for garbage at end of parameter lists, or other cases // where parameters and the size allocated to them don't jive. stream->skip_bytes (temp); if (stream->rd_ptr () != nested.rd_ptr ()) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } return size; } assert (TAO_CDR_Interpreter::table_[kind].size_ != 0); // 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_CDR_Interpreter::table_[kind].skipper_ == 0); break; case CORBA::tk_string: case CORBA::tk_wstring: if (stream->read_ulong (len) == 0) { 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->read_ulong (len) == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } tc->length_ = len; assert (len < UINT_MAX); tc->buffer_ = stream->rd_ptr (); stream->skip_bytes (len); break; } // Otherwise, consume any parameters without stuffing them into // a temporary TypeCode. } else if (TAO_CDR_Interpreter::table_[kind].skipper_ != 0 && TAO_CDR_Interpreter::table_[kind].skipper_ (stream) == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } // Return statically known values. alignment = TAO_CDR_Interpreter::table_[kind].alignment_; return TAO_CDR_Interpreter::table_[kind].size_; } size_t TAO_CDR_Interpreter::calc_nested_size_and_alignment (CORBA::TypeCode_ptr tc, TAO_InputCDR *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; if (stream->read_ulong (temp) == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } env.clear (); CORBA::TCKind kind = (CORBA::TCKind) temp; if (kind != (CORBA::TCKind) ~0u) { return TAO_CDR_Interpreter::calc_nested_size_and_alignment_i (tc, stream, kind, alignment, env); } // 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! // @@ ASG @@ - comparison with -8 or -4. I think the spec says it must be // larger than -4 (absolute value) // 09/04/98 - check this // CORBA::Long offset; if (!stream->read_long (offset) || offset >= -8 || ((-offset) & 0x03) != 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } // Notice how we change the sign of the offset to estimate the // maximum size. TAO_InputCDR indirected_stream (*stream, -offset, offset); // Fetch indirected-to TCKind. if (!indirected_stream.read_ulong (temp)) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } kind = (CORBA::TCKind) temp; return TAO_CDR_Interpreter::calc_nested_size_and_alignment_i (tc, &indirected_stream, kind, alignment, env); } // 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_CDR_Interpreter::calc_struct_and_except_attributes (TAO_InputCDR *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_CDR_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->read_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_CDR_Interpreter::calc_struct_attributes (TAO_InputCDR *stream, size_t &alignment, CORBA::Environment &env) { return calc_struct_and_except_attributes (stream, alignment, 0, env); } // Calculate size and alignment for an exception. size_t TAO_CDR_Interpreter::calc_exception_attributes (TAO_InputCDR *stream, size_t &alignment, CORBA::Environment &env) { return calc_struct_and_except_attributes (stream, alignment, 1, 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_CDR_Interpreter::calc_key_union_attributes (TAO_InputCDR *stream, size_t &overall_alignment, size_t &discrim_size_with_pad, CORBA::Environment &env) { CORBA::ULong members; CORBA::ULong temp; size_t discrim_and_base_size; size_t discrim_and_base_size_with_pad; size_t value_alignment; size_t value_size; // define a dummy structure to compute alignment of pointer type struct align_ptr { void *one; char dummy [TAO_MAXIMUM_NATIVE_TYPE_SIZE + 1 - sizeof (void*)]; void *two; }; align_ptr ap; // the first member of the union internal representation is the VPTR // since every union inherits from TAO_Base_Union overall_alignment = (char *) &ap.two - (char *) &ap.one - TAO_MAXIMUM_NATIVE_TYPE_SIZE; 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_and_base_size = sizeof (TAO_Base_Union) + calc_nested_size_and_alignment (&discrim_tc, stream, value_alignment, env); if (env.exception () != 0) return 0; if (value_alignment > overall_alignment) overall_alignment = value_alignment; // skip "default used" indicator, and save "member count" if (!stream->read_ulong (temp) // default used || !stream->read_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. value_alignment = 1; 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->read_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->read_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->read_char (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. // However, for variable sized member types and types that have // constructors, these become members of the pointer types. We need to // determine if we are dealing with such a member and accordingly adjust // the size and alignment CORBA::Boolean var_sized_member = 0; TAO_InputCDR temp (*stream); if (calc_union_attr_is_var_sized_member (&temp, var_sized_member) == -1) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } if (var_sized_member) { member_size = sizeof (void*); member_alignment = (char *) &ap.two - (char *) &ap.one - TAO_MAXIMUM_NATIVE_TYPE_SIZE; (void) CORBA::TypeCode::skip_typecode (*stream); } else { // proceed with the normal way of computing the 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_and_base_size_with_pad = (size_t) align_binary (discrim_and_base_size, value_alignment); discrim_size_with_pad = discrim_and_base_size_with_pad - sizeof (TAO_Base_Union); // 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_and_base_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_CDR_Interpreter::calc_union_attributes (TAO_InputCDR *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_CDR_Interpreter::calc_alias_attributes (TAO_InputCDR *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_CDR_Interpreter::calc_array_attributes (TAO_InputCDR *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->read_ulong (member_count) == 0 || 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; } #if defined (TAO_NO_COPY_OCTET_SEQUENCES) // Calculate size and alignment of a sequence. // If octet sequence optimizations are enabled the size of octet // sequences differ from the size of a regular sequence. size_t TAO_CDR_Interpreter::calc_seq_attributes (TAO_InputCDR *stream, size_t &alignment, CORBA::Environment &env) { CORBA::TCKind kind; // Get the "kind" ... if this is an indirection, this is a guess // which will soon be updated. CORBA::ULong temp; if (stream->read_ulong (temp) == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } if (temp == ~0u) { // 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 (!stream->read_long (offset) || offset >= -8 || ((-offset) & 0x03) != 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } // Notice how we change the sign of the offset to estimate the // maximum size. TAO_InputCDR indirected_stream (*stream, -offset, offset); // Fetch indirected-to TCKind; this *cannot* be an indirection // again because multiple indirections are non-complaint. if (indirected_stream.read_ulong (temp) == 0 || temp == ~0u) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } } kind = ACE_static_cast(CORBA::TCKind, temp); // Skip the rest of the stream because we don't use it. if (stream->skip_bytes (stream->length ()) == 0) { env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO)); return 0; } size_t size; if (kind == CORBA::tk_octet) { declare_entry (TAO_opaque, tk_sequence); align_struct_tk_sequence align; size = sizeof (TAO_opaque); #if defined (TAO_HAS_FIXED_BYTE_ALIGNMENT) alignment = 1; #else alignment = (char*)&align.two - (char*)&align.one - TAO_MAXIMUM_NATIVE_TYPE_SIZE; #endif /* TAO_HAS_FIXED_BYTE_ALIGNMENT */ } else { // Note: GHS can't handle TAO_Unbounded_Sequence below. // Instead, use TAO_Unbounded_String_Sequence. declare_entry (TAO_Unbounded_String_Sequence, tk_sequence); size = sizeof (TAO_Unbounded_String_Sequence); align_struct_tk_sequence align; #if defined (TAO_HAS_FIXED_BYTE_ALIGNMENT) alignment = 1; #else alignment = (char*)&align.two - (char*)&align.one - TAO_MAXIMUM_NATIVE_TYPE_SIZE; #endif /* TAO_HAS_FIXED_BYTE_ALIGNMENT */ } return size; } #endif /* defined (TAO_NO_COPY_OCTET_SEQUENCES) */ // Cast the discriminant values to the right type and compare them. CORBA::Boolean TAO_CDR_Interpreter::match_value (CORBA::TCKind kind, TAO_InputCDR *tc_stream, const void *value, CORBA::Environment &env) { CORBA::Boolean retval = 0; switch (kind) { case CORBA::tk_short: case CORBA::tk_ushort: { CORBA::UShort discrim; if (tc_stream->read_ushort (discrim) != 0) 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->read_ulong (discrim) != 0) 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->read_ulong (discrim) != 0) 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->read_boolean (discrim) != 0) 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->read_char (discrim) != 0) 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->read_wchar (discrim) != 0) 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; } int TAO_CDR_Interpreter ::calc_union_attr_is_var_sized_member (TAO_InputCDR *stream, CORBA::Boolean &flag) { CORBA::Environment env; CORBA::ULong temp; flag = 0; // Get the tk_ "kind" field if (stream->read_ulong (temp) == 0) { // error return -1; } env.clear (); CORBA::TCKind kind = (CORBA::TCKind) temp; switch (kind) { case CORBA::tk_null: case CORBA::tk_void: // error return -1; case CORBA::tk_short: case CORBA::tk_ushort: case CORBA::tk_long: case CORBA::tk_ulong: case CORBA::tk_longlong: case CORBA::tk_ulonglong: case CORBA::tk_float: case CORBA::tk_double: case CORBA::tk_longdouble: case CORBA::tk_boolean: case CORBA::tk_char: case CORBA::tk_wchar: case CORBA::tk_octet: case CORBA::tk_enum: case CORBA::tk_Principal: // not variable sized return 0; case CORBA::tk_any: case CORBA::tk_TypeCode: case CORBA::tk_objref: case CORBA::tk_union: case CORBA::tk_string: case CORBA::tk_wstring: case CORBA::tk_sequence: case CORBA::tk_array: case CORBA::tk_except: // always variable sized flag = 1; return 0; case CORBA::tk_alias: // find out what its base says { CORBA::ULong encap; // Pull encapsulation length out of the stream. if (stream->read_ulong (encap) == 0) { return -1; } assert (encap <= UINT_MAX); TAO_InputCDR nested (*stream, temp); if (nested.good_bit () == 0) { return -1; } // Skip type ID and name in the parameter stream if (!nested.skip_string () // type ID || !nested.skip_string ()) // typedef name { return -1; } // stream->skip_bytes (encap); return calc_union_attr_is_var_sized_member (&nested, flag); } ACE_NOTREACHED (break); case CORBA::tk_struct: // explore further based on members { CORBA::ULong encap; // Pull encapsulation length out of the stream. if (stream->read_ulong (encap) == 0) { return -1; } assert (encap <= UINT_MAX); TAO_InputCDR nested (*stream, temp); if (nested.good_bit () == 0) { return -1; } // stream.skip_bytes (encap); // Skip type ID and name in the parameter stream if (!nested.skip_string () // type ID || !nested.skip_string ()) // typedef name { return -1; } CORBA::ULong member_count; if (nested.read_ulong (member_count) == 0) { return -1; } for (CORBA::ULong i = 0; i < member_count && !flag; i++) { // stop this loop the moment we discover that a member is variable // in size // skip the name if (nested.skip_string () == 0) { return -1; } TAO_InputCDR member_tc (nested); if (calc_union_attr_is_var_sized_member (&member_tc, flag) == -1) { return -1; } CORBA::TypeCode::skip_typecode (nested); } } return flag; ACE_NOTREACHED (break); case ~0: // TO-DO return 0; default: // error return -1; } // cannot reach here ACE_NOTREACHED (return -1); } #if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) template class TAO_Unbounded_Sequence; #elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) #pragma instantiate TAO_Unbounded_Sequence #endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */