// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/Basic.h>
#include <OB/Except.h>
#include <OB/Template.h>
#include <OB/TemplateI.h>
#include <OB/Declarations.h>
#include <OB/Any.h>
#include <OB/TCKind.h>
#include <OB/TypeCode.h>
#include <OB/IOP.h>

// ----------------------------------------------------------------------
// External, non-inline duplicate/release for templates
// ----------------------------------------------------------------------

void
OBDuplicate(CORBA_TypeCode_ptr p)
{
    if(p)
	p -> _OB_incRef();
}

void
OBRelease(CORBA_TypeCode_ptr p)
{
    if(p)
    {
	if(p -> _OB_getRef() > 1)
	{
	    //
	    // Is this the last reference except for references from
	    // cyclic types?
	    //
	    if(p -> _OB_getRef() == p -> cyclicTypes_.length() + 1)
	    {
		CORBA_ULong i;

		for(i = 0 ; i < p -> cyclicTypes_.length() ; i++)
		{
		    //
		    // Does the cyclic type only have references from
		    // other cyclic types?
		    //
		    if(!(p -> cyclicTypes_[i] -> _OB_getRef() ==
			 p -> cyclicTypes_[i] -> cyclicTypes_.length()))
			break;
		}

		//
		// Do all cyclic types only have references from other
		// cyclic types?
		//
		if(i == p -> cyclicTypes_.length())
		{
		    //
		    // Create a copy of all cyclic types
		    //
		    OBObjSeq< CORBA_TypeCode > cyc = p -> cyclicTypes_;

		    //
		    // Empty the list of all cyclic types without
		    // releasing them
		    //
		    for(i = 0 ; i < p -> cyclicTypes_.length() ; i++)
			p -> cyclicTypes_[i]._retn();
		    p -> cyclicTypes_.length(0);
		    
		    //
		    // Iterate over the list with copies of cyclic
		    // types
		    //
		    for(i = 0 ; i < cyc.length() ; i++)
		    {
			//
			// Empty the list of all cyclic types of the
			// cyclic type without releasing them
			//
			CORBA_ULong j;
			for(j = 0 ; j < cyc[i] -> cyclicTypes_.length() ; j++)
			    cyc[i] -> cyclicTypes_[j]._retn();
			cyc[i] -> cyclicTypes_.length(0);
			
			//
			// Release contentType_ and memberTypes_, the
			// only data members that can point to cyclic
			// types
			//
			cyc[i] -> contentType_ = CORBA_TypeCode::_nil();
			cyc[i] -> memberTypes_.length(0);
		    }
		    
		    //
		    // Since there are now no cyclic types anymore,
		    // the reference count must be one
		    //
		    assert(p -> _OB_getRef() == 1);
		}
	    }
	}
	
	p -> _OB_decRef();
    }
}

// ----------------------------------------------------------------------
// Template instantiations
// ----------------------------------------------------------------------

#ifndef HAVE_NO_EXPLICIT_TEMPLATES
template class OBObjVar< CORBA_TypeCode >;
template class OBObjForSeq< CORBA_TypeCode >;
template class OBObjSeq< CORBA_TypeCode >;
template class OBSeqVar< OBObjSeq< CORBA_TypeCode > >;
#else
#ifdef HAVE_PRAGMA_DEFINE
#pragma define(OBObjVar< CORBA_TypeCode >)
#pragma define(OBObjForSeq< CORBA_TypeCode >)
#pragma define(OBObjSeq< CORBA_TypeCode >)
#pragma define(OBSeqVar< OBObjSeq< CORBA_TypeCode > >)
#endif
#endif

// ----------------------------------------------------------------------
// TypeCode constructor and destructor
// ----------------------------------------------------------------------

CORBA_TypeCode::CORBA_TypeCode()
{
}

CORBA_TypeCode::~CORBA_TypeCode()
{
    //
    // Empty the list of all cyclic types without releasing them
    //
    for(CORBA_ULong i = 0 ; i < cyclicTypes_.length() ; i++)
	cyclicTypes_[i]._retn();
}

// ----------------------------------------------------------------------
// TypeCode public member implementation
// ----------------------------------------------------------------------

CORBA_Boolean
CORBA_TypeCode::equal(CORBA_TypeCode_ptr p) const
{
    if(p == this)
	return true;

    CORBA_TypeCode_var tc1 = OBGetOrigType((CORBA_TypeCode_ptr)this);
    CORBA_TypeCode_var tc2 = OBGetOrigType(p);

    if(tc1 -> kind_ != tc2 -> kind_)
	return false;

    //
    // Repository ids are only required for tk_objref and tk_except
    //
    if(tc1 -> kind_ == CORBA_tk_objref ||
       tc1 -> kind_ == CORBA_tk_except)
    {
 	if(strcmp(tc1 -> id_, tc2 -> id_) != 0)
	    return false;
    }
    else if(tc1 -> kind_ == CORBA_tk_struct ||
            tc1 -> kind_ == CORBA_tk_union ||
            tc1 -> kind_ == CORBA_tk_enum ||
            tc1 -> kind_ == CORBA_tk_alias)
    {
 	if(strlen(tc1 -> id_) > 0 && strlen(tc2 -> id_) > 0 &&
           strcmp(tc1 -> id_, tc2 -> id_) != 0)
	    return false;
    }

    if(tc1 -> kind_ == CORBA_tk_struct ||
       tc1 -> kind_ == CORBA_tk_union ||
       tc1 -> kind_ == CORBA_tk_except)
    {
	if(tc1 -> memberTypes_.length() != tc2 -> memberTypes_.length())
	    return false;
	
	for(CORBA_ULong i = 0 ; i < tc1 -> memberTypes_.length() ; i++)
	    if(!(tc1 -> memberTypes_[i] ->
		 equal(tc2 -> memberTypes_[i])))
		return false;
    }
    
    if(tc1 -> kind_ == CORBA_tk_union)
    {
	if(tc1 -> labels_.length() != tc2 -> labels_.length())
	    return false;
	
	for(CORBA_ULong i = 0 ; i < tc1 -> labels_.length() ; i++)
	{
	    CORBA_TypeCode_var ltc1 = tc1 -> labels_[i].type();
	    CORBA_TypeCode_var ltc2 = tc2 -> labels_[i].type();
    
	    if(!ltc1 -> equal(ltc2))
		return false;

	    const void* v1 = tc1 -> labels_[i].value();
	    const void* v2 = tc2 -> labels_[i].value();

	    ltc1 = OBGetOrigType(ltc1);
	    switch(ltc1 -> kind())
	    {
	    case CORBA_tk_short:
		if(*(CORBA_Short*)v1 != *(CORBA_Short*)v2)
		    return false;
		break;

	    case CORBA_tk_ushort:
		if(*(CORBA_UShort*)v1 != *(CORBA_UShort*)v2)
		    return false;
		break;

	    case CORBA_tk_long:
		if(*(CORBA_Long*)v1 != *(CORBA_Long*)v2)
		    return false;
		break;

	    case CORBA_tk_ulong:
	    case CORBA_tk_enum:
		if(*(CORBA_ULong*)v1 != *(CORBA_ULong*)v2)
		    return false;
		break;

	    case CORBA_tk_char:
		if(*(CORBA_Char*)v1 != *(CORBA_Char*)v2)
		    return false;
		break;

	    case CORBA_tk_boolean:
		if(*(CORBA_Boolean*)v1 != *(CORBA_Boolean*)v2)
		    return false;
		break;

	    case CORBA_tk_octet:
		break;

	    default:
		assert(false);
		break;
	    }
	}
    }
    
    if(tc1 -> kind_ == CORBA_tk_union)
    {
	if(!(tc1 -> discriminatorType_ -> equal(tc2 -> discriminatorType_)))
	    return false;
    }
    
    if(tc1 -> kind_ == CORBA_tk_string ||
       tc1 -> kind_ == CORBA_tk_sequence ||
       tc1 -> kind_ == CORBA_tk_array)
    {
	if(tc1 -> length_ != tc2 -> length_)
	    return false;
    }
    
    if(tc1 -> kind_ == CORBA_tk_array ||
       tc1 -> kind_ == CORBA_tk_alias)
    {
	if(!(tc1 -> contentType_ -> equal(tc2 -> contentType_)))
	    return false;
    }

    if(tc1 -> kind_ == CORBA_tk_sequence)
    {
	if(tc1 -> offset_ == 0 && tc2 -> offset_ == 0)
	{
	    if(!(tc1 -> contentType_ -> equal(tc2 -> contentType_)))
		return false;
	}
	else
	{
	    if(tc1 -> offset_ != tc2 -> offset_)
		return false;

	    if(CORBA_is_nil(tc1 -> contentType_) !=
	       CORBA_is_nil(tc2 -> contentType_))
		return false;

	    if(!CORBA_is_nil(tc1 -> contentType_))
	    {
		if(tc1 -> contentType_ -> kind_ !=
		   tc2 -> contentType_ -> kind_)
		    return false;
		
		assert(tc1 -> contentType_ -> kind_ == CORBA_tk_struct ||
		       tc1 -> contentType_ -> kind_ == CORBA_tk_union ||
		       tc1 -> contentType_ -> kind_ == CORBA_tk_except);
		
		if(strcmp(tc1 -> contentType_ -> id_,
			  tc2 -> contentType_ -> id_) != 0 ||
		   strcmp(tc1 -> contentType_ -> name_,
			  tc2 -> contentType_ -> name_) != 0)
		    return false;
	    }
	}
    }
    
    return true;
}

CORBA_TCKind
CORBA_TypeCode::kind() const
{
    return kind_;
}

const char*
CORBA_TypeCode::id() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_objref ||
	 kind_ == CORBA_tk_struct ||
	 kind_ == CORBA_tk_union ||
	 kind_ == CORBA_tk_enum ||
	 kind_ == CORBA_tk_alias ||
	 kind_ == CORBA_tk_except))
    {
	throw BadKind();
    }
    
    return id_;
}

