// -*- C++ -*- // // $Id$ #include "CDR_Encaps_Codec.h" #include "CDR.h" #include "OctetSeqC.h" #include "Any.h" #include "Any_Impl.h" #include "Typecode.h" #include "Marshal.h" #include "Any_Unknown_IDL_Type.h" #include "SystemException.h" #include "ORB_Constants.h" #include "ace/OS_NS_string.h" ACE_RCSID (tao, CDR_Encaps_Codec, "$Id$") TAO_CDR_Encaps_Codec::TAO_CDR_Encaps_Codec (CORBA::Octet major, CORBA::Octet minor, TAO_ORB_Core * orb_core) : major_ (major), minor_ (minor), orb_core_ (orb_core) { } TAO_CDR_Encaps_Codec::~TAO_CDR_Encaps_Codec (void) { } CORBA::OctetSeq * TAO_CDR_Encaps_Codec::encode (const CORBA::Any & data ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, IOP::Codec::InvalidTypeForEncoding)) { this->check_type_for_encoding (data ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (0); // ---------------------------------------------------------------- TAO_OutputCDR cdr ((size_t) 0, // size (int) TAO_ENCAP_BYTE_ORDER, (ACE_Allocator *) 0, // buffer_allocator (ACE_Allocator *) 0, // data_block_allocator (ACE_Allocator *) 0, // message_block_allocator 0, // memcpy_tradeoff this->major_, this->minor_); if ((cdr << TAO_OutputCDR::from_boolean (TAO_ENCAP_BYTE_ORDER)) && (cdr << data)) { CORBA::OctetSeq * octet_seq = 0; ACE_NEW_THROW_EX (octet_seq, CORBA::OctetSeq, CORBA::NO_MEMORY ( CORBA::SystemException::_tao_minor_code ( 0, ENOMEM), CORBA::COMPLETED_NO)); ACE_CHECK_RETURN (0); CORBA::OctetSeq_var safe_octet_seq = octet_seq; octet_seq->length (static_cast (cdr.total_length ())); CORBA::Octet *buf = octet_seq->get_buffer (); for (const ACE_Message_Block *i = cdr.begin (); i != 0; i = i->cont ()) { size_t len = i->length (); ACE_OS::memcpy (buf, i->rd_ptr (), len); buf += len; } return safe_octet_seq._retn (); } ACE_THROW_RETURN (CORBA::MARSHAL (), 0); } CORBA::Any * TAO_CDR_Encaps_Codec::decode (const CORBA::OctetSeq & data ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, IOP::Codec::FormatMismatch)) { // @todo How do we check for a format mismatch so that we can throw // a IOP::Codec::FormatMismatch exception? // @todo Is this the best way to extract the Any from the OctetSeq? // Notice that we need to extract the TypeCode and the value from // the octet sequence, and place them into the Any. We can't just // insert the octet sequence into the Any. ACE_Message_Block mb (data.length () + 2 * ACE_CDR::MAX_ALIGNMENT); ACE_CDR::mb_align (&mb); ACE_OS::memcpy (mb.rd_ptr (), data.get_buffer (), data.length ()); size_t rd_pos = mb.rd_ptr () - mb.base (); size_t wr_pos = mb.wr_ptr () - mb.base () + data.length (); TAO_InputCDR cdr (mb.data_block (), ACE_Message_Block::DONT_DELETE, rd_pos, wr_pos, ACE_CDR_BYTE_ORDER, this->major_, this->minor_, this->orb_core_); CORBA::Boolean byte_order; if (cdr >> TAO_InputCDR::to_boolean (byte_order)) { cdr.reset_byte_order (static_cast (byte_order)); CORBA::Any * any = 0; ACE_NEW_THROW_EX (any, CORBA::Any, CORBA::NO_MEMORY ( CORBA::SystemException::_tao_minor_code ( 0, ENOMEM), CORBA::COMPLETED_NO)); ACE_CHECK_RETURN (0); CORBA::Any_var safe_any = any; if (cdr >> (*any)) return safe_any._retn (); } ACE_THROW_RETURN (IOP::Codec::FormatMismatch (), 0); } CORBA::OctetSeq * TAO_CDR_Encaps_Codec::encode_value (const CORBA::Any & data ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, IOP::Codec::InvalidTypeForEncoding)) { this->check_type_for_encoding (data ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (0); // ---------------------------------------------------------------- TAO_OutputCDR cdr ((size_t) 0, // size (int) TAO_ENCAP_BYTE_ORDER, (ACE_Allocator *) 0, // buffer_allocator (ACE_Allocator *) 0, // data_block_allocator (ACE_Allocator *) 0, // message_block_allocator 0, // memcpy_tradeoff this->major_, this->minor_); if ((cdr << TAO_OutputCDR::from_boolean (TAO_ENCAP_BYTE_ORDER))) { ACE_Message_Block * mb = data._tao_get_cdr (); if (mb == 0) { ACE_NEW_THROW_EX (mb, ACE_Message_Block, CORBA::NO_MEMORY ()); ACE_CHECK_RETURN (0); TAO_OutputCDR out; CORBA::Any any (data); any.impl ()->marshal_value (out); ACE_CDR::consolidate (mb, out.begin ()); } TAO_InputCDR input (mb, data._tao_byte_order (), this->major_, this->minor_, this->orb_core_); TAO_Marshal_Object::perform_append (data._tao_get_typecode (), &input, &cdr ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (0); // TAO extension: replace the contents of the octet sequence with // the CDR stream. CORBA::OctetSeq * octet_seq = 0; ACE_NEW_THROW_EX (octet_seq, CORBA::OctetSeq, CORBA::NO_MEMORY ( CORBA::SystemException::_tao_minor_code ( 0, ENOMEM ), CORBA::COMPLETED_NO )); ACE_CHECK_RETURN (0); CORBA::OctetSeq_var safe_octet_seq = octet_seq; octet_seq->length (static_cast (cdr.total_length ())); CORBA::Octet *buf = octet_seq->get_buffer (); for (const ACE_Message_Block *i = cdr.begin (); i != 0; i = i->cont ()) { size_t len = i->length (); ACE_OS::memcpy (buf, i->rd_ptr (), len); buf += len; } return safe_octet_seq._retn (); } ACE_THROW_RETURN (CORBA::MARSHAL (), 0); } CORBA::Any * TAO_CDR_Encaps_Codec::decode_value (const CORBA::OctetSeq & data, CORBA::TypeCode_ptr tc ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, IOP::Codec::FormatMismatch, IOP::Codec::TypeMismatch)) { // The ACE_CDR::mb_align() call can shift the rd_ptr by up // to ACE_CDR::MAX_ALIGNMENT-1 bytes. Similarly, the offset // adjustment can move the rd_ptr by up to the same amount. // We accommodate this by including // 2 * ACE_CDR::MAX_ALIGNMENT bytes of additional space in // the message block. ACE_Message_Block mb (data.length () + 2 * ACE_CDR::MAX_ALIGNMENT); ACE_CDR::mb_align (&mb); ACE_OS::memcpy (mb.rd_ptr (), data.get_buffer (), data.length ()); // @todo How do we check for a type mismatch so that we can // throw a IOP::Codec::TypeMismatch exception? // @@ I added a check below. See the comment. I'm not sure // if it is a valid check. // -Ossama // @todo Most of this code was copied from // operator>> (TAO_InputCDR &cdr, CORBA::Any &x) // in Any.cpp. Rather than copy the code, the code should be // refactored to make it possible to use the given TypeCode // rather than attempt to extract it from the CDR // encapsulation. CORBA::ULong sequence_length = data.length (); size_t rd_pos = mb.rd_ptr () - mb.base (); size_t wr_pos = mb.wr_ptr () - mb.base () + data.length (); TAO_InputCDR cdr (mb.data_block (), ACE_Message_Block::DONT_DELETE, rd_pos, wr_pos, ACE_CDR_BYTE_ORDER, this->major_, this->minor_, this->orb_core_); CORBA::Boolean byte_order; if (cdr >> TAO_InputCDR::to_boolean (byte_order)) { cdr.reset_byte_order (static_cast (byte_order)); // @@ (JP) The following code depends on the fact that // TAO_InputCDR does not contain chained message blocks, // otherwise and could be part of // different buffers! // This will be the start of a new message block. char *begin = cdr.rd_ptr (); // Skip over the next argument. TAO::traverse_status status = TAO_Marshal_Object::perform_skip (tc, &cdr ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (0); // @@ Should we throw a // IOP::Codec::TypeMismatch exception // here if this fails? if (status == TAO::TRAVERSE_CONTINUE) { // This will be the end of the new message block. char *end = cdr.rd_ptr (); size_t size = end - begin; // @@ I added the following check, but I'm not sure if it is // a valid check. Can someone verify this? // -Ossama // If the unaligned buffer size is not equal to the octet // sequence length (minus the "byte order byte") then the // TypeCode does not correspond to the data in the CDR // encapsulation. However, even if they do match it is // still uncertain if the TypeCode corresponds to the data // in the octet sequence. With this test, it is only // possible to determine if the TypeCode does *not* match // the data, not if it does match. if (size != sequence_length - 1) { ACE_THROW_RETURN (IOP::Codec::TypeMismatch (), 0); } ptrdiff_t offset = ptrdiff_t (begin) % ACE_CDR::MAX_ALIGNMENT; if (offset < 0) offset += ACE_CDR::MAX_ALIGNMENT; mb.rd_ptr (offset); mb.wr_ptr (offset + size); CORBA::Any * any = 0; ACE_NEW_THROW_EX (any, CORBA::Any, CORBA::NO_MEMORY ( CORBA::SystemException::_tao_minor_code ( 0, ENOMEM ), CORBA::COMPLETED_NO )); ACE_CHECK_RETURN (0); CORBA::Any_var safe_any = any; // Stick it into the Any. TAO::Unknown_IDL_Type *unk = 0; ACE_NEW_RETURN (unk, TAO::Unknown_IDL_Type (tc, &mb, cdr.byte_order ()), 0); any->replace (unk); return safe_any._retn (); } else { ACE_THROW_RETURN (IOP::Codec::TypeMismatch (), 0); } } ACE_THROW_RETURN (IOP::Codec::FormatMismatch (), 0); } void TAO_CDR_Encaps_Codec::check_type_for_encoding ( const CORBA::Any & data ACE_ENV_ARG_DECL ) { // @@ TODO: Are there any other conditions we need to check? CORBA::TypeCode_var typecode = data.type (); if (this->major_ == 1 && this->minor_ == 0 && typecode->equivalent (CORBA::_tc_wstring)) ACE_THROW (IOP::Codec::InvalidTypeForEncoding ()); }