// -*- C++ -*-

//=============================================================================
/**
 *  @file    CDR.h
 *
 *   Common Data Representation (CDR) marshaling streams.
 *
 *   This implementation assumes that the native numeric
 *   representation is two's complement for integers, IEEE
 *   single/double for floats.  Also that characters are in ISO
 *   Latin/1.
 *
 *   Note that CDR itself makes no such assumptions, but this
 *   implementation makes such assumptions for reasons of
 *   efficiency.  Careful enhancements could preserve that
 *   efficiency where the assumptions are true, yet still allow the
 *   code to work when they aren't true.
 *
 *   The implementation expects that buffers are aligned according
 *   to the strongest CDR alignment restriction.
 *
 *   @note This does everything "CDR 1.1" does ... that is, it
 *   supports the five extended OMG-IDL data types in UNO Appendix
 *   A, which provide richer arithmetic types (64 bit integers,
 *   "quad precision" FP) and UNICODE-based characters and strings.
 *   Those types are not standard parts of OMG-IDL at this time.
 *
 *   THREADING NOTE: CDR data structures must be protected against
 *   concurrent access by their owning thread.
 *
 *  @author  Copyright 1994-1995 by Sun Microsystems Inc.
 *  @author  Aniruddha Gokhale
 *  @author  Carlos O'Ryan
 */
//=============================================================================


#ifndef TAO_CDR_H
#define TAO_CDR_H

#include /**/ "ace/pre.h"

#include "tao/orbconf.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include /**/ "tao/TAO_Export.h"
#include "tao/Basic_Types_IDLv4.h"
#include "tao/GIOP_Message_Version.h"
#include "tao/Message_Semantics.h"
#include "tao/Intrusive_Ref_Count_Handle_T.h"
#include "tao/Intrusive_Ref_Count_Object_T.h"

#include "ace/CDR_Stream.h"
#include "ace/SString.h"
#include "ace/Hash_Map_Manager_T.h"
#include "ace/Null_Mutex.h"

#include <string>

TAO_BEGIN_VERSIONED_NAMESPACE_DECL

class TAO_ORB_Core;
class TAO_GIOP_Fragmentation_Strategy;
class TAO_Stub;

/**
 * @class TAO_OutputCDR
 *
 * @brief A CDR stream for writing, i.e. for marshalling.
 *
 * This class is based on the the CORBA spec for Java (98-02-29),
 * java class omg.org.CORBA.portable.OutputStream.
 * It diverts in a few ways:
 * + Operations taking arrays don't have offsets, because in C++
 * it is easier to describe an array starting from x+offset.
 * + Operations return an error status, because exceptions are
 * not widely available in C++ (yet).
 * A particularly useful static member function for this buffer is
 * an interpretive encoding routine, usable as a typecode
 * interpreter callback.  Ditto for decoding.  These are used to
 * support all OMG-IDL datatypes, even those not supported
 * directly by put/get primitives.
 */
class TAO_Export TAO_OutputCDR : public ACE_OutputCDR
{
public:
  /// For reading from a output CDR stream.
  friend class TAO_InputCDR;
  typedef ACE_Hash_Map_Manager<ACE_CString, char*, ACE_Null_Mutex> Repo_Id_Map;
  typedef Repo_Id_Map Codebase_URL_Map;
  typedef ACE_Hash_Map_Manager<void*, char*, ACE_Null_Mutex> Value_Map;

  typedef TAO_Intrusive_Ref_Count_Object<Repo_Id_Map, ACE_Null_Mutex> RC_Repo_Id_Map;
  typedef TAO_Intrusive_Ref_Count_Object<Codebase_URL_Map, ACE_Null_Mutex> RC_Codebase_URL_Map;
  typedef TAO_Intrusive_Ref_Count_Object<Value_Map, ACE_Null_Mutex> RC_Value_Map;

