// **********************************************************************
//
// Copyright (c) 2002
// IONA Technologies, Inc.
// Waltham, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_BASIC_H
#define OB_BASIC_H

//
// Apart from OB/Config.h, this file might not include any other
// ORBacus header files.
//

//
// Configuration stuff
//
#include <OB/Config.h>

//
// Include JThreads/C++ library
//
#include <JTC/JTC.h>

//
// DLL support (for building up to 4 linked DLLs)
//
#ifdef OB_DLL
#   if !defined(JTC_DLL)
#       error "Building ORBacus as a DLL requires JTC was build as a DLL"
#   endif
#   ifdef OB_BUILD_DLL
#       define OB_IMPORT /**/
#   else
#       define OB_IMPORT __declspec(dllimport)
#   endif
#else
#   define OB_IMPORT  /**/
#endif

//
// Only Visual C++ 6.0 and greater is supported.
//
#ifdef _MSC_VER
#   if _MSC_VER < 1200
#       error VC++ 6.0 or newer is required
#   endif
#endif

//
// Force user32, advapi32.lib and wsock32.lib to always be linked
//
#ifdef _MSC_VER
#   pragma comment(lib, "user32.lib")
#   pragma comment(lib, "advapi32.lib")
#   pragma comment(lib, "wsock32.lib")
#endif

//
// The ORBacus version, as string and as integer
//
// Format of OB_INTEGER_VERSION: ABBCCDD
//
// For regular releases (that is non-beta and non-alpha), A is the
// major version, BB the minor version, CC the patchlevel version, and
// DD is 00. Examples:
//
//                      ABBCCDD
// Version 3.2          3020000L
// Version 3.2.4        3020400L
// Version 4.0          4000000L
// Version 4.0.1        4000100L
//
// For alpha and beta releases, 1 must be substracted from ABBCC. For
// alpha releases, DD is then the alpha release number. For beta
// releases, DD is the beta release number plus 50. Examples:
//
//                         ABBCCDD
// Version 3.2a1           3019901L
// Version 3.2.4b2         3020352L
// Version 4.0b1           3999951L
// Version 4.0.1a1         4000001L
//
#define OB_VERSION "4.1.3"
#define OB_INTEGER_VERSION 4010300L

namespace OB
{

OB_IMPORT extern const char* Version;
OB_IMPORT extern unsigned long IntegerVersion;

}

//
// This is for GNU C++ < 2.95
//
#ifdef __GNUC__ 
#   if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
#       error GNU C++ older than version 2.95 is not supported anymore!
#   endif
#endif

//
// This is for GNU C++ 2.95.x and later
//
#ifdef __GNUC__ 
#   if (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) || __GNUC__ >= 3
//
// Workaround for *very* annoying warning messages like:
//
// "choosing `CORBA_String_var::operator char *&()' over
// `CORBA_String_var::operator const char *() const' for conversion
// from `CORBA_String_var' to `const char *' because conversion
// sequence for the argument is better"
//
#       define HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
#   endif
#endif

//
// This is for HP aCC
//
#if defined(__hpux)
//
// The definition of "alloca" as "malloc" is necessary since aCC has
// no builtin alloca() and there is also no library that includes an
// alloca() function. Normally substituting alloca() as malloc()
// results in huge memory leaks. However, ORBacus needs alloca() for
// the IDL-to-C++ translator only (for the file idl/Gram.cpp). Since
// the translator terminates and releases all resources immediately
// after doing its job, the leak doesn't matter that much. (Hopefully
// new versions of aCC will have builtin alloca() support or supply a
// library which contains alloca().)
//
#   define alloca(x) malloc(x)
#endif

//
// Define mutable keyword as empty if mutable is not supported
//
#ifdef HAVE_NO_MUTABLE
#   define mutable /**/
#endif

//
// Include common header files
//
#include <string.h>
#include <assert.h>
#include <stdlib.h>

#ifdef HAVE_SYS_TYPES_H
#   include <sys/types.h>
#endif

#ifdef HAVE_SYS_TIME_H
#   include <sys/time.h>
#endif

#ifdef HAVE_IOSTREAM
#   include <iostream>
#else
#   include <iostream.h>
#endif

//
// Some Unix flavors unfortunately define these as macros
//
#undef major
#undef minor

