/*
 *                         Vortex OpenSplice
 *
 *   This software and documentation are Copyright 2006 to TO_YEAR ADLINK
 *   Technology Limited, its affiliated companies and licensors. All rights
 *   reserved.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

#include "dds_dcps.h"
#include "sac_common.h"
#include "sac_objManag.h"
#include "sac_typeSupport.h"
#include "sac_object.h"
#include "sac_entity.h"
#include "sac_domainParticipant.h"
#include "sac_domainParticipantFactory.h"
#include "sac_genericCopyIn.h"
#include "sac_genericCopyOut.h"
#include "u_entity.h"
#include "u_domain.h"
#include "sd_typeInfoParser.h"
#include "sac_report.h"
#include "os_atomics.h"

#define DDS_TypeSupportClaim(_this, typeSupport) \
        DDS_Object_claim(DDS_Object(_this), DDS_TYPESUPPORT, (_Object *)typeSupport)

#define DDS_TypeSupportClaimRead(_this, typeSupport) \
        DDS_Object_claim(DDS_Object(_this), DDS_TYPESUPPORT, (_Object *)typeSupport)

#define DDS_TypeSupportRelease(_this) \
        DDS_Object_release(DDS_Object(_this))

#define DDS_TypeSupportCheck(_this, typeSupport) \
        DDS_Object_check_and_assign(DDS_Object(_this), DDS_TYPESUPPORT, (_Object *)typeSupport)

static DDS_ReturnCode_t
_TypeSupport_deinit (
    _Object _this)
{
    _TypeSupport ts;
    DDS_ReturnCode_t result;

    ts = _TypeSupport(_this);
    if (ts != NULL) {
        DDS_free(ts->type_name);
        DDS_free(ts->type_keys);
        /* In case type_descArrSize is set to -1 we have a user provided descriptor
         * string, that is equal to an array with only one string element, that
         * was duplicated upon the creation of this TypeSupport. So then and only
         * then release it, since in all other cases the array consists of const
         * string literals that may not be released.
         */
        if (ts->type_descArrSize == -1) {
            DDS_free((DDS_char *) ts->type_desc[0]);
            os_free((void *) ts->type_desc);
        }
        if (ts->copy_cache) {
            DDS_copyCacheFree(ts->copy_cache);
        }
        result = DDS_RETCODE_OK;
    } else {
        result = DDS_RETCODE_BAD_PARAMETER;
        SAC_REPORT(result, "Invalid TypeSupport");
    }
    return result;
}

DDS_TypeSupport
DDS_TypeSupportNew(
    const DDS_char *type_name,
    const DDS_char *internal_type_name,
    const DDS_char *type_keys,
    const DDS_char **type_desc,
    int type_descArrSize,
    int type_descLength,
    const DDS_copyIn copy_in,
    const DDS_copyOut copy_out,
    const DDS_unsigned_long alloc_size,
    const DDS_allocBuffer alloc_buffer)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;

    result = DDS_Object_new(DDS_TYPESUPPORT, _TypeSupport_deinit, (_Object *)&ts);
    if (result == DDS_RETCODE_OK) {
        ts->type_name = DDS_string_dup(type_name);
        /* internal_type_name does not need to be duplicated:
         * it always points to an already allocated string.
         * (Either the type_name, which is already duplicated,
         * or the internal type name which is always a constant)
         * It will therefore not be released afterwards.
         */
        if (strlen(internal_type_name) == 0) {
            ts->internal_type_name = ts->type_name;
        } else {
            ts->internal_type_name = internal_type_name;
        }
        ts->type_keys = DDS_string_dup(type_keys);
        ts->type_descArrSize = type_descArrSize;
        ts->type_descLength = type_descLength;
        /* We cannot guarantee that the type descriptor delivered by
         * a user for use in the Generic and Typeless API is always
         * a constant, so we will need to make a duplicate of it.
         * In all other cases, the typedescriptor is generated by
         * idlpp and consists of an array of const literals, which
         * will not need to be duplicated. In that case the size
         * of the array is passed in  type_descArrSize.
         * To distinguish the idlpp provided descriptor from the
         * user provided descriptor, we set type_descArrSize to
         * -1 in the latter case. That way the TypeSupport knows
         * that it will need to handle this case separately, by
         * making a duplicacate that also removes any unnecessary
         * white-spaces.
         * IMPORTANT: We deliberately choose to NOT concatenate the
         * descriptor at the creation of this TypeSupport, since the
         * descriptor will be stored in heap for the lifetime of the
         * participants to which it is registered. Typedescriptors
         * can become quite large, and we want to avoid using
         * unnecessary heap space, especially on embedded platforms
         * which might not have a lot of memory to offer in the first
         * place. Instead we will just concatenate them on request,
         * since that happens only once per participant and it is
         * not time-critical.
         */
        if (type_descArrSize == -1) {
            ts->type_desc = os_malloc(sizeof(DDS_char *));
            ts->type_desc[0] = DDS_string_dup_no_spaces(*type_desc);
        } else {
            ts->type_desc = type_desc;
        }
        ts->copy_in = copy_in;
        ts->copy_out = copy_out;
        ts->copy_cache = NULL;
        ts->alloc_size = alloc_size;
        ts->alloc_buffer = alloc_buffer;
    }
    return DDS_TypeSupport(ts);
}

