summaryrefslogtreecommitdiff
path: root/bridges/source/remote/urp/urp_unmarshal.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/remote/urp/urp_unmarshal.cxx')
-rw-r--r--bridges/source/remote/urp/urp_unmarshal.cxx707
1 files changed, 707 insertions, 0 deletions
diff --git a/bridges/source/remote/urp/urp_unmarshal.cxx b/bridges/source/remote/urp/urp_unmarshal.cxx
new file mode 100644
index 000000000000..79335bfeb6f0
--- /dev/null
+++ b/bridges/source/remote/urp/urp_unmarshal.cxx
@@ -0,0 +1,707 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_bridges.hxx"
+#include <string.h>
+
+#include <osl/diagnose.h>
+
+#include <rtl/alloc.h>
+#include <rtl/ustrbuf.hxx>
+
+#include <uno/data.h>
+#include <uno/any2.h>
+#include <uno/sequence2.h>
+
+#include <com/sun/star/uno/Any.hxx>
+
+#include "urp_unmarshal.hxx"
+#include "urp_bridgeimpl.hxx"
+
+
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+
+namespace bridges_urp
+{
+static int g_nDetectLittleEndian = 1;
+char g_bSystemIsLittleEndian = ((char*)&g_nDetectLittleEndian)[0];
+
+
+Unmarshal::Unmarshal( struct urp_BridgeImpl *pBridgeImpl,
+ uno_Environment *pEnvRemote,
+ remote_createStubFunc callback ) :
+ m_nBufferSize( 4096 ),
+ m_base( (sal_Int8*) rtl_allocateMemory( m_nBufferSize ) ),
+ m_pos( m_base ),
+ m_nLength( 0 ),
+ m_callback( callback ),
+ m_pEnvRemote( pEnvRemote ),
+ m_pBridgeImpl( pBridgeImpl )
+{
+}
+
+Unmarshal::~Unmarshal()
+{
+ rtl_freeMemory( m_base );
+}
+
+// special unpacks
+sal_Bool Unmarshal::unpackTid( sal_Sequence **ppThreadId )
+{
+ sal_Int32 nSize;
+ sal_Bool bReturn = unpackCompressedSize( &nSize );
+ if( bReturn )
+ {
+ if( nSize )
+ {
+ rtl_byte_sequence_constructFromArray( ppThreadId , m_pos , nSize );
+ m_pos += nSize;
+ sal_uInt16 nIndex;
+ bReturn = unpackInt16( &nIndex );
+ if( nIndex < m_pBridgeImpl->m_properties.nTidCacheSize )
+ {
+ m_pBridgeImpl->m_pTidIn[nIndex] = *(ByteSequence * )ppThreadId;
+ }
+ else if( 0xffff != nIndex )
+ {
+ bReturn = sal_False;
+ rtl_byte_sequence_construct( ppThreadId , 0 );
+
+ OUStringBuffer error( 128 );
+ error.appendAscii( "cache index for tid " );
+ OString o = byteSequence2HumanReadableString( *(ByteSequence * ) ppThreadId );
+ error.appendAscii( o.getStr(), o.getLength() );
+ error.appendAscii( "out of range(0x");
+ error.append( (sal_Int32) nIndex ,16 );
+ error.appendAscii( ")" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+ else
+ {
+ sal_uInt16 nIndex;
+ bReturn = unpackInt16( &nIndex );
+ if( nIndex < m_pBridgeImpl->m_properties.nTidCacheSize )
+ {
+ *ppThreadId = m_pBridgeImpl->m_pTidIn[nIndex].getHandle();
+ rtl_byte_sequence_acquire( *ppThreadId );
+ }
+ else
+ {
+ bReturn = sal_False;
+ rtl_byte_sequence_construct( ppThreadId , 0 );
+ OUStringBuffer error(128);
+ error.appendAscii( "cache index for tids out of range(0x" );
+ error.append( (sal_Int32) nIndex ,16 );
+ error.appendAscii( ")" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+ }
+ else
+ {
+ m_pBridgeImpl->addError( "couldn't unpack thread id because of previous errors" );
+ }
+ return bReturn;
+}
+
+sal_Bool Unmarshal::unpackOid( rtl_uString **ppOid )
+{
+ sal_Bool bReturn = sal_True;
+ sal_uInt16 nCacheIndex = 0;
+
+ bReturn = bReturn && unpackString( ppOid );
+ bReturn = bReturn && unpackInt16( &nCacheIndex );
+
+ if( bReturn &&
+ ! ( 0xffff == nCacheIndex && 0 == (*ppOid)->length ) /* null reference */ )
+ {
+ if( (*ppOid)->length )
+ {
+ // new unknown reference
+ if( 0xffff != nCacheIndex )
+ {
+ // oid should be cached ?
+ if( nCacheIndex < m_pBridgeImpl->m_properties.nOidCacheSize )
+ {
+ m_pBridgeImpl->m_pOidIn[nCacheIndex] = *ppOid;
+ }
+ else
+ {
+ OUStringBuffer error( 128 );
+ error.appendAscii( "new oid provided (" );
+ error.append( *ppOid );
+ error.appendAscii( "), but new cache index is out of range(0x");
+ error.append( (sal_Int32) nCacheIndex ,16 );
+ error.appendAscii( ")" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+
+ bReturn = sal_False;
+ rtl_uString_new( ppOid );
+ }
+ }
+ }
+ else
+ {
+ // reference in cache !
+ if( nCacheIndex < m_pBridgeImpl->m_properties.nOidCacheSize )
+ {
+ rtl_uString_assign( ppOid , m_pBridgeImpl->m_pOidIn[nCacheIndex].pData );
+ }
+ else
+ {
+ bReturn = sal_False;
+ rtl_uString_new( ppOid );
+
+ OUStringBuffer error( 128 );
+ error.appendAscii( "cache index for oids out of range(0x");
+ error.append( (sal_Int32) nCacheIndex ,16 );
+ error.appendAscii( ")" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+ }
+
+ return bReturn;
+}
+
+sal_Bool Unmarshal::unpack( void *pDestination ,
+ typelib_TypeDescription *pTypeDescr )
+{
+ // Note: We implement unpack functionality without recursions in order
+ // to avoid stack overflows caused by rotten URP blocks.
+
+ m_aItemsToUnpack.push( UnpackItem( pDestination, pTypeDescr ) );
+
+ sal_Bool bReturn = sal_True;
+ do
+ {
+ void * pDest = m_aItemsToUnpack.top().pDest;
+ typelib_TypeDescription * pType = m_aItemsToUnpack.top().pType;
+ m_aItemsToUnpack.pop();
+
+ switch( pType->eTypeClass )
+ {
+ case typelib_TypeClass_VOID:
+ // do nothing
+ break;
+ case typelib_TypeClass_BYTE:
+ {
+ bReturn = unpackInt8( pDest );
+ break;
+ }
+ case typelib_TypeClass_BOOLEAN:
+ {
+ bReturn = ! checkOverflow( 1 );
+ if( bReturn )
+ {
+ *((sal_Bool*)pDest) = (sal_Bool ) ( *m_pos);
+ m_pos ++;
+ }
+ else
+ {
+ *((sal_Bool*)pDest) = 0;
+ }
+ break;
+ }
+
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ {
+ unpackInt16( pDest );
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ {
+ bReturn = unpackInt32( pDest );
+ break;
+ }
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ {
+ sal_Int8 * p = static_cast< sal_Int8 * >(pDest);
+ bReturn = ! checkOverflow( 8 );
+ if( bReturn )
+ {
+ if( isSystemLittleEndian() )
+ {
+ p[7] = m_pos[0];
+ p[6] = m_pos[1];
+ p[5] = m_pos[2];
+ p[4] = m_pos[3];
+ p[3] = m_pos[4];
+ p[2] = m_pos[5];
+ p[1] = m_pos[6];
+ p[0] = m_pos[7];
+ }
+ else
+ {
+ p[0] = m_pos[0];
+ p[1] = m_pos[1];
+ p[2] = m_pos[2];
+ p[3] = m_pos[3];
+ p[4] = m_pos[4];
+ p[5] = m_pos[5];
+ p[6] = m_pos[6];
+ p[7] = m_pos[7];
+ }
+ m_pos += 8;
+ }
+ else
+ {
+ // Do not trigger alignment errors:
+ p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = 0;
+ }
+ break;
+ }
+ case typelib_TypeClass_STRING:
+ {
+ unpackString( pDest );
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ uno_Any *pAny = ( uno_Any * )pDest;
+
+ pAny->pType = 0;
+ // Type is acquired with typelib_typedescription_acquire
+
+ bReturn = unpackType( &(pAny->pType) );
+
+ typelib_TypeDescription *pDataType = 0;
+ if( bReturn && pAny->pType )
+ {
+ typelib_typedescriptionreference_getDescription( &pDataType , pAny->pType );
+
+ if( pDataType )
+ {
+ switch (pDataType->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (sizeof(void *) < sizeof(sal_Int64))
+ {
+ pAny->pData = rtl_allocateMemory( sizeof(sal_Int64) );
+ }
+ else
+ {
+ pAny->pData = &pAny->pReserved;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (sizeof(void *) < sizeof(float))
+ {
+ pAny->pData = rtl_allocateMemory( sizeof(float) );
+ }
+ else
+ {
+ pAny->pData = &pAny->pReserved;
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (sizeof(void *) < sizeof(double))
+ {
+ pAny->pData = rtl_allocateMemory( sizeof(double) );
+ }
+ else
+ {
+ pAny->pData = &pAny->pReserved;
+ }
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_UNION:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_ARRAY:
+ pAny->pData = rtl_allocateMemory( pDataType->nSize );
+ break;
+ case typelib_TypeClass_ANY:
+ {
+ m_pBridgeImpl->addError(
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "can't unmarshal any: any in any not supported!" ) ) );
+
+ pAny->pData = 0;
+ Type type; // void
+ pAny->pType = type.getTypeLibType();
+ typelib_typedescriptionreference_acquire( pAny->pType );
+
+ bReturn = sal_False;
+ break;
+ }
+ default:
+ pAny->pData = &pAny->pReserved;
+ }
+
+ if ( bReturn )
+ {
+ m_aItemsToUnpack.push(
+ UnpackItem( pAny->pData, pDataType ) );
+ }
+ }
+ else
+ {
+ OUStringBuffer error;
+ error.appendAscii( "can't unmarshal any because typedescription for " );
+ error.append( pAny->pType->pTypeName );
+ error.appendAscii( " is missing" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+
+ if( pDataType )
+ {
+ typelib_typedescription_release( pDataType );
+ }
+ else
+ {
+ pAny->pData = 0;
+ Type type; // void
+ pAny->pType = type.getTypeLibType();
+ typelib_typedescriptionreference_acquire( pAny->pType );
+
+ bReturn = sal_False;
+ }
+
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ *(remote_Interface**)pDest = 0;
+
+ rtl_uString *pString = 0;
+ bReturn = unpackOid( &pString ) && bReturn;
+
+ if( bReturn && pString && pString->length )
+ {
+ m_callback( (remote_Interface**) pDest ,
+ pString,
+ pType->pWeakRef ,
+ m_pEnvRemote,
+ urp_releaseRemoteCallback );
+ }
+ if( pString )
+ {
+ rtl_uString_release( pString );
+ }
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ bReturn = unpackType( pDest );
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_CompoundTypeDescription * pCompType =
+ (typelib_CompoundTypeDescription *)pType;
+
+ // direct members
+ typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets;
+ sal_Int32 nDescr = pCompType->nMembers;
+
+ // at least assume 1 byte per member
+ bReturn = bReturn && ! checkOverflow( nDescr * 1 );
+ for ( sal_Int32 nPos = nDescr; nPos; --nPos )
+ {
+ typelib_TypeDescription * pMemberType = 0;
+ typelib_typedescriptionreference_getDescription(
+ &pMemberType, ppTypeRefs[ nPos - 1 ] );
+
+ m_aItemsToUnpack.push(
+ UnpackItem( (char*)pDest + pMemberOffsets[ nPos - 1 ],
+ pMemberType,
+ true /* construct even in error case */ ) );
+
+ m_aTypesToRelease.push_back( pMemberType );
+ }
+
+ // parent
+ if (pCompType->pBaseTypeDescription)
+ {
+ m_aItemsToUnpack.push(
+ UnpackItem( pDest,
+ (typelib_TypeDescription *)
+ pCompType->pBaseTypeDescription ) );
+ }
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ sal_Int32 nLen;
+ bReturn = unpackCompressedSize( &nLen );
+
+ // urp protocol does not allow to use the elementsize as a guess, if enough data
+ // is available. However, at least one byte per member must be within the message
+ bReturn = bReturn && ! checkOverflow( 1 * nLen );
+ uno_Sequence *pSequence = 0;
+ if( nLen && bReturn )
+ {
+ typelib_TypeDescriptionReference * pETRef =
+ ((typelib_IndirectTypeDescription *)pType)->pType;
+
+ typelib_TypeDescription * pET = 0;
+ typelib_typedescriptionreference_getDescription( &pET , pETRef );
+
+ if( pET )
+ {
+ sal_Int32 nElementSize = pET->nSize;
+
+ pSequence = (uno_Sequence *)rtl_allocateMemory(
+ SAL_SEQUENCE_HEADER_SIZE + nElementSize * nLen );
+ pSequence->nRefCount = 1;
+ pSequence->nElements = nLen;
+
+ if( typelib_TypeClass_BYTE == pET->eTypeClass )
+ {
+ memcpy( pSequence->elements , m_pos , nLen );
+ m_pos += nLen;
+ }
+ else
+ {
+ for ( sal_Int32 i = nLen; i; --i )
+ {
+ m_aItemsToUnpack.push(
+ UnpackItem(
+ ((char*)pSequence->elements)
+ + (i - 1) * nElementSize,
+ pET ) );
+ }
+ }
+ m_aTypesToRelease.push_back( pET );
+ }
+ else
+ {
+ bReturn = sal_False;
+ uno_constructData( &pSequence , pType );
+ OUStringBuffer error;
+ error.appendAscii( "can't unmarshal sequence, because there is no typedescription for element type " );
+ error.append( pETRef->pTypeName );
+ error.appendAscii( " available" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+ else
+ {
+ uno_constructData( &pSequence , pType );
+ }
+
+ *((uno_Sequence **)pDest) = pSequence;
+ break;
+ }
+ case typelib_TypeClass_UNION:
+ case typelib_TypeClass_ARRAY:
+ case typelib_TypeClass_SERVICE:
+ case typelib_TypeClass_MODULE:
+ case typelib_TypeClass_INTERFACE_METHOD:
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ case typelib_TypeClass_UNKNOWN:
+ default:
+ {
+ ::rtl::OUStringBuffer buffer( 128 );
+ buffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Unsupported typeclass during unmarshaling ("));
+ buffer.append( ( sal_Int32 ) pType->eTypeClass , 10 );
+ buffer.appendAscii( ")" );
+ m_pBridgeImpl->addError( buffer.makeStringAndClear() );
+ bReturn = sal_False;
+ }
+ }
+
+ if ( !bReturn )
+ {
+ // construct default data for every remaining item.
+ while ( !m_aItemsToUnpack.empty() )
+ {
+ const UnpackItem & rItem = m_aItemsToUnpack.top();
+
+ if ( rItem.bMustBeConstructed )
+ uno_constructData( rItem.pDest , rItem.pType );
+
+ m_aItemsToUnpack.pop();
+ }
+ }
+ }
+ while ( !m_aItemsToUnpack.empty() );
+
+ // release pending type descriptions
+ TypeDescVector::const_iterator it = m_aTypesToRelease.begin();
+ const TypeDescVector::const_iterator end = m_aTypesToRelease.end();
+ while ( it != end )
+ {
+ typelib_typedescription_release( *it );
+ it++;
+ }
+ m_aTypesToRelease.clear();
+
+ return bReturn;
+}
+
+sal_Bool Unmarshal::unpackType( void *pDest )
+{
+ *(typelib_TypeDescriptionReference **) pDest = 0;
+
+ sal_uInt8 nTypeClass;
+ sal_Bool bReturn = unpackInt8( &nTypeClass );
+
+ typelib_TypeDescriptionReference *pTypeRef = 0;
+ if( bReturn )
+ {
+ if( nTypeClass <= 14 /* any */ )
+ {
+ pTypeRef = * typelib_static_type_getByTypeClass((typelib_TypeClass )nTypeClass);
+ typelib_typedescriptionreference_acquire( pTypeRef );
+ }
+ else
+ {
+ sal_uInt16 nCacheIndex = 0;
+ bReturn = bReturn && unpackInt16( &nCacheIndex );
+
+ if( bReturn )
+ {
+ if( nTypeClass & 0x80 )
+ {
+ // new type
+ rtl_uString *pString = 0;
+ bReturn = bReturn && unpackString( &pString );
+ if( bReturn )
+ {
+ typelib_TypeDescription *pType = 0;
+ typelib_typedescription_getByName( &pType, pString );
+ if( pType )
+ {
+ // type is known in this process
+ if( (typelib_TypeClass )(nTypeClass & 0x7f) == pType->eTypeClass )
+ {
+ //typename and typeclass match, this is as it should be
+ pTypeRef = pType->pWeakRef;
+ typelib_typedescriptionreference_acquire( pTypeRef );
+ }
+ else
+ {
+ // typename and typeclass do not match, dispose the bridge
+ // as there must be inconsistent type base between both processes
+ // or trash comes over the wire ...
+ bReturn = sal_False;
+ OUStringBuffer error( 128 );
+ error.appendAscii( "it is tried to introduce type " );
+ error.append( pString );
+ error.appendAscii( "with typeclass " );
+ error.append( (sal_Int32)( nTypeClass & 0x7f ) , 10 );
+ error.appendAscii( " , which does not match with typeclass " );
+ error.append( (sal_Int32) pType->eTypeClass ,10 );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ typelib_typedescription_release( pType );
+ pType = 0;
+ }
+ else
+ {
+ // a type by this name is not known in the process.
+ if( (nTypeClass & 0x7f) < typelib_TypeClass_UNKNOWN )
+ {
+ // typeclass is within a valid range, introduce the new
+ // type.
+ typelib_typedescriptionreference_new(
+ &pTypeRef, (typelib_TypeClass )(nTypeClass & 0x7f), pString );
+ }
+ else
+ {
+ // typeclass is out of range !
+ bReturn = sal_False;
+ OUStringBuffer error( 128 );
+ error.appendAscii( "it is tried to introduce type " );
+ error.append( pString );
+ error.appendAscii( "with an out of range typeclass " );
+ error.append( (sal_Int32)( nTypeClass & 0x7f ) , 10 );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+
+ if( bReturn && nCacheIndex != 0xffff )
+ {
+ if( nCacheIndex < m_pBridgeImpl->m_properties.nTypeCacheSize )
+ {
+ m_pBridgeImpl->m_pTypeIn[nCacheIndex] = *( Type * )&pTypeRef;
+ }
+ else
+ {
+ bReturn = sal_False;
+ OUStringBuffer error( 128 );
+ error.appendAscii( "cache index for type " );
+ error.append( pString );
+ error.appendAscii( "out of range(0x" );
+ error.append( (sal_Int32) nCacheIndex ,16 );
+ error.appendAscii( ")" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+ }
+ if( pString )
+ {
+ rtl_uString_release( pString );
+ }
+ }
+ else
+ {
+ if( nCacheIndex < m_pBridgeImpl->m_properties.nTypeCacheSize )
+ {
+ pTypeRef = m_pBridgeImpl->m_pTypeIn[nCacheIndex].getTypeLibType();
+ typelib_typedescriptionreference_acquire( pTypeRef );
+ }
+ else
+ {
+ bReturn = sal_False;
+ OUStringBuffer error;
+ error.appendAscii( "cache index for types out of range(0x" );
+ error.append( (sal_Int32) nCacheIndex ,16 );
+ error.appendAscii( ")" );
+ m_pBridgeImpl->addError( error.makeStringAndClear() );
+ }
+ }
+ }
+ }
+ }
+ if( ! pTypeRef )
+ {
+ pTypeRef = * typelib_static_type_getByTypeClass(typelib_TypeClass_VOID);
+ typelib_typedescriptionreference_acquire( pTypeRef );
+ }
+ // pTypeRef is already acquired
+ *(typelib_TypeDescriptionReference**)pDest = pTypeRef;
+ return bReturn;
+}
+
+}
+