const char*
CORBA_TypeCode::name() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_objref ||
	 kind_ == CORBA_tk_struct ||
	 kind_ == CORBA_tk_union ||
	 kind_ == CORBA_tk_enum ||
	 kind_ == CORBA_tk_alias ||
	 kind_ == CORBA_tk_except))
    {
	throw BadKind();
    }
    
    return name_;
}

CORBA_ULong
CORBA_TypeCode::member_count() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_struct ||
	 kind_ == CORBA_tk_union ||
	 kind_ == CORBA_tk_enum ||
	 kind_ == CORBA_tk_except))
    {
	throw BadKind();
    }
    
    return memberNames_.length();
}

const char*
CORBA_TypeCode::member_name(CORBA_ULong index) const
    throw(CORBA_TypeCode::BadKind, CORBA_TypeCode::Bounds)
{
    if(!(kind_ == CORBA_tk_struct ||
	 kind_ == CORBA_tk_union ||
	 kind_ == CORBA_tk_enum ||
	 kind_ == CORBA_tk_except))
    {
	throw BadKind();
    }

    if(index >= memberNames_.length())
    {
	throw Bounds();
    }

    return memberNames_[index];
}

CORBA_TypeCode_ptr
CORBA_TypeCode::member_type(CORBA_ULong index) const
    throw(CORBA_TypeCode::BadKind, CORBA_TypeCode::Bounds)
{
    if(!(kind_ == CORBA_tk_struct ||
	 kind_ == CORBA_tk_union ||
	 kind_ == CORBA_tk_except))
    {
	throw BadKind();
    }

    if(index >= memberNames_.length())
    {
	throw Bounds();
    }

    return CORBA_TypeCode::_duplicate(memberTypes_[index]);
}

CORBA_Any*
CORBA_TypeCode::member_label(CORBA_ULong index) const
    throw(CORBA_TypeCode::BadKind, CORBA_TypeCode::Bounds)
{
    if(!(kind_ == CORBA_tk_union))
    {
	throw BadKind();
    }

    if(index >= memberNames_.length())
    {
	throw Bounds();
    }

    return new CORBA_Any(labels_[index]);
}

CORBA_TypeCode_ptr
CORBA_TypeCode::discriminator_type() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_union))
    {
	throw BadKind();
    }

    return CORBA_TypeCode::_duplicate(discriminatorType_);
}

CORBA_Long
CORBA_TypeCode::default_index() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_union))
    {
	throw BadKind();
    }

    for(CORBA_Long i = 0 ; i < (CORBA_Long)labels_.length() ; i++)
    {
	CORBA_TypeCode_var tc = labels_[i].type();
	if(tc -> kind() == CORBA_tk_octet)
	    return i;
    }

    return -1;
}

CORBA_ULong
CORBA_TypeCode::length() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_string ||
	 kind_ == CORBA_tk_sequence ||
	 kind_ == CORBA_tk_array))
    {
	throw BadKind();
    }

    return length_;
}

CORBA_TypeCode_ptr
CORBA_TypeCode::content_type() const
    throw(CORBA_TypeCode::BadKind)
{
    if(!(kind_ == CORBA_tk_sequence ||
	 kind_ == CORBA_tk_array ||
	 kind_ == CORBA_tk_alias))
    {
	throw BadKind();
    }

    return CORBA_TypeCode::_duplicate(contentType_);
}

CORBA_Boolean
CORBA_TypeCode::exactly_equal(CORBA_TypeCode_ptr p) const
{
    if(p == this)
	return true;

    if(kind_ != p -> kind_)
	return false;

    if(kind_ == CORBA_tk_objref ||
       kind_ == CORBA_tk_struct ||
       kind_ == CORBA_tk_union ||
       kind_ == CORBA_tk_enum ||
       kind_ == CORBA_tk_alias ||
       kind_ == CORBA_tk_except)
    {
 	if(strcmp(id_, p -> id_) != 0 ||
	   strcmp(name_, p -> name_) != 0)
	    return false;
    }
    
    if(kind_ == CORBA_tk_struct ||
       kind_ == CORBA_tk_union ||
       kind_ == CORBA_tk_enum ||
       kind_ == CORBA_tk_except)
    {
 	if(memberNames_.length() != p -> memberNames_.length())
 	    return false;
	
 	for(CORBA_ULong i = 0 ; i < memberNames_.length() ; i++)
 	    if(strcmp(memberNames_[i], p -> memberNames_[i]) != 0)
 		return false;
    }
    
    if(kind_ == CORBA_tk_struct ||
       kind_ == CORBA_tk_union ||
       kind_ == CORBA_tk_except)
    {
	if(memberTypes_.length() != p -> memberTypes_.length())
	    return false;
	
	for(CORBA_ULong i = 0 ; i < memberTypes_.length() ; i++)
	    if(!memberTypes_[i] -> exactly_equal(p -> memberTypes_[i]))
		return false;
    }
    
    if(kind_ == CORBA_tk_union)
    {
	if(labels_.length() != p -> labels_.length())
	    return false;
	
	for(CORBA_ULong i = 0 ; i < labels_.length() ; i++)
	{
	    CORBA_TypeCode_var ltc1 = labels_[i].type();
	    CORBA_TypeCode_var ltc2 = p -> labels_[i].type();
    
	    if(!ltc1 -> exactly_equal(ltc2))
		return false;

	    const void* v1 = labels_[i].value();
	    const void* v2 = p -> labels_[i].value();

	    ltc1 = OBGetOrigType(ltc1);
	    switch(ltc1 -> kind())
	    {
	    case CORBA_tk_short:
		if(*(CORBA_Short*)v1 != *(CORBA_Short*)v2)
		    return false;
		break;

	    case CORBA_tk_ushort:
		if(*(CORBA_UShort*)v1 != *(CORBA_UShort*)v2)
		    return false;
		break;

	    case CORBA_tk_long:
		if(*(CORBA_Long*)v1 != *(CORBA_Long*)v2)
		    return false;
		break;

	    case CORBA_tk_ulong:
	    case CORBA_tk_enum:
		if(*(CORBA_ULong*)v1 != *(CORBA_ULong*)v2)
		    return false;
		break;

	    case CORBA_tk_char:
		if(*(CORBA_Char*)v1 != *(CORBA_Char*)v2)
		    return false;
		break;

	    case CORBA_tk_boolean:
		if(*(CORBA_Boolean*)v1 != *(CORBA_Boolean*)v2)
		    return false;
		break;

	    case CORBA_tk_octet:
		break;

	    default:
		assert(false);
		break;
	    }
	}
    }
    
    if(kind_ == CORBA_tk_union)
    {
	if(!discriminatorType_ -> exactly_equal(p -> discriminatorType_))
	    return false;
    }
    
    if(kind_ == CORBA_tk_string ||
       kind_ == CORBA_tk_sequence ||
       kind_ == CORBA_tk_array)
    {
	if(length_ != p -> length_)
	    return false;
    }
    
    if(kind_ == CORBA_tk_array ||
       kind_ == CORBA_tk_alias)
    {
	if(!contentType_ -> exactly_equal(p -> contentType_))
	    return false;
    }

    if(kind_ == CORBA_tk_sequence)
    {
	if(offset_ == 0 && p -> offset_ == 0)
	{
	    if(!contentType_ -> exactly_equal(p -> contentType_))
		return false;
	}
	else
	{
	    if(offset_ != p -> offset_)
		return false;

	    if(CORBA_is_nil(contentType_) !=
	       CORBA_is_nil(p -> contentType_))
		return false;

	    if(!CORBA_is_nil(contentType_))
	    {
		if(contentType_ -> kind_ !=
		   p -> contentType_ -> kind_)
		    return false;
		
		assert(contentType_ -> kind_ == CORBA_tk_struct ||
		       contentType_ -> kind_ == CORBA_tk_union ||
		       contentType_ -> kind_ == CORBA_tk_except);
		
		if(strcmp(contentType_ -> id_,
			  p -> contentType_ -> id_) != 0 ||
		   strcmp(contentType_ -> name_,
			  p -> contentType_ -> name_) != 0)
		    return false;
	    }
	}
    }
    
    return true;
}

CORBA_ULong
CORBA_TypeCode::offset() const
    throw(CORBA_TypeCode::BadKind)
{
    if(kind_ != CORBA_tk_sequence)
    {
	throw BadKind();
    }

    return offset_;
}

bool
CORBA_TypeCode::_OB_isSystemException() const
{
    if(kind_ != CORBA_tk_except)
	return false;

    //
    // XXX - candidate for optimization. Use lookup table, or
    // something similar.
    //
    if(strcmp(id_, "IDL:omg.org/CORBA/UNKNOWN:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/BAD_PARAM:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/NO_MEMORY:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/IMP_LIMIT:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/COMM_FAILURE:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INV_OBJREF:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/NO_PERMISSION:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INTERNAL:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/MARSHAL:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INITIALIZE:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/NO_IMPLEMENT:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/BAD_TYPECODE:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/BAD_OPERATION:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/NO_RESOURCES:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/NO_RESPONSE:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/PERSIST_STORE:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/BAD_INV_ORDER:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/TRANSIENT:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/FREE_MEM:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INV_IDENT:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INV_FLAG:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INTF_REPOS:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/BAD_CONTEXT:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/OBJ_ADAPTER:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/DATA_CONVERSION:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/OBJECT_NOT_EXIST:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/TRANSACTION_REQUIRED:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/TRANSACTION_ROLLEDBACK:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INVALID_TRANSACTION:1.0") == 0 ||
       strcmp(id_, "IDL:omg.org/CORBA/INV_POLICY:1.0") == 0)
    {
	return true;
    }
    else
    {
	return false;
    }
}

// ----------------------------------------------------------------------
// CDR functions
// ----------------------------------------------------------------------

//
// NOTE:
//
// No data with natural alignment of greater than four octets
// is needed for TypeCode. Therefore it is not necessary to do
// encapsulation in a seperate buffer (12.3.3)
//
// The "recursive" functions are needed for recursive sequence type codes.
// Indirection alone could be handled without the additonal sequence
// parameter.
//

void
OBMarshal(CORBA_TypeCode_ptr p, CORBA_Octet*& oct)
{
    OBFixSeq< CORBA_Long > seq;
    OBMarshalRec(p, oct, oct, seq);
    assert(seq.length() == 0);
}

void
OBMarshalRec(CORBA_TypeCode_ptr p, CORBA_Octet*& oct,
	     CORBA_Octet const * const ref, OBFixSeq< CORBA_Long >& seq)
{
    if(CORBA_is_nil(p))
	throw CORBA_BAD_TYPECODE();

    OBMarshal(p -> kind_, oct);

    seq.append(oct - ref - 4);

    switch(p -> kind_)
    {
    case CORBA_tk_null:
    case CORBA_tk_void:
    case CORBA_tk_short:
    case CORBA_tk_long:
    case CORBA_tk_ushort:
    case CORBA_tk_ulong:
    case CORBA_tk_float:
    case CORBA_tk_double:
    case CORBA_tk_boolean:
    case CORBA_tk_char:
    case CORBA_tk_octet:
    case CORBA_tk_any:
    case CORBA_tk_TypeCode:
    case CORBA_tk_Principal:
	break;

    case CORBA_tk_objref:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(OBEndian, encapsLen);
	OBMarshalCount(p -> id_, encapsLen);
	OBMarshalCount(p -> name_, encapsLen);

	OBMarshal(encapsLen, oct);
	OBMarshal(OBEndian, oct);
	OBMarshal(p -> id_, oct);
	OBMarshal(p -> name_, oct);

	break;
    }

    case CORBA_tk_struct:
    case CORBA_tk_except:
    {
	CORBA_ULong i;

	CORBA_ULong encapsLen = 0;
	OBMarshalCount(OBEndian, encapsLen);
	OBMarshalCount(p -> id_, encapsLen);
	OBMarshalCount(p -> name_, encapsLen);
	OBMarshalCount(p -> memberNames_.length(), encapsLen);
	for(i = 0 ; i < p -> memberNames_.length() ; i++)
	{
	    OBMarshalCount(p -> memberNames_[i], encapsLen);
	    OBMarshalCountRec(p -> memberTypes_[i], encapsLen, seq.length());
	}

	OBMarshal(encapsLen, oct);
	OBMarshal(OBEndian, oct);
	OBMarshal(p -> id_, oct);
	OBMarshal(p -> name_, oct);
	OBMarshal(p -> memberNames_.length(), oct);
	for(i = 0 ; i < p -> memberNames_.length() ; i++)
	{
	    OBMarshal(p -> memberNames_[i], oct);
	    OBMarshalRec(p -> memberTypes_[i], oct, ref, seq);
	}
	
	break;
    }
	
    case CORBA_tk_union:
    {
	CORBA_ULong i;
	CORBA_TypeCode_var origDiscType =
	    OBGetOrigType(p -> discriminatorType_);

	CORBA_ULong encapsLen = 0;
	OBMarshalCount(OBEndian, encapsLen);
	OBMarshalCount(p -> id_, encapsLen);
	OBMarshalCount(p -> name_, encapsLen);
	OBMarshalCountRec(p -> discriminatorType_, encapsLen, seq.length());
 	CORBA_Long defaultIndex = p -> default_index();
 	OBMarshalCount(defaultIndex, encapsLen);
	OBMarshalCount(p -> memberNames_.length(), encapsLen);
	for(i = 0 ; i < p -> memberNames_.length() ; i++)
	{
            //
            // Check for default label value
            //
            if((CORBA_Long)i == defaultIndex)
            {
                //
                // Marshal a dummy value of the appropriate size
                // for the discriminator type
                //
                switch(origDiscType -> kind())
                {
                case CORBA_tk_short:
                    OBMarshalCount((CORBA_Short)0, encapsLen);
                    break;
                case CORBA_tk_ushort:
                    OBMarshalCount((CORBA_UShort)0, encapsLen);
                    break;
                case CORBA_tk_long:
                    OBMarshalCount((CORBA_Long)0, encapsLen);
                    break;
                case CORBA_tk_ulong:
                case CORBA_tk_enum:
                    OBMarshalCount((CORBA_ULong)0, encapsLen);
                    break;
                case CORBA_tk_boolean:
                    OBMarshalCount(CORBA_FALSE, encapsLen);
                    break;
                case CORBA_tk_char:
                    OBMarshalCount((CORBA_Char)0, encapsLen);
                    break;
                default:
                    assert(false);
                    break;
                }
            }
            else
            {
		OBMarshalCountNoTypeCode(p -> labels_[i], encapsLen);
            }
	    OBMarshalCount(p -> memberNames_[i], encapsLen);
	    OBMarshalCountRec(p -> memberTypes_[i], encapsLen, seq.length());
	}
	
	OBMarshal(encapsLen, oct);
	OBMarshal(OBEndian, oct);
	OBMarshal(p -> id_, oct);
	OBMarshal(p -> name_, oct);
	OBMarshalRec(p -> discriminatorType_, oct, ref, seq);
 	OBMarshal(defaultIndex, oct);
	OBMarshal(p -> memberNames_.length(), oct);
	for(i = 0 ; i < p -> memberNames_.length() ; i++)
	{
            //
            // Check for default label value
            //
            if((CORBA_Long)i == defaultIndex)
            {
                //
                // Marshal a dummy value of the appropriate size
                // for the discriminator type
                //
                switch(origDiscType -> kind())
                {
                case CORBA_tk_short:
                    OBMarshal((CORBA_Short)0, oct);
                    break;
                case CORBA_tk_ushort:
                    OBMarshal((CORBA_UShort)0, oct);
                    break;
                case CORBA_tk_long:
                    OBMarshal((CORBA_Long)0, oct);
                    break;
                case CORBA_tk_ulong:
                case CORBA_tk_enum:
                    OBMarshal((CORBA_ULong)0, oct);
                    break;
                case CORBA_tk_boolean:
                    OBMarshal(CORBA_FALSE, oct);
                    break;
                case CORBA_tk_char:
                    OBMarshal((CORBA_Char)0, oct);
                    break;
                default:
                    assert(false);
                    break;
                }
            }
            else
            {
		OBMarshalNoTypeCode(p -> labels_[i], oct);
            }
	    OBMarshal(p -> memberNames_[i], oct);
	    OBMarshalRec(p -> memberTypes_[i], oct, ref, seq);
	}
	
	break;
    }

    case CORBA_tk_enum:
    {
	CORBA_ULong i;

	CORBA_ULong encapsLen = 0;
	OBMarshalCount(OBEndian, encapsLen);
	OBMarshalCount(p -> id_, encapsLen);
	OBMarshalCount(p -> name_, encapsLen);
	OBMarshalCount(p -> memberNames_.length(), encapsLen);
	for(i = 0 ; i < p -> memberNames_.length() ; i++)
	    OBMarshalCount(p -> memberNames_[i], encapsLen);

	OBMarshal(encapsLen, oct);
	OBMarshal(OBEndian, oct);
	OBMarshal(p -> id_, oct);
	OBMarshal(p -> name_, oct);
	OBMarshal(p -> memberNames_.length(), oct);
	for(i = 0 ; i < p -> memberNames_.length() ; i++)
	    OBMarshal(p -> memberNames_[i], oct);
	
	break;
    }

    case CORBA_tk_string:
	OBMarshal(p -> length_, oct);
	break;

    case CORBA_tk_sequence:
    case CORBA_tk_array:
    {
	CORBA_ULong last = seq.length() - 1;
	if(p -> kind_ == CORBA_tk_sequence &&
	   p -> offset_ > 0 && last >= p -> offset_)
	{
	    CORBA_TCKind kind = (CORBA_TCKind)0xffffffff;
	    CORBA_Long octOffset = 0;
	    CORBA_ULong encapsLen = 0;
	    OBMarshalCount(OBEndian, encapsLen);
	    OBMarshalCount(kind, encapsLen);
	    OBMarshalCount(octOffset, encapsLen);
	    OBMarshalCount(p -> length_, encapsLen);
	    
	    OBMarshal(encapsLen, oct);
	    OBMarshal(OBEndian, oct);
	    OBMarshal(kind, oct);
	    octOffset = seq[last - p -> offset_] - (oct - ref);
	    assert(octOffset < -4);
	    OBMarshal(octOffset, oct);
	    OBMarshal(p -> length_, oct);
	}
	else
	{
	    CORBA_ULong encapsLen = 0;
	    OBMarshalCount(OBEndian, encapsLen);
	    OBMarshalCountRec(p -> contentType_, encapsLen, seq.length());
	    OBMarshalCount(p -> length_, encapsLen);
	    
	    OBMarshal(encapsLen, oct);
	    OBMarshal(OBEndian, oct);
	    OBMarshalRec(p -> contentType_, oct, ref, seq);
	    OBMarshal(p -> length_, oct);
	}

	break;
    }

    case CORBA_tk_alias:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(OBEndian, encapsLen);
	OBMarshalCount(p -> id_, encapsLen);
	OBMarshalCount(p -> name_, encapsLen);
	OBMarshalCountRec(p -> contentType_, encapsLen, seq.length());
	
	OBMarshal(encapsLen, oct);
	OBMarshal(OBEndian, oct);
	OBMarshal(p -> id_, oct);
	OBMarshal(p -> name_, oct);
	OBMarshalRec(p -> contentType_, oct, ref, seq);
	
	break;
    }
    }

    assert(seq.length() > 0);
    seq.length(seq.length() - 1);
}

