/*
 * SPDX-FileCopyrightText: 2025 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
#include <tango/common/zmq_event_marshalling.h>

namespace Tango
{

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqAttrValUnion::operator<<=()
//
// description :
//        Write our own unmarshalling method. The omniORB one allocate memory and copy data. We already have memory
//        allocated in the ZMQ message. No need to allocate once more and to copy data. We are doing this only for
//        attribute data. For the remaining, keep using omniORB stuff
//
// argument :
//        in :
//            - n :
//
//-------------------------------------------------------------------------------------------------------------------

void ZmqAttrValUnion::operator<<=(TangoCdrMemoryStream &_n)
{
    char *data_ptr;
    if(_n.get_un_marshal_type() == TangoCdrMemoryStream::UN_ATT)
    {
        data_ptr = (char *) _n.bufPtr();
    }
    else
    {
        data_ptr = (char *) _n.get_mkr_in_buf();
    }

    //
    // Get union discriminator from cdr and if data type is string or device_state let omniORB do its stuff.
    // Don't forget to rewind memory ptr before returning to omniORB
    //

    AttributeDataType _pd__d = ATT_BOOL;
    _pd__d <<= _n;

    if(_pd__d == ATT_STRING || _pd__d == DEVICE_STATE)
    {
        if(_n.get_un_marshal_type() == TangoCdrMemoryStream::UN_ATT)
        {
            _n.rewindPtrs();
        }
        else
        {
            _n.rewind_in(4);
        }
        AttrValUnion::operator<<=(_n);
    }
    else
    {
        //
        // Get data length from cdr
        //

        CORBA::ULong length = 0ul;
        if(_pd__d != ATT_NO_DATA)
        {
            length <<= _n;
            if(length == 0)
            {
                return;
            }
        }

        //
        // Get att data depending on type
        //

        switch(_pd__d)
        {
        case ATT_SHORT:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_2);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevShort, DevVarShortArray>(data_ptr, length, _n);
        }
        break;

        case ATT_DOUBLE:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_8);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevDouble, DevVarDoubleArray>(data_ptr, length, _n);
        }
        break;

        case ATT_FLOAT:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_4);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevFloat, DevVarFloatArray>(data_ptr, length, _n);
        }
        break;

        case ATT_USHORT:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_2);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevUShort, DevVarUShortArray>(data_ptr, length, _n);
        }
        break;

        case ATT_BOOL:
        {
            init_seq<DevBoolean, DevVarBooleanArray>(data_ptr, length, _n);
        }
        break;

        case ATT_LONG:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_4);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevLong, DevVarLongArray>(data_ptr, length, _n);
        }
        break;

        case ATT_LONG64:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_8);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevLong64, DevVarLong64Array>(data_ptr, length, _n);
        }
        break;

        case ATT_ULONG:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_4);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevULong, DevVarULongArray>(data_ptr, length, _n);
        }
        break;

        case ATT_ULONG64:
        {
            omni::ptr_arith_t in = (omni::ptr_arith_t) _n.get_mkr_in_buf();
            omni::ptr_arith_t p1 = _n.align_to(in, omni::ALIGN_8);
            _n.set_mkr_in_buf((void *) p1);
            init_seq<DevULong64, DevVarULong64Array>(data_ptr, length, _n);
        }
        break;

        case ATT_UCHAR:
        {
            init_seq<DevUChar, DevVarUCharArray>(data_ptr, length, _n);
        }
        break;

        case ATT_STATE:
        {
            init_seq<DevState, DevVarStateArray>(data_ptr, length, _n);
        }
        break;

            //
            // We have special cases for DevEncoded (a structure) and ATT_NO_DATA
            //

        case ATT_ENCODED:
        {
            DevVarEncodedArray dummy_seq;
            encoded_att_value(dummy_seq);

            DevVarEncodedArray &dvea = encoded_att_value();
            dvea.length(length);

            for(CORBA::ULong i = 0; i < length; i++)
            {
                dvea[i].encoded_format = _n.unmarshalString(0);
                CORBA::ULong seq_length;
                seq_length <<= _n;
                _CORBA_Octet *ptr = (_CORBA_Octet *) (data_ptr + _n.currentInputPtr());
                dvea[i].encoded_data.replace(seq_length, seq_length, ptr, false);
                _n.tango_get_octet_array((seq_length * sizeof(_CORBA_Octet)));
            }
        }
        break;

        case ATT_NO_DATA:
        {
            DevBoolean bo;
            bo = _n.unmarshalBoolean();

            union_no_data(bo);
        }
        break;

        default:
            TANGO_ASSERT_ON_DEFAULT(_pd__d);
        }
    }
}

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqAttributeValue_4::operator<<=()
//
// description :
//
// argument :
//        in :
//
//--------------------------------------------------------------------------------------------------------------------

void Tango::ZmqAttributeValue_4::operator<<=(TangoCdrMemoryStream &_n)
{
    zvalue <<= _n;
    quality <<= _n;
    data_format <<= _n;
    time <<= _n;
    name = _n.unmarshalString(0);
    r_dim <<= _n;
    w_dim <<= _n;
    err_list <<= _n;
}

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqAttributeValue_5::operator<<=()
//
// description :
//
// argument :
//        in :
//
//--------------------------------------------------------------------------------------------------------------------

void Tango::ZmqAttributeValue_5::operator<<=(TangoCdrMemoryStream &_n)
{
    zvalue <<= _n;
    quality <<= _n;
    data_format <<= _n;
    data_type <<= _n;
    time <<= _n;
    name = _n.unmarshalString(0);
    r_dim <<= _n;
    w_dim <<= _n;
    err_list <<= _n;
}

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqDevPipeData::operator<<=()
//
// description :
//
// argument :
//        in :
//
//--------------------------------------------------------------------------------------------------------------------

void Tango::ZmqDevPipeData::operator<<=(TangoCdrMemoryStream &_n)
{
    name = _n.unmarshalString(0);
    time <<= _n;
    (ZmqDevPipeBlob &) data_blob <<= _n;
}

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqDevPipeBlob::operator<<=()
//
// description :
//
// argument :
//        in :
//
//--------------------------------------------------------------------------------------------------------------------

#ifdef __clang__
// UBSAN: downcast of address 0x55daeb87ca40 which does not point to an object of type
// 'Tango::ZmqDevVarPipeDataEltArray'
//        0x55daeb87ca40: note: object is of type 'Tango::DevVarPipeDataEltArray'
// TODO: All these downcasts to dummy Zmq... types are UB and eventually should be fixed.
[[clang::no_sanitize("vptr")]]
#elif defined(__GNUC__)
__attribute__((no_sanitize("vptr")))
#endif
void Tango::ZmqDevPipeBlob::operator<<=(TangoCdrMemoryStream &_n)
{
    name = _n.unmarshalString(0);
    (ZmqDevVarPipeDataEltArray &) blob_data <<= _n;
}

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqDevVarPipeDataEltArray::operator<<=()
//
// description :
//
// argument :
//        in :
//
//--------------------------------------------------------------------------------------------------------------------

void Tango::ZmqDevVarPipeDataEltArray::operator<<=(TangoCdrMemoryStream &_n)
{
    CORBA::ULong _l;
    _l <<= _n;
    if(!_n.checkInputOverrun(1, _l))
    {
        _CORBA_marshal_sequence_range_check_error(_n);
        // never reach here
    }
    length(_l);
    for(CORBA::ULong _i = 0; _i < _l; _i++)
    {
        DevPipeDataElt &dpde = pd_buf[_i];
        ZmqDevPipeDataElt &z_dpde = static_cast<ZmqDevPipeDataElt &>(dpde);
        z_dpde <<= _n;
    }
}

//--------------------------------------------------------------------------------------------------------------------
//
// method :
//        ZmqDevPipeDataElt::operator<<=()
//
// description :
//
// argument :
//        in :
//
//--------------------------------------------------------------------------------------------------------------------

#ifdef __clang__
// Same problem as in: void Tango::ZmqDevPipeBlob::operator<<= (TangoCdrMemoryStream &_n)
[[clang::no_sanitize("vptr")]]
#elif defined(__GNUC__)
__attribute__((no_sanitize("vptr")))
#endif
void Tango::ZmqDevPipeDataElt::operator<<=(TangoCdrMemoryStream &_n)
{
    name = _n.unmarshalString(0);
    (ZmqAttrValUnion &) value <<= _n;
    (ZmqDevVarPipeDataEltArray &) inner_blob <<= _n;
    inner_blob_name = _n.unmarshalString(0);
}
} // namespace Tango