//
// In case we have the std:: namespace
//
#ifdef HAVE_STD_IOSTREAM
#   define OB_STD(x) std::x
#   define OB_IFSTREAM std::ifstream
#   define OB_OFSTREAM std::ofstream
#   define OB_CIN std::cin
#   define OB_COUT std::cout
#   define OB_CERR std::cerr
#   define OB_FLUSH std::flush
#   define OB_ENDL std::endl
#   define OB_INFO(x) ( std::cout << x << std::flush )
#   define OB_INFO_LN(x) ( std::cout << x << std::endl )
#   define OB_ERROR(x) ( std::cerr << x << std::endl )
#else
#   define OB_STD(x) x
#   define OB_IFSTREAM ifstream
#   define OB_OFSTREAM ofstream
#   define OB_CIN cin
#   define OB_COUT cout
#   define OB_CERR cerr
#   define OB_FLUSH flush
#   define OB_ENDL endl
#   define OB_INFO(x) ( cout << x << flush )
#   define OB_INFO_LN(x) ( cout << x << endl )
#   define OB_ERROR(x) ( cerr << x << endl )
#endif

//
// Suppress warnings from newer compilers that offer reinterpret_cast
//
#ifdef HAVE_NEW_CASTS
#   define OB_REINTERPRET_CAST(t,v) reinterpret_cast<t>(v)
#else
#   define OB_REINTERPRET_CAST(t,v) (t)(v)
#endif

namespace OB
{

//
// Assert macro for "non-compliant application"
//
enum NCAReason
{
    NCANotImpl,         // Not implemented yet
    NCADeprecated,      // Deprecated feature

    NCAWrongAlloc,      // Memory was not allocated with Alloc()
    NCADoubleFree,      // Memory was already freed by Free()

    NCARefCountNotZero, // Object deleted without a reference count of zero
    NCARefCountZero,    // Object already deleted (reference count is zero)

    NCASeqLenGrMax,     // Sequence length greater than maximum length
    NCASeqRange,        // Out of range error in sequence operator[]()
                        // or remove()
    NCASeqBound,        // Violation of sequence bound  

    NCANullInit,        // Initialization of T_var type with null pointer
    NCANullPtr,         // operator->() used on null pointer or nil reference
    NCANullDeref,       // Null pointer dereferencing
    NCANullString,      // Null pointer passed as string
    NCANullValue,       // Null value passed as argument

    NCASelfAssign,      // Self assignment causing a dangling pointer

    NCAAnySelfReplace,  // Any content was replaced by its own value

    NCADiscType,        // Wrong union discriminator type
    NCADiscMismatch,    // Union discriminator mismatch
    NCAUnionInit,       // Uninitialized union used

    NCANoExceptionTC,   // CORBA_Any::operator<<=(Exception*) used for an
                        // exception for which not TypeCode is available

    NCAUnembeddedRecTC, // An operation on an unembedded recursive
                        // TypeCode was invoked
    NCAEmbeddedRecTC,   // An already embedded TypeCode was reused

