Listing 1: XDRStream.h

/****************************************************************
File: XDRStream.h
Copyright (c) 1999-2001 Bleading Edge Software Technologies, Inc.

This Software is distributed under the open source, free 
software model. Permission to use, modify, and distribute this 
Software, including incorporating it into proprietary software, 
is granted without fee, provided this copyright notice appear in 
all copies of the code. You are under no obligation to distribute 
source code which is derived from or uses this Software. You may
not do anything however, to prevent the continued distribution of
this Software under an open source distribution model. This 
includes, but is not limited to, such things as copyrighting or 
claiming authorship of the Software. This Software is distributed 
in the hope that it will be useful, but it is provide "as 
is", WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

//$--------------------------------------------------------------
$Header: $
Author: Jack W. Reeves

//!-------------------------------------------------------------|
Description:
XDR_Stream is an iostream that reads and writes XDR.

//#-------------------------------------------------------------|
Notes:

//%*************************************************************/
#ifndef UTIL_XDR_STREAM_H
#define UTIL_XDR_STREAM_H

// configuration info
#include <platform.h>

// Standard C++ headers
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <cwchar>

namespace Util {

// uint32_t on all my current platforms
typedef unsigned long XDR_Char;    

// We need a traits class for XDR_Char. I could explicitly
// specialize std::char_traits<> but, after doing that
// originally decided against it. In particular, I  think 
// you want to be careful about adding explicit specializations
// to namespace std. You run a large risk of name conflicts.

struct XDR_Char_Traits {
  typedef XDR_Char         char_type;
  typedef long             int_type;
  typedef std::streamoff   off_type;
  typedef std::streampos   pos_type;
  // not used so removed for now
  typedef std::mbstate_t   state_type; 

  static void assign
    (char_type& c1, const char_type& c2);
  static bool eq
    (const char_type& c1, const char_type& c2);
  static bool lt
    (const char_type& c1, const char_type& c2);

  static int compare
    (const char_type* s1, const char_type* s2);
  static size_t length
    (const char_type* s1);
  static const char_type* find
    (const char_type* s, size_t n, const char_type& a);

  static char_type* move
    (char_type* s1, const char_type* s2, size_t n);
  static char_type* copy
    (char_type* s1, const char_type* s2, size_t n);
  static char_type* assign
    (char_type* s, size_t n, char_type a);

  static int_type not_eof(const int_type& c);
  static char_type to_char_type(const int_type& c);
  static int_type to_int_type(const char_type& c);
  static bool eq_int_type
    (const int_type& c1, const int_type& c2);
  static int_type eof();

