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>
27 #include <com/sun/star/io/IOException.hpp>
28 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <com/sun/star/uno/Sequence.hxx>
30 #include <cppu/unotype.hxx>
31 #include <rtl/byteseq.hxx>
32 #include <rtl/ref.hxx>
33 #include <rtl/textcvt.h>
34 #include <rtl/textenc.h>
35 #include <rtl/ustring.h>
36 #include <rtl/ustring.hxx>
37 #include <sal/types.h>
38 #include <typelib/typeclass.h>
39 #include <typelib/typedescription.h>
40 #include <typelib/typedescription.hxx>
43 #include <uno/dispatcher.hxx>
45 #include "binaryany.hxx"
48 #include "readerstate.hxx"
49 #include "unmarshal.hxx"
55 void * allocate(sal_Size size
) {
56 void * p
= std::malloc(size
);
58 throw std::bad_alloc();
63 std::vector
< BinaryAny
>::iterator
copyMemberValues(
64 css::uno::TypeDescription
const & type
,
65 std::vector
< BinaryAny
>::iterator
const & it
, void * buffer
) throw ()
69 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
70 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
73 std::vector
< BinaryAny
>::iterator
i(it
);
74 typelib_CompoundTypeDescription
* ctd
=
75 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
76 if (ctd
->pBaseTypeDescription
!= nullptr) {
78 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
), i
,
81 for (sal_Int32 j
= 0; j
!= ctd
->nMembers
; ++j
) {
83 static_cast< char * >(buffer
) + ctd
->pMemberOffsets
[j
],
84 i
++->getValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[j
])),
85 ctd
->ppTypeRefs
[j
], nullptr);
93 rtl::Reference
< Bridge
> const & bridge
, ReaderState
& state
,
94 css::uno::Sequence
< sal_Int8
> const & buffer
):
95 bridge_(bridge
), state_(state
), buffer_(buffer
)
97 data_
= reinterpret_cast< sal_uInt8
const * >(buffer_
.getConstArray());
98 end_
= data_
+ buffer_
.getLength();
101 Unmarshal::~Unmarshal() {}
103 sal_uInt8
Unmarshal::read8() {
108 sal_uInt16
Unmarshal::read16() {
110 sal_uInt16 n
= static_cast< sal_uInt16
>(*data_
++) << 8;
114 sal_uInt32
Unmarshal::read32() {
116 sal_uInt32 n
= static_cast< sal_uInt32
>(*data_
++) << 24;
117 n
|= static_cast< sal_uInt32
>(*data_
++) << 16;
118 n
|= static_cast< sal_uInt32
>(*data_
++) << 8;
122 css::uno::TypeDescription
Unmarshal::readType() {
123 sal_uInt8 flags
= read8();
124 typelib_TypeClass tc
= static_cast< typelib_TypeClass
>(flags
& 0x7F);
126 case typelib_TypeClass_VOID
:
127 case typelib_TypeClass_BOOLEAN
:
128 case typelib_TypeClass_BYTE
:
129 case typelib_TypeClass_SHORT
:
130 case typelib_TypeClass_UNSIGNED_SHORT
:
131 case typelib_TypeClass_LONG
:
132 case typelib_TypeClass_UNSIGNED_LONG
:
133 case typelib_TypeClass_HYPER
:
134 case typelib_TypeClass_UNSIGNED_HYPER
:
135 case typelib_TypeClass_FLOAT
:
136 case typelib_TypeClass_DOUBLE
:
137 case typelib_TypeClass_CHAR
:
138 case typelib_TypeClass_STRING
:
139 case typelib_TypeClass_TYPE
:
140 case typelib_TypeClass_ANY
:
141 if ((flags
& 0x80) != 0) {
142 throw css::io::IOException(
143 "binaryurp::Unmarshal: cache flag of simple type is set");
145 return css::uno::TypeDescription(
146 *typelib_static_type_getByTypeClass(tc
));
147 case typelib_TypeClass_SEQUENCE
:
148 case typelib_TypeClass_ENUM
:
149 case typelib_TypeClass_STRUCT
:
150 case typelib_TypeClass_EXCEPTION
:
151 case typelib_TypeClass_INTERFACE
:
153 sal_uInt16 idx
= readCacheIndex();
154 if ((flags
& 0x80) == 0) {
155 if (idx
== cache::ignore
|| !state_
.typeCache
[idx
].is()) {
156 throw css::io::IOException(
157 "binaryurp::Unmarshal: unknown type cache index");
159 return state_
.typeCache
[idx
];
161 OUString
const str(readString());
162 css::uno::TypeDescription
t(str
);
163 if (!t
.is() || t
.get()->eTypeClass
!= tc
) {
165 throw css::io::IOException(
166 "binaryurp::Unmarshal: type with unknown name: " + str
);
168 for (css::uno::TypeDescription
t2(t
);
169 t2
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
;)
172 t2
= css::uno::TypeDescription(
173 reinterpret_cast< typelib_IndirectTypeDescription
* >(
176 throw css::io::IOException(
177 "binaryurp::Unmarshal: sequence type with unknown"
180 switch (t2
.get()->eTypeClass
) {
181 case typelib_TypeClass_VOID
:
182 case typelib_TypeClass_EXCEPTION
:
183 throw css::io::IOException(
184 "binaryurp::Unmarshal: sequence type with bad"
190 if (idx
!= cache::ignore
) {
191 state_
.typeCache
[idx
] = t
;
197 throw css::io::IOException(
198 "binaryurp::Unmarshal: type of unknown type class");
202 OUString
Unmarshal::readOid() {
203 OUString
oid(readString());
204 for (sal_Int32 i
= 0; i
!= oid
.getLength(); ++i
) {
206 throw css::io::IOException(
207 "binaryurp::Unmarshal: OID contains non-ASCII character");
210 sal_uInt16 idx
= readCacheIndex();
211 if (oid
.isEmpty() && idx
!= cache::ignore
) {
212 if (state_
.oidCache
[idx
].isEmpty()) {
213 throw css::io::IOException(
214 "binaryurp::Unmarshal: unknown OID cache index");
216 return state_
.oidCache
[idx
];
218 if (idx
!= cache::ignore
) {
219 state_
.oidCache
[idx
] = oid
;
224 rtl::ByteSequence
Unmarshal::readTid() {
225 rtl::ByteSequence
tid(
226 *static_cast< sal_Sequence
* const * >(
228 css::uno::TypeDescription(
229 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get())).
231 css::uno::TypeDescription(
232 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get()))));
233 sal_uInt16 idx
= readCacheIndex();
234 if (tid
.getLength() == 0) {
235 if (idx
== cache::ignore
|| state_
.tidCache
[idx
].getLength() == 0) {
236 throw css::io::IOException(
237 "binaryurp::Unmarshal: unknown TID cache index");
239 return state_
.tidCache
[idx
];
241 if (idx
!= cache::ignore
) {
242 state_
.tidCache
[idx
] = tid
;
247 BinaryAny
Unmarshal::readValue(css::uno::TypeDescription
const & type
) {
249 switch (type
.get()->eTypeClass
) {
251 std::abort(); // this cannot happen
252 // pseudo fall-through to avoid compiler warnings
253 case typelib_TypeClass_VOID
:
255 case typelib_TypeClass_BOOLEAN
:
257 sal_uInt8 v
= read8();
259 throw css::io::IOException(
260 "binaryurp::Unmarshal: boolean of unknown value");
262 return BinaryAny(type
, &v
);
264 case typelib_TypeClass_BYTE
:
266 sal_uInt8 v
= read8();
267 return BinaryAny(type
, &v
);
269 case typelib_TypeClass_SHORT
:
270 case typelib_TypeClass_UNSIGNED_SHORT
:
271 case typelib_TypeClass_CHAR
:
273 sal_uInt16 v
= read16();
274 return BinaryAny(type
, &v
);
276 case typelib_TypeClass_LONG
:
277 case typelib_TypeClass_UNSIGNED_LONG
:
278 case typelib_TypeClass_FLOAT
:
280 sal_uInt32 v
= read32();
281 return BinaryAny(type
, &v
);
283 case typelib_TypeClass_HYPER
:
284 case typelib_TypeClass_UNSIGNED_HYPER
:
285 case typelib_TypeClass_DOUBLE
:
287 sal_uInt64 v
= read64();
288 return BinaryAny(type
, &v
);
290 case typelib_TypeClass_STRING
:
292 OUString
v(readString());
293 return BinaryAny(type
, &v
.pData
);
295 case typelib_TypeClass_TYPE
:
297 css::uno::TypeDescription
v(readType());
298 typelib_TypeDescription
* p
= v
.get();
299 return BinaryAny(type
, &p
);
301 case typelib_TypeClass_ANY
:
303 css::uno::TypeDescription
t(readType());
304 if (t
.get()->eTypeClass
== typelib_TypeClass_ANY
) {
305 throw css::io::IOException(
306 "binaryurp::Unmarshal: any of type ANY");
310 case typelib_TypeClass_SEQUENCE
:
312 return readSequence(type
);
313 case typelib_TypeClass_ENUM
:
315 sal_Int32 v
= static_cast< sal_Int32
>(read32());
317 typelib_EnumTypeDescription
* etd
=
318 reinterpret_cast< typelib_EnumTypeDescription
* >(type
.get());
320 for (sal_Int32 i
= 0; i
!= etd
->nEnumValues
; ++i
) {
321 if (etd
->pEnumValues
[i
] == v
) {
327 throw css::io::IOException(
328 "binaryurp::Unmarshal: unknown enum value");
330 return BinaryAny(type
, &v
);
332 case typelib_TypeClass_STRUCT
:
333 case typelib_TypeClass_EXCEPTION
:
335 std::vector
< BinaryAny
> as
;
336 readMemberValues(type
, &as
);
337 void * buf
= allocate(type
.get()->nSize
);
338 copyMemberValues(type
, as
.begin(), buf
);
340 raw
.pType
= reinterpret_cast< typelib_TypeDescriptionReference
* >(
343 raw
.pReserved
= nullptr;
344 return BinaryAny(raw
);
346 case typelib_TypeClass_INTERFACE
:
348 css::uno::UnoInterfaceReference
obj(
349 bridge_
->registerIncomingInterface(readOid(), type
));
350 return BinaryAny(type
, &obj
.m_pUnoI
);
355 void Unmarshal::done() const {
357 throw css::io::IOException(
358 "binaryurp::Unmarshal: block contains excess data");
362 void Unmarshal::check(sal_Int32 size
) const {
363 if (end_
- data_
< size
) {
364 throw css::io::IOException(
365 "binaryurp::Unmarshal: trying to read past end of block");
369 sal_uInt32
Unmarshal::readCompressed() {
370 sal_uInt8 n
= read8();
371 return n
== 0xFF ? read32() : n
;
374 sal_uInt16
Unmarshal::readCacheIndex() {
375 sal_uInt16 idx
= read16();
376 if (idx
>= cache::size
&& idx
!= cache::ignore
) {
377 throw css::io::IOException(
378 "binaryurp::Unmarshal: cache index out of range");
383 sal_uInt64
Unmarshal::read64() {
385 sal_uInt64 n
= static_cast< sal_uInt64
>(*data_
++) << 56;
386 n
|= static_cast< sal_uInt64
>(*data_
++) << 48;
387 n
|= static_cast< sal_uInt64
>(*data_
++) << 40;
388 n
|= static_cast< sal_uInt64
>(*data_
++) << 32;
389 n
|= static_cast< sal_uInt64
>(*data_
++) << 24;
390 n
|= static_cast< sal_uInt64
>(*data_
++) << 16;
391 n
|= static_cast< sal_uInt64
>(*data_
++) << 8;
395 OUString
Unmarshal::readString() {
396 sal_uInt32 n
= readCompressed();
397 if (n
> SAL_MAX_INT32
) {
398 throw css::uno::RuntimeException(
399 "binaryurp::Unmarshal: string size too large");
401 check(static_cast< sal_Int32
>(n
));
403 if (!rtl_convertStringToUString(
404 &s
.pData
, reinterpret_cast< char const * >(data_
),
405 static_cast< sal_Int32
>(n
), RTL_TEXTENCODING_UTF8
,
406 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
407 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
408 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
410 throw css::io::IOException(
411 "binaryurp::Unmarshal: string does not contain UTF-8");
417 BinaryAny
Unmarshal::readSequence(css::uno::TypeDescription
const & type
) {
418 assert(type
.is() && type
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
);
419 sal_uInt32 n
= readCompressed();
420 if (n
> SAL_MAX_INT32
) {
421 throw css::uno::RuntimeException(
422 "binaryurp::Unmarshal: sequence size too large");
425 return BinaryAny(type
, nullptr);
427 css::uno::TypeDescription
ctd(
428 reinterpret_cast< typelib_IndirectTypeDescription
* >(
430 if (ctd
.get()->eTypeClass
== typelib_TypeClass_BYTE
) {
431 check(static_cast< sal_Int32
>(n
));
433 reinterpret_cast< sal_Int8
const * >(data_
),
434 static_cast< sal_Int32
>(n
));
436 sal_Sequence
* p
= s
.getHandle();
437 return BinaryAny(type
, &p
);
439 std::vector
< BinaryAny
> as
;
440 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
441 as
.push_back(readValue(ctd
));
443 assert(ctd
.get()->nSize
>= 0);
444 sal_uInt64 size
= static_cast< sal_uInt64
>(n
) *
445 static_cast< sal_uInt64
>(ctd
.get()->nSize
);
446 // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow
447 if (size
> SAL_MAX_SIZE
- SAL_SEQUENCE_HEADER_SIZE
) {
448 throw css::uno::RuntimeException(
449 "binaryurp::Unmarshal: sequence size too large");
451 void * buf
= allocate(
452 SAL_SEQUENCE_HEADER_SIZE
+ static_cast< sal_Size
>(size
));
453 static_cast< sal_Sequence
* >(buf
)->nRefCount
= 0;
454 static_cast< sal_Sequence
* >(buf
)->nElements
=
455 static_cast< sal_Int32
>(n
);
456 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
458 static_cast< sal_Sequence
* >(buf
)->elements
+ i
* ctd
.get()->nSize
,
459 as
[i
].getValue(ctd
), ctd
.get(), nullptr);
461 return BinaryAny(type
, &buf
);
464 void Unmarshal::readMemberValues(
465 css::uno::TypeDescription
const & type
, std::vector
< BinaryAny
> * values
)
469 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
470 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
473 typelib_CompoundTypeDescription
* ctd
=
474 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
475 if (ctd
->pBaseTypeDescription
!= nullptr) {
477 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
),
480 for (sal_Int32 i
= 0; i
!= ctd
->nMembers
; ++i
) {
482 readValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[i
])));
488 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */