/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef COPY_HXX
#define COPY_HXX

#include "prim.hxx"
#include "constr.hxx"


namespace cppu
{

//##################################################################################################
//#### copy construction ###########################################################################
//##################################################################################################

//------------------------------------------------------------------------------
inline uno_Sequence * allocSeq(
    sal_Int32 nElementSize, sal_Int32 nElements )
{
    OSL_ASSERT( nElements >= 0 && nElementSize >= 0 );
    uno_Sequence * pSeq = 0;
    sal_uInt32 nSize = calcSeqMemSize( nElementSize, nElements );
    if (nSize > 0)
    {
        pSeq = (uno_Sequence *) rtl_allocateMemory( nSize );
        if (pSeq != 0)
        {
            // header init
            pSeq->nRefCount = 1;
            pSeq->nElements = nElements;
        }
    }
    return pSeq;
}

//--------------------------------------------------------------------------------------------------
void copyConstructStruct(
    void * pDest, void * pSource,
    typelib_CompoundTypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
    SAL_THROW ( () );
//--------------------------------------------------------------------------------------------------
inline void _copyConstructStruct(
    void * pDest, void * pSource,
    typelib_CompoundTypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
    SAL_THROW ( () )
{
    if (pTypeDescr->pBaseTypeDescription)
    {
        // copy base value
        copyConstructStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription, acquire, mapping );
    }

    // then copy members
    typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs;
    sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
    sal_Int32 nDescr = pTypeDescr->nMembers;

    if (mapping)
    {
        while (nDescr--)
        {
            ::uno_type_copyAndConvertData(
                (char *)pDest + pMemberOffsets[nDescr],
                (char *)pSource + pMemberOffsets[nDescr],
                ppTypeRefs[nDescr], mapping );
        }
    }
    else
    {
        while (nDescr--)
        {
            ::uno_type_copyData(
                (char *)pDest + pMemberOffsets[nDescr],
                (char *)pSource + pMemberOffsets[nDescr],
                ppTypeRefs[nDescr], acquire );
        }
    }
}
//--------------------------------------------------------------------------------------------------
inline void _copyConstructArray(
    void * pDest, void * pSource,
    typelib_ArrayTypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
{
    typelib_TypeDescriptionReference * pElementTypeRef = ((typelib_IndirectTypeDescription *)pTypeDescr)->pType;
    typelib_TypeDescription * pElementTypeDescr = NULL;
    TYPELIB_DANGER_GET( &pElementTypeDescr, pElementTypeRef );
    sal_Int32 nElementSize = ((typelib_TypeDescription*)pElementTypeDescr)->nSize;
    TYPELIB_DANGER_RELEASE( pElementTypeDescr );
    sal_Int32 nTotalElements = pTypeDescr->nTotalElements;

    if (mapping)
    {
        for(sal_Int32 i = 0; i < nTotalElements; i++)
        {
            ::uno_type_copyAndConvertData(
                (sal_Char *)pDest + i * nElementSize,
                (sal_Char *)pSource + i * nElementSize,
                pElementTypeRef, mapping );
        }
    }
    else
    {
        for(sal_Int32 i = 0; i < nTotalElements; i++)
        {
            ::uno_type_copyData(
                (sal_Char *)pDest + (i * nElementSize),
                (sal_Char *)pSource + (i * nElementSize),
                pElementTypeRef, acquire );
        }
    }
}
//--------------------------------------------------------------------------------------------------
inline void _copyConstructUnion(
    void * pDest, void * pSource,
    typelib_TypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
    SAL_THROW ( () )
{
    typelib_TypeDescriptionReference * pSetType = _unionGetSetType( pSource, pTypeDescr );
    if (mapping)
    {
        ::uno_type_copyAndConvertData(
            (char *)pDest + ((typelib_UnionTypeDescription *)pTypeDescr)->nValueOffset,
            (char *)pSource + ((typelib_UnionTypeDescription *)pTypeDescr)->nValueOffset,
            pSetType, mapping );
    }
    else
    {
        ::uno_type_copyData(
            (char *)pDest + ((typelib_UnionTypeDescription *)pTypeDescr)->nValueOffset,
            (char *)pSource + ((typelib_UnionTypeDescription *)pTypeDescr)->nValueOffset,
            pSetType, acquire );
    }
    *(sal_Int64 *)pDest = *(sal_Int64 *)pSource;
    typelib_typedescriptionreference_release( pSetType );
}

//------------------------------------------------------------------------------
uno_Sequence * copyConstructSequence(
    uno_Sequence * pSource,
    typelib_TypeDescriptionReference * pElementType,
    uno_AcquireFunc acquire, uno_Mapping * mapping );

//--------------------------------------------------------------------------------------------------
inline void _copyConstructAnyFromData(
    uno_Any * pDestAny, void * pSource,
    typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
    SAL_THROW ( () )
{
    TYPE_ACQUIRE( pType );
    pDestAny->pType = pType;

    switch (pType->eTypeClass)
    {
    case typelib_TypeClass_CHAR:
        pDestAny->pData = &pDestAny->pReserved;
        *(sal_Unicode *)&pDestAny->pReserved = *(sal_Unicode *)pSource;
        break;
    case typelib_TypeClass_BOOLEAN:
        pDestAny->pData = &pDestAny->pReserved;
        *(sal_Bool *)&pDestAny->pReserved = (*(sal_Bool *)pSource != sal_False);
        break;
    case typelib_TypeClass_BYTE:
        pDestAny->pData = &pDestAny->pReserved;
        *(sal_Int8 *)&pDestAny->pReserved = *(sal_Int8 *)pSource;
        break;
    case typelib_TypeClass_SHORT:
    case typelib_TypeClass_UNSIGNED_SHORT:
        pDestAny->pData = &pDestAny->pReserved;
        *(sal_Int16 *)&pDestAny->pReserved = *(sal_Int16 *)pSource;
        break;
    case typelib_TypeClass_LONG:
    case typelib_TypeClass_UNSIGNED_LONG:
        pDestAny->pData = &pDestAny->pReserved;
        *(sal_Int32 *)&pDestAny->pReserved = *(sal_Int32 *)pSource;
        break;
    case typelib_TypeClass_HYPER:
    case typelib_TypeClass_UNSIGNED_HYPER:
        if (sizeof(void *) >= sizeof(sal_Int64))
        {
            pDestAny->pData = &pDestAny->pReserved;
            *(sal_Int64 *)&pDestAny->pReserved = *(sal_Int64 *)pSource;
        }
        else
        {
            pDestAny->pData = ::rtl_allocateMemory( sizeof(sal_Int64) );
            *(sal_Int64 *)pDestAny->pData = *(sal_Int64 *)pSource;
        }
        break;
    case typelib_TypeClass_FLOAT:
        if (sizeof(void *) >= sizeof(float))
        {
            pDestAny->pData = &pDestAny->pReserved;
            *(float *)&pDestAny->pReserved = *(float *)pSource;
        }
        else
        {
            pDestAny->pData = ::rtl_allocateMemory( sizeof(float) );
            *(float *)pDestAny->pData = *(float *)pSource;
        }
        break;
    case typelib_TypeClass_DOUBLE:
        if (sizeof(void *) >= sizeof(double))
        {
            pDestAny->pData = &pDestAny->pReserved;
            *(double *)&pDestAny->pReserved = *(double *)pSource;
        }
        else
        {
            pDestAny->pData = ::rtl_allocateMemory( sizeof(double) );
            *(double *)pDestAny->pData = *(double *)pSource;
        }
        break;
    case typelib_TypeClass_STRING:
        ::rtl_uString_acquire( *(rtl_uString **)pSource );
        pDestAny->pData = &pDestAny->pReserved;
        *(rtl_uString **)&pDestAny->pReserved = *(rtl_uString **)pSource;
        break;
    case typelib_TypeClass_TYPE:
        TYPE_ACQUIRE( *(typelib_TypeDescriptionReference **)pSource );
        pDestAny->pData = &pDestAny->pReserved;
        *(typelib_TypeDescriptionReference **)&pDestAny->pReserved = *(typelib_TypeDescriptionReference **)pSource;
        break;
    case typelib_TypeClass_ANY:
        OSL_ENSURE( 0, "### unexpected nested any!" );
        break;
    case typelib_TypeClass_ENUM:
        pDestAny->pData = &pDestAny->pReserved;
        // enum is forced to 32bit long
        *(sal_Int32 *)&pDestAny->pReserved = *(sal_Int32 *)pSource;
        break;
    case typelib_TypeClass_STRUCT:
    case typelib_TypeClass_EXCEPTION:
        if (pTypeDescr)
        {
            pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
            _copyConstructStruct(
                pDestAny->pData, pSource,
                (typelib_CompoundTypeDescription *)pTypeDescr,
                acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
            _copyConstructStruct(
                pDestAny->pData, pSource,
                (typelib_CompoundTypeDescription *)pTypeDescr,
                acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_ARRAY:
        if (pTypeDescr)
        {
            pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
            _copyConstructArray(
                pDestAny->pData, pSource,
                (typelib_ArrayTypeDescription *)pTypeDescr,
                acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
            _copyConstructArray(
                pDestAny->pData, pSource,
                (typelib_ArrayTypeDescription *)pTypeDescr,
                acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_UNION:
        if (pTypeDescr)
        {
            pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
            _copyConstructUnion( pDestAny->pData, pSource, pTypeDescr, acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
            _copyConstructUnion( pDestAny->pData, pSource, pTypeDescr, acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_SEQUENCE:
        pDestAny->pData = &pDestAny->pReserved;
        if (pTypeDescr)
        {
            *(uno_Sequence **)&pDestAny->pReserved = copyConstructSequence(
                *(uno_Sequence **)pSource,
                ((typelib_IndirectTypeDescription *)pTypeDescr)->pType,
                acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            *(uno_Sequence **)&pDestAny->pReserved = copyConstructSequence(
                *(uno_Sequence **)pSource,
                ((typelib_IndirectTypeDescription *)pTypeDescr)->pType,
                acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_INTERFACE:
        pDestAny->pData = &pDestAny->pReserved;
        if (mapping)
        {
            pDestAny->pReserved = _map( *(void **)pSource, pType, pTypeDescr, mapping );
        }
        else
        {
            _acquire( pDestAny->pReserved = *(void **)pSource, acquire );
        }
        break;
    default:
        OSL_ASSERT(false);
        break;
    }
}
//--------------------------------------------------------------------------------------------------
inline void _copyConstructAny(
    uno_Any * pDestAny, void * pSource,
    typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
    SAL_THROW ( () )
{
    if (typelib_TypeClass_VOID == pType->eTypeClass)
    {
        CONSTRUCT_EMPTY_ANY( pDestAny );
    }
    else
    {
        if (typelib_TypeClass_ANY == pType->eTypeClass)
        {
            if (pSource)
            {
                pType = ((uno_Any *)pSource)->pType;
                if (typelib_TypeClass_VOID == pType->eTypeClass)
                {
                    CONSTRUCT_EMPTY_ANY( pDestAny );
                    return;
                }
                pTypeDescr = 0;
                pSource = ((uno_Any *)pSource)->pData;
            }
            else
            {
                CONSTRUCT_EMPTY_ANY( pDestAny );
                return;
            }
        }
        if (pSource)
        {
            _copyConstructAnyFromData( pDestAny, pSource, pType, pTypeDescr, acquire, mapping );
        }
        else // default construct
        {
            TYPE_ACQUIRE( pType );
            pDestAny->pType = pType;
            switch (pType->eTypeClass)
            {
            case typelib_TypeClass_CHAR:
                pDestAny->pData = &pDestAny->pReserved;
                *(sal_Unicode *)&pDestAny->pReserved = '\0';
                break;
            case typelib_TypeClass_BOOLEAN:
                pDestAny->pData = &pDestAny->pReserved;
                *(sal_Bool *)&pDestAny->pReserved = sal_False;
                break;
            case typelib_TypeClass_BYTE:
                pDestAny->pData = &pDestAny->pReserved;
                *(sal_Int8 *)&pDestAny->pReserved = 0;
                break;
            case typelib_TypeClass_SHORT:
            case typelib_TypeClass_UNSIGNED_SHORT:
                pDestAny->pData = &pDestAny->pReserved;
                *(sal_Int16 *)&pDestAny->pReserved = 0;
                break;
            case typelib_TypeClass_LONG:
            case typelib_TypeClass_UNSIGNED_LONG:
                pDestAny->pData = &pDestAny->pReserved;
                *(sal_Int32 *)&pDestAny->pReserved = 0;
                break;
            case typelib_TypeClass_HYPER:
            case typelib_TypeClass_UNSIGNED_HYPER:
                if (sizeof(void *) >= sizeof(sal_Int64))
                {
                    pDestAny->pData = &pDestAny->pReserved;
                    *(sal_Int64 *)&pDestAny->pReserved = 0;
                }
                else
                {
                    pDestAny->pData = ::rtl_allocateMemory( sizeof(sal_Int64) );
                    *(sal_Int64 *)pDestAny->pData = 0;
                }
                break;
            case typelib_TypeClass_FLOAT:
                if (sizeof(void *) >= sizeof(float))
                {
                    pDestAny->pData = &pDestAny->pReserved;
                    *(float *)&pDestAny->pReserved = 0.0;
                }
                else
                {
                    pDestAny->pData = ::rtl_allocateMemory( sizeof(float) );
                    *(float *)pDestAny->pData = 0.0;
                }
                break;
            case typelib_TypeClass_DOUBLE:
                if (sizeof(void *) >= sizeof(double))
                {
                    pDestAny->pData = &pDestAny->pReserved;
                    *(double *)&pDestAny->pReserved = 0.0;
                }
                else
                {
                    pDestAny->pData = ::rtl_allocateMemory( sizeof(double) );
                    *(double *)pDestAny->pData = 0.0;
                }
                break;
            case typelib_TypeClass_STRING:
                pDestAny->pData = &pDestAny->pReserved;
                *(rtl_uString **)&pDestAny->pReserved = 0;
                ::rtl_uString_new( (rtl_uString **)&pDestAny->pReserved );
                break;
            case typelib_TypeClass_TYPE:
                pDestAny->pData = &pDestAny->pReserved;
                *(typelib_TypeDescriptionReference **)&pDestAny->pReserved = _getVoidType();
                break;
            case typelib_TypeClass_ENUM:
                pDestAny->pData = &pDestAny->pReserved;
                if (pTypeDescr)
                {
                    *(sal_Int32 *)&pDestAny->pReserved = ((typelib_EnumTypeDescription *)pTypeDescr)->nDefaultEnumValue;
                }
                else
                {
                    TYPELIB_DANGER_GET( &pTypeDescr, pType );
                    *(sal_Int32 *)&pDestAny->pReserved = ((typelib_EnumTypeDescription *)pTypeDescr)->nDefaultEnumValue;
                    TYPELIB_DANGER_RELEASE( pTypeDescr );
                }
                break;
            case typelib_TypeClass_STRUCT:
            case typelib_TypeClass_EXCEPTION:
                if (pTypeDescr)
                {
                    pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
                    _defaultConstructStruct(
                        pDestAny->pData, (typelib_CompoundTypeDescription *)pTypeDescr );
                }
                else
                {
                    TYPELIB_DANGER_GET( &pTypeDescr, pType );
                    pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
                    _defaultConstructStruct(
                        pDestAny->pData, (typelib_CompoundTypeDescription *)pTypeDescr );
                    TYPELIB_DANGER_RELEASE( pTypeDescr );
                }
                break;
            case typelib_TypeClass_ARRAY:
                if (pTypeDescr)
                {
                    pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
                    _defaultConstructArray(
                        pDestAny->pData, (typelib_ArrayTypeDescription *)pTypeDescr );
                }
                else
                {
                    TYPELIB_DANGER_GET( &pTypeDescr, pType );
                    pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
                    _defaultConstructArray(
                        pDestAny->pData, (typelib_ArrayTypeDescription *)pTypeDescr );
                    TYPELIB_DANGER_RELEASE( pTypeDescr );
                }
                break;
            case typelib_TypeClass_UNION:
                if (pTypeDescr)
                {
                    pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
                    _defaultConstructUnion( pDestAny->pData, pTypeDescr );
                }
                else
                {
                    TYPELIB_DANGER_GET( &pTypeDescr, pType );
                    pDestAny->pData = ::rtl_allocateMemory( pTypeDescr->nSize );
                    _defaultConstructUnion( pDestAny->pData, pTypeDescr );
                    TYPELIB_DANGER_RELEASE( pTypeDescr );
                }
                break;
            case typelib_TypeClass_SEQUENCE:
                pDestAny->pData = &pDestAny->pReserved;
                *(uno_Sequence **)&pDestAny->pReserved = createEmptySequence();
                break;
            case typelib_TypeClass_INTERFACE:
                pDestAny->pData = &pDestAny->pReserved;
                pDestAny->pReserved = 0; // either cpp or c-uno interface
                break;
            default:
                OSL_ASSERT(false);
                break;
            }
        }
    }
}
//------------------------------------------------------------------------------
inline uno_Sequence * icopyConstructSequence(
    uno_Sequence * pSource,
    typelib_TypeDescriptionReference * pElementType,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
{
    typelib_TypeClass eTypeClass = pElementType->eTypeClass;
    if (!mapping ||
        (eTypeClass <= typelib_TypeClass_ENUM &&
         eTypeClass != typelib_TypeClass_ANY))
    {
        ::osl_incrementInterlockedCount( &pSource->nRefCount );
        return pSource;
    }
    else // create new sequence
    {
        uno_Sequence * pDest;
        sal_Int32 nElements = pSource->nElements;
        if (nElements)
        {
            switch (eTypeClass)
            {
            case typelib_TypeClass_ANY:
            {
                pDest = allocSeq( sizeof (uno_Any), nElements );
                if (pDest != 0)
                {
                    uno_Any * pDestElements = (uno_Any *)pDest->elements;
                    uno_Any * pSourceElements = (uno_Any *)pSource->elements;
                    for ( sal_Int32 nPos = nElements; nPos--; )
                    {
                        typelib_TypeDescriptionReference * pType =
                            pSourceElements[nPos].pType;
                        if (typelib_TypeClass_VOID == pType->eTypeClass)
                        {
                            CONSTRUCT_EMPTY_ANY( &pDestElements[nPos] );
                        }
                        else
                        {
                            _copyConstructAnyFromData(
                                &pDestElements[nPos],
                                pSourceElements[nPos].pData,
                                pType, 0,
                                acquire, mapping );
                        }
                    }
                }
                break;
            }
            case typelib_TypeClass_STRUCT:
            case typelib_TypeClass_EXCEPTION:
            {
                typelib_TypeDescription * pElementTypeDescr = 0;
                TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
                sal_Int32 nElementSize = pElementTypeDescr->nSize;
                char * pSourceElements = pSource->elements;
                pDest = allocSeq( nElementSize, nElements );
                if (pDest != 0)
                {
                    char * pElements = pDest->elements;
                    for ( sal_Int32 nPos = nElements; nPos--; )
                    {
                        _copyConstructStruct(
                            pElements + (nPos * nElementSize),
                            pSourceElements + (nPos * nElementSize),
                            (typelib_CompoundTypeDescription *)
                            pElementTypeDescr,
                            acquire, mapping );
                    }
                }
                TYPELIB_DANGER_RELEASE( pElementTypeDescr );
                break;
            }
            case typelib_TypeClass_ARRAY:
            {
                typelib_TypeDescription * pElementTypeDescr = 0;
                TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
                sal_Int32 nElementSize = pElementTypeDescr->nSize;
                char * pSourceElements = pSource->elements;
                pDest = allocSeq( nElementSize, nElements );
                if (pDest != 0)
                {
                    char * pElements = pDest->elements;
                    for ( sal_Int32 nPos = nElements; nPos--; )
                    {
                        _copyConstructArray(
                            pElements + (nPos * nElementSize),
                            pSourceElements + (nPos * nElementSize),
                            (typelib_ArrayTypeDescription *)pElementTypeDescr,
                            acquire, mapping );
                    }
                }
                TYPELIB_DANGER_RELEASE( pElementTypeDescr );
                break;
            }
            case typelib_TypeClass_UNION:
            {
                typelib_TypeDescription * pElementTypeDescr = 0;
                TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
                sal_Int32 nElementSize = pElementTypeDescr->nSize;
                sal_Int32 nValueOffset =
                    ((typelib_UnionTypeDescription *)
                     pElementTypeDescr)->nValueOffset;
                pDest = allocSeq( nElementSize, nElements );
                if (pDest != 0)
                {
                    char * pElements = pDest->elements;
                    char * pSourceElements = pSource->elements;
                    for ( sal_Int32 nPos = nElements; nPos--; )
                    {
                        char * pDest2 =
                            pElements + (nPos * nElementSize);
                        char * pSource2 =
                            pSourceElements + (nPos * nElementSize);

                        typelib_TypeDescriptionReference * pSetType =
                            _unionGetSetType( pSource2, pElementTypeDescr );
                        ::uno_type_copyAndConvertData(
                            pDest2 + nValueOffset, pSource2 + nValueOffset,
                            pSetType, mapping );
                        *(sal_Int64 *)pDest2 = *(sal_Int64 *)pSource2;
                        ::typelib_typedescriptionreference_release( pSetType );
                    }
                }
                TYPELIB_DANGER_RELEASE( pElementTypeDescr );
                break;
            }
            case typelib_TypeClass_SEQUENCE: // sequence of sequence
            {
                pDest = allocSeq( sizeof (uno_Sequence *), nElements );
                if (pDest != 0)
                {
                    typelib_TypeDescription * pElementTypeDescr = 0;
                    TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
                    typelib_TypeDescriptionReference * pSeqElementType =
                        ((typelib_IndirectTypeDescription *)
                         pElementTypeDescr)->pType;

                    uno_Sequence ** pDestElements =
                        (uno_Sequence **) pDest->elements;
                    uno_Sequence ** pSourceElements =
                        (uno_Sequence **) pSource->elements;
                    for ( sal_Int32 nPos = nElements; nPos--; )
                    {
                        uno_Sequence * pNew = copyConstructSequence(
                            pSourceElements[nPos],
                            pSeqElementType,
                            acquire, mapping );
                        OSL_ASSERT( pNew != 0 );
                        // ought never be a memory allocation problem,
                        // because of reference counted sequence handles
                        pDestElements[ nPos ] = pNew;
                    }

                    TYPELIB_DANGER_RELEASE( pElementTypeDescr );
                }
                break;
            }
            case typelib_TypeClass_INTERFACE:
            {
                pDest = allocSeq( sizeof (void *), nElements );
                if (pDest != 0)
                {
                    char * pElements = pDest->elements;
                    void ** pSourceElements = (void **)pSource->elements;
                    if (mapping)
                    {
                        typelib_TypeDescription * pElementTypeDescr = 0;
                        TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
                        for ( sal_Int32 nPos = nElements; nPos--; )
                        {
                            ((void **)pElements)[nPos] = 0;
                            if (((void **)pSourceElements)[nPos])
                            {
                                (*mapping->mapInterface)(
                                    mapping, (void **)pElements + nPos,
                                    pSourceElements[nPos],
                                    (typelib_InterfaceTypeDescription *)
                                    pElementTypeDescr );
                            }
                        }
                        TYPELIB_DANGER_RELEASE( pElementTypeDescr );
                    }
                    else
                    {
                        for ( sal_Int32 nPos = nElements; nPos--; )
                        {
                            ((void **)pElements)[nPos] = pSourceElements[nPos];
                            _acquire( ((void **)pElements)[nPos], acquire );
                        }
                    }
                }
                break;
            }
            default:
                OSL_ENSURE( 0, "### unexepcted sequence element type!" );
                pDest = 0;
                break;
            }
        }
        else // empty sequence
        {
            pDest = allocSeq( 0, 0 );
        }

        return pDest;
    }
}

//--------------------------------------------------------------------------------------------------
inline void _copyConstructData(
    void * pDest, void * pSource,
    typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
    uno_AcquireFunc acquire, uno_Mapping * mapping )
    SAL_THROW ( () )
{
    switch (pType->eTypeClass)
    {
    case typelib_TypeClass_CHAR:
        *(sal_Unicode *)pDest = *(sal_Unicode *)pSource;
        break;
    case typelib_TypeClass_BOOLEAN:
        *(sal_Bool *)pDest = (*(sal_Bool *)pSource != sal_False);
        break;
    case typelib_TypeClass_BYTE:
        *(sal_Int8 *)pDest = *(sal_Int8 *)pSource;
        break;
    case typelib_TypeClass_SHORT:
    case typelib_TypeClass_UNSIGNED_SHORT:
        *(sal_Int16 *)pDest = *(sal_Int16 *)pSource;
        break;
    case typelib_TypeClass_LONG:
    case typelib_TypeClass_UNSIGNED_LONG:
        *(sal_Int32 *)pDest = *(sal_Int32 *)pSource;
        break;
    case typelib_TypeClass_HYPER:
    case typelib_TypeClass_UNSIGNED_HYPER:
        *(sal_Int64 *)pDest = *(sal_Int64 *)pSource;
        break;
    case typelib_TypeClass_FLOAT:
        *(float *)pDest = *(float *)pSource;
        break;
    case typelib_TypeClass_DOUBLE:
        *(double *)pDest = *(double *)pSource;
        break;
    case typelib_TypeClass_STRING:
        ::rtl_uString_acquire( *(rtl_uString **)pSource );
        *(rtl_uString **)pDest = *(rtl_uString **)pSource;
        break;
    case typelib_TypeClass_TYPE:
        TYPE_ACQUIRE( *(typelib_TypeDescriptionReference **)pSource );
        *(typelib_TypeDescriptionReference **)pDest = *(typelib_TypeDescriptionReference **)pSource;
        break;
    case typelib_TypeClass_ANY:
        _copyConstructAny(
            (uno_Any *)pDest, ((uno_Any *)pSource)->pData,
            ((uno_Any *)pSource)->pType, 0,
            acquire, mapping );
        break;
    case typelib_TypeClass_ENUM:
        *(sal_Int32 *)pDest = *(sal_Int32 *)pSource;
        break;
    case typelib_TypeClass_STRUCT:
    case typelib_TypeClass_EXCEPTION:
        if (pTypeDescr)
        {
            _copyConstructStruct(
                pDest, pSource,
                (typelib_CompoundTypeDescription *)pTypeDescr,
                acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            _copyConstructStruct(
                pDest, pSource,
                (typelib_CompoundTypeDescription *)pTypeDescr,
                acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_ARRAY:
        if (pTypeDescr)
        {
            _copyConstructArray(
                pDest, pSource,
                (typelib_ArrayTypeDescription *)pTypeDescr,
                acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            _copyConstructArray(
                pDest, pSource,
                (typelib_ArrayTypeDescription *)pTypeDescr,
                acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_UNION:
        if (pTypeDescr)
        {
            _copyConstructUnion( pDest, pSource, pTypeDescr, acquire, mapping );
        }
        else
        {
            TYPELIB_DANGER_GET( &pTypeDescr, pType );
            _copyConstructUnion( pDest, pSource, pTypeDescr, acquire, mapping );
            TYPELIB_DANGER_RELEASE( pTypeDescr );
        }
        break;
    case typelib_TypeClass_SEQUENCE:
        if (mapping)
        {
            if (pTypeDescr)
            {
                *(uno_Sequence **)pDest = icopyConstructSequence(
                    *(uno_Sequence **)pSource,
                    ((typelib_IndirectTypeDescription *)pTypeDescr)->pType,
                    acquire, mapping );
            }
            else
            {
                TYPELIB_DANGER_GET( &pTypeDescr, pType );
                *(uno_Sequence **)pDest = icopyConstructSequence(
                    *(uno_Sequence **)pSource,
                    ((typelib_IndirectTypeDescription *)pTypeDescr)->pType,
                    acquire, mapping );
                TYPELIB_DANGER_RELEASE( pTypeDescr );
            }
        }
        else
        {
            ::osl_incrementInterlockedCount( &(*(uno_Sequence **)pSource)->nRefCount );
            *(uno_Sequence **)pDest = *(uno_Sequence **)pSource;
        }
        break;
    case typelib_TypeClass_INTERFACE:
        if (mapping)
            *(void **)pDest = _map( *(void **)pSource, pType, pTypeDescr, mapping );
        else
            _acquire( *(void **)pDest = *(void **)pSource, acquire );
        break;
    default:
        break;
    }
}

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
