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/Reference.hxx>
29 #include <com/sun/star/uno/RuntimeException.hpp>
30 #include <com/sun/star/uno/Sequence.hxx>
31 #include <com/sun/star/uno/XInterface.hpp>
32 #include <cppu/unotype.hxx>
33 #include <rtl/byteseq.hxx>
34 #include <rtl/ref.hxx>
35 #include <rtl/textcvt.h>
36 #include <rtl/textenc.h>
37 #include <rtl/ustring.h>
38 #include <rtl/ustring.hxx>
39 #include <sal/types.h>
40 #include <typelib/typeclass.h>
41 #include <typelib/typedescription.h>
42 #include <typelib/typedescription.hxx>
45 #include <uno/dispatcher.hxx>
47 #include "binaryany.hxx"
50 #include "readerstate.hxx"
51 #include "unmarshal.hxx"
57 void * allocate(sal_Size size
) {
58 void * p
= std::malloc(size
);
60 throw std::bad_alloc();
65 std::vector
< BinaryAny
>::iterator
copyMemberValues(
66 css::uno::TypeDescription
const & type
,
67 std::vector
< BinaryAny
>::iterator
const & it
, void * buffer
) throw ()
71 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
72 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
75 std::vector
< BinaryAny
>::iterator
i(it
);
76 typelib_CompoundTypeDescription
* ctd
=
77 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
78 if (ctd
->pBaseTypeDescription
!= nullptr) {
80 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
), i
,
83 for (sal_Int32 j
= 0; j
!= ctd
->nMembers
; ++j
) {
85 static_cast< char * >(buffer
) + ctd
->pMemberOffsets
[j
],
86 i
++->getValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[j
])),
87 ctd
->ppTypeRefs
[j
], nullptr);
95 rtl::Reference
< Bridge
> const & bridge
, ReaderState
& state
,
96 css::uno::Sequence
< sal_Int8
> const & buffer
):
97 bridge_(bridge
), state_(state
), buffer_(buffer
)
99 data_
= reinterpret_cast< sal_uInt8
const * >(buffer_
.getConstArray());
100 end_
= data_
+ buffer_
.getLength();
103 Unmarshal::~Unmarshal() {}
105 sal_uInt8
Unmarshal::read8() {
110 sal_uInt16
Unmarshal::read16() {
112 sal_uInt16 n
= static_cast< sal_uInt16
>(*data_
++) << 8;
116 sal_uInt32
Unmarshal::read32() {
118 sal_uInt32 n
= static_cast< sal_uInt32
>(*data_
++) << 24;
119 n
|= static_cast< sal_uInt32
>(*data_
++) << 16;
120 n
|= static_cast< sal_uInt32
>(*data_
++) << 8;
124 css::uno::TypeDescription
Unmarshal::readType() {
125 sal_uInt8 flags
= read8();
126 typelib_TypeClass tc
= static_cast< typelib_TypeClass
>(flags
& 0x7F);
128 case typelib_TypeClass_VOID
:
129 case typelib_TypeClass_BOOLEAN
:
130 case typelib_TypeClass_BYTE
:
131 case typelib_TypeClass_SHORT
:
132 case typelib_TypeClass_UNSIGNED_SHORT
:
133 case typelib_TypeClass_LONG
:
134 case typelib_TypeClass_UNSIGNED_LONG
:
135 case typelib_TypeClass_HYPER
:
136 case typelib_TypeClass_UNSIGNED_HYPER
:
137 case typelib_TypeClass_FLOAT
:
138 case typelib_TypeClass_DOUBLE
:
139 case typelib_TypeClass_CHAR
:
140 case typelib_TypeClass_STRING
:
141 case typelib_TypeClass_TYPE
:
142 case typelib_TypeClass_ANY
:
143 if ((flags
& 0x80) != 0) {
144 throw css::io::IOException(
145 "binaryurp::Unmarshal: cache flag of simple type is set");
147 return css::uno::TypeDescription(
148 *typelib_static_type_getByTypeClass(tc
));
149 case typelib_TypeClass_SEQUENCE
:
150 case typelib_TypeClass_ENUM
:
151 case typelib_TypeClass_STRUCT
:
152 case typelib_TypeClass_EXCEPTION
:
153 case typelib_TypeClass_INTERFACE
:
155 sal_uInt16 idx
= readCacheIndex();
156 if ((flags
& 0x80) == 0) {
157 if (idx
== cache::ignore
|| !state_
.typeCache
[idx
].is()) {
158 throw css::io::IOException(
159 "binaryurp::Unmarshal: unknown type cache index");
161 return state_
.typeCache
[idx
];
163 OUString
const str(readString());
164 css::uno::TypeDescription
t(str
);
165 if (!t
.is() || t
.get()->eTypeClass
!= tc
) {
167 throw css::io::IOException(
168 "binaryurp::Unmarshal: type with unknown name: " + str
);
170 for (css::uno::TypeDescription
t2(t
);
171 t2
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
;)
174 t2
= css::uno::TypeDescription(
175 reinterpret_cast< typelib_IndirectTypeDescription
* >(
178 throw css::io::IOException(
179 "binaryurp::Unmarshal: sequence type with unknown"
182 switch (t2
.get()->eTypeClass
) {
183 case typelib_TypeClass_VOID
:
184 case typelib_TypeClass_EXCEPTION
:
185 throw css::io::IOException(
186 "binaryurp::Unmarshal: sequence type with bad"
192 if (idx
!= cache::ignore
) {
193 state_
.typeCache
[idx
] = t
;
199 throw css::io::IOException(
200 "binaryurp::Unmarshal: type of unknown type class");
204 OUString
Unmarshal::readOid() {
205 OUString
oid(readString());
206 for (sal_Int32 i
= 0; i
!= oid
.getLength(); ++i
) {
208 throw css::io::IOException(
209 "binaryurp::Unmarshal: OID contains non-ASCII character");
212 sal_uInt16 idx
= readCacheIndex();
213 if (oid
.isEmpty() && idx
!= cache::ignore
) {
214 if (state_
.oidCache
[idx
].isEmpty()) {
215 throw css::io::IOException(
216 "binaryurp::Unmarshal: unknown OID cache index");
218 return state_
.oidCache
[idx
];
220 if (idx
!= cache::ignore
) {
221 state_
.oidCache
[idx
] = oid
;
226 rtl::ByteSequence
Unmarshal::readTid() {
227 rtl::ByteSequence
tid(
228 *static_cast< sal_Sequence
* const * >(
230 css::uno::TypeDescription(
231 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get())).
233 css::uno::TypeDescription(
234 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get()))));
235 sal_uInt16 idx
= readCacheIndex();
236 if (tid
.getLength() == 0) {
237 if (idx
== cache::ignore
|| state_
.tidCache
[idx
].getLength() == 0) {
238 throw css::io::IOException(
239 "binaryurp::Unmarshal: unknown TID cache index");
241 return state_
.tidCache
[idx
];
243 if (idx
!= cache::ignore
) {
244 state_
.tidCache
[idx
] = tid
;
249 BinaryAny
Unmarshal::readValue(css::uno::TypeDescription
const & type
) {
251 switch (type
.get()->eTypeClass
) {
253 std::abort(); // this cannot happen
254 // pseudo fall-through to avoid compiler warnings
255 case typelib_TypeClass_VOID
:
257 case typelib_TypeClass_BOOLEAN
:
259 sal_uInt8 v
= read8();
261 throw css::io::IOException(
262 "binaryurp::Unmarshal: boolean of unknown value");
264 return BinaryAny(type
, &v
);
266 case typelib_TypeClass_BYTE
:
268 sal_uInt8 v
= read8();
269 return BinaryAny(type
, &v
);
271 case typelib_TypeClass_SHORT
:
272 case typelib_TypeClass_UNSIGNED_SHORT
:
273 case typelib_TypeClass_CHAR
:
275 sal_uInt16 v
= read16();
276 return BinaryAny(type
, &v
);
278 case typelib_TypeClass_LONG
:
279 case typelib_TypeClass_UNSIGNED_LONG
:
280 case typelib_TypeClass_FLOAT
:
282 sal_uInt32 v
= read32();
283 return BinaryAny(type
, &v
);
285 case typelib_TypeClass_HYPER
:
286 case typelib_TypeClass_UNSIGNED_HYPER
:
287 case typelib_TypeClass_DOUBLE
:
289 sal_uInt64 v
= read64();
290 return BinaryAny(type
, &v
);
292 case typelib_TypeClass_STRING
:
294 OUString
v(readString());
295 return BinaryAny(type
, &v
.pData
);
297 case typelib_TypeClass_TYPE
:
299 css::uno::TypeDescription
v(readType());
300 typelib_TypeDescription
* p
= v
.get();
301 return BinaryAny(type
, &p
);
303 case typelib_TypeClass_ANY
:
305 css::uno::TypeDescription
t(readType());
306 if (t
.get()->eTypeClass
== typelib_TypeClass_ANY
) {
307 throw css::io::IOException(
308 "binaryurp::Unmarshal: any of type ANY");
312 case typelib_TypeClass_SEQUENCE
:
314 return readSequence(type
);
315 case typelib_TypeClass_ENUM
:
317 sal_Int32 v
= static_cast< sal_Int32
>(read32());
319 typelib_EnumTypeDescription
* etd
=
320 reinterpret_cast< typelib_EnumTypeDescription
* >(type
.get());
322 for (sal_Int32 i
= 0; i
!= etd
->nEnumValues
; ++i
) {
323 if (etd
->pEnumValues
[i
] == v
) {
329 throw css::io::IOException(
330 "binaryurp::Unmarshal: unknown enum value");
332 return BinaryAny(type
, &v
);
334 case typelib_TypeClass_STRUCT
:
335 case typelib_TypeClass_EXCEPTION
:
337 std::vector
< BinaryAny
> as
;
338 readMemberValues(type
, &as
);
339 void * buf
= allocate(type
.get()->nSize
);
340 copyMemberValues(type
, as
.begin(), buf
);
342 raw
.pType
= reinterpret_cast< typelib_TypeDescriptionReference
* >(
345 raw
.pReserved
= nullptr;
346 return BinaryAny(raw
);
348 case typelib_TypeClass_INTERFACE
:
350 css::uno::UnoInterfaceReference
obj(
351 bridge_
->registerIncomingInterface(readOid(), type
));
352 return BinaryAny(type
, &obj
.m_pUnoI
);
357 void Unmarshal::done() const {
359 throw css::io::IOException(
360 "binaryurp::Unmarshal: block contains excess data");
364 void Unmarshal::check(sal_Int32 size
) const {
365 if (end_
- data_
< size
) {
366 throw css::io::IOException(
367 "binaryurp::Unmarshal: trying to read past end of block");
371 sal_uInt32
Unmarshal::readCompressed() {
372 sal_uInt8 n
= read8();
373 return n
== 0xFF ? read32() : n
;
376 sal_uInt16
Unmarshal::readCacheIndex() {
377 sal_uInt16 idx
= read16();
378 if (idx
>= cache::size
&& idx
!= cache::ignore
) {
379 throw css::io::IOException(
380 "binaryurp::Unmarshal: cache index out of range");
385 sal_uInt64
Unmarshal::read64() {
387 sal_uInt64 n
= static_cast< sal_uInt64
>(*data_
++) << 56;
388 n
|= static_cast< sal_uInt64
>(*data_
++) << 48;
389 n
|= static_cast< sal_uInt64
>(*data_
++) << 40;
390 n
|= static_cast< sal_uInt64
>(*data_
++) << 32;
391 n
|= static_cast< sal_uInt64
>(*data_
++) << 24;
392 n
|= static_cast< sal_uInt64
>(*data_
++) << 16;
393 n
|= static_cast< sal_uInt64
>(*data_
++) << 8;
397 OUString
Unmarshal::readString() {
398 sal_uInt32 n
= readCompressed();
399 if (n
> SAL_MAX_INT32
) {
400 throw css::uno::RuntimeException(
401 "binaryurp::Unmarshal: string size too large");
403 check(static_cast< sal_Int32
>(n
));
405 if (!rtl_convertStringToUString(
406 &s
.pData
, reinterpret_cast< char const * >(data_
),
407 static_cast< sal_Int32
>(n
), RTL_TEXTENCODING_UTF8
,
408 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
409 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
410 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
412 throw css::io::IOException(
413 "binaryurp::Unmarshal: string does not contain UTF-8");
419 BinaryAny
Unmarshal::readSequence(css::uno::TypeDescription
const & type
) {
420 assert(type
.is() && type
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
);
421 sal_uInt32 n
= readCompressed();
422 if (n
> SAL_MAX_INT32
) {
423 throw css::uno::RuntimeException(
424 "binaryurp::Unmarshal: sequence size too large");
427 return BinaryAny(type
, nullptr);
429 css::uno::TypeDescription
ctd(
430 reinterpret_cast< typelib_IndirectTypeDescription
* >(
432 if (ctd
.get()->eTypeClass
== typelib_TypeClass_BYTE
) {
433 check(static_cast< sal_Int32
>(n
));
435 reinterpret_cast< sal_Int8
const * >(data_
),
436 static_cast< sal_Int32
>(n
));
438 sal_Sequence
* p
= s
.getHandle();
439 return BinaryAny(type
, &p
);
441 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 for (sal_Int32 i
= 0; i
!= ctd
->nMembers
; ++i
) {
484 readValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[i
])));
490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */