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

#ifndef OB_BASIC_H
#define OB_BASIC_H

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

//
// DLL support
//
#ifdef OB_DLL
#   ifdef OB_BUILD_DLL
#       define OB_IMPORT /**/
#   else
#       define OB_IMPORT __declspec(dllimport)
#   endif
#else
#   define OB_IMPORT /**/
#endif

//
// The ORBacus version, as string and as integer
//
#define OB_VERSION "3.2"
#define OB_INTEGER_VERSION 3020000L
OB_IMPORT extern const char* OBVersion;
OB_IMPORT extern unsigned long OBIntegerVersion;

//
// The ORBacus license, as string
//
OB_IMPORT extern const char* OBLicense;

//
// This is for GNU C++ 2.7.x
//
#ifdef __GNUC__ 
#   if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 7)
#       error GNU C++ 2.7.2 is not supported anymore!
#   endif
#endif

//
// This is for GNU C++ 2.95.x and later
//
#ifdef __GNUC__ 
#   if __GNUC__ == 2 && __GNUC_MINOR__ >= 95
//
// 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 AIX xlC
//
#if defined(_AIX) && !defined(__GNUC__)
#   define HAVE_PRAGMA_DEFINE
#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

//
// This is for DEC C++ 6.0-010
//
#ifdef __DECCXX
//
// The DEC C++ compiler has a very strange and annoying exception
// handling bug. In case there is a try block, which does not have a
// local variable with a destructor, the compiler sometimes runs into
// the following internal error:
//
// Internal error: Unexpected null cleanup_block in
// unwind_cleanup_state.IOT/Abort trap (core dumped)
//
// To avoid this, a "dummy" variable with a destructor must be added
// to the try block.
//
#   define OB_DEC_TRY_FIX CORBA_Object_var fixForDECCXX;
#else
#   define OB_DEC_TRY_FIX /**/
#endif

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

//
// Typedef for bool type if bool is not supported
//
#if SIZEOF_BOOL == 0
#   ifndef HAVE_BOOL_TYPEDEF
#       define HAVE_BOOL_TYPEDEF
typedef int bool;
#       ifndef true
const bool true = 1;
#       endif
#       ifndef false
const bool false = 0;
#       endif
#   endif
#endif

//
// Include JThreads/C++ library
//
#ifdef HAVE_JTC

#   ifndef MAKEDEPEND
#       include <JTC/JTC.h>
#   endif


#   define OB_COMMA_MONITOR , public JTCMonitor
#   define OB_COLON_MONITOR : public JTCMonitor
#   define OB_COMMA_RECURSIVE_MUTEX , public JTCRecursiveMutex
#   define OB_COLON_RECURSIVE_MUTEX : public JTCRecursiveMutex
#   define OB_COMMA_MUTEX , public JTCMutex
#   define OB_COLON_MUTEX : public JTCMutex
#   define OB_SYNCHRONIZED JTCSynchronized synchronized(*this);

#else

#   define OB_COMMA_MONITOR /**/
#   define OB_COLON_MONITOR /**/
#   define OB_COMMA_RECURSIVE_MUTEX /**/
#   define OB_COLON_RECURSIVE_MUTEX /**/
#   define OB_COMMA_MUTEX /**/
#   define OB_COLON_MUTEX /**/
#   define OB_SYNCHRONIZED /**/

#endif

//
// Include common header files
//
#include <string.h>
#include <assert.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

//
// In case the header files define everything in the std namespace...
//
#ifdef HAVE_STD_NAMESPACE
using namespace std;
#endif

//
// Assert macro for "non-compliant application"
//
enum OBNCAReason
{
    OBNCANotImpl,         // Not implemented yet

    OBNCAWrongAlloc,      // Memory was not allocated with OBAlloc()
    OBNCADoubleFree,      // Memory was already freed by OBFree()

    OBNCARefCountNotZero, // Object deleted without a reference count of zero
    OBNCARefCountZero,    // Object already deleted (reference count is zero)

    OBNCASeqLenGrMax,     // Sequence length greater than maximum length
    OBNCASeqRange,        // Out of range error in sequence operator[]()
                          // or remove()

    OBNCANullInit,        // Initialization of T_var type with null pointer
    OBNCANullPtr,         // operator->() used on null pointer or nil reference
    OBNCANullDeref,       // Null pointer dereferencing
    OBNCANullString,      // Null pointer passed as string

    OBNCASelfAssign,      // Self assignment causing a dangling pointer

    OBNCAAnySelfReplace,  // Any content was replaced by it's own value

    OBNCADiscType,        // Wrong union discriminator type
    OBNCADiscMismatch,    // Union discriminator mismatch
    OBNCAUnionInit,       // Uninitialized union used

    OBNCADynamicAsStatic  // Dynamic implementation object used as static
};

void OBNCA(OBNCAReason);

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

#    define assert_nca(ex, reason) \
( ((int)(ex)) ? ((void)0) : (OBNCA(reason), assert((int)(ex))) )

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

//
// Basic types
//
#if SIZEOF_CHAR == 1
typedef unsigned char OBUnsignedChar;
typedef OBUnsignedChar CORBA_Boolean;
typedef OBUnsignedChar CORBA_Char;
typedef OBUnsignedChar CORBA_Octet;
#else
#   error SIZEOF_CHAR must be 1!
#endif

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

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

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

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

//
// True and false
//
const CORBA_Boolean CORBA_TRUE = 1;
const CORBA_Boolean CORBA_FALSE = 0;

//
// Status and Flags
//
typedef void CORBA_Status;
typedef CORBA_Long CORBA_Flags;
const CORBA_Flags CORBA_ARG_IN = 1;
const CORBA_Flags CORBA_ARG_OUT = 2;
const CORBA_Flags CORBA_ARG_INOUT = 3;
const CORBA_Flags CORBA_OUT_LIST_MEMORY = 4;
const CORBA_Flags CORBA_IN_COPY_VALUE = 5;
const CORBA_Flags CORBA_CTX_RESTRICT_SCOPE = 6;

//
// Byte order constant:
//
// OBEndian == TRUE (1)  : little endian
// OBEndian == FALSE (0) : big endian
//
#ifdef WORDS_BIGENDIAN
const CORBA_Boolean OBEndian = 0;
#else
const CORBA_Boolean OBEndian = 1;
#endif

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

// 
// marshal/unmarshal functions:
//
// OBMarshal(T value, CORBA_Octet*& oct):
// -> marshals value into oct, increments oct
//
// OBMarshalMulti(const T* value, CORBA_Octet*& oct, CORBA_ULong n):
// -> marshals n values into oct, increments oct
//
// OBMarshalCount(T value, CORBA_ULong& count):
// -> does not marshal the value into oct, but increments count
//
// OBMarshalCountMulti(const T* value, CORBA_ULong& count, CORBA_ULong n):
// -> does not marshal the n values into oct, but increments count
//
// OBUnmarshal(T& value, const CORBA_Octet*& oct, bool swap):
// -> OBUnmarshals value from oct, increments oct, swaps byteorder
//    if swap == true
//
// OBUnmarshalMulti(T& value, const CORBA_Octet*& oct, bool swap, CORBA_ULong n):
// -> OBUnmarshals n values from oct, increments oct, swaps byteorder
//    if swap == true
//
inline void
OBMarshal(OBUnsignedChar val, CORBA_Octet*& oct)
{
    *oct++ = val;
}

inline void
OBMarshalMulti(const OBUnsignedChar* val, CORBA_Octet*& oct, CORBA_ULong n)
{
    if(n)
    {
	memcpy(oct, val, n);
	oct += n;
    }
}

inline void
OBMarshalCount(OBUnsignedChar, CORBA_ULong& count)
{
    count++;
}

inline void
OBMarshalCountMulti(const OBUnsignedChar*, CORBA_ULong& count, CORBA_ULong n)
{
    count += n;
}

inline void
OBUnmarshal(OBUnsignedChar& val, const CORBA_Octet*& oct, bool)
{
    val = *oct++;
}

inline void
OBUnmarshalMulti(OBUnsignedChar* val, const CORBA_Octet*& oct, bool,
		 CORBA_ULong n)
{
    if(n)
    {
	memcpy(val, oct, n);
	oct += n;
    }
}

void OBMarshal(CORBA_Short, CORBA_Octet*&);
void OBMarshalMulti(const CORBA_Short*, CORBA_Octet*&, CORBA_ULong);
void OBMarshalCount(CORBA_Short, CORBA_ULong&);
void OBMarshalCountMulti(const CORBA_Short*, CORBA_ULong&, CORBA_ULong);
void OBUnmarshal(CORBA_Short&, const CORBA_Octet*&, bool);
void OBUnmarshalMulti(CORBA_Short*, const CORBA_Octet*&, bool, CORBA_ULong);

void OBMarshal(CORBA_Long, CORBA_Octet*&);
void OBMarshalMulti(const CORBA_Long*, CORBA_Octet*&, CORBA_ULong);
void OBMarshalCount(CORBA_Long, CORBA_ULong&);
void OBMarshalCountMulti(const CORBA_Long*, CORBA_ULong&, CORBA_ULong);
void OBUnmarshal(CORBA_Long&, const CORBA_Octet*&, bool);
void OBUnmarshalMulti(CORBA_Long*, const CORBA_Octet*&, bool, CORBA_ULong);

void OBMarshal(CORBA_UShort, CORBA_Octet*&);
void OBMarshalMulti(const CORBA_UShort*, CORBA_Octet*&, CORBA_ULong);
void OBMarshalCount(CORBA_UShort, CORBA_ULong&);
void OBMarshalCountMulti(const CORBA_UShort*, CORBA_ULong&, CORBA_ULong);
void OBUnmarshal(CORBA_UShort&, const CORBA_Octet*&, bool);
void OBUnmarshalMulti(CORBA_UShort*, const CORBA_Octet*&, bool, CORBA_ULong);

void OBMarshal(CORBA_ULong, CORBA_Octet*&);
void OBMarshalMulti(const CORBA_ULong*, CORBA_Octet*&, CORBA_ULong);
void OBMarshalCount(CORBA_ULong, CORBA_ULong&);
void OBMarshalCountMulti(const CORBA_ULong*, CORBA_ULong&, CORBA_ULong);
void OBUnmarshal(CORBA_ULong&, const CORBA_Octet*&, bool);
void OBUnmarshalMulti(CORBA_ULong*, const CORBA_Octet*&, bool, CORBA_ULong);

void OBMarshal(CORBA_Float, CORBA_Octet*&);
void OBMarshalMulti(const CORBA_Float*, CORBA_Octet*&, CORBA_ULong);
void OBMarshalCount(CORBA_Float, CORBA_ULong&);
void OBMarshalCountMulti(const CORBA_Float*, CORBA_ULong&, CORBA_ULong);
void OBUnmarshal(CORBA_Float&, const CORBA_Octet*&, bool);
void OBUnmarshalMulti(CORBA_Float*, const CORBA_Octet*&, bool, CORBA_ULong);

void OBMarshal(CORBA_Double, CORBA_Octet*&);
void OBMarshalMulti(const CORBA_Double*, CORBA_Octet*&, CORBA_ULong);
void OBMarshalCount(CORBA_Double, CORBA_ULong&);
void OBMarshalCountMulti(const CORBA_Double*, CORBA_ULong&, CORBA_ULong);
void OBUnmarshal(CORBA_Double&, const CORBA_Octet*&, bool);
void OBUnmarshalMulti(CORBA_Double*, const CORBA_Octet*&, bool, CORBA_ULong);

void OBMarshal(const char*, CORBA_Octet*&);
void OBMarshalCount(const char*, CORBA_ULong&);
void OBUnmarshal(char*&, const CORBA_Octet*&, bool);

//
// Convert between octet sequence and ascii string
//
char* OBOctetsToAscii(const CORBA_Octet*, CORBA_ULong);
CORBA_Octet* OBAsciiToOctets(const char*);

//
// String memory management
//
// - CORBA_string_alloc:
//   Allocates new string (terminating '\0' must not be included in
//   the length argument)
//
// - CORBA_string_free:
//   Frees a string allocated with CORBA_string_alloc
//
// - CORBA_string_dup:
//   Duplicates a string using the functions CORBA_string_alloc
//
// - CORBA_string_allocated:
//   Returns the length argument that was used with CORBA_string_alloc
//
// - CORBA_string_check:
//   Checks if a string was allocated with CORBA_string_alloc (does only
//   work if the library was compiled without NDEBUG set)
//
char* CORBA_string_alloc(CORBA_ULong);
void CORBA_string_free(char*);
CORBA_ULong CORBA_string_allocated(const char*);
char* CORBA_string_dup(const char*);
#ifdef NDEBUG
inline CORBA_Boolean CORBA_string_check(const char*) { return true; }
#else
CORBA_Boolean CORBA_string_check(const char*);
#endif

//
// The String_var class
//
class OBStrForSeq;
class CORBA_String_var
{
    char* ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    CORBA_String_var() : ptr_(0) { }
    CORBA_String_var(char*);
    CORBA_String_var(const char* p) : ptr_(CORBA_string_dup(p)) { }
    CORBA_String_var(const CORBA_String_var&);
    CORBA_String_var(const OBStrForSeq&);
    ~CORBA_String_var() { CORBA_string_free(ptr_); }
    
    CORBA_String_var& operator=(char*);
    CORBA_String_var& operator=(const char*);
    CORBA_String_var& operator=(const CORBA_String_var&);
    CORBA_String_var& operator=(const OBStrForSeq&);

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

    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 HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator char*&() const { return (char*&)ptr_; }
#else
#ifndef OB_ONLY_IN_TYPE_CONVERSION
    operator char*&() { return ptr_; }
#endif
    operator const char*() const { return ptr_; }
#endif

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

    CORBA_String_var& operator+=(long);
    CORBA_String_var& operator+=(unsigned long);

    CORBA_String_var& operator+=(short n)
    { return operator+=((long)n); }
    CORBA_String_var& operator+=(unsigned short n)
    { return operator+=((unsigned long)n); }

    CORBA_String_var& operator+=(int n)
    { return operator+=((long)n); }
    CORBA_String_var& operator+=(unsigned int n)
    { return operator+=((unsigned long)n); }
};

//
// String type used by string sequences
//
class OBStrForSeq
{	
    char** ptr_;
    CORBA_Boolean rel_;
    
public:

    //
    // ORBacus specific constructor that works together with
    // the corresponding sequence type
    //
    OBStrForSeq(char** p, CORBA_Boolean rel) : ptr_(p), rel_(rel) { }
    OBStrForSeq(const OBStrForSeq& r) : ptr_(r.ptr_), rel_(r.rel_) { }
    
    //
    // Standard IDL to C++ Mapping
    //
    OBStrForSeq& operator=(char*);
    OBStrForSeq& operator=(const char*);
    OBStrForSeq& operator=(const CORBA_String_var&);
    OBStrForSeq& operator=(const OBStrForSeq&);
    
    const char* in() const { return *ptr_; }
    char*& inout() { return *ptr_; }
    char*& out();
    char* _retn();

    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 HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator char*&() const { return *ptr_; }
#else
#ifndef OB_ONLY_IN_TYPE_CONVERSION
    operator char*&() { return *ptr_; }
#endif
    operator const char*() const { return *ptr_; }
#endif
};

//
// CORBA_String_var and OBStrForSeq output on output stream
//
extern ostream& operator<<(ostream&, const CORBA_String_var&);
extern ostream& operator<<(ostream&, const OBStrForSeq&);
extern istream& operator>>(istream&, CORBA_String_var&);
extern istream& operator>>(istream&, OBStrForSeq&);

//
// "Simple" reference counting class, non thread-safe
//
class OBSimpleRefCount
{
    CORBA_Long ref_; // The reference count

    //
    // Hide copy-constructor and asignment operator
    //
    OBSimpleRefCount(const OBSimpleRefCount&);
    void operator=(const OBSimpleRefCount&);

public:

    OBSimpleRefCount() : ref_(1) { }
    virtual ~OBSimpleRefCount()
    { assert_nca(ref_ == 0, OBNCARefCountNotZero); }

    //
    // 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, OBNCARefCountZero);
	if(--ref_ == 0)
	    delete this;
    }

    //
    // Get and set reference count
    //
    CORBA_ULong _OB_getRef() const { return ref_; }
    void _OB_setRef(CORBA_ULong ref) { ref_ = ref; }
};

//
// Reference counting class, thread-safe
//
#ifndef HAVE_JTC

typedef OBSimpleRefCount OBRefCount;

#else

#ifdef WIN32
class OBRefCount
{
    CORBA_Long ref_; // The reference count

    //
    // Hide copy-constructor and asignment operator
    //
    OBRefCount(const OBRefCount&);
    void operator=(const OBRefCount&);

public:

    OBRefCount() : ref_(1) { }
    virtual ~OBRefCount()
    { assert_nca(ref_ == 0, OBNCARefCountNotZero); }

    //
    // 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, OBNCARefCountZero);
	if(InterlockedDecrement(&ref_) == 0)
	    delete this;
    }

    //
    // Get and set reference count
    //
    CORBA_ULong _OB_getRef() const { return ref_; }
    void _OB_setRef(CORBA_ULong ref) { ref_ = ref; }
};

#else

class OBRefCount
{
    CORBA_Long ref_; // The reference count
    JTCMutex mut_; // The reference count mutex

    //
    // Hide copy-constructor and asignment operator
    //
    OBRefCount(const OBRefCount&);
    void operator=(const OBRefCount&);

public:

    OBRefCount() : ref_(1) { }
    virtual ~OBRefCount() { assert_nca(ref_ == 0, OBNCARefCountNotZero); }

    //
    // 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, OBNCARefCountZero);
	    deleteThis = (--ref_ == 0);
	}

	//
	// Pretty awkward to delete an object like this but a bug in
	// the Sun CC 4.2 forces us to do it this way.
	//
	if(deleteThis)
	    delete this;
    }

    //
    // Get and set reference count
    //
    CORBA_ULong _OB_getRef() const { return ref_; }
    void _OB_setRef(CORBA_ULong ref)
    { JTCSynchronized sync(mut_); ref_ = ref; }
};

#endif

#endif

//
// A simple buffer struct
//

#ifdef WIN32

struct OBBuffer
{
    OBBuffer()
	: real(0), data(0), len(0)
    {
    }

private: // I don't want that this constructor is used somewhere
    OBBuffer(const OBBuffer& buf)
	: real(new CORBA_Octet[buf.len + 7]), len(buf.len)
    {
	data = real + 7;
	data -= (unsigned int)data % 8;
	memcpy(data, buf.data, len);
    }
public:

    OBBuffer(CORBA_ULong n)
	: real(new CORBA_Octet[n + 7]), len(n)
    {
	data = real + 7;
	data -= (unsigned int)data % 8;
#ifdef OB_CLEAR_MEM
	memset(data, 0, len);
#endif
    }

    ~OBBuffer()
    {
	delete [] real;
    }

private: // I don't want that the assignment operator is used somewhere
    OBBuffer& operator=(const OBBuffer& buf)
    {
	if(&buf != this)
	{
	    delete [] real;
	    len = buf.len;
	    real = new CORBA_Octet[len + 7];
	    data = real + 7;
	    data -= (unsigned int)data % 8;
	    memcpy(data, buf.data, len);
	}
	return *this;
    }
public:

    void alloc(CORBA_ULong n)
    {
	delete [] real;
	len = n;
	real = new CORBA_Octet[len + 7];
	data = real + 7;
	data -= (unsigned int)data % 8;
#ifdef OB_CLEAR_MEM
	memset(data, 0, n);
#endif
    }

    void realloc(CORBA_ULong n)
    {
	// Shrinking the buffer is illegal
	assert(n >= len);

	if(n > len)
	{
	    CORBA_Octet* newReal = new CORBA_Octet[n + 7];
	    CORBA_Octet* newData = newReal + 7;
	    newData -= (unsigned int)newData % 8;
	    memcpy(newData, data, len);
#ifdef OB_CLEAR_MEM
	    memset(newData + len, 0, n - len);
#endif
	    delete [] real;
	    real = newReal;
	    data = newData;
	    len = n;
	}
    }

    void consume(OBBuffer& buf)
    {
	delete [] real;
	real = buf.real;
	data = buf.data;
	len = buf.len;
	buf.real = 0;
	buf.data = 0;
	buf.len = 0;
    }

private:
    CORBA_Octet* real; // Points to the "real" buffer
public:
    CORBA_Octet* data; // Points to the buffer
    CORBA_ULong len; // The buffer length
};    

#else

struct OBBuffer
{
    OBBuffer()
	: data(0), len(0)
    {
    }

private: // I don't want that this constructor is used somewhere
    OBBuffer(const OBBuffer& buf)
	: data(new CORBA_Octet(buf.len)), len(buf.len)
    {
	memcpy(data, buf.data, len);
    }
public:

    OBBuffer(CORBA_ULong n)
	: data(new CORBA_Octet[n]), len(n)
    {
#ifdef OB_CLEAR_MEM
	memset(data, 0, len);
#endif
    }

    ~OBBuffer()
    {
	delete [] data;
    }

private: // I don't want that the assignment operator is used somewhere
    OBBuffer& operator=(const OBBuffer& buf)
    {
	if(&buf != this)
	{
	    delete [] data;
	    len = buf.len;
	    data = new CORBA_Octet[len];
	    memcpy(data, buf.data, len);
	}
	return *this;
    }
public:

    void alloc(CORBA_ULong n)
    {
	delete [] data;
	data = new CORBA_Octet[n];
	len = n;
#ifdef OB_CLEAR_MEM
	memset(data, 0, n);
#endif
    }

    void realloc(CORBA_ULong n)
    {
	// Shrinking the buffer is illegal
	assert(n >= len);

	if(n > len)
	{
	    CORBA_Octet* newData = new CORBA_Octet[n];
	    memcpy(newData, data, len);
#ifdef OB_CLEAR_MEM
	    memset(newData + len, 0, n - len);
#endif
	    delete [] data;
	    data = newData;
	    len = n;
	}
    }

    void consume(OBBuffer& buf)
    {
	delete [] data;
	data = buf.data;
	len = buf.len;
	buf.data = 0;
	buf.len = 0;
    }

    CORBA_Octet* data; // Points to the buffer
    CORBA_ULong len; // The buffer length
};

#endif

#endif