  // extra utility functions
  static void swap_bytes(char_type& c);
  static void pad(char_type& c, int);
};


// The stream buffer class is just a specialization
typedef 
std::basic_streambuf<XDR_Char, XDR_Char_Traits> XDR_Streambuf;

// input streams 
class iXDR_Stream : 
  virtual public std::basic_ios<XDR_Char, XDR_Char_Traits> 
{
public:
  // Types inherited from basic_ios
  typedef std::basic_ios<XDR_Char, XDR_Char_Traits> inherited;
  typedef XDR_Char                 char_type;
  typedef XDR_Char_Traits          traits_type;
  typedef traits_type::int_type    int_type;
  typedef traits_type::pos_type    pos_type;
  typedef traits_type::off_type    off_type;

  // Input stream sentry class
  class sentry {
    bool    _ok;
  public:
    explicit sentry(iXDR_Stream& ixs) : _ok(ixs.good()) {}
    ~sentry() {}
    operator bool() const    { return _ok; }
  };

  // Support for reference semantics
  class IdToObjMap {
    typedef std::map<long, void*> ObjMap;
    ObjMap    _objMap;
  public:
    IdToObjMap();
    ~IdToObjMap();
    void*                   find(long id);
    std::pair<void*, bool>  insert(long id, 
      void* obj);
    void*&                  operator[](long id);
  private:
    IdToObjMap(const IdToObjMap&);
    IdToObjMap& operator=(const IdToObjMap&);
  };

  class IdToTypeMap {
    typedef std::map<long, std::string> TypeMap;
    TypeMap    _typeMap;
  public:
    IdToTypeMap();
    ~IdToTypeMap();
    std::string                 find(long id);
    std::pair<std::string,bool> insert
      (long id, const std::string& type);
    std::string&                operator[](long id);
  private:
    IdToTypeMap(const IdToTypeMap&);
    IdToTypeMap& operator=(const IdToTypeMap&);
  };

private:
  // data
  std::streamsize    _gcount;
  IdToObjMap         _id2objMap;
  IdToTypeMap        _id2typeMap;

public:
  // constructor / destructor
  explicit iXDR_Stream(XDR_Streambuf* sb);
  virtual ~iXDR_Stream();

  // standard manipulators
  iXDR_Stream&   operator>>
    (iXDR_Stream& (*pf)(iXDR_Stream&));
  iXDR_Stream&   operator>>
    (inherited& (*pf)(inherited&));
  iXDR_Stream&   operator>>
    (std::ios_base& (*pf)(std::ios_base&));

  // encoded input
  iXDR_Stream&   operator>>(bool& n);
  iXDR_Stream&   operator>>(char& n);
  iXDR_Stream&   operator>>(signed char& n);
  iXDR_Stream&   operator>>(unsigned char& n);
  iXDR_Stream&   operator>>(short& n);
  iXDR_Stream&   operator>>(unsigned short& n);
  iXDR_Stream&   operator>>(int& n);
  iXDR_Stream&   operator>>(unsigned int& n);
  iXDR_Stream&   operator>>(long& n);
  iXDR_Stream&   operator>>(unsigned long& n);
  iXDR_Stream&   operator>>(float& f);
  iXDR_Stream&   operator>>(double& f);
  iXDR_Stream&   operator>>(long double& f);

  // copy
  iXDR_Stream&   operator>>(XDR_Streambuf* sb);

  // opaque data extractors
  size_t            get_opaque(void* d, size_t l);
  size_t            vget_opaque(void* d, size_t l);

  // array extractors
  template<typename T>
  ptrdiff_t         get_array(T* a, ptrdiff_t l);
  template<typename T>
  ptrdiff_t         vget_array(T* a, ptrdiff_t l);

  // string extractors
  size_t            vget_string(char* s, size_t l);

  // unformated input
  std::streamsize   gcount() const    { return _gcount; }

  int_type          get();
  iXDR_Stream&  get(char_type& c);
  iXDR_Stream&  read(char_type* s, std::streamsize n);

  int               sync();

  pos_type          tellg();
  iXDR_Stream&  seekg(pos_type);
  iXDR_Stream&  seekg(off_type, std::ios_base::seekdir);

  // Support for reference semantics
  IdToObjMap&   id2obj()    { return _id2objMap; }
  IdToTypeMap&  id2type()   { return _id2typeMap; }

protected:
  iXDR_Stream();
};

// opaque data extractors
iXDR_Stream& operator>>
  (iXDR_Stream&, std::vector<unsigned char>& data);

// array extractors
template<typename T>
iXDR_Stream& operator>>
  (iXDR_Stream&, std::vector<T>& arr);

// string extractors
iXDR_Stream& operator>>
  (iXDR_Stream&, char* s);
iXDR_Stream& operator>>
  (iXDR_Stream&, signed char* s);
iXDR_Stream& operator>>
  (iXDR_Stream&, unsigned char* s);
iXDR_Stream& operator>>
  (iXDR_Stream&, std::string& str);

// functions which allocate the data area from the free
// store and return it 
// NOTE: clients are responsible for calling delete[] on the 
//       returned  pointer
// NOTE: the 'string' version always null terminates the 
//       returned string
std::pair<unsigned char*, size_t> vget_opaque
  (iXDR_Stream& ixs, size_t max = size_t(-1));
template<typename T> std::pair<T*, ptrdiff_t> vget_array
  (iXDR_Stream& ixs, ptrdiff_t max = -1);
std::pair<char*, size_t> vget_string
  (iXDR_Stream& ixs, size_t max =  size_t(-1));

// optional data
template<typename T> T* get_optional(iXDR_Stream& ixs);

// support for reference semantics
void* get_objId(iXDR_Stream& ixs, long& id);
void  map_objId(iXDR_Stream& ixs, long id, void* obj);

// support for polymorphism
std::string get_typeId(iXDR_Stream& ixs, long& id);
void        map_typeId(iXDR_Stream& ixs, long id, 
  const std::string& type);


//
// Output streams
//
class oXDR_Stream :
  virtual public std::basic_ios<XDR_Char, XDR_Char_Traits> 
{
public:
  // Types inherited from basic_ios
  typedef std::basic_ios<XDR_Char, XDR_Char_Traits> inherited;
  typedef XDR_Char               char_type;
  typedef XDR_Char_Traits        traits_type;
  typedef traits_type::int_type  int_type;
  typedef traits_type::pos_type  pos_type;
  typedef traits_type::off_type  off_type;

  // Output stream sentry
  class sentry {
    bool    _ok;
  public:
    explicit sentry(oXDR_Stream& oxs) : _ok(oxs.good()) {}
    ~sentry() {}
    operator bool() const { return _ok; }
  };

  // Support for reference semantics
  class ObjToIdMap {
    typedef std::map<const void*, long> IdMap;
    long    _id;
    IdMap   _idMap;
  public:
    ObjToIdMap();
    ~ObjToIdMap();
    long    find(const void* obj);
    std::pair<long,bool> insert(const void* obj);
    long    operator[](const void* obj);
  private:
    ObjToIdMap(const ObjToIdMap&);
    ObjToIdMap& operator=(const ObjToIdMap&);
  };

  // Support for polymorphism
  class TypeToIdMap {
    typedef std::map<std::string, long> IdMap;
    long    _id;
    IdMap   _idMap;
  public:
    TypeToIdMap();
    ~TypeToIdMap();
    long    find(const std::string& type);
    std::pair<long,bool> insert(const std::string& type);
    long    operator[](const std::string& type);
  private:
    TypeToIdMap(const TypeToIdMap&);
    TypeToIdMap& operator=(const TypeToIdMap&);
  };


private:
  // data
  ObjToIdMap    _obj2idMap;
  TypeToIdMap   _type2idMap;

public:
  // constructor / destructor
  explicit oXDR_Stream(XDR_Streambuf* sb);
  virtual ~oXDR_Stream();

  // prefix / suffix
  class sentry;

  // standard manipulators
  oXDR_Stream& operator<<(oXDR_Stream& (*pf)(oXDR_Stream&));
  oXDR_Stream& operator<<(inherited& (*pf)(inherited&));
  oXDR_Stream& operator<<(std::ios_base& (*pf)(std::ios_base&));

  // encoded output
  oXDR_Stream&   operator<<(bool n);
  oXDR_Stream&   operator<<(char n);
  oXDR_Stream&   operator<<(signed char n);
  oXDR_Stream&   operator<<(unsigned char n);
  oXDR_Stream&   operator<<(short n);
  oXDR_Stream&   operator<<(unsigned short n);
  oXDR_Stream&   operator<<(int n);
  oXDR_Stream&   operator<<(unsigned int n);
  oXDR_Stream&   operator<<(long n);
  oXDR_Stream&   operator<<(unsigned long n);
  oXDR_Stream&   operator<<(float f);
  oXDR_Stream&   operator<<(double f);
  oXDR_Stream&   operator<<(long double f);

  //copy
  oXDR_Stream&   operator<<(XDR_Streambuf* sb);

  // opaque data inserters
  oXDR_Stream&   put_opaque(const void* d, size_t l);
  oXDR_Stream&   vput_opaque(const void* d, size_t l);

  // array inserters
  export template<typename T>
  oXDR_Stream&   put_array(const T* a, ptrdiff_t l);
  export template<typename T>
  oXDR_Stream&   vput_array(const T* a, ptrdiff_t l);

  // string inserters
  oXDR_Stream&   vput_string(const char* s, size_t l);

  // unformated output
  oXDR_Stream&   put(char_type c);
  oXDR_Stream&   write(const char_type* s, std::streamsize n);

  oXDR_Stream&   flush();

  pos_type           tellp();
  oXDR_Stream&   seekp(pos_type);
  oXDR_Stream&   seekp(off_type, ios_base::seekdir);

  // Support for reference semantics and polymorphism
  ObjToIdMap&    obj2id()    { return _obj2idMap; }
  TypeToIdMap&   type2id()   { return _type2idMap; }

protected:
  oXDR_Stream();
};

// opaque data inserters
oXDR_Stream& operator<<
  (oXDR_Stream&, const std::vector<unsigned char>& data);

// array inserters
template<typename T>
oXDR_Stream& operator<<
  (oXDR_Stream&, const std::vector<T>& data);

// string inserters
oXDR_Stream& operator<<
  (oXDR_Stream&, const char* s);
oXDR_Stream& operator<<
  (oXDR_Stream&, const signed char* s);
oXDR_Stream& operator<<
  (oXDR_Stream&, const unsigned char* s);
oXDR_Stream& operator<<
  (oXDR_Stream&, const std::string& str);

// optional data
template<typename T>
oXDR_Stream& put_optional
  (oXDR_Stream& oxs, const T* data);

// manipulators
oXDR_Stream& flush(oXDR_Stream&);

// reference objects
bool put_objId
  (oXDR_Stream& oxs, const void* obj);

// polymorphic objects
bool put_typeId
  (oXDR_Stream& oxs, const std::string& type);

//
// Input / output streams
//
class XDR_Stream : 
  public iXDR_Stream, public oXDR_Stream {
public:
  XDR_Stream(XDR_Streambuf* sb);
  virtual ~XDR_Stream();

protected:
  XDR_Stream();
};


//
// Inline implemetations
//


//
// XDR_Char_Traits
//
inline void
XDR_Char_Traits::assign
  (char_type& c1, const char_type& c2)
{  c1 = c2; }

inline bool
XDR_Char_Traits::eq
  (const char_type& c1, const char_type& c2)
{  return c1 == c2; }

inline bool
XDR_Char_Traits::lt
  (const char_type& c1, const char_type& c2)
{  return c1 < c2; }

inline XDR_Char_Traits::int_type
XDR_Char_Traits::not_eof(const int_type& c)
{  return (eq_int_type(eof(), c) ? 0 : c); }

inline XDR_Char_Traits::char_type
XDR_Char_Traits::to_char_type(const int_type& c)
{  return c; }

inline XDR_Char_Traits::int_type
XDR_Char_Traits::to_int_type(const char_type& c)
{  return c; }

inline bool
XDR_Char_Traits::eq_int_type
  (const int_type& c1, const int_type& c2)
{  return c1 == c2; }

inline XDR_Char_Traits::int_type
XDR_Char_Traits::eof() 
{  return -1; }


//
// iXDR_Stream -
//  member functions
inline iXDR_Stream&
iXDR_Stream::operator>>
  (iXDR_Stream& (*pf)(iXDR_Stream&))
{
  pf(*this); return *this;
}

inline iXDR_Stream&
iXDR_Stream::operator>>
  (inherited& (*pf)(inherited&))
{
  pf(*this); return *this;
}

inline iXDR_Stream&
iXDR_Stream::operator>>
  (std::ios_base& (*pf)(std::ios_base&))
{
  pf(*this); return *this;
}


// iXDR_Stream -
//  non-member functions
inline iXDR_Stream&
operator>>
  (iXDR_Stream& xis, signed char* s)
{
  return operator>>
  (xis, reinterpret_cast<char*>(s));
}


inline iXDR_Stream&
operator>>
  (iXDR_Stream& xis, unsigned char* s)
{
  return operator>>
  (xis, reinterpret_cast<char*>(s));
}


//
// oXDR_Stream -
//  member functions
inline oXDR_Stream&
oXDR_Stream::operator<<
  (oXDR_Stream& (*pf)(oXDR_Stream&))
{
  pf(*this); return *this;
}
  

inline oXDR_Stream&
oXDR_Stream::operator<<
  (inherited& (*pf)(inherited&))
{
  pf(*this); return *this;
}


inline oXDR_Stream&
oXDR_Stream::operator<<
  (std::ios_base& (*pf)(std::ios_base&))
{
  pf(*this); return *this;
}


inline oXDR_Stream&
oXDR_Stream::operator<<(bool n)
{
  return operator<<
  (static_cast<long>(n ? 1 : 0));
}
  

inline oXDR_Stream&
oXDR_Stream::operator<<(char n)
{
  return operator<<
    (static_cast<long>( static_cast<signed char>(n) ));
}


inline oXDR_Stream& 
oXDR_Stream::operator<<(signed char n)
{
  return operator<<
    (static_cast<long>(n));
}


inline oXDR_Stream&
oXDR_Stream::operator<<(unsigned char n)
{
  return operator<<
    (static_cast<unsigned long>(n));
}


inline oXDR_Stream&
oXDR_Stream::operator<<(short n)
{
  return operator<<
    (static_cast<long>(n));
}


inline oXDR_Stream&
oXDR_Stream::operator<<(unsigned short n)
{
  return operator<<
    (static_cast<unsigned long>(n));
}


inline oXDR_Stream&
oXDR_Stream::operator<<(int n)
{
  return operator<<
    (static_cast<long>(n));
}


inline oXDR_Stream&
oXDR_Stream::operator<<(unsigned int n)
{
  return operator<<
    (static_cast<unsigned long>(n));
}


//
// oXDR_Stream -
//  non-member functions
inline oXDR_Stream&
operator<<
  (oXDR_Stream& oxs, const std::vector<unsigned char>& d)
{
  return oxs.vput_opaque(&d[0], d.size());
}


template<typename T>
inline oXDR_Stream&
operator<<
  (oXDR_Stream& oxs, 
  const std::vector<T>& v)
{
  return oxs.vput_array(&v[0], v.size());
}


inline oXDR_Stream&
operator<<
  (oXDR_Stream& oxs, const char* s)
{
  return oxs.vput_string(s, ::strlen(s));
}


inline oXDR_Stream&
operator<<
  (oXDR_Stream& oxs, const signed char* s)
{
  return oxs << reinterpret_cast<const char*>(s);
}


inline oXDR_Stream&
operator<<
  (oXDR_Stream& oxs, const unsigned char* s)
{
  return oxs << reinterpret_cast<const char*>(s);
}


inline oXDR_Stream&
operator<<
  (oXDR_Stream& oxs, const std::string& str)
{
  return oxs.vput_string(str.data(), str.size());
}


//
// oXDR_Stream -
//  manipulators
inline oXDR_Stream&
flush(oXDR_Stream& oxs)
{
  return oxs.flush();
}

} //> namespace Util


#ifdef EXPORT_NOT_SUPPORTED
#include "XDRStream_reader.hxx"
#include "XDRStream_writer.hxx"
#endif

#endif