void
OBMarshalCount(CORBA_TypeCode_ptr p, CORBA_ULong& count)
{
    OBMarshalCountRec(p, count, 0);
}

void
OBMarshalCountRec(CORBA_TypeCode_ptr p, CORBA_ULong& count, CORBA_ULong length)
{
    if(CORBA_is_nil(p))
	throw CORBA_BAD_TYPECODE();

    OBMarshalCount(p -> kind_, count);

    length++;

    switch(p -> kind_)
    {
    case CORBA_tk_null:
    case CORBA_tk_void:
    case CORBA_tk_short:
    case CORBA_tk_long:
    case CORBA_tk_ushort:
    case CORBA_tk_ulong:
    case CORBA_tk_float:
    case CORBA_tk_double:
    case CORBA_tk_boolean:
    case CORBA_tk_char:
    case CORBA_tk_octet:
    case CORBA_tk_any:
    case CORBA_tk_TypeCode:
    case CORBA_tk_Principal:
	break;

    case CORBA_tk_objref:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(encapsLen, count);
	OBMarshalCount(OBEndian, count);
	OBMarshalCount(p -> id_, count);
	OBMarshalCount(p -> name_, count);

	break;
    }

    case CORBA_tk_struct:
    case CORBA_tk_except:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(encapsLen, count);
	OBMarshalCount(OBEndian, count);
	OBMarshalCount(p -> id_, count);
	OBMarshalCount(p -> name_, count);
	OBMarshalCount(p -> memberNames_.length(), count);
	for(CORBA_ULong i = 0 ; i < p -> memberNames_.length() ; i++)
	{
	    OBMarshalCount(p -> memberNames_[i], count);
	    OBMarshalCountRec(p -> memberTypes_[i], count, length);
	}
	
	break;
    }
	
    case CORBA_tk_union:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(encapsLen, count);
	OBMarshalCount(OBEndian, count);
	OBMarshalCount(p -> id_, count);
	OBMarshalCount(p -> name_, count);
	OBMarshalCountRec(p -> discriminatorType_, count, length);
        CORBA_Long defaultIndex = p -> default_index();
 	OBMarshalCount(defaultIndex, count);
	OBMarshalCount(p -> memberNames_.length(), count);
	for(CORBA_ULong i = 0 ; i < p -> memberNames_.length() ; i++)
	{
            //
            // Check for default label value
            //
            if((CORBA_Long)i == defaultIndex)
            {
		CORBA_TypeCode_var origDiscType =
		    OBGetOrigType(p -> discriminatorType_);

                //
                // Marshal a dummy value of the appropriate size
                // for the discriminator type
                //
                switch(origDiscType -> kind())
                {
                case CORBA_tk_short:
                    OBMarshalCount((CORBA_Short)0, count);
                    break;
                case CORBA_tk_ushort:
                    OBMarshalCount((CORBA_UShort)0, count);
                    break;
                case CORBA_tk_long:
                    OBMarshalCount((CORBA_Long)0, count);
                    break;
                case CORBA_tk_ulong:
                case CORBA_tk_enum:
                    OBMarshalCount((CORBA_ULong)0, count);
                    break;
                case CORBA_tk_boolean:
                    OBMarshalCount(CORBA_FALSE, count);
                    break;
                case CORBA_tk_char:
                    OBMarshalCount((CORBA_Char)0, count);
                    break;
                default:
                    assert(false);
                    break;
                }
            }
            else
            {
		OBMarshalCountNoTypeCode(p -> labels_[i], count);
            }
	    OBMarshalCount(p -> memberNames_[i], count);
	    OBMarshalCountRec(p -> memberTypes_[i], count, length);
	}
	
	break;
    }

    case CORBA_tk_enum:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(encapsLen, count);
	OBMarshalCount(OBEndian, count);
	OBMarshalCount(p -> id_, count);
	OBMarshalCount(p -> name_, count);
	OBMarshalCount(p -> memberNames_.length(), count);
	for(CORBA_ULong i = 0 ; i < p -> memberNames_.length() ; i++)
	    OBMarshalCount(p -> memberNames_[i], count);
	
	break;
    }

    case CORBA_tk_string:
	OBMarshalCount(p -> length_, count);
	break;

    case CORBA_tk_sequence:
    case CORBA_tk_array:
    {
	CORBA_ULong last = length - 1;
	if(p -> kind_ == CORBA_tk_sequence &&
	   p -> offset_ > 0 && last >= p -> offset_)
	{
	    CORBA_TCKind kind = (CORBA_TCKind)0xffffffff;
	    CORBA_Long octOffset = 0;
	    CORBA_ULong encapsLen = 0;
	    OBMarshalCount(encapsLen, count);
	    OBMarshalCount(OBEndian, count);
	    OBMarshalCount(kind, count);
	    OBMarshalCount(octOffset, count);
	    OBMarshalCount(p -> length_, count);
	}
	else
	{
	    CORBA_ULong encapsLen = 0;
	    OBMarshalCount(encapsLen, count);
	    OBMarshalCount(OBEndian, count);
	    OBMarshalCountRec(p -> contentType_, count, length);
	    OBMarshalCount(p -> length_, count);
	}

	break;
    }

    case CORBA_tk_alias:
    {
	CORBA_ULong encapsLen = 0;
	OBMarshalCount(encapsLen, count);
	OBMarshalCount(OBEndian, count);
	OBMarshalCount(p -> id_, count);
	OBMarshalCount(p -> name_, count);
	OBMarshalCountRec(p -> contentType_, count, length);
	
	break;
    }
    }
}

void
OBUnmarshal(CORBA_TypeCode_ptr& p, const CORBA_Octet*& oct, bool swap)
{
    OBFixSeq< CORBA_Long > seq;
    OBUnmarshalRec(p, oct, swap, oct, seq);
    assert(seq.length() == 0);
}