    NCANoLongDouble     // LongDouble type is not supported on this platform
};

void NCA(NCAReason, const char*, const char*, unsigned int);

#ifdef NDEBUG
 
#    define assert_nca(ex, reason) ((void)0)
 
#else

#    define assert_nca(ex, reason) \
( (int)(ex) ? (void)0 : (OB::NCA(reason, #ex, __FILE__, __LINE__), abort()) )

#   define OB_TRACE 1 // By default if NDEBUG is not defined we will trace
    
#endif

//
// Wide string helper functions, platform independent
//
size_t wcslen(const wchar_t*);
wchar_t* wcscpy(wchar_t*, const wchar_t*);
wchar_t* wcsncpy(wchar_t*, const wchar_t*, size_t);
wchar_t* wcscat(wchar_t*, const wchar_t*);
int wcscmp(const wchar_t*, const wchar_t*);
wchar_t* wcschr(const wchar_t*, const wchar_t);

//
// Forward declarations needed by String_var
//
class StrForStruct;
class StrForSeq;

//
// Forward declarations needed for WString_var
//
class WStrForStruct;
class WStrForSeq;

//
// Special "singleton" values for empty strings
// Note: These value must not be const! 
//
OB_IMPORT extern char* EmptyString;
OB_IMPORT extern wchar_t* EmptyWString;

} // End of namespace OB

namespace CORBA
{

//
// Basic types
//
#if SIZEOF_BOOL == 1
typedef bool Boolean;
#else
typedef unsigned char Boolean;
#endif

#if SIZEOF_CHAR == 1
typedef char Char;
typedef unsigned char Octet;
#else
#   error SIZEOF_CHAR must be 1!
#endif

#if SIZEOF_WCHAR_T != 0
typedef wchar_t WChar;
#else
#   error SIZEOF_WCHAR_T must not be 0!
#endif

#if SIZEOF_SHORT == 2
typedef signed short Short;
typedef unsigned short UShort;
#else
#if SIZEOF_INT == 2
typedef signed int Short;
typedef unsigned int UShort;
#else
#   error Neither SIZEOF_SHORT nor SIZEOF_INT is 2!
#endif
#endif

#if SIZEOF_LONG == 4
typedef signed long Long;
typedef unsigned long ULong;
#else
#if SIZEOF_INT == 4
typedef signed int Long;
typedef unsigned int ULong;
#else
#   error Neither SIZEOF_LONG nor SIZEOF_INT is 4!
#endif
#endif

#if SIZEOF_LONG_LONG == 8
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
typedef long long LongLong;
typedef unsigned long long ULongLong;
#else
typedef __int64 LongLong;
typedef unsigned __int64 ULongLong;
#endif
#else
#   error SIZEOF_LONG_LONG must be 8!
#endif

#if !defined(_MSC_VER) && !defined(__BORLANDC__)
#ifdef __hpux
#   define OB_LONGLONG(x) CORBA::LongLong(x)
#   define OB_ULONGLONG(x) CORBA::ULongLong(x)
#else
#   define OB_LONGLONG(x) CORBA::LongLong(x##ULL)
#   define OB_ULONGLONG(x) CORBA::ULongLong(x##ULL)
#endif
#else
#   define OB_LONGLONG(x) CORBA::LongLong(x##i64)
#   define OB_ULONGLONG(x) CORBA::ULongLong(x##i64)
#endif

#if SIZEOF_FLOAT == 4
typedef float Float;
#else
#   error SIZEOF_FLOAT must be 4!
#endif

#if SIZEOF_DOUBLE == 8
typedef double Double;
#else
#   error SIZEOF_DOUBLE must be 8!
#endif

#if SIZEOF_LONG_DOUBLE >= 12
typedef long double LongDouble;
#else
class LongDouble { };
#endif

//
// Define _out versions of the basic types
//
typedef Short& Short_out;
typedef Long& Long_out;
typedef LongLong& LongLong_out;
typedef ULongLong& ULongLong_out;
typedef UShort& UShort_out;
typedef ULong& ULong_out;
typedef Float& Float_out;
typedef Double& Double_out;
typedef LongDouble& LongDouble_out;
typedef Char& Char_out;
typedef WChar& WChar_out;
typedef Boolean& Boolean_out;
typedef Octet& Octet_out;

//
// CORBA::Flags
//
typedef ULong Flags;
const Flags ARG_IN = 1;
const Flags ARG_OUT = 2;
const Flags ARG_INOUT = 3;
const Flags OUT_LIST_MEMORY = 4;
const Flags IN_COPY_VALUE = 5;
const Flags CTX_RESTRICT_SCOPE = 6;

//
// String memory management
//
// - string_alloc/wstring_alloc:
//   Allocates new string (terminating '\0' must not be included in
//   the length argument)
//
// - string_free/wstring_free:
//   Frees a string allocated with string_alloc
//
// - string_dup/wstring_dup:
//   Duplicates a string using the functions string_alloc
//
char* string_alloc(ULong);
wchar_t* wstring_alloc(ULong);

void string_free(char*);
void wstring_free(wchar_t*);

char* string_dup(const char*);
wchar_t* wstring_dup(const wchar_t*);

//
// The String_var class
//
class String_var
{
protected:

    char* ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    String_var() : ptr_(0) { }
    String_var(char*);
    String_var(const char* p) : ptr_(string_dup(p)) { }
    String_var(const String_var&);
    String_var(const OB::StrForSeq&);
    String_var(const OB::StrForStruct&);
    ~String_var() { string_free(ptr_); }
    
    String_var& operator=(char*);
    String_var& operator=(const char*);
    String_var& operator=(const String_var&);
    String_var& operator=(const OB::StrForStruct&);
    String_var& operator=(const OB::StrForSeq&);

    char& operator[](short idx) { return ptr_[idx]; }
    char operator[](short idx) const { return ptr_[idx]; }
    char& operator[](unsigned short idx) { return ptr_[idx]; }
    char operator[](unsigned short idx) const { return ptr_[idx]; }
    char& operator[](int idx) { return ptr_[idx]; }
    char operator[](int idx) const { return ptr_[idx]; }
    char& operator[](unsigned int idx) { return ptr_[idx]; }
    char operator[](unsigned int idx) const { return ptr_[idx]; }
    char& operator[](long idx) { return ptr_[idx]; }
    char operator[](long idx) const { return ptr_[idx]; }
    char& operator[](unsigned long idx) { return ptr_[idx]; }
    char operator[](unsigned long idx) const { return ptr_[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const char*() const { return ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator char*&() const { return (char*&)ptr_; }
#   else
    operator const char*() const { return ptr_; }
    operator char*&() { return ptr_; }
#   endif
#endif

    const char* in() const { return ptr_; }
    char*& inout() { return ptr_; }
    char*& out();
    char* _retn();

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    char*& ptr() { return ptr_; }

    //
    // Additional ORBacus specific functions
    //
    String_var& operator+=(const char*);
    String_var& operator+=(char);
    String_var& operator+=(unsigned char);

    String_var& operator+=(LongLong);
    String_var& operator+=(ULongLong);

    String_var& operator+=(long n)
    { return operator+=((LongLong)n); }
    String_var& operator+=(unsigned long n)
    { return operator+=((ULongLong)n); }

    String_var& operator+=(short n)
    { return operator+=((LongLong)n); }
    String_var& operator+=(unsigned short n)
    { return operator+=((ULongLong)n); }

    String_var& operator+=(int n)
    { return operator+=((LongLong)n); }
    String_var& operator+=(unsigned int n)
    { return operator+=((ULongLong)n); }

    //
    // The class String_out needs access to the internals of String_var
    //
    friend class String_out;
};

class String_out; // NEEDED FOR VISUALAGE 5.0

} // End of namespace CORBA


namespace OB
{

//
// String type used by structs, exceptions and arrays
//
class StrForStruct : public CORBA::String_var
{
public:

    //
    // Standard IDL to C++ Mapping
    //
    StrForStruct() : CORBA::String_var(OB::EmptyString) { }
    StrForStruct(char* p) : CORBA::String_var(p) { }
    StrForStruct(const char* p) : CORBA::String_var(p) { }
    StrForStruct(const StrForStruct& r) : CORBA::String_var(r) { }
    StrForStruct(const StrForSeq& r) : CORBA::String_var(r) { }

#ifdef _MSC_VER
    StrForStruct& operator=(char* p)
    { String_var::operator=(p); return *this; }
    StrForStruct& operator=(const char* p)
    { String_var::operator=(p); return *this; }
    StrForStruct& operator=(const CORBA::String_var& r)
    { String_var::operator=(r); return *this; }
    StrForStruct& operator=(const StrForStruct& r)
    { String_var::operator=(r); return *this; }
    StrForStruct& operator=(const StrForSeq& r)
    { String_var::operator=(r); return *this; }
#else
    StrForStruct& operator=(char* p)
    { CORBA::String_var::operator=(p); return *this; }
    StrForStruct& operator=(const char* p)
    { CORBA::String_var::operator=(p); return *this; }
    StrForStruct& operator=(const CORBA::String_var& r)
    { CORBA::String_var::operator=(r); return *this; }
    StrForStruct& operator=(const StrForStruct& r)
    { CORBA::String_var::operator=(r); return *this; }
    StrForStruct& operator=(const StrForSeq& r)
    { CORBA::String_var::operator=(r); return *this; }
#endif
};

//
// String type used by string sequences
//
class StrForSeq
{	
    char** ptr_;
    CORBA::Boolean rel_;
    
public:

    //
    // ORBacus specific constructors that work together with the
    // string sequence
    //
    StrForSeq(char** p, CORBA::Boolean rel) : ptr_(p), rel_(rel) { }
    StrForSeq(const StrForSeq& r) : ptr_(r.ptr_), rel_(r.rel_) { }
    
    //
    // Standard IDL to C++ Mapping
    //
    StrForSeq& operator=(char*);
    StrForSeq& operator=(const char*);
    StrForSeq& operator=(const CORBA::String_var&);
    StrForSeq& operator=(const StrForStruct&);
    StrForSeq& operator=(const StrForSeq&);
    
    char& operator[](short idx) { return (*ptr_)[idx]; }
    char operator[](short idx) const { return (*ptr_)[idx]; }
    char& operator[](unsigned short idx) { return (*ptr_)[idx]; }
    char operator[](unsigned short idx) const { return (*ptr_)[idx]; }
    char& operator[](int idx) { return (*ptr_)[idx]; }
    char operator[](int idx) const { return (*ptr_)[idx]; }
    char& operator[](unsigned int idx) { return (*ptr_)[idx]; }
    char operator[](unsigned int idx) const { return (*ptr_)[idx]; }
    char& operator[](long idx) { return (*ptr_)[idx]; }
    char operator[](long idx) const { return (*ptr_)[idx]; }
    char& operator[](unsigned long idx) { return (*ptr_)[idx]; }
    char operator[](unsigned long idx) const { return (*ptr_)[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const char*() const { return *ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator char*&() const { return (char*&)*ptr_; }
#   else
    operator const char*() const { return *ptr_; }
    operator char*&() { return *ptr_; }
#   endif
#endif

    const char* in() const { return *ptr_; }
    char*& inout() { return *ptr_; }
    char*& out();
    char* _retn();

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    char*& ptr() { return *ptr_; }

    //
    // The class String_out needs access to the internals of StrForSeq
    //
    friend class CORBA::String_out;
};

} // End of namespace OB


namespace CORBA
{

//
// The String_out class
//
class String_out
{
    // Assignment from String_var and OB::StrForSeq disallowed
    void operator=(const String_var&);
    void operator=(const OB::StrForSeq&);

    char*& ptr_;

public:

    String_out(char*& p)
        : ptr_(p)
    {
	ptr_ = 0;
    }
    
    String_out(String_var& p)
        : ptr_(p.ptr_)
    {
        string_free(ptr_);
        ptr_ = 0;
    }
    
    String_out(OB::StrForSeq& p)
        : ptr_(*p.ptr_)
    {
        string_free(ptr_);
        ptr_ = 0;
    }
    
    String_out(const String_out& p)
        : ptr_(p.ptr_)
    {
    }
    
    String_out& operator=(const String_out& p)
    {
        ptr_ = p.ptr_;
        return *this;
    }
    
    String_out& operator=(char* p)
    {
        ptr_ = p;
        return *this;
    }
    
    String_out& operator=(const char* p)
    {
        ptr_ = string_dup(p);
        return *this;
    }
    
    char& operator[](short idx) { return ptr_[idx]; }
    char& operator[](unsigned short idx) { return ptr_[idx]; }
    char& operator[](int idx) { return ptr_[idx]; }
    char& operator[](unsigned int idx) { return ptr_[idx]; }
    char& operator[](long idx) { return ptr_[idx]; }
    char& operator[](unsigned long idx) { return ptr_[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const char*() { return ptr_; }
#else
    operator char*&() { return ptr_; }
#endif

    char*& ptr() { return ptr_; }
};

//
// The WString_var class
//
class WString_var
{
protected:

    wchar_t* ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    WString_var() : ptr_(0) { }
    WString_var(wchar_t*);
    WString_var(const wchar_t* p) : ptr_(wstring_dup(p)) { }
    WString_var(const WString_var&);
    WString_var(const OB::WStrForSeq&);
    WString_var(const OB::WStrForStruct&);
    ~WString_var() { wstring_free(ptr_); }
    
    WString_var& operator=(wchar_t*);
    WString_var& operator=(const wchar_t*);
    WString_var& operator=(const WString_var&);
    WString_var& operator=(const OB::WStrForStruct&);
    WString_var& operator=(const OB::WStrForSeq&);

    wchar_t& operator[](short idx) { return ptr_[idx]; }
    wchar_t operator[](short idx) const { return ptr_[idx]; }
    wchar_t& operator[](unsigned short idx) { return ptr_[idx]; }
    wchar_t operator[](unsigned short idx) const { return ptr_[idx]; }
    wchar_t& operator[](int idx) { return ptr_[idx]; }
    wchar_t operator[](int idx) const { return ptr_[idx]; }
    wchar_t& operator[](unsigned int idx) { return ptr_[idx]; }
    wchar_t operator[](unsigned int idx) const { return ptr_[idx]; }
    wchar_t& operator[](long idx) { return ptr_[idx]; }
    wchar_t operator[](long idx) const { return ptr_[idx]; }
    wchar_t& operator[](unsigned long idx) { return ptr_[idx]; }
    wchar_t operator[](unsigned long idx) const { return ptr_[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const wchar_t*() const { return ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator wchar_t*&() const { return (wchar_t*&)ptr_; }
#   else
    operator const wchar_t*() const { return ptr_; }
    operator wchar_t*&() { return ptr_; }
#   endif
#endif

    const wchar_t* in() const { return ptr_; }
    wchar_t*& inout() { return ptr_; }
    wchar_t*& out();
    wchar_t* _retn();

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    wchar_t*& ptr() { return ptr_; }

    //
    // Additional ORBacus specific functions
    //
    WString_var& operator+=(const wchar_t*);
    WString_var& operator+=(wchar_t);
    WString_var& operator+=(const char*);
    WString_var& operator+=(char);

    WString_var& operator+=(LongLong);
    WString_var& operator+=(ULongLong);

    WString_var& operator+=(long n)
    { return operator+=((LongLong)n); }
    WString_var& operator+=(unsigned long n)
    { return operator+=((ULongLong)n); }

    WString_var& operator+=(short n)
    { return operator+=((LongLong)n); }
#ifndef HAVE_WIN32_WCHAR_TYPE
    WString_var& operator+=(unsigned short n)
    { return operator+=((ULongLong)n); }
#endif

    WString_var& operator+=(int n)
    { return operator+=((LongLong)n); }
    WString_var& operator+=(unsigned int n)
    { return operator+=((ULongLong)n); }

    //
    // The class WString_out needs access to the internals of WString_var
    //
    friend class WString_out;
};

class WString_out; // NEEDED FOR VISUALAGE 5.0

} // End of namespace CORBA


namespace OB
{

//
// WString type used by structs, exceptions and arrays
//
class WStrForStruct : public CORBA::WString_var
{
public:

    //
    // Standard IDL to C++ Mapping
    //
    WStrForStruct() : CORBA::WString_var(OB::EmptyWString) { }
    WStrForStruct(wchar_t* p) : CORBA::WString_var(p) { }
    WStrForStruct(const wchar_t* p) : CORBA::WString_var(p) { }
    WStrForStruct(const WStrForStruct& r) : CORBA::WString_var(r) { }
    WStrForStruct(const WStrForSeq& r) : CORBA::WString_var(r) { }

#ifdef _MSC_VER
    WStrForStruct& operator=(wchar_t* p)
    { WString_var::operator=(p); return *this; }
    WStrForStruct& operator=(const wchar_t* p)
    { WString_var::operator=(p); return *this; }
    WStrForStruct& operator=(const CORBA::WString_var& r)
    { WString_var::operator=(r); return *this; }
    WStrForStruct& operator=(const WStrForStruct& r)
    { WString_var::operator=(r); return *this; }
    WStrForStruct& operator=(const WStrForSeq& r)
    { WString_var::operator=(r); return *this; }
#else
    WStrForStruct& operator=(wchar_t* p)
    { CORBA::WString_var::operator=(p); return *this; }
    WStrForStruct& operator=(const wchar_t* p)
    { CORBA::WString_var::operator=(p); return *this; }
    WStrForStruct& operator=(const CORBA::WString_var& r)
    { CORBA::WString_var::operator=(r); return *this; }
    WStrForStruct& operator=(const WStrForStruct& r)
    { CORBA::WString_var::operator=(r); return *this; }
    WStrForStruct& operator=(const WStrForSeq& r)
    { CORBA::WString_var::operator=(r); return *this; }
#endif
};

//
// String type used by wstring sequences
//
class WStrForSeq
{	
    wchar_t** ptr_;
    CORBA::Boolean rel_;
    
public:

    //
    // ORBacus specific constructor that works together with
    // the corresponding sequence type
    //
    WStrForSeq(wchar_t** p, CORBA::Boolean rel) : ptr_(p), rel_(rel) { }
    WStrForSeq(const WStrForSeq& r) : ptr_(r.ptr_), rel_(r.rel_) { }
    
    //
    // Standard IDL to C++ Mapping
    //
    WStrForSeq& operator=(wchar_t*);
    WStrForSeq& operator=(const wchar_t*);
    WStrForSeq& operator=(const CORBA::WString_var&);
    WStrForSeq& operator=(const WStrForStruct&);
    WStrForSeq& operator=(const WStrForSeq&);
    
    wchar_t& operator[](short idx) { return (*ptr_)[idx]; }
    wchar_t operator[](short idx) const { return (*ptr_)[idx]; }
    wchar_t& operator[](unsigned short idx) { return (*ptr_)[idx]; }
    wchar_t operator[](unsigned short idx) const { return (*ptr_)[idx]; }
    wchar_t& operator[](int idx) { return (*ptr_)[idx]; }
    wchar_t operator[](int idx) const { return (*ptr_)[idx]; }
    wchar_t& operator[](unsigned int idx) { return (*ptr_)[idx]; }
    wchar_t operator[](unsigned int idx) const { return (*ptr_)[idx]; }
    wchar_t& operator[](long idx) { return (*ptr_)[idx]; }
    wchar_t operator[](long idx) const { return (*ptr_)[idx]; }
    wchar_t& operator[](unsigned long idx) { return (*ptr_)[idx]; }
    wchar_t operator[](unsigned long idx) const { return (*ptr_)[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const wchar_t*() const { return *ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator wchar_t*&() const { return (wchar_t*&)*ptr_; }
#   else
    operator const wchar_t*() const { return *ptr_; }
    operator wchar_t*&() { return *ptr_; }
#   endif
#endif

    const wchar_t* in() const { return *ptr_; }
    wchar_t*& inout() { return *ptr_; }
    wchar_t*& out();
    wchar_t* _retn();

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    wchar_t*& ptr() { return *ptr_; }

    //
    // The class WString_out needs access to the internals of WStrForSeq
    //
    friend class CORBA::WString_out;
};

} // End of namespace OB


namespace CORBA
{

//
// The WString_out class
//
class WString_out
{
    // Assignment from WString_var and OB::WStrForSeq disallowed
    void operator=(const WString_var&);
    void operator=(const OB::WStrForSeq&);

    WChar*& ptr_;

public:

    WString_out(WChar*& p)
        : ptr_(p)
    {
        ptr_ = 0;
    }
    
    WString_out(WString_var& p)
        : ptr_(p.ptr_)
    {
        wstring_free(ptr_);
        ptr_ = 0;
    }

    WString_out(OB::WStrForSeq& p)
        : ptr_(*p.ptr_)
    {
        wstring_free(ptr_);
        ptr_ = 0;
    }
    
    WString_out(const WString_out& p)
        : ptr_(p.ptr_)
    {
    }
    
    WString_out& operator=(const WString_out& p)
    {
        ptr_ = p.ptr_;
        return *this;
    }
    
    WString_out& operator=(WChar* p)
    {
        ptr_ = p;
        return *this;
    }
    
    WString_out& operator=(const WChar* p)
    {
        ptr_ = wstring_dup(p);
        return *this;
    }
    
    wchar_t& operator[](short idx) { return ptr_[idx]; }
    wchar_t& operator[](unsigned short idx) { return ptr_[idx]; }
    wchar_t& operator[](int idx) { return ptr_[idx]; }
    wchar_t& operator[](unsigned int idx) { return ptr_[idx]; }
    wchar_t& operator[](long idx) { return ptr_[idx]; }
    wchar_t& operator[](unsigned long idx) { return ptr_[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const wchar_t*() { return ptr_; }
#else
    operator wchar_t*&() { return ptr_; }
#endif

    wchar_t*& ptr() { return ptr_; }
};

} // End of namespace CORBA

//
// String_var, String_out and OB::StrForSeq output on
// ostream
//
OB_STD(ostream)& operator<<(OB_STD(ostream)&, const CORBA::String_var&);
OB_STD(ostream)& operator<<(OB_STD(ostream)&, CORBA::String_out&);
OB_STD(ostream)& operator<<(OB_STD(ostream)&, const OB::StrForSeq&);
OB_STD(istream)& operator>>(OB_STD(istream)&, CORBA::String_var&);
OB_STD(istream)& operator>>(OB_STD(istream)&, CORBA::String_out&);
OB_STD(istream)& operator>>(OB_STD(istream)&, OB::StrForSeq&);

#ifdef HAVE_IOSTREAM
//
// WString_var, WString_out and WStrForSeq output on
// OB_STD(ostream)
//
#ifndef HAVE_NO_WCHAR_T_SUPPORT_IN_STREAMS
OB_STD(wostream)& operator<<(OB_STD(wostream)&, const CORBA::WString_var&);
OB_STD(wostream)& operator<<(OB_STD(wostream)&, CORBA::WString_out&);
OB_STD(wostream)& operator<<(OB_STD(wostream)&, const OB::WStrForSeq&);
OB_STD(wistream)& operator>>(OB_STD(wistream)&, CORBA::WString_var&);
OB_STD(wistream)& operator>>(OB_STD(wistream)&, CORBA::WString_out&);
OB_STD(wistream)& operator>>(OB_STD(wistream)&, OB::WStrForSeq&);
#endif
#endif

namespace OB
{

//
// Byte order constant:
//
// Endian == true (1)  : little endian
// Endian == false (0) : big endian
//
#ifdef WORDS_BIGENDIAN
const CORBA::Boolean Endian = false;
#else
const CORBA::Boolean Endian = true;
#endif

//
// Memory allocation functions
//
// - Alloc:
//   Allocates memory
//
// - Free:
//   Frees memory allocated with Alloc
//
// - Allocated:
//   Returns the unsigned long argument that was used with Alloc
//
// - AllocCheck:
//   Checks if memory was allocated with Alloc (does only
//   work if the library was compiled without NDEBUG set)
//
void* Alloc(size_t, CORBA::ULong);
void Free(void*);
CORBA::ULong Allocated(const void*);
#ifdef NDEBUG
inline bool AllocCheck(const void*) { return true; }
#else
bool AllocCheck(const void*);
#endif

//
// Memory allocation functions used by string sequences
//
char** StrSeqAllocbuf(CORBA::ULong);
void StrSeqFreebuf(char**);
wchar_t** WStrSeqAllocbuf(CORBA::ULong);
void WStrSeqFreebuf(wchar_t**);

//
// Convert between octet sequence and ascii string
//
char* OctetsToAscii(const CORBA::Octet*, CORBA::ULong);
CORBA::Octet* AsciiToOctets(const char*);

//
// Convert between LongLong/ULongLong and string. Returns true on success
// or false for errors.
//
bool StringToULongLong(const char*, const char**, CORBA::UShort,
                       CORBA::ULongLong&);
bool StringToLongLong(const char*, const char**, CORBA::UShort,
                      CORBA::LongLong&);
char* ULongLongToString(CORBA::ULongLong);
char* LongLongToString(CORBA::LongLong);

//
// Convert a string to lowercase
//
void LowerCase(char*);

//
// "Simple" reference counting class, not thread-safe
//
class SimpleRefCount
{
    CORBA::Long ref_; // The reference count

    //
    // Hide copy-constructor and assignment operator
    //
    SimpleRefCount(const SimpleRefCount&);
    void operator=(const SimpleRefCount&);

public:

    SimpleRefCount() : ref_(1) { }
    virtual ~SimpleRefCount()
    { assert_nca(ref_ == 0, NCARefCountNotZero); }

    //
    // Increment reference count
    //
    void _OB_incRef() { ++ref_; }

    //
    // Decrement reference count - delete object if reference count
    // falls to zero
    //
    void _OB_decRef()
    {
	assert_nca(ref_ > 0, NCARefCountZero);
	if(--ref_ == 0)
	    delete this;
    }

    //
    // Get and set reference count
    //
    CORBA::ULong _OB_getRef() const { return (CORBA::ULong)ref_; }
    void _OB_setRef(CORBA::ULong ref)
    { ref_ = (CORBA::Long)ref; assert(ref_ >= 0); }
};

//
// Reference counting class, thread-safe
//
#ifdef WIN32

class RefCount
{
    CORBA::Long ref_; // The reference count

    //
    // Hide copy-constructor and assignment operator
    //
    RefCount(const RefCount&);
    void operator=(const RefCount&);

public:

    RefCount() : ref_(1) { }
    virtual ~RefCount()
	{ assert_nca(ref_ == 0, NCARefCountNotZero); }

    //
    // Increment reference count
    //
    void _OB_incRef() { InterlockedIncrement(&ref_); }

    //
    // Decrement reference count - delete object if reference count
    // falls to zero
    //
    void _OB_decRef()
    {
	assert_nca(ref_ > 0, NCARefCountZero);
	if(InterlockedDecrement(&ref_) == 0)
	    delete this;
    }

    //
    // Get and set reference count
    //
    CORBA::ULong _OB_getRef() const { return (CORBA::ULong)ref_; }
    void _OB_setRef(CORBA::ULong ref)
    { ref_ = (CORBA::Long)ref; assert(ref_ >= 0); }
};

#else // !WIN32

class RefCount
{
    CORBA::Long ref_; // The reference count
    JTCMutex mut_; // The reference count mutex

    //
    // Hide copy-constructor and assignment operator
    //
    RefCount(const RefCount&);
    void operator=(const RefCount&);

public:

    RefCount() : ref_(1) { }
    virtual ~RefCount() { assert_nca(ref_ == 0, NCARefCountNotZero); }

    //
    // Increment reference count
    //
    void _OB_incRef() { JTCSynchronized sync(mut_); ++ref_; }

    //
    // Decrement reference count - delete object if reference count
    // falls to zero
    //
    void _OB_decRef()
    {
        bool deleteThis;

        {
            JTCSynchronized sync(mut_);
            assert_nca(ref_ > 0, NCARefCountZero);
            deleteThis = (--ref_ == 0);
        }

        if(deleteThis)
            delete this;
    }

    //
    // Get and set reference count
    //
    CORBA::ULong _OB_getRef() const { return (CORBA::ULong)ref_; }
    void _OB_setRef(CORBA::ULong ref)
    { JTCSynchronized sync(mut_); ref_ = (CORBA::Long)ref; assert(ref_ >= 0); }
};

#endif // WIN32

//
// Reference counted classes may implement this interface.
//
class RefCountable
{
public:

    virtual ~RefCountable() { }

    virtual void _add_ref() = 0;
    virtual void _remove_ref() = 0;
};

} // End of namespace OB

#endif