  typedef TAO_Intrusive_Ref_Count_Handle<RC_Repo_Id_Map> Repo_Id_Map_Handle;
  typedef TAO_Intrusive_Ref_Count_Handle<RC_Codebase_URL_Map> Codebase_URL_Map_Handle;
  typedef TAO_Intrusive_Ref_Count_Handle<RC_Value_Map> Value_Map_Handle;

  // The default values for the allocators and memcpy_tradeoff
  // in these constructors are not 0, but are generated by the
  // ORB. Refer to the constructor bodies in CDR.cpp for the
  // code that supplies these values to the base class constructor.

  /// Default constructor, allocates @a size bytes in the internal
  /// buffer, if @a size == 0 it allocates the default size.
  TAO_OutputCDR (size_t size = 0,
                 int byte_order = ACE_CDR_BYTE_ORDER,
                 ACE_Allocator* buffer_allocator = 0,
                 ACE_Allocator* data_block_allocator = 0,
                 ACE_Allocator* message_block_allocator = 0,
                 size_t memcpy_tradeoff = 0,
                 ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                 ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR);

  /// Build a CDR stream with an initial buffer, it will *not* remove
  /// @a data, since it did not allocated it.
  TAO_OutputCDR (char *data,
                 size_t size,
                 int byte_order = ACE_CDR_BYTE_ORDER,
                 ACE_Allocator* buffer_allocator = 0,
                 ACE_Allocator* data_block_allocator = 0,
                 ACE_Allocator* message_block_allocator = 0,
                 size_t memcpy_tradeoff = 0,
                 ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                 ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR);

  /// Build a CDR stream with an initial buffer, it will *not* remove
  /// @a data since it did not allocated it, and enable fragmentation
  /// support.
  TAO_OutputCDR (char *data,
                 size_t size,
                 int byte_order,
                 ACE_Allocator* buffer_allocator,
                 ACE_Allocator* data_block_allocator,
                 ACE_Allocator* message_block_allocator,
                 size_t memcpy_tradeoff,
                 TAO_GIOP_Fragmentation_Strategy * fs,
                 ACE_CDR::Octet major_version,
                 ACE_CDR::Octet minor_version);

  /// Build a CDR stream with an initial Message_Block chain, it will *not*
  /// remove @a data, since it did not allocate it.
  TAO_OutputCDR (ACE_Message_Block *data,
                 int byte_order = ACE_CDR_BYTE_ORDER,
                 size_t memcpy_tradeoff = 0,
                 ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                 ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR);

  /// Build a CDR stream with an initial data block, it will *not* remove
  /// @a data, since it did not allocated it.
  TAO_OutputCDR (ACE_Data_Block *data,
                 int byte_order = ACE_CDR_BYTE_ORDER,
                 ACE_Allocator* message_block_allocator = 0,
                 size_t memcpy_tradeoff = 0,
                 TAO_GIOP_Fragmentation_Strategy * fs = 0,
                 ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                 ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR);

  /// Destructor.
  ~TAO_OutputCDR ();

  // @todo do we want a special method to write an array of
  // strings and wstrings?

  // = TAO specific methods.
  static void throw_stub_exception (int error_num);
  static void throw_skel_exception (int error_num);

  void get_version (TAO_GIOP_Message_Version& giop_version);

  /**
   * @name Outgoing GIOP Fragment Related Methods
   *
   * These methods are only used when fragmenting outgoing GIOP
   * requests and replies.
   */
  //@{
  /// Fragment this output CDR stream if necessary.
  /**
   * Fragmentation will done through GIOP fragments when the length of
   * the CDR stream length will exceed the configured threshold.
   */
  bool fragment_stream (ACE_CDR::ULong pending_alignment,
                        ACE_CDR::ULong pending_length);

  /// Are there more data fragments to come?
  bool more_fragments () const;

  /// Specify whether there are more data fragments to come.
  void more_fragments (bool more);

  /// Set fragmented message attributes.
  void message_attributes (CORBA::ULong request_id,
                           TAO_Stub * stub,
                           TAO_Message_Semantics message_semantics,
                           ACE_Time_Value * timeout);

  /// Fragmented message request ID.
  CORBA::ULong request_id () const;

  /// Stub object associated with the request.
  TAO_Stub * stub () const;

  /// Message semantics (twoway, oneway, reply)
  TAO_Message_Semantics message_semantics () const;

  /// Maximum time to wait for outgoing message to be sent.
  ACE_Time_Value * timeout () const;
  //@}

  /// These methods are used by valuetype indirection support.
  /// Accessor to the indirect maps.
  Repo_Id_Map_Handle& get_repo_id_map ();
#ifdef TAO_HAS_VALUETYPE_CODEBASE
  Codebase_URL_Map_Handle& get_codebase_url_map ();
#endif
  Value_Map_Handle& get_value_map ();

  /// Updater of the maps.
  /// These updaters are used to make indirect maps in original stream
  /// take effect even during marshalling/demarshalling a redirected stream.
  void set_repo_id_map (Repo_Id_Map_Handle& map);
#ifdef TAO_HAS_VALUETYPE_CODEBASE
  Codebase_URL_Map_Handle& get_codebase_url_map ();
  void set_codebase_url_map (Codebase_URL_Map_Handle& map);
#endif
  void set_value_map (Value_Map_Handle& map);

  /// If indirect map is not nil and not empty, unbind all entries.
  /// Called after marshalling.
  void reset_vt_indirect_maps ();

  /// Calculate the offset between pos and current wr_ptr.
  int offset (char* pos);

private:
  TAO_OutputCDR (const TAO_OutputCDR&rhs) = delete;
  TAO_OutputCDR& operator= (const TAO_OutputCDR&) = delete;
  TAO_OutputCDR (TAO_OutputCDR&&) = delete;
  TAO_OutputCDR& operator= (TAO_OutputCDR&&) = delete;

private:
  /**
   * @name Outgoing GIOP Fragment Related Attributes
   *
   * These attributes are only used when fragmenting outgoing GIOP
   * requests and replies.
   */
  //@{
  /// Strategy that sends data currently marshaled into this
  /// TAO_OutputCDR stream if necessary.
  TAO_GIOP_Fragmentation_Strategy * const fragmentation_strategy_;

  /// Are there more data fragments to come?
  bool more_fragments_;

  /// Request ID for the request currently being marshaled.
  CORBA::ULong request_id_;

  /// Stub object associated with the request.
  TAO_Stub * stub_;

  /// Twoway, oneway, reply?
  /**
   * @see TAO_Transport
   */
  TAO_Message_Semantics message_semantics_;

  /// Request/reply send timeout.
  ACE_Time_Value * timeout_;
  //@}

  /// These maps are used by valuetype indirection support.
  Repo_Id_Map_Handle repo_id_map_;
#ifdef TAO_HAS_VALUETYPE_CODEBASE
  Codebase_URL_Map_Handle codebase_map_;
#endif
  Value_Map_Handle value_map_;
};

/**
 * @class TAO_InputCDR
 *
 * @brief A CDR stream for reading, i.e. for demarshalling.
 *
 * This class is based on the the CORBA spec for Java (98-02-29),
 * java class omg.org.CORBA.portable.InputStream.
 * It diverts in a few ways:
 * + Operations to retrieve basic types take parameters by
 * reference.
 * + Operations taking arrays don't have offsets, because in C++
 * it is easier to describe an array starting from x+offset.
 * + Operations return an error status, because exceptions are
 * not widely available in C++ (yet).
 * A particularly useful static member function for this buffer is
 * an interpretive encoding routine, usable as a typecode
 * interpreter callback.  Ditto for decoding.  These are used to
 * support all OMG-IDL datatypes, even those not supported
 * directly by put/get primitives.
 */
class TAO_Export TAO_InputCDR : public ACE_InputCDR
{
public:
  typedef ACE_Hash_Map_Manager<void*, ACE_CString, ACE_Null_Mutex> Repo_Id_Map;
  typedef Repo_Id_Map Codebase_URL_Map;
  typedef ACE_Hash_Map_Manager<void*, void*, ACE_Null_Mutex> Value_Map;