void
OBUnmarshalRec(CORBA_TypeCode_ptr& p, const CORBA_Octet*& oct, bool swap,
	       CORBA_Octet const * const ref, OBFixSeq< CORBA_Long >& seq)
{
    CORBA_release(p);
    p = CORBA_TypeCode::_nil();
    
    const CORBA_Octet* oldOct = 0;
    CORBA_TCKind kind;
    do
    {
	OBUnmarshal(kind, oct, swap);
	if(kind == (CORBA_TCKind)0xffffffff)
	{
	    CORBA_Long octOffset;
	    OBUnmarshal(octOffset, oct, swap);
	    assert(octOffset < -4);
	    if(oldOct == 0)
		oldOct = oct;
	    oct = oct - 4 + octOffset;
	    assert(oct >= ref);
	}
    }
    while(kind == (CORBA_TCKind)0xffffffff);
    
    seq.append(oct - ref - 4);

    switch(kind)
    {
    case CORBA_tk_null:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_null);
	break;

    case CORBA_tk_void:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_void);
	break;

    case CORBA_tk_short:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_short);
	break;

    case CORBA_tk_long:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_long);
	break;

    case CORBA_tk_ushort:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_ushort);
	break;

    case CORBA_tk_ulong:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_ulong);
	break;

    case CORBA_tk_float:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_float);
	break;

    case CORBA_tk_double:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_double);
	break;

    case CORBA_tk_boolean:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_boolean);
	break;

    case CORBA_tk_char:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_char);
	break;

    case CORBA_tk_octet:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_octet);
	break;

    case CORBA_tk_any:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_any);
	break;

    case CORBA_tk_TypeCode:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_TypeCode);
	break;

    case CORBA_tk_Principal:
	p = CORBA_TypeCode::_duplicate(CORBA__tc_Principal);
	break;

    case CORBA_tk_objref:
    {
	CORBA_TypeCode_var tc = new CORBA_TypeCode;
	tc -> kind_ = kind;
	CORBA_ULong encapsLen;
	CORBA_Boolean endian;
	OBUnmarshal(encapsLen, oct, swap);
	OBUnmarshal(endian, oct, swap);
	OBUnmarshal(tc -> id_.inout(), oct, endian != OBEndian);
	OBUnmarshal(tc -> name_.inout(), oct, endian != OBEndian);
	
	p = tc._retn();
	
	break;
    }

    case CORBA_tk_struct:
    case CORBA_tk_except:
    {
	CORBA_TypeCode_var tc = new CORBA_TypeCode;
	tc -> kind_ = kind;
	CORBA_ULong encapsLen;
	CORBA_Boolean endian;
	OBUnmarshal(encapsLen, oct, swap);
	OBUnmarshal(endian, oct, swap);
	OBUnmarshal(tc -> id_.inout(), oct, endian != OBEndian);
	OBUnmarshal(tc -> name_.inout(), oct, endian != OBEndian);
	CORBA_ULong num;
	OBUnmarshal(num, oct, endian != OBEndian);
	tc -> memberNames_.length(num);
	tc -> memberTypes_.length(num);
	for(CORBA_ULong i = 0 ; i < num ; i++)
	{
	    OBUnmarshal(tc -> memberNames_[i].inout(), oct,
			endian != OBEndian);
	    OBUnmarshalRec(tc -> memberTypes_[i].inout(), oct,
			   endian != OBEndian, ref, seq);
	    OBFillRec(tc -> memberTypes_[i].inout(), tc, 1);
	}
	
	p = tc._retn();
	
	break;
    }
	
    case CORBA_tk_union:
    {
	CORBA_TypeCode_var tc = new CORBA_TypeCode;
	tc -> kind_ = kind;
	CORBA_ULong encapsLen;
	CORBA_Boolean endian;
	OBUnmarshal(encapsLen, oct, swap);
	OBUnmarshal(endian, oct, swap);
	OBUnmarshal(tc -> id_.inout(), oct, endian != OBEndian);
	OBUnmarshal(tc -> name_.inout(), oct, endian != OBEndian);
	OBUnmarshalRec(tc -> discriminatorType_.inout(), oct,
		       endian != OBEndian, ref, seq);
 	CORBA_Long defaultIndex;
 	OBUnmarshal(defaultIndex, oct, endian != OBEndian);
	CORBA_ULong num;
	OBUnmarshal(num, oct, endian != OBEndian);
	tc -> labels_.length(num);
	tc -> memberNames_.length(num);
	tc -> memberTypes_.length(num);
	for(CORBA_ULong i = 0 ; i < num ; i++)
	{
	    if((CORBA_Long)i == defaultIndex)
	    {
		CORBA_TypeCode_var origDiscType =
		    OBGetOrigType(tc -> discriminatorType_);

		//
		// Unmarshal a dummy value of the appropriate size
		// for the discriminator type
		//
		switch(origDiscType -> kind())
		{
		case CORBA_tk_short:
		{
		    CORBA_Short dummy;
		    OBUnmarshal(dummy, oct, endian != OBEndian);
		    break;
		}
		case CORBA_tk_ushort:
		{
		    CORBA_UShort dummy;
		    OBUnmarshal(dummy, oct, endian != OBEndian);
		    break;
		}
		case CORBA_tk_long:
		{
		    CORBA_Long dummy;
		    OBUnmarshal(dummy, oct, endian != OBEndian);
		    break;
		}
		case CORBA_tk_ulong:
		case CORBA_tk_enum:
		{
		    CORBA_ULong dummy;
		    OBUnmarshal(dummy, oct, endian != OBEndian);
		    break;
		}
		case CORBA_tk_boolean:
		{
		    CORBA_Boolean dummy;
		    OBUnmarshal(dummy, oct, endian != OBEndian);
		    break;
		}
		case CORBA_tk_char:
		{
		    CORBA_Char dummy;
		    OBUnmarshal(dummy, oct, endian != OBEndian);
		    break;
		}
		default:
		    assert(false);
		    break;
		}

		//
		// Default label value is the zero octet
		//
		tc -> labels_[i] <<= CORBA_Any::from_octet(0);
	    }
	    else
	    {
		OBUnmarshalNoTypeCode(tc -> labels_[i], oct,
				      endian != OBEndian,
				      tc -> discriminatorType_);
	    }
	    
	    OBUnmarshal(tc -> memberNames_[i].inout(), oct,
			endian != OBEndian);
	    OBUnmarshalRec(tc -> memberTypes_[i].inout(), oct,
			   endian != OBEndian, ref, seq);
	    OBFillRec(tc -> memberTypes_[i].inout(), tc, 1);
	}
	
	p = tc._retn();
	
	break;
    }

    case CORBA_tk_enum:
    {
	CORBA_TypeCode_var tc = new CORBA_TypeCode;
	tc -> kind_ = kind;
	CORBA_ULong encapsLen;
	CORBA_Boolean endian;
	OBUnmarshal(encapsLen, oct, swap);
	OBUnmarshal(endian, oct, swap);
	OBUnmarshal(tc -> id_.inout(), oct, endian != OBEndian);
	OBUnmarshal(tc -> name_.inout(), oct, endian != OBEndian);
	CORBA_ULong num;
	OBUnmarshal(num, oct, endian != OBEndian);
	tc -> memberNames_.length(num);
	for(CORBA_ULong i = 0 ; i < num ; i++)
	    OBUnmarshal(tc -> memberNames_[i].inout(), oct,
			endian != OBEndian);
	
	p = tc._retn();

	break;
    }

    case CORBA_tk_string:
    {
	CORBA_ULong bound;
	OBUnmarshal(bound, oct, swap);
	
	if(bound == 0)
	    p = CORBA_TypeCode::_duplicate(CORBA__tc_string);
	else
	{
	    CORBA_TypeCode_var tc = new CORBA_TypeCode;
	    tc -> kind_ = kind;
	    tc -> length_ = bound;
	
	    p = tc._retn();
	}

	break;
    }

    case CORBA_tk_sequence:
    case CORBA_tk_array:
    {
	CORBA_TypeCode_var tc = new CORBA_TypeCode;
	tc -> kind_ = kind;
	CORBA_ULong encapsLen;
	CORBA_Boolean endian;
	OBUnmarshal(encapsLen, oct, swap);
	OBUnmarshal(endian, oct, swap);

	CORBA_TCKind k;
	OBUnmarshal(k, oct, endian != OBEndian);
	if(k == (CORBA_TCKind)0xffffffff)
	{
	    CORBA_Long octOffset;
	    OBUnmarshal(octOffset, oct, endian != OBEndian);
	    assert(octOffset < -4);

	    CORBA_ULong offset;
	    CORBA_ULong last = seq.length() - 1;
	    for(offset = 1 ; offset <= last ; offset++)
		if(octOffset == seq[last - offset] - (oct - ref - 4))
		    break;

	    if(offset <= last)
	    {
		// Recursive type code
		tc -> contentType_ = CORBA_TypeCode::_nil();
		tc -> offset_ = offset;
	    }
	    else
	    {
		// Non-recursive, but indirection
		oct -= 8;
		OBUnmarshalRec(tc -> contentType_.inout(), oct,
			       endian != OBEndian, ref, seq);
		tc -> offset_ = 0;
	    }
	}
	else
	{
	    // Non-recursive, no indirection
	    oct -= 4;
	    OBUnmarshalRec(tc -> contentType_.inout(), oct,
			   endian != OBEndian, ref, seq);
	    tc -> offset_ = 0;
	}
	
	OBUnmarshal(tc -> length_, oct, endian != OBEndian);
	p = tc._retn();

	break;
    }

    case CORBA_tk_alias:
    {
	CORBA_TypeCode_var tc = new CORBA_TypeCode;
	tc -> kind_ = kind;
	CORBA_ULong encapsLen;
	CORBA_Boolean endian;
	OBUnmarshal(encapsLen, oct, swap);
	OBUnmarshal(endian, oct, swap);
	OBUnmarshal(tc -> id_.inout(), oct, endian != OBEndian);
	OBUnmarshal(tc -> name_.inout(), oct, endian != OBEndian);
	OBUnmarshalRec(tc -> contentType_.inout(), oct,
		       endian != OBEndian, ref, seq);
	
	p = tc._retn();

	break;
    }
    }

    assert(seq.length() > 0);
    seq.length(seq.length() - 1);

    if(oldOct != 0)
	oct = oldOct;
}

void
OBMarshalBuffer(CORBA_TypeCode_ptr tc, const CORBA_Octet*& from,
		CORBA_Octet*& to, bool swap)
{
    switch(tc -> kind_)
    {
    case CORBA_tk_null:
    case CORBA_tk_void:
	break;
	
    case CORBA_tk_boolean:
    case CORBA_tk_char:
    case CORBA_tk_octet:
    {
	CORBA_Octet val;
	OBUnmarshal(val, from, swap);
	OBMarshal(val, to);
	break;
    }

    case CORBA_tk_short:
    case CORBA_tk_ushort:
    {
	CORBA_UShort val;
	OBUnmarshal(val, from, swap);
	OBMarshal(val, to);
	break;
    }
    
    case CORBA_tk_long:
    case CORBA_tk_ulong:
    case CORBA_tk_float:
    case CORBA_tk_enum:
    {
	CORBA_ULong val;
	OBUnmarshal(val, from, swap);
	OBMarshal(val, to);
	break;
    }
    
    case CORBA_tk_double:
    {
	CORBA_Double val;
	OBUnmarshal(val, from, swap);
	OBMarshal(val, to);
	break;
    }

    case CORBA_tk_any:
    {
	// Don't do this:
	//
	// CORBA_Any any;
	// OBUnmarshal(any, from, swap);
	// OBMarshal(any, to);
	//
	// This is faster:

	CORBA_TypeCode_var p;
	OBUnmarshal(p.inout(), from, swap);
	OBMarshal(p, to);
	OBMarshalBuffer(p, from, to, swap);
	break;
    }
    
    case CORBA_tk_TypeCode:
    {
	// Don't do this:
	//
	// CORBA_TypeCode_var p;
	// OBUnmarshal(p.inout(), from, swap);
	// OBMarshal(p, to);
	//
	// This is faster:
	
	CORBA_TCKind kind;
	OBUnmarshal(kind, from, swap);
	OBMarshal(kind, to);
	
	if(kind == (CORBA_TCKind)0xffffffff)
	{
	    CORBA_Long octOffset;
	    OBUnmarshal(octOffset, from, swap);
	    OBMarshal(octOffset, to);
	}
	else
	{
	    switch(kind)
	    {
	    case CORBA_tk_null:
	    case CORBA_tk_void:
	    case CORBA_tk_short:
	    case CORBA_tk_long:
	    case CORBA_tk_ushort:
	    case CORBA_tk_ulong:
	    case CORBA_tk_float:
	    case CORBA_tk_double:
	    case CORBA_tk_boolean:
	    case CORBA_tk_char:
	    case CORBA_tk_octet:
	    case CORBA_tk_any:
	    case CORBA_tk_TypeCode:
	    case CORBA_tk_Principal:
		break;
		
	    case CORBA_tk_objref:
	    case CORBA_tk_struct:
	    case CORBA_tk_except:
	    case CORBA_tk_union:
	    case CORBA_tk_enum:
	    case CORBA_tk_sequence:
	    case CORBA_tk_array:
	    case CORBA_tk_alias:
	    {
		CORBA_ULong len;
		OBUnmarshal(len, from, swap);
		OBMarshal(len, to);
		OBUnmarshalMulti(to, from, swap, len);
		to += len;
		break;
	    }
	    
	    case CORBA_tk_string:
	    {
		CORBA_ULong bound;
		OBUnmarshal(bound, from, swap);
		OBMarshal(bound, to);
		break;
	    }
	    }
	}
	
	break;
    }
    
    case CORBA_tk_Principal:
    {
	OBFixSeq<CORBA_Octet> seq;
	OBUnmarshal(seq, from, swap);
	OBMarshal(seq, to);
	break;
    }

    case CORBA_tk_objref:
    {
	// Don't do this:
	//
	// CORBA_Object_var p;
	// OBUnmarshal(p.inout(), from, swap);
	// OBMarshal(p, to);
	//
	// This is faster:

	IOP_IOR ior;
	OBUnmarshal(ior, from, swap);
	OBMarshal(ior, to);
	break;
    }
	
    case CORBA_tk_struct:
    {
	for(CORBA_ULong i = 0 ; i < tc -> memberTypes_.length() ; i++)
	    OBMarshalBuffer(tc -> memberTypes_[i], from, to, swap);
	
	break;
    }
	
    case CORBA_tk_except:
    {
	CORBA_String_var id;
	OBUnmarshal(id.inout(), from, swap);
	OBMarshal(id, to);

	for(CORBA_ULong i = 0 ; i < tc -> memberTypes_.length() ; i++)
	    OBMarshalBuffer(tc -> memberTypes_[i], from, to, swap);
	
	break;
    }
	
    case CORBA_tk_union:
    {
	CORBA_Long defaultIndex = tc -> default_index();
	CORBA_Long memberIndex = -1;

	CORBA_TypeCode_var discType = OBGetOrigType(tc -> discriminatorType_);

	switch(discType -> kind())
	{
	case CORBA_tk_short:
	{
	    CORBA_Short val;
	    OBUnmarshal(val, from, swap);
	    OBMarshal(val, to);
	    
	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Short*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }
	    
	    break;
	}

	case CORBA_tk_ushort:
	{
	    CORBA_UShort val;
	    OBUnmarshal(val, from, swap);
	    OBMarshal(val, to);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_UShort*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_long:
	{
	    CORBA_Long val;
	    OBUnmarshal(val, from, swap);
	    OBMarshal(val, to);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Long*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_ulong:
	case CORBA_tk_enum:
	{
	    CORBA_ULong val;
	    OBUnmarshal(val, from, swap);
	    OBMarshal(val, to);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_ULong*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_char:
	{
	    CORBA_Char val;
	    OBUnmarshal(val, from, swap);
	    OBMarshal(val, to);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Char*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_boolean:
	{
	    CORBA_Boolean val;
	    OBUnmarshal(val, from, swap);
	    OBMarshal(val, to);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Boolean*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	default:
	    assert(false);
	    break;
	}

	if(memberIndex >= 0)
	    OBMarshalBuffer(tc -> memberTypes_[memberIndex],
			    from, to, swap);
	else if(defaultIndex >= 0)
	    OBMarshalBuffer(tc -> memberTypes_[defaultIndex],
			    from, to, swap);

	break;
    }
	
    case CORBA_tk_string:
    {
	CORBA_String_var s;
	OBUnmarshal(s.inout(), from, swap);
	OBMarshal(s, to);
	break;
    }

    case CORBA_tk_sequence:
    case CORBA_tk_array:
    {
	CORBA_ULong len;

	if(tc -> kind_ == CORBA_tk_sequence)
	{
	    OBUnmarshal(len, from, swap);
	    OBMarshal(len, to);
	}
	else
	    len = tc -> length_;
	
	if(len > 0)
	{
	    assert(!CORBA_is_nil(tc -> contentType_));

	    CORBA_TypeCode_var origContentType =
		OBGetOrigType(tc -> contentType_);
	    
	    switch(origContentType -> kind_)
	    {
	    case CORBA_tk_null:
	    case CORBA_tk_void:
		break;
		
	    case CORBA_tk_short:
	    case CORBA_tk_ushort:
	    {
		to += (unsigned long)to % 2;
		OBUnmarshalMulti((CORBA_UShort*)to, from, swap, len);
		to += len * 2;
		break;
	    }
	    
	    case CORBA_tk_long:
	    case CORBA_tk_ulong:
	    case CORBA_tk_float:
	    {
		to += 3;
		to -= (unsigned long)to % 4;
		OBUnmarshalMulti((CORBA_ULong*)to, from, swap, len);
		to += len * 4;
		break;
	    }
	    
	    case CORBA_tk_double:
	    {
		to += 7;
		to -= (unsigned long)to % 8;
		OBUnmarshalMulti((CORBA_Double*)to, from, swap, len);
		to += len * 8;
		break;
	    }
	    
	    case CORBA_tk_boolean:
	    case CORBA_tk_char:
	    case CORBA_tk_octet:
	    {
		OBUnmarshalMulti(to, from, swap, len);
		to += len;
		break;
	    }
	    
	    case CORBA_tk_alias:
		assert(false);
		break;
		
	    default:
		for(CORBA_ULong i = 0 ; i < len ; i++)
		    OBMarshalBuffer(tc -> contentType_, from, to, swap);
		break;
	    }
	}

	break;
    }

    case CORBA_tk_alias:
	OBMarshalBuffer(tc -> contentType_, from, to, swap);
	break;
    }
}

void
OBMarshalBufferCount(CORBA_TypeCode_ptr tc, const CORBA_Octet*& from,
		     CORBA_ULong& count, bool swap)
{
    switch(tc -> kind_)
    {
    case CORBA_tk_null:
    case CORBA_tk_void:
	break;
	
    case CORBA_tk_boolean:
    case CORBA_tk_char:
    case CORBA_tk_octet:
    {
	CORBA_Octet val;
	OBUnmarshal(val, from, swap);
	OBMarshalCount(val, count);
	break;
    }

    case CORBA_tk_short:
    case CORBA_tk_ushort:
    {
	CORBA_UShort val;
	OBUnmarshal(val, from, swap);
	OBMarshalCount(val, count);
	break;
    }
    
    case CORBA_tk_long:
    case CORBA_tk_ulong:
    case CORBA_tk_float:
    case CORBA_tk_enum:
    {
	CORBA_ULong val;
	OBUnmarshal(val, from, swap);
	OBMarshalCount(val, count);
	break;
    }
    
    case CORBA_tk_double:
    {
	CORBA_Double val;
	OBUnmarshal(val, from, swap);
	OBMarshalCount(val, count);
	break;
    }

    case CORBA_tk_any:
    {
	// Don't do this:
	//
	// CORBA_Any any;
	// OBUnmarshal(any, from, swap);
	// OBMarshalCount(any, count);
	//
	// This is faster:

	CORBA_TypeCode_var p;
	OBUnmarshal(p.inout(), from, swap);
	OBMarshalCount(p, count);
	OBMarshalBufferCount(p, from, count, swap);
	break;
    }
    
    case CORBA_tk_TypeCode:
    {
	// Don't do this:
	//
	// CORBA_TypeCode_var p;
	// OBUnmarshal(p.inout(), from, swap);
	// OBMarshalCount(p, count);
	//
	// This is faster:
	
	CORBA_TCKind kind;
	OBUnmarshal(kind, from, swap);
	OBMarshalCount(kind, count);
	
	if(kind == (CORBA_TCKind)0xffffffff)
	{
	    CORBA_Long octOffset;
	    OBUnmarshal(octOffset, from, swap);
	    OBMarshalCount(octOffset, count);
	}
	else
	{
	    switch(kind)
	    {
	    case CORBA_tk_null:
	    case CORBA_tk_void:
	    case CORBA_tk_short:
	    case CORBA_tk_long:
	    case CORBA_tk_ushort:
	    case CORBA_tk_ulong:
	    case CORBA_tk_float:
	    case CORBA_tk_double:
	    case CORBA_tk_boolean:
	    case CORBA_tk_char:
	    case CORBA_tk_octet:
	    case CORBA_tk_any:
	    case CORBA_tk_TypeCode:
	    case CORBA_tk_Principal:
		break;
		
	    case CORBA_tk_objref:
	    case CORBA_tk_struct:
	    case CORBA_tk_except:
	    case CORBA_tk_union:
	    case CORBA_tk_enum:
	    case CORBA_tk_sequence:
	    case CORBA_tk_array:
	    case CORBA_tk_alias:
	    {
		CORBA_ULong len;
		OBUnmarshal(len, from, swap);
		OBMarshalCount(len, count);
		from += len;
		count += len;
		break;
	    }
	    
	    case CORBA_tk_string:
	    {
		CORBA_ULong bound;
		OBUnmarshal(bound, from, swap);
		OBMarshalCount(bound, count);
		break;
	    }
	    }
	}
	
	break;
    }
    
    case CORBA_tk_Principal:
    {
	OBFixSeq<CORBA_Octet> seq;
	OBUnmarshal(seq, from, swap);
	OBMarshalCount(seq, count);
	break;
    }

    case CORBA_tk_objref:
    {
	// Don't do this:
	//
	// CORBA_Object_var p;
	// OBUnmarshal(p.inout(), from, swap);
	// OBMarshalCount(p, count);
	//
	// This is faster:

	IOP_IOR ior;
	OBUnmarshal(ior, from, swap);
	OBMarshalCount(ior, count);
	break;
    }
	
    case CORBA_tk_struct:
    {
	for(CORBA_ULong i = 0 ; i < tc -> memberTypes_.length() ; i++)
	    OBMarshalBufferCount(tc -> memberTypes_[i],
				 from, count, swap);
	
	break;
    }
	
    case CORBA_tk_except:
    {
	CORBA_String_var id;
	OBUnmarshal(id.inout(), from, swap);
	OBMarshalCount(id, count);

	for(CORBA_ULong i = 0 ; i < tc -> memberTypes_.length() ; i++)
	    OBMarshalBufferCount(tc -> memberTypes_[i],
				 from, count, swap);
	
	break;
    }

    case CORBA_tk_union:
    {
	CORBA_Long defaultIndex = tc -> default_index();
	CORBA_Long memberIndex = -1;
	
	CORBA_TypeCode_var discType = OBGetOrigType(tc -> discriminatorType_);

	switch(discType -> kind())
	{
	case CORBA_tk_short:
	{
	    CORBA_Short val;
	    OBUnmarshal(val, from, swap);
	    OBMarshalCount(val, count);
	    
	    CORBA_ULong i;
	    for(i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Short*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }
	    
	    break;
	}

	case CORBA_tk_ushort:
	{
	    CORBA_UShort val;
	    OBUnmarshal(val, from, swap);
	    OBMarshalCount(val, count);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_UShort*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_long:
	{
	    CORBA_Long val;
	    OBUnmarshal(val, from, swap);
	    OBMarshalCount(val, count);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Long*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_ulong:
	case CORBA_tk_enum:
	{
	    CORBA_ULong val;
	    OBUnmarshal(val, from, swap);
	    OBMarshalCount(val, count);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_ULong*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_char:
	{
	    CORBA_Char val;
	    OBUnmarshal(val, from, swap);
	    OBMarshalCount(val, count);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Char*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	case CORBA_tk_boolean:
	{
	    CORBA_Boolean val;
	    OBUnmarshal(val, from, swap);
	    OBMarshalCount(val, count);

	    for(CORBA_ULong i = 0 ; i < tc -> labels_.length() ; i++)
		if((CORBA_Long)i != defaultIndex)
		    if(val == *(CORBA_Boolean*)tc -> labels_[i].value())
		    {
			memberIndex = i;
			break;
		    }

	    break;
	}

	default:
	    assert(false);
	    break;
	}

	if(memberIndex >= 0)
	    OBMarshalBufferCount(tc -> memberTypes_[memberIndex],
				 from, count, swap);
	else if(defaultIndex >= 0)
	    OBMarshalBufferCount(tc -> memberTypes_[defaultIndex],
				 from, count, swap);

	break;
    }
	
    case CORBA_tk_string:
    {
	CORBA_String_var s;
	OBUnmarshal(s.inout(), from, swap);
	OBMarshalCount(s, count);
	break;
    }

    case CORBA_tk_sequence:
    case CORBA_tk_array:
    {
	CORBA_ULong len;

	if(tc -> kind_ == CORBA_tk_sequence)
	{
	    OBUnmarshal(len, from, swap);
	    OBMarshalCount(len, count);
	}
	else
	    len = tc -> length_;

	if(len > 0)
	{
	    assert(!CORBA_is_nil(tc -> contentType_));

	    CORBA_TypeCode_var origContentType =
		OBGetOrigType(tc -> contentType_);
	    
	    switch(origContentType -> kind_)
	    {
	    case CORBA_tk_null:
	    case CORBA_tk_void:
		break;
		
	    case CORBA_tk_short:
	    case CORBA_tk_ushort:
	    {
		from += (unsigned long)from % 2;
		from += len * 2;
		count += count % 2;
		count += len * 2;
		break;
	    }
	    
	    case CORBA_tk_long:
	    case CORBA_tk_ulong:
	    case CORBA_tk_float:
	    {
		from += 3;
		from -= (unsigned long)from % 4;
		from += len * 4;
		count += 3;
		count -= count % 4;
		count += len * 4;
		break;
	    }
	    
	    case CORBA_tk_double:
	    {
		from += 7;
		from -= (unsigned long)from % 8;
		from += len * 8;
		count += 7;
		count -= count % 8;
		count += len * 8;
		break;
	    }
	    
	    case CORBA_tk_boolean:
	    case CORBA_tk_char:
	    case CORBA_tk_octet:
	    {
		from += len;
		count += len;
		break;
	    }
	    
	    case CORBA_tk_alias:
		assert(false);
		break;
		
	    default:
		for(CORBA_ULong i = 0 ; i < len ; i++)
		    OBMarshalBufferCount(tc -> contentType_, from,
					 count, swap);
		break;
	    }
	}
	
	break;
    }

    case CORBA_tk_alias:
	OBMarshalBufferCount(tc -> contentType_, from, count, swap);
	break;
    }
}

void
OBMarshal(const OBObjSeq< CORBA_TypeCode >& seq, CORBA_Octet*& oct)
{
    OBMarshal(seq.length(), oct);
    for(CORBA_ULong i = 0 ; i < seq.length() ; i++)
        OBMarshal(seq[i], oct);
}

void
OBMarshalCount(const OBObjSeq< CORBA_TypeCode >& seq, CORBA_ULong& count)
{
    OBMarshalCount(seq.length(), count);
    for(CORBA_ULong i = 0 ; i < seq.length() ; i++)
        OBMarshalCount(seq[i], count);
}

void
OBUnmarshal(OBObjSeq< CORBA_TypeCode >& seq, const CORBA_Octet*& oct,
	    bool swap)
{
    CORBA_ULong len;
    OBUnmarshal(len, oct, swap);
    seq.length(len);
    for(CORBA_ULong i = 0 ; i < len ; i++)
        OBUnmarshal(seq[i].inout(), oct, swap);
}

// ----------------------------------------------------------------------
// Classes for CORBA__tc_<type> constant
// ----------------------------------------------------------------------

OBTypeCodeSimpleConst::OBTypeCodeSimpleConst(CORBA_TCKind k)
    : typeCode_(CORBA_TypeCode::_nil()), kind_(k)
{
    assert(kind_ == CORBA_tk_null ||
	   kind_ == CORBA_tk_void ||
	   kind_ == CORBA_tk_short ||
	   kind_ == CORBA_tk_long ||
	   kind_ == CORBA_tk_ushort ||
	   kind_ == CORBA_tk_ulong ||
	   kind_ == CORBA_tk_float ||
	   kind_ == CORBA_tk_double ||
	   kind_ == CORBA_tk_boolean ||
	   kind_ == CORBA_tk_char ||
	   kind_ == CORBA_tk_octet ||
	   kind_ == CORBA_tk_any ||
	   kind_ == CORBA_tk_TypeCode ||
	   kind_ == CORBA_tk_Principal);
};

OBTypeCodeSimpleConst::operator CORBA_TypeCode_ptr()
{
    if(CORBA_is_nil(typeCode_)) // Double checked locking
    {
	OB_SYNCHRONIZED
	    
	if(CORBA_is_nil(typeCode_))
	{
	    //
	    // We must construct the TypeCode in a temporary variable to
	    // avoid returning a partially constructed TypeCode.
	    //
	    CORBA_TypeCode_ptr tmp = new CORBA_TypeCode;
	    tmp -> kind_ = kind_;

	    typeCode_ = tmp;
	}
    }

    return typeCode_; // No _duplicate() here !
}

OBTypeCodeStringConst::OBTypeCodeStringConst()
    : typeCode_(CORBA_TypeCode::_nil())
{
};

OBTypeCodeStringConst::operator CORBA_TypeCode_ptr()
{
    if(CORBA_is_nil(typeCode_)) // Double checked locking
    {
	OB_SYNCHRONIZED
	
	if(CORBA_is_nil(typeCode_))
	{
	    //
	    // We must construct the TypeCode in a temporary variable to
	    // avoid returning a partially constructed TypeCode.
	    //
	    CORBA_TypeCode_ptr tmp = new CORBA_TypeCode;
	    tmp -> kind_ = CORBA_tk_string;
	    tmp -> length_ = 0;

	    typeCode_ = tmp;
	}
    }

    return typeCode_; // No _duplicate() here !
}

CORBA_TypeCode_ptr
OBTypeCodeStringConst::bounded(CORBA_ULong bound)
{
    CORBA_TypeCode_var tc = new CORBA_TypeCode;

    tc -> kind_ = CORBA_tk_string;
    tc -> length_ = bound;

    return tc._retn();
}

OBTypeCodeObjectConst::OBTypeCodeObjectConst()
    : typeCode_(CORBA_TypeCode::_nil())
{
};

OBTypeCodeObjectConst::operator CORBA_TypeCode_ptr()
{
    if(CORBA_is_nil(typeCode_)) // Double checked locking
    {
	OB_SYNCHRONIZED

	if(CORBA_is_nil(typeCode_))
	{
	    //
	    // We must construct the TypeCode in a temporary variable to
	    // avoid returning a partially constructed TypeCode.
	    //
	    CORBA_TypeCode_ptr tmp = new CORBA_TypeCode;
	    tmp -> kind_ = CORBA_tk_objref;
	    tmp -> id_ = CORBA_string_dup("IDL:omg.org/CORBA/Object:1.0");
	    tmp -> name_ = CORBA_string_dup("Object");

	    typeCode_ = tmp;
	}
    }

    return typeCode_; // No _duplicate() here !
}

OBTypeCodeSysExConst::OBTypeCodeSysExConst(const char* name)
    : name_(name)
{
};

OBTypeCodeSysExConst::operator CORBA_TypeCode_ptr()
{
    if(CORBA_is_nil(typeCode_)) // Double checked locking
    {
	OB_SYNCHRONIZED

	if(CORBA_is_nil(typeCode_))
	{
	    //
	    // We must construct the TypeCode in a temporary variable to
	    // avoid returning a partially constructed TypeCode.
	    //
	    CORBA_TypeCode_ptr tmp = new CORBA_TypeCode;
	    tmp -> kind_ = CORBA_tk_except;
	    tmp -> id_ = CORBA_string_dup("IDL:omg.org/CORBA/");
	    tmp -> id_ += name_;
	    tmp -> id_ += ":1.0";
	    tmp -> name_ = CORBA_string_dup(name_);
	    tmp -> memberNames_.length(2);
	    tmp -> memberNames_[0] = CORBA_string_dup("minor");
	    tmp -> memberNames_[1] = CORBA_string_dup("completed");
	    tmp -> memberTypes_.length(2);
	    tmp -> memberTypes_[0] =
		CORBA_TypeCode::_duplicate(CORBA__tc_ulong);
	    CORBA_TypeCode_var et = new CORBA_TypeCode;
	    et -> kind_ = CORBA_tk_enum;
	    et -> id_ =
		CORBA_string_dup("IDL:omg.org/CORBA/CompletionStatus:1.0");
	    et -> name_ = CORBA_string_dup("CompletionStatus");
	    et -> memberNames_.length(3);
	    et -> memberNames_[0] = CORBA_string_dup("COMPLETED_YES");
	    et -> memberNames_[1] = CORBA_string_dup("COMPLETED_NO");
	    et -> memberNames_[2] = CORBA_string_dup("COMPLETED_MAYBE");
	    tmp -> memberTypes_[1] = et;

	    typeCode_ = tmp;
	}
    }

    return typeCode_; // No _duplicate() here !
}

OBTypeCodeConst::operator CORBA_TypeCode_ptr()
{
    if(CORBA_is_nil(typeCode_)) // Double checked locking
    {
	OB_SYNCHRONIZED

	if(CORBA_is_nil(typeCode_))
	{
	    //
	    // We must construct the TypeCode in a temporary variable to
	    // avoid returning a partially constructed TypeCode.
	    //
	    assert(str_ != 0);
	    CORBA_Octet* oct = OBAsciiToOctets(str_);
	    const CORBA_Octet* from = oct;
	    CORBA_Boolean endian;
	    OBUnmarshal(endian, from, false);

	    CORBA_TypeCode_ptr tmp = CORBA_TypeCode::_nil();
	    OBUnmarshal(tmp, from, endian != OBEndian);
	    delete [] oct;

	    typeCode_ = tmp;
	}
    }
    
    return typeCode_; // No _duplicate() here !
}

OBTypeCodeSimpleConst CORBA__tc_null(CORBA_tk_null);
OBTypeCodeSimpleConst CORBA__tc_void(CORBA_tk_void);
OBTypeCodeSimpleConst CORBA__tc_short(CORBA_tk_short);
OBTypeCodeSimpleConst CORBA__tc_long(CORBA_tk_long);
OBTypeCodeSimpleConst CORBA__tc_ushort(CORBA_tk_ushort);
OBTypeCodeSimpleConst CORBA__tc_ulong(CORBA_tk_ulong);
OBTypeCodeSimpleConst CORBA__tc_float(CORBA_tk_float);
OBTypeCodeSimpleConst CORBA__tc_double(CORBA_tk_double);
OBTypeCodeSimpleConst CORBA__tc_boolean(CORBA_tk_boolean);
OBTypeCodeSimpleConst CORBA__tc_char(CORBA_tk_char);
OBTypeCodeSimpleConst CORBA__tc_octet(CORBA_tk_octet);
OBTypeCodeSimpleConst CORBA__tc_any(CORBA_tk_any);
OBTypeCodeSimpleConst CORBA__tc_TypeCode(CORBA_tk_TypeCode);
OBTypeCodeSimpleConst CORBA__tc_Principal(CORBA_tk_Principal);

OBTypeCodeStringConst CORBA__tc_string;

OBTypeCodeObjectConst CORBA__tc_Object;

OBTypeCodeSysExConst CORBA__tc_UNKNOWN("UNKNOWN");
OBTypeCodeSysExConst CORBA__tc_BAD_PARAM("BAD_PARAM");
OBTypeCodeSysExConst CORBA__tc_NO_MEMORY("NO_MEMORY");
OBTypeCodeSysExConst CORBA__tc_IMP_LIMIT("IMP_LIMIT");
OBTypeCodeSysExConst CORBA__tc_COMM_FAILURE("COMM_FAILURE");
OBTypeCodeSysExConst CORBA__tc_INV_OBJREF("INV_OBJREF");
OBTypeCodeSysExConst CORBA__tc_NO_PERMISSION("NO_PERMISSION");
OBTypeCodeSysExConst CORBA__tc_INTERNAL("INTERNAL");
OBTypeCodeSysExConst CORBA__tc_MARSHAL("MARSHAL");
OBTypeCodeSysExConst CORBA__tc_INITIALIZE("INITIALIZE");
OBTypeCodeSysExConst CORBA__tc_NO_IMPLEMENT("NO_IMPLEMENT");
OBTypeCodeSysExConst CORBA__tc_BAD_TYPECODE("BAD_TYPECODE");
OBTypeCodeSysExConst CORBA__tc_BAD_OPERATION("BAD_OPERATION");
OBTypeCodeSysExConst CORBA__tc_NO_RESOURCES("NO_RESOURCES");
OBTypeCodeSysExConst CORBA__tc_NO_RESPONSE("NO_RESPONSE");
OBTypeCodeSysExConst CORBA__tc_PERSIST_STORE("PERSIST_STORE");
OBTypeCodeSysExConst CORBA__tc_BAD_INV_ORDER("BAD_INV_ORDER");
OBTypeCodeSysExConst CORBA__tc_TRANSIENT("TRANSIENT");
OBTypeCodeSysExConst CORBA__tc_FREE_MEM("FREE_MEM");
OBTypeCodeSysExConst CORBA__tc_INV_IDENT("INV_IDENT");
OBTypeCodeSysExConst CORBA__tc_INV_FLAG("INV_FLAG");
OBTypeCodeSysExConst CORBA__tc_INTF_REPOS("INTF_REPOS");
OBTypeCodeSysExConst CORBA__tc_BAD_CONTEXT("BAD_CONTEXT");
OBTypeCodeSysExConst CORBA__tc_OBJ_ADAPTER("OBJ_ADAPTER");
OBTypeCodeSysExConst CORBA__tc_DATA_CONVERSION("DATA_CONVERSION");
OBTypeCodeSysExConst CORBA__tc_OBJECT_NOT_EXIST("OBJECT_NOT_EXIST");
OBTypeCodeSysExConst CORBA__tc_TRANSACTION_REQUIRED("TRANSACTION_REQUIRED");
OBTypeCodeSysExConst
    CORBA__tc_TRANSACTION_ROLLEDBACK("TRANSACTION_ROLLEDBACK");
OBTypeCodeSysExConst CORBA__tc_INVALID_TRANSACTION("INVALID_TRANSACTION");
OBTypeCodeSysExConst CORBA__tc_INV_POLICY("INV_POLICY");

// ----------------------------------------------------------------------
// Get original type, i.e. remove aliases
// ----------------------------------------------------------------------

CORBA_TypeCode_ptr
OBGetOrigType(CORBA_TypeCode_ptr p)
{
    CORBA_TypeCode_var tc = CORBA_TypeCode::_duplicate(p);

    while(tc -> kind() == CORBA_tk_alias)
	tc = tc -> content_type();

    return tc._retn();
}

// ----------------------------------------------------------------------
// Fill in recursive type codes
// ----------------------------------------------------------------------

bool
OBFillRec(CORBA_TypeCode_ptr& inner, CORBA_TypeCode_ptr outer,
	  CORBA_ULong offset)
{
    //
    // Check for recursive sequence type code with same offset
    //
    if(inner -> kind_ == CORBA_tk_sequence &&
       inner -> offset_ > 0 && inner -> offset_ == offset)
    {
	CORBA_TypeCode_ptr p = new CORBA_TypeCode;
	
	p -> kind_ = CORBA_tk_sequence;
	p -> length_ = inner -> length_;
	p -> offset_ = inner -> offset_;

	p -> contentType_ = CORBA_TypeCode::_duplicate(outer);
	outer -> cyclicTypes_.append(p); // No duplicate!
	p -> cyclicTypes_.append(outer); // No duplicate!

	CORBA_release(inner);
	inner = p;

	return true;
    }

    //
    // Check for non-recursive sequences, arrays and aliases
    //
    if((inner -> kind_ == CORBA_tk_sequence && inner -> offset_ == 0) ||
       inner -> kind_ == CORBA_tk_array ||
       inner -> kind_ == CORBA_tk_alias)
    {
	CORBA_TypeCode_var contentType = inner -> contentType_;
	
	if(OBFillRec(contentType.inout(), outer, offset + 1))
	{
	    CORBA_TypeCode_ptr p = new CORBA_TypeCode;

	    p -> kind_ = inner -> kind_;

	    if(inner -> kind_ == CORBA_tk_alias)
	    {
		p -> id_ = inner -> id_;
		p -> name_ = inner -> name_;
	    }
	    else
	    {
		p -> length_ = inner -> length_;

		if(inner -> kind_ == CORBA_tk_sequence)
		    p -> offset_ = inner -> offset_;
	    }
		
	    p -> contentType_ = contentType;

	    CORBA_release(inner);
	    inner = p;

	    return true;
	}
    }

    //
    // Check for structs, unions and exceptions
    //
    if(inner -> kind_ == CORBA_tk_struct ||
       inner -> kind_ == CORBA_tk_union ||
       inner -> kind_ == CORBA_tk_except)
    {
	OBObjSeq<CORBA_TypeCode> memberTypes = inner -> memberTypes_;
	
	bool changed = false;
	for(CORBA_ULong i = 0 ; i < memberTypes.length() ; i++)
	{
	    if(OBFillRec(memberTypes[i].inout(), outer, offset + 1))
		changed = true;
	}

	if(changed)
	{
	    CORBA_TypeCode_ptr p = new CORBA_TypeCode;

	    p -> kind_ = inner -> kind_;
	    p -> id_ = inner -> id_;
	    p -> name_ = inner -> name_;
	    p -> memberNames_ = inner -> memberNames_;

	    if(inner -> kind_ == CORBA_tk_union)
	    {
		p -> labels_ = inner -> labels_;
		p -> discriminatorType_ = inner -> discriminatorType_;
	    }

	    p -> memberTypes_ = memberTypes;

	    CORBA_release(inner);
	    inner = p;

	    return true;
	}
    }

    return false;
}
