summaryrefslogtreecommitdiff
path: root/TAO/tao/interp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/tao/interp.cpp')
-rw-r--r--TAO/tao/interp.cpp1496
1 files changed, 1496 insertions, 0 deletions
diff --git a/TAO/tao/interp.cpp b/TAO/tao/interp.cpp
new file mode 100644
index 00000000000..5776784b6f0
--- /dev/null
+++ b/TAO/tao/interp.cpp
@@ -0,0 +1,1496 @@
+// $Id$
+//
+// @(#)interp.cpp 1.4 95/11/04
+// Copyright 1994-1995 by Sun Microsystems Inc.
+// All Rights Reserved
+//
+// TYPECODE: interpreter, traverses data structures
+//
+// This uses the standard C/C++ representation for data, and knows how
+// to do things like align and pad according to standard rules. It is
+// driven by CDR marshaled representations of TypeCodes.
+//
+// It does two key things: (a) calculate size and alignment
+// restrictions for the data type described by any given typecode; and
+// (b) "visits" each element of a data type in the order those
+// elements are defined in the type's IDL definition.
+//
+// A typical use is that some application-specific "visit" function
+// will be called with a typecode and data value. Then that "visit"
+// function may choose to use the interpreter's knowledge of the
+// environment's size, padding, and alignment rules to help it examine
+// each of the constituents of complex data values. It does so by
+// making a call to TypeCode::traverse(), and passing itself for
+// future recursive calls.
+//
+// NOTE that this module has system dependent parts, and so should be
+// examined when porting to new CPU architectures, compilers, and so
+// forth to make sure it correctly implements the appropriate binary
+// interfaces.
+//
+// Issues of concern are primarily that sizes and representations of
+// CORBA primitive data types are correct (key issues are verified
+// when the ORB initializes) and that the alignment rules are
+// recognized.
+//
+// Also, exceptions have vtables in them, which may cause trouble if
+// they aren't located at the very beginning by the compiler in
+// question.
+//
+// So for example, moving to another CPU architecture which still uses
+// standard sized two's complement integers and IEEE floating point,
+// and expects "natural" alignment, won't be hard. Even using PC
+// style tightly packed data is simple; the alignment rules are just
+// simpler. Most volume microprocessors used in 1995 are correctly
+// supported.
+//
+// Using data representations that are far from the standard C/C++
+// style data layout is probably not practical with this
+// implementation. LISP systems, as one example, probably won't use
+// "in-memory" representations much like C/C++, even though its "wire
+// form" could directly match CDR.
+//
+// ALSO, the treatment of exceptions may need to be examined in
+// language environments which actually rely on C++ exceptions. The
+// RTTI data that identifies exceptions can easily be ignored by this
+// interpreter (if it's taught about that compiler's RTTI) but it may
+// not be practical for any code not generated by that specific C++
+// compiler to store such data in the right place to look like a C++
+// exception, or to throw exceptions when that's needed. (RTTI ==
+// "Run Time Typing Information", needed to make C++ exceptions work
+// correctly and partially exposed to users by the ANSI standards
+// comittee. It provides type-safe "downcasting" and other features
+// previously unavailable in C++.)
+//
+// THREADING NOTE: Data structures being traversed should only be
+// modified by the thread doing the traversal. The interpretive code
+// itself is reentrant (recursive!) so presents no threading issues;
+// only the data being fed to the interpreter must be protected
+// against concurrency.
+
+#include "tao/corba.h"
+
+// Utility routines are used to manipulate CDR-encapsulated TypeCode
+// parameter lists, calculating the size and alignment of the data
+// type being described. The TCKind value has always been removed
+// from the CDR stream when these calculator routines get called.
+
+typedef size_t attribute_calculator (CDR *stream,
+ size_t &alignment,
+ CORBA::Environment &env);
+
+static attribute_calculator calc_struct_attributes;
+static attribute_calculator calc_exception_attributes;
+static attribute_calculator calc_union_attributes;
+static attribute_calculator calc_alias_attributes;
+static attribute_calculator calc_array_attributes;
+
+// Other utility routines are used to skip the parameter lists when
+// they're not needed.
+
+typedef CORBA::Boolean param_skip_rtn (CDR *);
+
+static CORBA::Boolean
+skip_encapsulation (CDR *stream)
+{
+ return stream->skip_string ();
+}
+
+static CORBA::Boolean
+skip_long (CDR *stream)
+{
+ CORBA::ULong scratch;
+
+ return stream->get_ulong (scratch);
+}
+
+// Table supporting calculation of size and alignment requirements for
+// any one instance of a given data types.
+//
+// This is indexed via CDR's TCKind values, which are "frozen" as part
+// of the CDR standard. Entries hold either the size and alignment
+// values for that data type, or a pointer to a function that is used
+// to calculate those values. Function pointers are normally needed
+// only for constructed types.
+//
+// A "skipper" routine is provided for some data types whose size is
+// known statically (e.g. objrefs, structures, strings) but whose
+// typecodes have parameters that sometimes need to be ignored when
+// found in a CDR stream. Any attribute calculator routine always
+// skips parameters in the CDR input stream, so no type with such a
+// routine also needs a "skipper".
+//
+// Rather than growing a set of processor-specific #ifdefs, we
+// calculate most of this table (except functions) at ORB
+// initialization time.
+
+struct table_element
+{
+ size_t size;
+ size_t alignment;
+ attribute_calculator *calc;
+ param_skip_rtn *skipper;
+};
+
+static table_element 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) \
+ { \
+ table [t].size = sizeof (x); \
+ 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; \
+ table [t].size = sizeof (x); \
+ 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
+__TC_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);
+ table [CORBA::tk_enum].size = sizeof (generic_enum);
+ 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
+
+// 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.
+
+static size_t
+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 (table [kind].calc != 0)
+ {
+ assert (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 = 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 (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 (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 (table [kind].skipper != 0
+ && table [kind].skipper (stream) == CORBA::B_FALSE)
+ {
+ env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO));
+ return 0;
+ }
+
+ // Return statically known values.
+ alignment = table [kind].alignment;
+ return 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.
+
+static size_t
+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 = 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.
+
+static size_t
+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.
+
+static size_t
+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
+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:
+ {
+ 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).
+
+static size_t
+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.
+
+static size_t
+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.)
+
+static size_t
+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.
+
+static CORBA::TypeCode::traverse_status
+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.
+
+static CORBA::Boolean
+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.
+
+static CORBA::TypeCode::traverse_status
+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;
+}
+
+// For each node in "data", visit it. For singleton nodes that's all
+// but a NOP; for structs, unions, etc it's more interesting. The
+// visit routine can descend, if it chooses.
+//
+// NOTE: this does no memory allocation or deallocation except through
+// use of the stack. Or at least, it should do none -- if you find
+// that just traversing a data value allocates any memory, that's a
+// bug to fix!
+
+CORBA::TypeCode::traverse_status
+CORBA::TypeCode::traverse (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)
+{
+ env.clear ();
+
+ // Quickly accomodate the bulk of cases, which are just (tail) calls
+ // to the visit() routine. We take advantage of the fact that these
+ // are largely in a convenient numeric range to work around poor
+ // optimization of "switch" code in some compilers. This
+ // improvement has in some cases been more than 5% faster
+ // (significant).
+ //
+ // NOTE: if for some reason the constants in the protocol spec
+ // (including Appendix A) change, this logic may need to be verified
+ // again. Luckily, changing protocol constants is quite rare; they
+ // normally just get added to (at the end).
+ //
+ if (kind_ <= CORBA::tk_objref
+ || (CORBA::tk_longlong <= kind_ && kind_ <= CORBA::tk_wstring))
+ return visit (this, value1, value2, context, env);
+
+ // Handle the cases that aren't in convenient numeric ranges.
+
+ traverse_status retval;
+
+ switch (kind_)
+ {
+ case CORBA::tk_string:
+ case CORBA::tk_enum:
+ return visit (this, value1, value2, context, env);
+
+ // Typedefs just add a delay, while we skip the typedef ID
+ // and name ...
+
+ case CORBA::tk_alias:
+ {
+ CORBA::TypeCode_ptr tcp;
+ CORBA::Environment env2;
+
+ // XXX rework for efficiency, this doesn't need to allocate
+ // memory during the traversal!
+
+ tcp = typecode_param (2, env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ retval = tcp->traverse (value1, value2, visit, context, env);
+
+ tcp->Release ();
+ }
+ return retval;
+
+ // Exceptions in-memory are structures, except that there are data
+ // members "hidden" in front: vtable, typecode, refcount. We skip
+ // them, and allow the traversal code to account for the internal
+ // padding before the other elements of the exception.
+ //
+ // NOTE: see header comment re treatment of these values as "real"
+ // C++ exceptions. C++ RTTI data might need to be skipped. Also,
+ // see the comments in unmarshaling code: hard to throw these
+ // values.
+ //
+ // Not enough of the exception runtime is public for binary
+ // standards to exist for C++ exceptions yet. Compiler-specific
+ // code will need to handle examining, unmarshaling, and throwing
+ // of CORBA exceptions (in C++ environments) for some time.
+ case CORBA::tk_except:
+ value1 = sizeof (CORBA::Exception) + (char *) value1;
+ value2 = sizeof (CORBA::Exception) + (char *) value2;
+ // FALLTHROUGH
+
+ case CORBA::tk_struct:
+ // XXX for OLE Automation, we'll probably need BOTH exceptions
+ // and structs to inherit IUnknown, hence we'll need to be
+ // skipping the vtable pointer ...
+ {
+ // Create the sub-encapsulation stream that holds the
+ // parameters for the typecode.
+
+ CDR stream;
+
+ stream.setup_encapsulation (buffer_, (size_t) length_);
+
+ return struct_traverse (&stream, value1, value2,
+ visit, context, env);
+ }
+
+ case CORBA::tk_union:
+ {
+ // visit the discriminant, then search the typecode for the
+ // relevant union member and then visit that member.
+ CDR stream;
+
+ stream.setup_encapsulation (buffer_, (size_t) length_);
+
+ return union_traverse (&stream, value1, value2,
+ visit, context, env);
+ }
+
+ // Sequences are just arrays with bound determined at runtime,
+ // rather than compile time. Multidimensional arrays are nested
+ // C-style: the leftmost dimension in the IDL definition is
+ // "outermost", etc.
+ {
+ CORBA::TypeCode_ptr tc2;
+ size_t size;
+ CORBA::ULong bounds;
+ CORBA::OctetSeq *seq;
+
+ case CORBA::tk_sequence:
+ // Find out how many elements there are, and adjust the data
+ // pointers to point to those elements rather than to the
+ // sequence itself.
+ seq = (CORBA::OctetSeq *)value1;
+
+ bounds = seq->length;
+ value1 = seq->buffer;
+
+ if (value2)
+ {
+ seq = (CORBA::OctetSeq *)value2;
+ value2 = seq->buffer;
+ }
+ goto shared_seq_array_code;
+
+ case CORBA::tk_array:
+ // Array bounds are in the typecode itself.
+ bounds = ulong_param (1, env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ shared_seq_array_code:
+ // Find element's type, and size ...
+ tc2 = typecode_param (0, env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ size = tc2->size (env);
+ if (env.exception () != 0)
+ return TRAVERSE_STOP;
+
+ // ... then visit the elements in order.
+ //
+ // NOTE: for last element, could turn visit() call into
+ // something subject to compiler's tail call optimization and
+ // thus save a stack frame
+ while (bounds--)
+ {
+ if (visit (tc2, value1, value2, context, env) == TRAVERSE_STOP)
+ return TRAVERSE_STOP;
+
+ value1 = size + (char *) value1;
+ value2 = size + (char *) value2;
+ }
+ CORBA::release (tc2);
+ env.clear ();
+ }
+ return TRAVERSE_CONTINUE;
+
+ // case ~0: // indirection, illegal at top level
+ default: // invalid/illegal
+ break;
+ } // end switch on typecode "kind"
+
+ env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO));
+ return TRAVERSE_STOP;
+}
+
+// Tell user the size of an instance of the data type described by
+// this typecode ... typically used to allocate memory.
+
+size_t
+CORBA::TypeCode::private_size (CORBA::Environment &env)
+{
+ if (kind_ >= CORBA::TC_KIND_COUNT)
+ {
+ env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO));
+ return 0;
+ }
+ env.clear ();
+
+ if (table [kind_].calc == 0)
+ {
+ private_state_->tc_size_known_ = CORBA::B_TRUE;
+ private_state_->tc_size_ = table [kind_].size;
+ return private_state_->tc_size_;
+ }
+
+ size_t alignment;
+ CDR stream;
+
+ stream.setup_encapsulation (buffer_, (size_t) length_);
+
+ private_state_->tc_size_known_ = CORBA::B_TRUE;
+ private_state_->tc_size_ = table [kind_].calc (&stream, alignment, env);
+ return private_state_->tc_size_;
+}
+
+// Tell user the alignment restriction for the data type described by
+// an instance of this data type. Rarely used; provided for
+// completeness.
+
+size_t
+CORBA::TypeCode::private_alignment (CORBA::Environment &env)
+{
+ if (kind_ >= CORBA::TC_KIND_COUNT)
+ {
+ env.exception (new CORBA::BAD_TYPECODE (CORBA::COMPLETED_NO));
+ return 0;
+ }
+ env.clear ();
+
+ if (table [kind_].calc == 0)
+ {
+ private_state_->tc_alignment_known_ = CORBA::B_TRUE;
+ private_state_->tc_alignment_ = table [kind_].alignment;
+ return private_state_->tc_alignment_;
+ }
+
+ size_t alignment;
+ CDR stream;
+
+ stream.setup_encapsulation (buffer_, (size_t) length_);
+
+ (void) table [kind_].calc (&stream, alignment, env);
+ private_state_->tc_alignment_known_ = CORBA::B_TRUE;
+ private_state_->tc_alignment_ = alignment;
+ return alignment;
+}