  typedef TAO_Intrusive_Ref_Count_Object<Repo_Id_Map, ACE_Null_Mutex> RC_Repo_Id_Map;
  typedef TAO_Intrusive_Ref_Count_Object<Codebase_URL_Map, ACE_Null_Mutex> RC_Codebase_URL_Map;
  typedef TAO_Intrusive_Ref_Count_Object<Value_Map, ACE_Null_Mutex> RC_Value_Map;

  typedef TAO_Intrusive_Ref_Count_Handle<RC_Repo_Id_Map> Repo_Id_Map_Handle;
  typedef TAO_Intrusive_Ref_Count_Handle<RC_Codebase_URL_Map> Codebase_URL_Map_Handle;
  typedef TAO_Intrusive_Ref_Count_Handle<RC_Value_Map> Value_Map_Handle;

  /**
   * Create an input stream from an arbitrary buffer, care must be
   * exercised wrt alignment, because this constructor will *not* work
   * if the buffer is unproperly aligned.
   */
  TAO_InputCDR (const char* buf,
                size_t bufsiz,
                int byte_order = ACE_CDR_BYTE_ORDER,
                ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR,
                TAO_ORB_Core* orb_core = 0);

  /// Create an empty input stream. The caller is responsible for
  /// putting the right data and providing the right alignment.
  TAO_InputCDR (size_t bufsiz,
                int byte_order = ACE_CDR_BYTE_ORDER,
                ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR,
                TAO_ORB_Core* orb_core = 0);

  /// Create an input stream from an ACE_Message_Block
  TAO_InputCDR (const ACE_Message_Block *data,
                int byte_order = ACE_CDR_BYTE_ORDER,
                ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR,
                TAO_ORB_Core* orb_core = 0);

  /// Create an input stream from an ACE_Message_Block with an optional lock
  /// used to protect the data.
  TAO_InputCDR (const ACE_Message_Block *data,
                ACE_Lock* lock,
                int byte_order = ACE_CDR_BYTE_ORDER,
                ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR,
                TAO_ORB_Core* orb_core = 0);


  /// Create an input stream from an ACE_Data_Block
  TAO_InputCDR (ACE_Data_Block *data,
                ACE_Message_Block::Message_Flags flag = 0,
                int byte_order = ACE_CDR_BYTE_ORDER,
                ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR,
                TAO_ORB_Core* orb_core = 0);

  /// Create an input stream from an ACE_Data_Block
  TAO_InputCDR (ACE_Data_Block *data,
                ACE_Message_Block::Message_Flags flag,
                size_t read_pointer_position,
                size_t write_pointer_position,
                int byte_order = ACE_CDR_BYTE_ORDER,
                ACE_CDR::Octet major_version = TAO_DEF_GIOP_MAJOR,
                ACE_CDR::Octet minor_version = TAO_DEF_GIOP_MINOR,
                TAO_ORB_Core* orb_core = 0);

  /**
   * Make a copy of the current stream state, but does not copy the
   * internal buffer; so the same stream can be read multiple times
   * efficiently.
   */
  TAO_InputCDR (const TAO_InputCDR& rhs);

  /// When interpreting indirected TypeCodes it is useful to make a
  /// "copy" of the stream starting in the new position.
  TAO_InputCDR (const TAO_InputCDR& rhs,
                size_t size,
                ACE_CDR::Long offset);
  /**
   * This creates an encapsulated stream, the first byte must be (per
   * the spec) the byte order of the encapsulation.  The default
   * values for the allocators in this constructor are not 0, but are
   * generated by the ORB. Refer to the constructor body in CDR.cpp
   * for the code that supplies these values to the base class
   * constructor.
   */
  TAO_InputCDR (const TAO_InputCDR& rhs,
                size_t size);

