1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
28 #include <com/sun/star/io/IOException.hpp>
29 #include <com/sun/star/uno/RuntimeException.hpp>
30 #include <com/sun/star/uno/Sequence.hxx>
31 #include <cppu/unotype.hxx>
32 #include <rtl/byteseq.hxx>
33 #include <rtl/ref.hxx>
34 #include <rtl/textcvt.h>
35 #include <rtl/textenc.h>
36 #include <rtl/ustring.h>
37 #include <rtl/ustring.hxx>
38 #include <sal/types.h>
39 #include <typelib/typeclass.h>
40 #include <typelib/typedescription.h>
41 #include <typelib/typedescription.hxx>
44 #include <uno/dispatcher.hxx>
46 #include "binaryany.hxx"
49 #include "readerstate.hxx"
50 #include "unmarshal.hxx"
56 void * allocate(sal_Size size
) {
57 void * p
= std::malloc(size
);
59 throw std::bad_alloc();
64 std::vector
< BinaryAny
>::iterator
copyMemberValues(
65 css::uno::TypeDescription
const & type
,
66 std::vector
< BinaryAny
>::iterator
const & it
, void * buffer
) noexcept
70 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
71 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
74 std::vector
< BinaryAny
>::iterator
i(it
);
75 typelib_CompoundTypeDescription
* ctd
=
76 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
77 if (ctd
->pBaseTypeDescription
!= nullptr) {
79 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
), i
,
82 for (sal_Int32 j
= 0; j
!= ctd
->nMembers
; ++j
) {
84 static_cast< char * >(buffer
) + ctd
->pMemberOffsets
[j
],
85 i
++->getValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[j
])),
86 ctd
->ppTypeRefs
[j
], nullptr);
94 rtl::Reference
< Bridge
> bridge
, ReaderState
& state
,
95 css::uno::Sequence
< sal_Int8
> const & buffer
):
96 bridge_(std::move(bridge
)), state_(state
), buffer_(buffer
)
98 data_
= reinterpret_cast< sal_uInt8
const * >(buffer_
.getConstArray());
99 end_
= data_
+ buffer_
.getLength();
102 Unmarshal::~Unmarshal() {}
104 sal_uInt8
Unmarshal::read8() {
109 sal_uInt16
Unmarshal::read16() {
111 sal_uInt16 n
= static_cast< sal_uInt16
>(*data_
++) << 8;
115 sal_uInt32
Unmarshal::read32() {
117 sal_uInt32 n
= static_cast< sal_uInt32
>(*data_
++) << 24;
118 n
|= static_cast< sal_uInt32
>(*data_
++) << 16;
119 n
|= static_cast< sal_uInt32
>(*data_
++) << 8;
123 css::uno::TypeDescription
Unmarshal::readType() {
124 sal_uInt8 flags
= read8();
125 typelib_TypeClass tc
= static_cast< typelib_TypeClass
>(flags
& 0x7F);
127 case typelib_TypeClass_VOID
:
128 case typelib_TypeClass_BOOLEAN
:
129 case typelib_TypeClass_BYTE
:
130 case typelib_TypeClass_SHORT
:
131 case typelib_TypeClass_UNSIGNED_SHORT
:
132 case typelib_TypeClass_LONG
:
133 case typelib_TypeClass_UNSIGNED_LONG
:
134 case typelib_TypeClass_HYPER
:
135 case typelib_TypeClass_UNSIGNED_HYPER
:
136 case typelib_TypeClass_FLOAT
:
137 case typelib_TypeClass_DOUBLE
:
138 case typelib_TypeClass_CHAR
:
139 case typelib_TypeClass_STRING
:
140 case typelib_TypeClass_TYPE
:
141 case typelib_TypeClass_ANY
:
142 if ((flags
& 0x80) != 0) {
143 throw css::io::IOException(
144 "binaryurp::Unmarshal: cache flag of simple type is set");
146 return css::uno::TypeDescription(
147 *typelib_static_type_getByTypeClass(tc
));
148 case typelib_TypeClass_SEQUENCE
:
149 case typelib_TypeClass_ENUM
:
150 case typelib_TypeClass_STRUCT
:
151 case typelib_TypeClass_EXCEPTION
:
152 case typelib_TypeClass_INTERFACE
:
154 sal_uInt16 idx
= readCacheIndex();
155 if ((flags
& 0x80) == 0) {
156 if (idx
== cache::ignore
|| !state_
.typeCache
[idx
].is()) {
157 throw css::io::IOException(
158 "binaryurp::Unmarshal: unknown type cache index");
160 return state_
.typeCache
[idx
];
162 OUString
const str(readString());
163 css::uno::TypeDescription
t(str
);
164 if (!t
.is() || t
.get()->eTypeClass
!= tc
) {
166 throw css::io::IOException(
167 "binaryurp::Unmarshal: type with unknown name: " + str
);
169 for (css::uno::TypeDescription
t2(t
);
170 t2
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
;)
173 t2
= css::uno::TypeDescription(
174 reinterpret_cast< typelib_IndirectTypeDescription
* >(
177 throw css::io::IOException(
178 "binaryurp::Unmarshal: sequence type with unknown"
181 switch (t2
.get()->eTypeClass
) {
182 case typelib_TypeClass_VOID
:
183 case typelib_TypeClass_EXCEPTION
:
184 throw css::io::IOException(
185 "binaryurp::Unmarshal: sequence type with bad"
191 if (idx
!= cache::ignore
) {
192 state_
.typeCache
[idx
] = t
;
198 throw css::io::IOException(
199 "binaryurp::Unmarshal: type of unknown type class");
203 OUString
Unmarshal::readOid() {
204 OUString
oid(readString());
205 for (sal_Int32 i
= 0; i
!= oid
.getLength(); ++i
) {
207 throw css::io::IOException(
208 "binaryurp::Unmarshal: OID contains non-ASCII character");
211 sal_uInt16 idx
= readCacheIndex();
212 if (oid
.isEmpty() && idx
!= cache::ignore
) {
213 if (state_
.oidCache
[idx
].isEmpty()) {
214 throw css::io::IOException(
215 "binaryurp::Unmarshal: unknown OID cache index");
217 return state_
.oidCache
[idx
];
219 if (idx
!= cache::ignore
) {
220 state_
.oidCache
[idx
] = oid
;
225 rtl::ByteSequence
Unmarshal::readTid() {
226 rtl::ByteSequence
tid(
227 *static_cast< sal_Sequence
* const * >(
229 css::uno::TypeDescription(
230 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get())).
232 css::uno::TypeDescription(
233 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get()))));
234 sal_uInt16 idx
= readCacheIndex();
235 if (tid
.getLength() == 0) {
236 if (idx
== cache::ignore
|| state_
.tidCache
[idx
].getLength() == 0) {
237 throw css::io::IOException(
238 "binaryurp::Unmarshal: unknown TID cache index");
240 return state_
.tidCache
[idx
];
242 if (idx
!= cache::ignore
) {
243 state_
.tidCache
[idx
] = tid
;
248 BinaryAny
Unmarshal::readValue(css::uno::TypeDescription
const & type
) {
250 switch (type
.get()->eTypeClass
) {
252 std::abort(); // this cannot happen
253 // pseudo fall-through to avoid compiler warnings
254 case typelib_TypeClass_VOID
:
256 case typelib_TypeClass_BOOLEAN
:
258 sal_uInt8 v
= read8();
260 throw css::io::IOException(
261 "binaryurp::Unmarshal: boolean of unknown value");
263 return BinaryAny(type
, &v
);
265 case typelib_TypeClass_BYTE
:
267 sal_uInt8 v
= read8();
268 return BinaryAny(type
, &v
);
270 case typelib_TypeClass_SHORT
:
271 case typelib_TypeClass_UNSIGNED_SHORT
:
272 case typelib_TypeClass_CHAR
:
274 sal_uInt16 v
= read16();
275 return BinaryAny(type
, &v
);
277 case typelib_TypeClass_LONG
:
278 case typelib_TypeClass_UNSIGNED_LONG
:
279 case typelib_TypeClass_FLOAT
:
281 sal_uInt32 v
= read32();
282 return BinaryAny(type
, &v
);
284 case typelib_TypeClass_HYPER
:
285 case typelib_TypeClass_UNSIGNED_HYPER
:
286 case typelib_TypeClass_DOUBLE
:
288 sal_uInt64 v
= read64();
289 return BinaryAny(type
, &v
);
291 case typelib_TypeClass_STRING
:
293 OUString
v(readString());
294 return BinaryAny(type
, &v
.pData
);
296 case typelib_TypeClass_TYPE
:
298 css::uno::TypeDescription
v(readType());
299 typelib_TypeDescription
* p
= v
.get();
300 return BinaryAny(type
, &p
);
302 case typelib_TypeClass_ANY
:
304 css::uno::TypeDescription
t(readType());
305 if (t
.get()->eTypeClass
== typelib_TypeClass_ANY
) {
306 throw css::io::IOException(
307 "binaryurp::Unmarshal: any of type ANY");
311 case typelib_TypeClass_SEQUENCE
:
313 return readSequence(type
);
314 case typelib_TypeClass_ENUM
:
316 sal_Int32 v
= static_cast< sal_Int32
>(read32());
318 typelib_EnumTypeDescription
* etd
=
319 reinterpret_cast< typelib_EnumTypeDescription
* >(type
.get());
321 for (sal_Int32 i
= 0; i
!= etd
->nEnumValues
; ++i
) {
322 if (etd
->pEnumValues
[i
] == v
) {
328 throw css::io::IOException(
329 "binaryurp::Unmarshal: unknown enum value");
331 return BinaryAny(type
, &v
);
333 case typelib_TypeClass_STRUCT
:
334 case typelib_TypeClass_EXCEPTION
:
336 std::vector
< BinaryAny
> as
;
337 readMemberValues(type
, &as
);
338 void * buf
= allocate(type
.get()->nSize
);
339 copyMemberValues(type
, as
.begin(), buf
);
341 raw
.pType
= reinterpret_cast< typelib_TypeDescriptionReference
* >(
344 raw
.pReserved
= nullptr;
345 return BinaryAny(raw
);
347 case typelib_TypeClass_INTERFACE
:
349 css::uno::UnoInterfaceReference
obj(
350 bridge_
->registerIncomingInterface(readOid(), type
));
351 return BinaryAny(type
, &obj
.m_pUnoI
);
356 void Unmarshal::done() const {
358 throw css::io::IOException(
359 "binaryurp::Unmarshal: block contains excess data");
363 void Unmarshal::check(sal_Int32 size
) const {
364 if (end_
- data_
< size
) {
365 throw css::io::IOException(
366 "binaryurp::Unmarshal: trying to read past end of block");
370 sal_uInt32
Unmarshal::readCompressed() {
371 sal_uInt8 n
= read8();
372 return n
== 0xFF ? read32() : n
;
375 sal_uInt16
Unmarshal::readCacheIndex() {
376 sal_uInt16 idx
= read16();
377 if (idx
>= cache::size
&& idx
!= cache::ignore
) {
378 throw css::io::IOException(
379 "binaryurp::Unmarshal: cache index out of range");
384 sal_uInt64
Unmarshal::read64() {
386 sal_uInt64 n
= static_cast< sal_uInt64
>(*data_
++) << 56;
387 n
|= static_cast< sal_uInt64
>(*data_
++) << 48;
388 n
|= static_cast< sal_uInt64
>(*data_
++) << 40;
389 n
|= static_cast< sal_uInt64
>(*data_
++) << 32;
390 n
|= static_cast< sal_uInt64
>(*data_
++) << 24;
391 n
|= static_cast< sal_uInt64
>(*data_
++) << 16;
392 n
|= static_cast< sal_uInt64
>(*data_
++) << 8;
396 OUString
Unmarshal::readString() {
397 sal_uInt32 n
= readCompressed();
398 if (n
> SAL_MAX_INT32
) {
399 throw css::uno::RuntimeException(
400 "binaryurp::Unmarshal: string size too large");
402 check(static_cast< sal_Int32
>(n
));
404 if (!rtl_convertStringToUString(
405 &s
.pData
, reinterpret_cast< char const * >(data_
),
406 static_cast< sal_Int32
>(n
), RTL_TEXTENCODING_UTF8
,
407 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
408 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
409 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
411 throw css::io::IOException(
412 "binaryurp::Unmarshal: string does not contain UTF-8");
418 BinaryAny
Unmarshal::readSequence(css::uno::TypeDescription
const & type
) {
419 assert(type
.is() && type
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
);
420 sal_uInt32 n
= readCompressed();
421 if (n
> SAL_MAX_INT32
) {
422 throw css::uno::RuntimeException(
423 "binaryurp::Unmarshal: sequence size too large");
426 return BinaryAny(type
, nullptr);
428 css::uno::TypeDescription
ctd(
429 reinterpret_cast< typelib_IndirectTypeDescription
* >(
431 if (ctd
.get()->eTypeClass
== typelib_TypeClass_BYTE
) {
432 check(static_cast< sal_Int32
>(n
));
434 reinterpret_cast< sal_Int8
const * >(data_
),
435 static_cast< sal_Int32
>(n
));
437 sal_Sequence
* p
= s
.getHandle();
438 return BinaryAny(type
, &p
);
440 std::vector
< BinaryAny
> as
;
442 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
443 as
.push_back(readValue(ctd
));
445 assert(ctd
.get()->nSize
>= 0);
446 sal_uInt64 size
= static_cast< sal_uInt64
>(n
) *
447 static_cast< sal_uInt64
>(ctd
.get()->nSize
);
448 // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow
449 if (size
> SAL_MAX_SIZE
- SAL_SEQUENCE_HEADER_SIZE
) {
450 throw css::uno::RuntimeException(
451 "binaryurp::Unmarshal: sequence size too large");
453 void * buf
= allocate(
454 SAL_SEQUENCE_HEADER_SIZE
+ static_cast< sal_Size
>(size
));
455 static_cast< sal_Sequence
* >(buf
)->nRefCount
= 0;
456 static_cast< sal_Sequence
* >(buf
)->nElements
=
457 static_cast< sal_Int32
>(n
);
458 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
460 static_cast< sal_Sequence
* >(buf
)->elements
+ i
* ctd
.get()->nSize
,
461 as
[i
].getValue(ctd
), ctd
.get(), nullptr);
463 return BinaryAny(type
, &buf
);
466 void Unmarshal::readMemberValues(
467 css::uno::TypeDescription
const & type
, std::vector
< BinaryAny
> * values
)
471 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
472 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
475 typelib_CompoundTypeDescription
* ctd
=
476 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
477 if (ctd
->pBaseTypeDescription
!= nullptr) {
479 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
),
482 values
->reserve(values
->size() + ctd
->nMembers
);
483 for (sal_Int32 i
= 0; i
!= ctd
->nMembers
; ++i
) {
485 readValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[i
])));
491 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */