diff options
Diffstat (limited to 'binaryurp/source/unmarshal.cxx')
-rwxr-xr-x | binaryurp/source/unmarshal.cxx | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/binaryurp/source/unmarshal.cxx b/binaryurp/source/unmarshal.cxx new file mode 100755 index 000000000000..62f8683e33ad --- /dev/null +++ b/binaryurp/source/unmarshal.cxx @@ -0,0 +1,563 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 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. +* +************************************************************************/ + +#include "sal/config.h" + +#include <cstdlib> +#include <new> +#include <vector> + +#include "boost/noncopyable.hpp" +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppu/unotype.hxx" +#include "osl/diagnose.h" +#include "rtl/byteseq.hxx" +#include "rtl/ref.hxx" +#include "rtl/textcvt.h" +#include "rtl/textenc.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/any2.h" +#include "uno/data.h" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "cache.hxx" +#include "readerstate.hxx" +#include "unmarshal.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +void * allocate(sal_Size size) { + void * p = rtl_allocateMemory(size); + if (p == 0) { + throw std::bad_alloc(); + } + return p; +} + +std::vector< BinaryAny >::iterator copyMemberValues( + css::uno::TypeDescription const & type, + std::vector< BinaryAny >::iterator const & it, void * buffer) throw () +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_STRUCT || + type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) && + buffer != 0); + type.makeComplete(); + std::vector< BinaryAny >::iterator i(it); + typelib_CompoundTypeDescription * ctd = + reinterpret_cast< typelib_CompoundTypeDescription * >(type.get()); + if (ctd->pBaseTypeDescription != 0) { + i = copyMemberValues( + css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i, + buffer); + } + for (sal_Int32 j = 0; j != ctd->nMembers; ++j) { + uno_type_copyData( + static_cast< char * >(buffer) + ctd->pMemberOffsets[j], + const_cast< void * >( + i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j]))), + ctd->ppTypeRefs[j], 0); + } + return i; +} + +} + +Unmarshal::Unmarshal( + rtl::Reference< Bridge > const & bridge, ReaderState & state, + css::uno::Sequence< sal_Int8 > const & buffer): + bridge_(bridge), state_(state), buffer_(buffer) +{ + data_ = reinterpret_cast< sal_uInt8 const * >(buffer_.getConstArray()); + end_ = data_ + buffer_.getLength(); +} + +Unmarshal::~Unmarshal() {} + +sal_uInt8 Unmarshal::read8() { + check(1); + return *data_++; +} + +sal_uInt16 Unmarshal::read16() { + check(2); + sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8; + return n | *data_++; +} + +sal_uInt32 Unmarshal::read32() { + check(4); + sal_uInt32 n = static_cast< sal_uInt32 >(*data_++) << 24; + n |= static_cast< sal_uInt32 >(*data_++) << 16; + n |= static_cast< sal_uInt32 >(*data_++) << 8; + return n | *data_++; +} + +css::uno::TypeDescription Unmarshal::readType() { + sal_uInt8 flags = read8(); + typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F); + switch (tc) { + case typelib_TypeClass_VOID: + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + case typelib_TypeClass_CHAR: + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + if ((flags & 0x80) != 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: cache flag of simple type is" + " set")), + css::uno::Reference< css::uno::XInterface >()); + } + return css::uno::TypeDescription( + *typelib_static_type_getByTypeClass( + static_cast< typelib_TypeClass >(tc))); + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_ENUM: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_INTERFACE: + { + sal_uInt16 idx = readCacheIndex(); + if ((flags & 0x80) == 0) { + if (idx == cache::ignore || !state_.typeCache[idx].is()) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown type cache" + " index")), + css::uno::Reference< css::uno::XInterface >()); + } + return state_.typeCache[idx]; + } else { + css::uno::TypeDescription t(readString()); + if (!t.is() || + t.get()->eTypeClass != static_cast< typelib_TypeClass >(tc)) + { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: type with unknown" + " name")), + css::uno::Reference< css::uno::XInterface >()); + } + for (css::uno::TypeDescription t2(t); + t2.get()->eTypeClass == typelib_TypeClass_SEQUENCE;) + { + t2.makeComplete(); + t2 = css::uno::TypeDescription( + reinterpret_cast< typelib_IndirectTypeDescription * >( + t2.get())->pType); + if (!t2.is()) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence type with" + " unknown component type")), + css::uno::Reference< css::uno::XInterface >()); + } + switch (t2.get()->eTypeClass) { + case typelib_TypeClass_VOID: + case typelib_TypeClass_EXCEPTION: + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence type with" + " bad component type")), + css::uno::Reference< css::uno::XInterface >()); + default: + break; + } + } + if (idx != cache::ignore) { + state_.typeCache[idx] = t; + } + return t; + } + } + default: + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: type of unknown type class")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +rtl::OUString Unmarshal::readOid() { + rtl::OUString oid(readString()); + for (sal_Int32 i = 0; i != oid.getLength(); ++i) { + if (oid[i] > 0x7F) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: OID contains non-ASCII" + " character")), + css::uno::Reference< css::uno::XInterface >()); + } + } + sal_uInt16 idx = readCacheIndex(); + if (oid.getLength() == 0 && idx != cache::ignore) { + if (state_.oidCache[idx].getLength() == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown OID cache index")), + css::uno::Reference< css::uno::XInterface >()); + } + return state_.oidCache[idx]; + } + if (idx != cache::ignore) { + state_.oidCache[idx] = oid; + } + return oid; +} + +rtl::ByteSequence Unmarshal::readTid() { + rtl::ByteSequence tid( + *static_cast< sal_Sequence * const * >( + readSequence( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())). + getValue( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())))); + sal_uInt16 idx = readCacheIndex(); + if (tid.getLength() == 0) { + if (idx == cache::ignore || state_.tidCache[idx].getLength() == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown TID cache index")), + css::uno::Reference< css::uno::XInterface >()); + } + return state_.tidCache[idx]; + } + if (idx != cache::ignore) { + state_.tidCache[idx] = tid; + } + return tid; +} + +BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) { + OSL_ASSERT(type.is()); + switch (type.get()->eTypeClass) { + default: + std::abort(); // this cannot happen + // pseudo fall-through to avoid compiler warnings + case typelib_TypeClass_VOID: + return BinaryAny(); + case typelib_TypeClass_BOOLEAN: + { + sal_uInt8 v = read8(); + if (v > 1) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: boolean of unknown value")), + css::uno::Reference< css::uno::XInterface >()); + } + return BinaryAny(type, &v); + } + case typelib_TypeClass_BYTE: + { + sal_uInt8 v = read8(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_CHAR: + { + sal_uInt16 v = read16(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_FLOAT: + { + sal_uInt32 v = read32(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_DOUBLE: + { + sal_uInt64 v = read64(); + return BinaryAny(type, &v); + } + case typelib_TypeClass_STRING: + { + rtl::OUString v(readString()); + return BinaryAny(type, &v.pData); + } + case typelib_TypeClass_TYPE: + { + css::uno::TypeDescription v(readType()); + typelib_TypeDescription * p = v.get(); + return BinaryAny(type, &p); + } + case typelib_TypeClass_ANY: + { + css::uno::TypeDescription t(readType()); + if (t.get()->eTypeClass == typelib_TypeClass_ANY) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: any of type ANY")), + css::uno::Reference< css::uno::XInterface >()); + } + return readValue(t); + } + case typelib_TypeClass_SEQUENCE: + type.makeComplete(); + return readSequence(type); + case typelib_TypeClass_ENUM: + { + sal_Int32 v = static_cast< sal_Int32 >(read32()); + type.makeComplete(); + typelib_EnumTypeDescription * etd = + reinterpret_cast< typelib_EnumTypeDescription * >(type.get()); + bool found = false; + for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) { + if (etd->pEnumValues[i] == v) { + found = true; + break; + } + } + if (!found) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: unknown enum value")), + css::uno::Reference< css::uno::XInterface >()); + } + return BinaryAny(type, &v); + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + std::vector< BinaryAny > as; + readMemberValues(type, &as); + void * buf = allocate(type.get()->nSize); + copyMemberValues(type, as.begin(), buf); + uno_Any raw; + raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >( + type.get()); + raw.pData = buf; + raw.pReserved = 0; + return BinaryAny(raw); + } + case typelib_TypeClass_INTERFACE: + { + css::uno::UnoInterfaceReference obj( + bridge_->registerIncomingInterface(readOid(), type)); + return BinaryAny(type, &obj.m_pUnoI); + } + } +} + +void Unmarshal::done() const { + if (data_ != end_) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: block contains excess data")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +void Unmarshal::check(sal_Int32 size) const { + if (end_ - data_ < size) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: trying to read past end of block")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +sal_uInt32 Unmarshal::readCompressed() { + sal_uInt8 n = read8(); + return n == 0xFF ? read32() : n; +} + +sal_uInt16 Unmarshal::readCacheIndex() { + sal_uInt16 idx = read16(); + if (idx >= cache::size && idx != cache::ignore) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: cache index out of range")), + css::uno::Reference< css::uno::XInterface >()); + } + return idx; +} + +sal_uInt64 Unmarshal::read64() { + check(8); + sal_uInt64 n = static_cast< sal_uInt64 >(*data_++) << 56; + n |= static_cast< sal_uInt64 >(*data_++) << 48; + n |= static_cast< sal_uInt64 >(*data_++) << 40; + n |= static_cast< sal_uInt64 >(*data_++) << 32; + n |= static_cast< sal_uInt64 >(*data_++) << 24; + n |= static_cast< sal_uInt64 >(*data_++) << 16; + n |= static_cast< sal_uInt64 >(*data_++) << 8; + return n | *data_++; +} + +rtl::OUString Unmarshal::readString() { + sal_uInt32 n = readCompressed(); + if (n > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: string size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + check(static_cast< sal_Int32 >(n)); + rtl::OUString s; + if (!rtl_convertStringToUString( + &s.pData, reinterpret_cast< char const * >(data_), + static_cast< sal_Int32 >(n), RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: string does not contain UTF-8")), + css::uno::Reference< css::uno::XInterface >()); + } + data_ += n; + return s; +} + +BinaryAny Unmarshal::readSequence(css::uno::TypeDescription const & type) { + OSL_ASSERT( + type.is() && type.get()->eTypeClass == typelib_TypeClass_SEQUENCE); + sal_uInt32 n = readCompressed(); + if (n > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + if (n == 0) { + return BinaryAny(type, 0); + } + css::uno::TypeDescription ctd( + reinterpret_cast< typelib_IndirectTypeDescription * >( + type.get())->pType); + if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) { + check(static_cast< sal_Int32 >(n)); + rtl::ByteSequence s( + reinterpret_cast< sal_Int8 const * >(data_), + static_cast< sal_Int32 >(n)); + data_ += n; + sal_Sequence * p = s.getHandle(); + return BinaryAny(type, &p); + } + std::vector< BinaryAny > as; + for (sal_uInt32 i = 0; i != n; ++i) { + as.push_back(readValue(ctd)); + } + OSL_ASSERT(ctd.get()->nSize >= 0); + sal_uInt64 size = static_cast< sal_uInt64 >(n) * + static_cast< sal_uInt64 >(ctd.get()->nSize); + // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow + if (size > SAL_MAX_SIZE - SAL_SEQUENCE_HEADER_SIZE) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: sequence size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + void * buf = allocate( + SAL_SEQUENCE_HEADER_SIZE + static_cast< sal_Size >(size)); + static_cast< sal_Sequence * >(buf)->nRefCount = 0; + static_cast< sal_Sequence * >(buf)->nElements = + static_cast< sal_Int32 >(n); + for (sal_uInt32 i = 0; i != n; ++i) { + uno_copyData( + static_cast< sal_Sequence * >(buf)->elements + i * ctd.get()->nSize, + const_cast< void * >(as[i].getValue(ctd)), ctd.get(), 0); + } + return BinaryAny(type, reinterpret_cast< sal_Sequence ** >(&buf)); +} + +void Unmarshal::readMemberValues( + css::uno::TypeDescription const & type, std::vector< BinaryAny > * values) +{ + OSL_ASSERT( + type.is() && + (type.get()->eTypeClass == typelib_TypeClass_STRUCT || + type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) && + values != 0); + type.makeComplete(); + typelib_CompoundTypeDescription * ctd = + reinterpret_cast< typelib_CompoundTypeDescription * >(type.get()); + if (ctd->pBaseTypeDescription != 0) { + readMemberValues( + css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), + values); + } + for (sal_Int32 i = 0; i != ctd->nMembers; ++i) { + values->push_back( + readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i]))); + } +} + +} |