  /// Create an input CDR from an output CDR.
  TAO_InputCDR (const TAO_OutputCDR& rhs,
                ACE_Allocator* buffer_allocator = 0,
                ACE_Allocator* data_block_allocator = 0,
                ACE_Allocator* message_block_allocator = 0,
                TAO_ORB_Core* orb_core = 0);

  /// Initialize the contents of one CDR from another, without data
  /// copying and with minimum locking overhead.
  TAO_InputCDR (ACE_InputCDR::Transfer_Contents rhs,
                TAO_ORB_Core* orb_core = 0);

  TAO_InputCDR& operator= (const TAO_InputCDR&) = default;

  /// Destructor
  virtual ~TAO_InputCDR ();

  // = TAO specific methods.

  /// Accessor
  TAO_ORB_Core *orb_core () const;

  ACE_Message_Block::Message_Flags
    clr_mb_flags( ACE_Message_Block::Message_Flags less_flags );

  // = TAO specific methods.
  static void throw_stub_exception (int error_num);
  static void throw_skel_exception (int error_num);

  /// These methods are used by valuetype indirection support.
  /// Accessor to the indirect maps.
  Repo_Id_Map_Handle& get_repo_id_map ();
  Codebase_URL_Map_Handle& get_codebase_url_map ();
  Value_Map_Handle& get_value_map ();

  /// Updater of the maps.
  /// These updaters are used to make indirect maps in original stream
  /// take effect even during marshalling/demarshalling a redirected stream.
  void set_repo_id_map (Repo_Id_Map_Handle& map);
  void set_codebase_url_map (Codebase_URL_Map_Handle& map);
  void set_value_map (Value_Map_Handle& map);

  /// If indirect map is not nil and not empty, unbind all entries.
  /// Called after demarshalling.
  void reset_vt_indirect_maps ();

private:
  /// The ORB_Core, required to extract object references.
  TAO_ORB_Core* orb_core_;

  /// These maps are used by valuetype indirection support.
  Repo_Id_Map_Handle repo_id_map_;
  Codebase_URL_Map_Handle codebase_map_;
  Value_Map_Handle value_map_;
};

TAO_END_VERSIONED_NAMESPACE_DECL

#if defined(__ACE_INLINE__)
# include "tao/CDR.inl"
#else

TAO_BEGIN_VERSIONED_NAMESPACE_DECL

// CDR output operators for CORBA types

TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::Short x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::UShort x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::Long x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::ULong x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::LongLong x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::ULongLong x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR& os,
                                      CORBA::LongDouble x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::Float x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      CORBA::Double x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      const CORBA::Char* x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      const CORBA::WChar* x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      ACE_OutputCDR::from_string x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      ACE_OutputCDR::from_wstring x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      const std::string &x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      ACE_OutputCDR::from_std_string x);
#if !defined(ACE_LACKS_STD_WSTRING)
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      const std::wstring &x);
TAO_Export CORBA::Boolean operator<< (TAO_OutputCDR &os,
                                      ACE_OutputCDR::from_std_wstring x);
#endif /* ACE_LACKS_STD_WSTRING */

// CDR input operators for CORBA types

TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::Short &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::UShort &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::Long &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::ULong &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::LongLong &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::ULongLong &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::LongDouble &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::Float &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::Double &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::Char* &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &is,
                                      CORBA::WChar* &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &os,
                                      ACE_InputCDR::to_string x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &os,
                                      ACE_InputCDR::to_wstring x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &os,
                                      std::string &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &os,
                                      ACE_InputCDR::to_std_string x);
#if !defined(ACE_LACKS_STD_WSTRING)
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &os,
                                      std::wstring &x);
TAO_Export CORBA::Boolean operator>> (TAO_InputCDR &os,
                                      ACE_InputCDR::to_std_wstring x);
#endif /* ACE_LACKS_STD_WSTRING */

TAO_END_VERSIONED_NAMESPACE_DECL

#endif /* __ACE_INLINE */

#include /**/ "ace/post.h"
#endif /* TAO_CDR_H */