DDS_TypeSupport
DDS_TypeSupport__alloc(const DDS_char *name, const DDS_char *keys, const DDS_char *spec)
{
    /* Set type_descArrSize to -1 to indicate a User-provided descriptor string. */
    return DDS_TypeSupportNew(name, "", keys, &spec, -1, -1, NULL, NULL, 0, NULL);
}



typedef struct {
    DDS_registerType load_function;
    DDS_ReturnCode_t result;
} register_typeActionArg;


static DDS_ReturnCode_t
_TypeSupport_load_type(
    _TypeSupport ts,
    const DDS_DomainParticipant dp)
{
    DDS_ReturnCode_t result;
    u_result uResult;
    u_participant uParticipant;
    u_domain uDomain;

    assert(ts != NULL);
    assert(dp != NULL);

    result = DDS_Entity_get_user_entity(dp, DDS_DOMAINPARTICIPANT, (u_entity *)&uParticipant);
    if (result == DDS_RETCODE_OK ) {
        uDomain = u_participantDomain(uParticipant);
        if ( ts->type_desc ) {
            DDS_char *descriptor = DDS_TypeSupport_get_description((DDS_TypeSupport) ts);
            uResult = u_domain_load_xml_descriptor(uDomain, descriptor);
            result = DDS_ReturnCode_get(uResult);
            DDS_free(descriptor);
        } else {
            /* nothing to do */
            result = DDS_RETCODE_OK;
        }
    }
    if ( result == DDS_RETCODE_OK ) {
        /* If either of the copy routines is NULL,
         * the generic copy routines will be used for both
         */
        if( (ts->copy_in  == NULL) || (ts->copy_out == NULL))
        {
            c_metaObject md;

            ts->copy_in  = (DDS_copyIn)DDS_copyInStruct;
            ts->copy_out = (DDS_copyOut)DDS_copyOutStruct;

            md = c_metaObject(u_domain_lookup_type(uDomain, ts->type_name));
            if (md != NULL)
            {
                ts->copy_cache = DDS_copyCacheNew(md) ;
                /* TODO: next 9 line should move to DDS_copyCacheNew() */
                if ( ts->copy_cache != NULL ) {
                    if ( ts->alloc_size == 0 ) {
                        ts->alloc_size = DDS_copyCacheGetUserSize(ts->copy_cache);
                    } else {
                        assert(ts->alloc_size == DDS_copyCacheGetUserSize(ts->copy_cache));
                    }
                } else {
                    result = DDS_RETCODE_OUT_OF_RESOURCES;
                }
                c_free(md);
            }
            else
            {
                result = DDS_RETCODE_BAD_PARAMETER;
                SAC_REPORT(result, "Could not lookup type %s", ts->type_name);
            }
        }
    }

    return result;
}

DDS_ReturnCode_t
DDS_TypeSupport_register_type(
    DDS_TypeSupport _this,
    const DDS_DomainParticipant dp,
    const DDS_char *name)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_TypeSupport found;
    const DDS_char *regName = NULL;
    DDS_char *typeName = NULL;
    DDS_char *typeKeys = NULL;

    SAC_REPORT_STACK();

    result = DDS_TypeSupportClaim(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        if ( name ) {
            regName = name;
        } else {
            regName = ts->type_name;
        }
        if ( !regName ) {
            result = DDS_RETCODE_PRECONDITION_NOT_MET;
            SAC_REPORT(result, "No type name specified");
        } else {
            result = DDS_DomainParticipant_find_type(dp, regName, &found);
            if ( result == DDS_RETCODE_OK ) {
                if (found != NULL) {
                    if (found != _this) {
                        /* registry type name is used before */
                        /* OSPL-103: PRECONDITION_NOT_MET must be returned if type_keys
                           does not match. _TypeSupportEquals uses a simple strcmp to
                           verify, I'm assuming that's enough and the order of keys is out
                           of our scope. */
                        typeName = DDS_TypeSupport_get_type_name(found);
                        typeKeys = DDS_TypeSupport_get_key_list(found);
                        if ((typeName != NULL) && (typeKeys != NULL)) {
                            if (strcmp(ts->type_name, typeName) != 0) {
                                result = DDS_RETCODE_PRECONDITION_NOT_MET;
                                SAC_REPORT(result,
                                           "Type \"%s\" already registered with different name \"%s\"",
                                           ts->type_name, typeName);
                            }
                            if (strcmp(ts->type_keys, typeKeys) != 0) {
                                result = DDS_RETCODE_PRECONDITION_NOT_MET;
                                SAC_REPORT(result,
                                           "Type \"%s\" already registered with different keys \"%s != %s\"",
                                           ts->type_name, ts->type_keys, typeKeys);
                            }
                        } else {
                            result = DDS_RETCODE_ERROR;
                        }
                        DDS_free(typeName);
                        DDS_free(typeKeys);
                    }
                } else {
                    result = _TypeSupport_load_type(ts, dp);
                }
            }
        }
        DDS_TypeSupportRelease(_this);
        if ( result == DDS_RETCODE_OK ) {
            result = DDS_DomainParticipant_register_type(dp, regName, ts);
        }
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);
    return result;
}

DDS_char *
DDS_TypeSupport_get_description(
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_char *description = NULL;

    SAC_REPORT_STACK();

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        int i, nrLiterals;
        os_size_t strlength = 0;
        /* In case type_descArrSize is set to -1 we have a user provided descriptor
         * string, that is equal to an array with only one string element.
         */
        if (ts->type_descArrSize == -1) {
            assert(ts->type_descLength == -1);
            nrLiterals = 1;
            strlength = strlen(ts->type_desc[0]);
        } else {
            nrLiterals = ts->type_descArrSize;
            strlength = ts->type_descLength;
        }

        description = (DDS_char *)DDS_string_alloc(strlength+1);
        description[0] = '\0';
        for (i = 0; i < nrLiterals; i++) {
            strncat(description, ts->type_desc[i], strlength);
        }
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);
    return description;
}

DDS_string
DDS_TypeSupport_get_key_list(
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_string keys = NULL;

    SAC_REPORT_STACK();

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        keys = DDS_string_dup(ts->type_keys);
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);
    return keys;
}

DDS_TypeSupport
DDS_TypeSupportKeep(
   DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;

    SAC_REPORT_STACK();

    result = DDS_TypeSupportClaim(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        DDS_keep(_this);
        DDS_TypeSupportRelease(_this);
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);
    return _this;
}

DDS_string
DDS_TypeSupport_get_type_name(
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_string name = NULL;

    SAC_REPORT_STACK();

    result = DDS_TypeSupportClaimRead(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        name = DDS_string_dup(ts->type_name);
        DDS_TypeSupportRelease(_this);
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);
    return name;
}

DDS_string
DDS_TypeSupport_get_internal_type_name(
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_string name = NULL;

    SAC_REPORT_STACK();

    result = DDS_TypeSupportClaimRead(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        name = DDS_string_dup(ts->internal_type_name);
        DDS_TypeSupportRelease(_this);
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);
    return name;
}

DDS_long
DDS_TypeSupport_get_alloc_size (
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_long size = 0;

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        size = ts->alloc_size;
    }
    return size;
}

DDS_allocBuffer
DDS_TypeSupport_get_alloc_buffer (
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_allocBuffer buffer = NULL;

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        buffer = ts->alloc_buffer;
    }
    return buffer;
}

DDS_copyIn
DDS_TypeSupportCopyIn (
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_copyIn func = NULL;

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        func = ts->copy_in;
    }
    return func;
}

DDS_copyOut
DDS_TypeSupportCopyOut (
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_copyOut func = NULL;

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        func = ts->copy_out;
    }
    return func;
}

DDS_copyCache
DDS_TypeSupportCopyCache (
    DDS_TypeSupport _this)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;
    DDS_copyCache func = NULL;

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        func = ts->copy_cache;
    }
    return func;
}

void *
DDS_TypeSupport_allocbuf(
    DDS_TypeSupport _this,
    DDS_unsigned_long len)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts = NULL;
    void *buffer = NULL;

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        if ( ts->alloc_buffer ) {
            buffer = ts->alloc_buffer(len);
        } else {
            if ( ts->copy_cache ) {
                buffer = DDS_copyOutAllocBuffer(ts->copy_cache, len);
            } else {
                buffer = NULL;
            }
        }
    }
    return buffer;
}

typedef struct DDS_ParserCallbackArg_s {
    DDS_TypeParserCallback  callback;
    void                    *argument;
} DDS_ParserCallbackArg;

static DDS_TypeElementKind typeInfoKindConversion (sd_typeInfoKind kind)
{
    switch (kind) {
        case SD_TYPEINFO_KIND_MODULE:      return DDS_TYPE_ELEMENT_KIND_MODULE;
        case SD_TYPEINFO_KIND_STRUCT:      return DDS_TYPE_ELEMENT_KIND_STRUCT;
        case SD_TYPEINFO_KIND_MEMBER:      return DDS_TYPE_ELEMENT_KIND_MEMBER;
        case SD_TYPEINFO_KIND_UNION:       return DDS_TYPE_ELEMENT_KIND_UNION;
        case SD_TYPEINFO_KIND_UNIONCASE:   return DDS_TYPE_ELEMENT_KIND_UNIONCASE;
        case SD_TYPEINFO_KIND_UNIONSWITCH: return DDS_TYPE_ELEMENT_KIND_UNIONSWITCH;
        case SD_TYPEINFO_KIND_UNIONLABEL:  return DDS_TYPE_ELEMENT_KIND_UNIONLABEL;
        case SD_TYPEINFO_KIND_TYPEDEF:     return DDS_TYPE_ELEMENT_KIND_TYPEDEF;
        case SD_TYPEINFO_KIND_ENUM:        return DDS_TYPE_ELEMENT_KIND_ENUM;
        case SD_TYPEINFO_KIND_ENUMLABEL:   return DDS_TYPE_ELEMENT_KIND_ENUMLABEL;
        case SD_TYPEINFO_KIND_TYPE:        return DDS_TYPE_ELEMENT_KIND_TYPE;
        case SD_TYPEINFO_KIND_ARRAY:       return DDS_TYPE_ELEMENT_KIND_ARRAY;
        case SD_TYPEINFO_KIND_SEQUENCE:    return DDS_TYPE_ELEMENT_KIND_SEQUENCE;
        case SD_TYPEINFO_KIND_STRING:      return DDS_TYPE_ELEMENT_KIND_STRING;
        case SD_TYPEINFO_KIND_CHAR:        return DDS_TYPE_ELEMENT_KIND_CHAR;
        case SD_TYPEINFO_KIND_BOOLEAN:     return DDS_TYPE_ELEMENT_KIND_BOOLEAN;
        case SD_TYPEINFO_KIND_OCTET:       return DDS_TYPE_ELEMENT_KIND_OCTET;
        case SD_TYPEINFO_KIND_SHORT:       return DDS_TYPE_ELEMENT_KIND_SHORT;
        case SD_TYPEINFO_KIND_USHORT:      return DDS_TYPE_ELEMENT_KIND_USHORT;
        case SD_TYPEINFO_KIND_LONG:        return DDS_TYPE_ELEMENT_KIND_LONG;
        case SD_TYPEINFO_KIND_ULONG:       return DDS_TYPE_ELEMENT_KIND_ULONG;
        case SD_TYPEINFO_KIND_LONGLONG:    return DDS_TYPE_ELEMENT_KIND_LONGLONG;
        case SD_TYPEINFO_KIND_ULONGLONG:   return DDS_TYPE_ELEMENT_KIND_ULONGLONG;
        case SD_TYPEINFO_KIND_FLOAT:       return DDS_TYPE_ELEMENT_KIND_FLOAT;
        case SD_TYPEINFO_KIND_DOUBLE:      return DDS_TYPE_ELEMENT_KIND_DOUBLE;
        case SD_TYPEINFO_KIND_TIME:        return DDS_TYPE_ELEMENT_KIND_TIME;
        case SD_TYPEINFO_KIND_UNIONLABELDEFAULT: return DDS_TYPE_ELEMENT_KIND_UNIONLABELDEFAULT;
    }
    assert(0);
    return (DDS_TypeElementKind) 0;
}

static c_bool
DDS_ParserCallback (
    sd_typeInfoKind   kind,
    c_char           *name,
    sd_list           attributes,
    void             *argument,
    sd_typeInfoHandle handle)
{
    DDS_ParserCallbackArg *info = (DDS_ParserCallbackArg *) argument;
    DDS_TypeAttributeSeq   seq;
    DDS_unsigned_long      size;
    DDS_unsigned_long      i;
    c_bool                  result = FALSE;

    memset(&seq, 0, sizeof(seq));

    size = sd_listSize(attributes);
    if ( size > 0 ) {
        seq._buffer  = os_malloc(sizeof(DDS_TypeAttribute) * size);
        seq._maximum = size;
        seq._length  = size;

        for ( i = 0; i < size; i++ ) {
            sd_typeInfoAttribute *attribute = sd_listAt(attributes, i);
            seq._buffer[i].name = attribute->name;
            switch ( attribute->d ) {
                case SD_TYPEINFO_ATTR_KIND_STRING:
                    seq._buffer[i].value._d = DDS_TYPE_ATTRIBUTE_KIND_STRING;
                    seq._buffer[i].value._u.svalue = attribute->u.svalue;
                    break;
                case SD_TYPEINFO_ATTR_KIND_NUMBER:
                    seq._buffer[i].value._d = DDS_TYPE_ATTRIBUTE_KIND_NUMBER;
                    seq._buffer[i].value._u.nvalue = attribute->u.nvalue;
                    break;
            }
        }
    }
    if ( info->callback ) {
        if ( info->callback(typeInfoKindConversion(kind), name, &seq, handle, info->argument) ) {
            result = TRUE;
        }
    }
    if ( seq._length > 0 ) {
        os_free(seq._buffer);
    }
    return result;
}

DDS_ReturnCode_t
DDS_TypeSupport_parse_type_description(
    const DDS_string        description,
    DDS_TypeParserCallback  callback,
    void                   *argument)
{
    DDS_ReturnCode_t result = DDS_RETCODE_BAD_PARAMETER;
    DDS_ParserCallbackArg info;
    sd_errorReport errorInfo = NULL;

    SAC_REPORT_STACK();

    info.callback = callback;
    info.argument = argument;

    if ( sd_typeInfoParserParse((c_char *)description,
                                DDS_ParserCallback,
                                &info,
                                &errorInfo) )
    {
        result = DDS_RETCODE_OK;
    } else {
        sd_errorReportFlush(errorInfo);
        sd_errorReportFree(errorInfo);
    }
    SAC_REPORT_FLUSH(NULL, result != DDS_RETCODE_OK);
    return result;
}

DDS_ReturnCode_t
DDS_TypeSupport_walk_type_description(
    DDS_TypeParserHandle    handle,
    DDS_TypeParserCallback  callback,
    void                   *argument)
{
    DDS_ReturnCode_t result = DDS_RETCODE_BAD_PARAMETER;
    DDS_ParserCallbackArg info;

    if ( callback ) {
        info.callback = callback;
        info.argument = argument;

        if ( sd_typeInfoParserNext((sd_typeInfoHandle)handle,
                                   DDS_ParserCallback,
                                   &info) )
        {
            result = DDS_RETCODE_OK;
        }
    } else {
        if ( sd_typeInfoParserNext((sd_typeInfoHandle)handle, NULL, NULL) )
        {
            result = DDS_RETCODE_OK;
        }
    }
    return result;
}

DDS_ReturnCode_t
DDS_TypeSupport_compatible(
    DDS_TypeSupport _this,
    const DDS_DomainParticipant dp)
{
    DDS_ReturnCode_t result;
    _TypeSupport ts;

    u_participant uParticipant;
    u_domain uDomain;
    u_result uResult;

    assert(_this);
    assert(dp);

    SAC_REPORT_STACK();

    result = DDS_TypeSupportCheck(_this, &ts);
    if (result == DDS_RETCODE_OK) {
        if ( ts->type_desc ) {
            DDS_char *descriptor = DDS_TypeSupport_get_description(_this);
            result = DDS_Entity_get_user_entity(dp, DDS_DOMAINPARTICIPANT, (u_entity *)&uParticipant);
            assert(result == DDS_RETCODE_OK);
            uDomain = u_participantDomain(uParticipant);
            assert(uDomain);
            /* Try to re-load this descriptor to see if it is compatible
             * with the current in the given domain. */
            uResult = u_domain_load_xml_descriptor(uDomain, descriptor);
            result = DDS_ReturnCode_get(uResult);
            DDS_free(descriptor);
        }
    }
    SAC_REPORT_FLUSH(_this, result != DDS_RETCODE_OK);

    return result;
}

struct DDS_TypeSupportCopyInfo_s
{
    DDS_unsigned_long allocSize; /* the buffer element type size. */
    DDS_allocBuffer allocBuffer;
    DDS_copyCache copyCache;
    DDS_copyOut copy_out;
};

DDS_TypeSupportCopyInfo
DDS_TypeSupportCopyInfo_new (
    DDS_TypeSupport typeSupport)
{
    DDS_ReturnCode_t result;
    DDS_TypeSupportCopyInfo info = NULL;
    _TypeSupport ts;

    result = DDS_TypeSupportCheck(typeSupport, &ts);
    if (result == DDS_RETCODE_OK) {
        info = os_malloc(sizeof(*info));
        info->allocBuffer = ts->alloc_buffer;
        info->allocSize = ts->alloc_size;
        info->copyCache = ts->copy_cache;
        info->copy_out = ts->copy_out;
    }

    return info;
}

void
DDS_TypeSupportCopyInfo_free(
   DDS_TypeSupportCopyInfo _this)
{
    os_free(_this);
}


DDS_unsigned_long
DDS_TypeSupportCopyInfo_alloc_size (
    DDS_TypeSupportCopyInfo _this)
{
    if (_this) {
        return _this->allocSize;
    }

    return 0;
}

void *
DDS_TypeSupportCopyInfo_alloc_buffer (
    DDS_TypeSupportCopyInfo _this,
    DDS_long length)
{
    void *buffer = NULL;

    if (_this) {
        if (_this->allocBuffer != NULL) {
            buffer = _this->allocBuffer(length);
        } else {
            buffer = DDS_copyOutAllocBuffer(_this->copyCache, length);
        }
    }

    return buffer;
}

void
DDS_TypeSupportCopyInfo_copy_out (
    DDS_TypeSupportCopyInfo _this,
    void *buffer,
    void *dst,
    void *src)
{
    C_STRUCT(DDS_dstInfo) dstInfo;

    if (_this) {
        if (_this->copyCache != NULL) {
            dstInfo.dst         = dst;
            dstInfo.buf         = buffer;
            dstInfo.copyProgram = _this->copyCache;
            _this->copy_out(src, &dstInfo);
        } else {
            _this->copy_out(src, dst);
        }
    }
}
