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 "boost/noncopyable.hpp"
28 #include "com/sun/star/io/IOException.hpp"
29 #include "com/sun/star/uno/Reference.hxx"
30 #include "com/sun/star/uno/RuntimeException.hpp"
31 #include "com/sun/star/uno/Sequence.hxx"
32 #include "com/sun/star/uno/XInterface.hpp"
33 #include "cppu/unotype.hxx"
34 #include "rtl/byteseq.hxx"
35 #include "rtl/ref.hxx"
36 #include "rtl/textcvt.h"
37 #include "rtl/textenc.h"
38 #include "rtl/ustring.h"
39 #include "rtl/ustring.hxx"
40 #include "sal/types.h"
41 #include "typelib/typeclass.h"
42 #include "typelib/typedescription.h"
43 #include "typelib/typedescription.hxx"
46 #include "uno/dispatcher.hxx"
48 #include "binaryany.hxx"
51 #include "readerstate.hxx"
52 #include "unmarshal.hxx"
58 void * allocate(sal_Size size
) {
59 void * p
= rtl_allocateMemory(size
);
61 throw std::bad_alloc();
66 std::vector
< BinaryAny
>::iterator
copyMemberValues(
67 css::uno::TypeDescription
const & type
,
68 std::vector
< BinaryAny
>::iterator
const & it
, void * buffer
) throw ()
72 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
73 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
76 std::vector
< BinaryAny
>::iterator
i(it
);
77 typelib_CompoundTypeDescription
* ctd
=
78 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
79 if (ctd
->pBaseTypeDescription
!= 0) {
81 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
), i
,
84 for (sal_Int32 j
= 0; j
!= ctd
->nMembers
; ++j
) {
86 static_cast< char * >(buffer
) + ctd
->pMemberOffsets
[j
],
88 i
++->getValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[j
]))),
89 ctd
->ppTypeRefs
[j
], 0);
97 rtl::Reference
< Bridge
> const & bridge
, ReaderState
& state
,
98 css::uno::Sequence
< sal_Int8
> const & buffer
):
99 bridge_(bridge
), state_(state
), buffer_(buffer
)
101 data_
= reinterpret_cast< sal_uInt8
const * >(buffer_
.getConstArray());
102 end_
= data_
+ buffer_
.getLength();
105 Unmarshal::~Unmarshal() {}
107 sal_uInt8
Unmarshal::read8() {
112 sal_uInt16
Unmarshal::read16() {
114 sal_uInt16 n
= static_cast< sal_uInt16
>(*data_
++) << 8;
118 sal_uInt32
Unmarshal::read32() {
120 sal_uInt32 n
= static_cast< sal_uInt32
>(*data_
++) << 24;
121 n
|= static_cast< sal_uInt32
>(*data_
++) << 16;
122 n
|= static_cast< sal_uInt32
>(*data_
++) << 8;
126 css::uno::TypeDescription
Unmarshal::readType() {
127 sal_uInt8 flags
= read8();
128 typelib_TypeClass tc
= static_cast< typelib_TypeClass
>(flags
& 0x7F);
130 case typelib_TypeClass_VOID
:
131 case typelib_TypeClass_BOOLEAN
:
132 case typelib_TypeClass_BYTE
:
133 case typelib_TypeClass_SHORT
:
134 case typelib_TypeClass_UNSIGNED_SHORT
:
135 case typelib_TypeClass_LONG
:
136 case typelib_TypeClass_UNSIGNED_LONG
:
137 case typelib_TypeClass_HYPER
:
138 case typelib_TypeClass_UNSIGNED_HYPER
:
139 case typelib_TypeClass_FLOAT
:
140 case typelib_TypeClass_DOUBLE
:
141 case typelib_TypeClass_CHAR
:
142 case typelib_TypeClass_STRING
:
143 case typelib_TypeClass_TYPE
:
144 case typelib_TypeClass_ANY
:
145 if ((flags
& 0x80) != 0) {
146 throw css::io::IOException(
147 "binaryurp::Unmarshal: cache flag of simple type is set",
148 css::uno::Reference
< css::uno::XInterface
>());
150 return css::uno::TypeDescription(
151 *typelib_static_type_getByTypeClass(
152 static_cast< typelib_TypeClass
>(tc
)));
153 case typelib_TypeClass_SEQUENCE
:
154 case typelib_TypeClass_ENUM
:
155 case typelib_TypeClass_STRUCT
:
156 case typelib_TypeClass_EXCEPTION
:
157 case typelib_TypeClass_INTERFACE
:
159 sal_uInt16 idx
= readCacheIndex();
160 if ((flags
& 0x80) == 0) {
161 if (idx
== cache::ignore
|| !state_
.typeCache
[idx
].is()) {
162 throw css::io::IOException(
163 "binaryurp::Unmarshal: unknown type cache index",
164 css::uno::Reference
< css::uno::XInterface
>());
166 return state_
.typeCache
[idx
];
168 OUString
const str(readString());
169 css::uno::TypeDescription
t(str
);
171 t
.get()->eTypeClass
!= static_cast< typelib_TypeClass
>(tc
))
174 throw css::io::IOException(
175 "binaryurp::Unmarshal: type with unknown name: " + str
,
176 css::uno::Reference
< css::uno::XInterface
>());
178 for (css::uno::TypeDescription
t2(t
);
179 t2
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
;)
182 t2
= css::uno::TypeDescription(
183 reinterpret_cast< typelib_IndirectTypeDescription
* >(
186 throw css::io::IOException(
187 ("binaryurp::Unmarshal: sequence type with unknown"
189 css::uno::Reference
< css::uno::XInterface
>());
191 switch (t2
.get()->eTypeClass
) {
192 case typelib_TypeClass_VOID
:
193 case typelib_TypeClass_EXCEPTION
:
194 throw css::io::IOException(
195 ("binaryurp::Unmarshal: sequence type with bad"
197 css::uno::Reference
< css::uno::XInterface
>());
202 if (idx
!= cache::ignore
) {
203 state_
.typeCache
[idx
] = t
;
209 throw css::io::IOException(
210 "binaryurp::Unmarshal: type of unknown type class",
211 css::uno::Reference
< css::uno::XInterface
>());
215 OUString
Unmarshal::readOid() {
216 OUString
oid(readString());
217 for (sal_Int32 i
= 0; i
!= oid
.getLength(); ++i
) {
219 throw css::io::IOException(
220 "binaryurp::Unmarshal: OID contains non-ASCII character",
221 css::uno::Reference
< css::uno::XInterface
>());
224 sal_uInt16 idx
= readCacheIndex();
225 if (oid
.isEmpty() && idx
!= cache::ignore
) {
226 if (state_
.oidCache
[idx
].isEmpty()) {
227 throw css::io::IOException(
228 "binaryurp::Unmarshal: unknown OID cache index",
229 css::uno::Reference
< css::uno::XInterface
>());
231 return state_
.oidCache
[idx
];
233 if (idx
!= cache::ignore
) {
234 state_
.oidCache
[idx
] = oid
;
239 rtl::ByteSequence
Unmarshal::readTid() {
240 rtl::ByteSequence
tid(
241 *static_cast< sal_Sequence
* const * >(
243 css::uno::TypeDescription(
244 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get())).
246 css::uno::TypeDescription(
247 cppu::UnoType
< css::uno::Sequence
< sal_Int8
> >::get()))));
248 sal_uInt16 idx
= readCacheIndex();
249 if (tid
.getLength() == 0) {
250 if (idx
== cache::ignore
|| state_
.tidCache
[idx
].getLength() == 0) {
251 throw css::io::IOException(
252 "binaryurp::Unmarshal: unknown TID cache index",
253 css::uno::Reference
< css::uno::XInterface
>());
255 return state_
.tidCache
[idx
];
257 if (idx
!= cache::ignore
) {
258 state_
.tidCache
[idx
] = tid
;
263 BinaryAny
Unmarshal::readValue(css::uno::TypeDescription
const & type
) {
265 switch (type
.get()->eTypeClass
) {
267 std::abort(); // this cannot happen
268 // pseudo fall-through to avoid compiler warnings
269 case typelib_TypeClass_VOID
:
271 case typelib_TypeClass_BOOLEAN
:
273 sal_uInt8 v
= read8();
275 throw css::io::IOException(
276 "binaryurp::Unmarshal: boolean of unknown value",
277 css::uno::Reference
< css::uno::XInterface
>());
279 return BinaryAny(type
, &v
);
281 case typelib_TypeClass_BYTE
:
283 sal_uInt8 v
= read8();
284 return BinaryAny(type
, &v
);
286 case typelib_TypeClass_SHORT
:
287 case typelib_TypeClass_UNSIGNED_SHORT
:
288 case typelib_TypeClass_CHAR
:
290 sal_uInt16 v
= read16();
291 return BinaryAny(type
, &v
);
293 case typelib_TypeClass_LONG
:
294 case typelib_TypeClass_UNSIGNED_LONG
:
295 case typelib_TypeClass_FLOAT
:
297 sal_uInt32 v
= read32();
298 return BinaryAny(type
, &v
);
300 case typelib_TypeClass_HYPER
:
301 case typelib_TypeClass_UNSIGNED_HYPER
:
302 case typelib_TypeClass_DOUBLE
:
304 sal_uInt64 v
= read64();
305 return BinaryAny(type
, &v
);
307 case typelib_TypeClass_STRING
:
309 OUString
v(readString());
310 return BinaryAny(type
, &v
.pData
);
312 case typelib_TypeClass_TYPE
:
314 css::uno::TypeDescription
v(readType());
315 typelib_TypeDescription
* p
= v
.get();
316 return BinaryAny(type
, &p
);
318 case typelib_TypeClass_ANY
:
320 css::uno::TypeDescription
t(readType());
321 if (t
.get()->eTypeClass
== typelib_TypeClass_ANY
) {
322 throw css::io::IOException(
323 "binaryurp::Unmarshal: any of type ANY",
324 css::uno::Reference
< css::uno::XInterface
>());
328 case typelib_TypeClass_SEQUENCE
:
330 return readSequence(type
);
331 case typelib_TypeClass_ENUM
:
333 sal_Int32 v
= static_cast< sal_Int32
>(read32());
335 typelib_EnumTypeDescription
* etd
=
336 reinterpret_cast< typelib_EnumTypeDescription
* >(type
.get());
338 for (sal_Int32 i
= 0; i
!= etd
->nEnumValues
; ++i
) {
339 if (etd
->pEnumValues
[i
] == v
) {
345 throw css::io::IOException(
346 "binaryurp::Unmarshal: unknown enum value",
347 css::uno::Reference
< css::uno::XInterface
>());
349 return BinaryAny(type
, &v
);
351 case typelib_TypeClass_STRUCT
:
352 case typelib_TypeClass_EXCEPTION
:
354 std::vector
< BinaryAny
> as
;
355 readMemberValues(type
, &as
);
356 void * buf
= allocate(type
.get()->nSize
);
357 copyMemberValues(type
, as
.begin(), buf
);
359 raw
.pType
= reinterpret_cast< typelib_TypeDescriptionReference
* >(
363 return BinaryAny(raw
);
365 case typelib_TypeClass_INTERFACE
:
367 css::uno::UnoInterfaceReference
obj(
368 bridge_
->registerIncomingInterface(readOid(), type
));
369 return BinaryAny(type
, &obj
.m_pUnoI
);
374 void Unmarshal::done() const {
376 throw css::io::IOException(
377 "binaryurp::Unmarshal: block contains excess data",
378 css::uno::Reference
< css::uno::XInterface
>());
382 void Unmarshal::check(sal_Int32 size
) const {
383 if (end_
- data_
< size
) {
384 throw css::io::IOException(
385 "binaryurp::Unmarshal: trying to read past end of block",
386 css::uno::Reference
< css::uno::XInterface
>());
390 sal_uInt32
Unmarshal::readCompressed() {
391 sal_uInt8 n
= read8();
392 return n
== 0xFF ? read32() : n
;
395 sal_uInt16
Unmarshal::readCacheIndex() {
396 sal_uInt16 idx
= read16();
397 if (idx
>= cache::size
&& idx
!= cache::ignore
) {
398 throw css::io::IOException(
399 "binaryurp::Unmarshal: cache index out of range",
400 css::uno::Reference
< css::uno::XInterface
>());
405 sal_uInt64
Unmarshal::read64() {
407 sal_uInt64 n
= static_cast< sal_uInt64
>(*data_
++) << 56;
408 n
|= static_cast< sal_uInt64
>(*data_
++) << 48;
409 n
|= static_cast< sal_uInt64
>(*data_
++) << 40;
410 n
|= static_cast< sal_uInt64
>(*data_
++) << 32;
411 n
|= static_cast< sal_uInt64
>(*data_
++) << 24;
412 n
|= static_cast< sal_uInt64
>(*data_
++) << 16;
413 n
|= static_cast< sal_uInt64
>(*data_
++) << 8;
417 OUString
Unmarshal::readString() {
418 sal_uInt32 n
= readCompressed();
419 if (n
> SAL_MAX_INT32
) {
420 throw css::uno::RuntimeException(
421 "binaryurp::Unmarshal: string size too large",
422 css::uno::Reference
< css::uno::XInterface
>());
424 check(static_cast< sal_Int32
>(n
));
426 if (!rtl_convertStringToUString(
427 &s
.pData
, reinterpret_cast< char const * >(data_
),
428 static_cast< sal_Int32
>(n
), RTL_TEXTENCODING_UTF8
,
429 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
430 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
431 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
433 throw css::io::IOException(
434 "binaryurp::Unmarshal: string does not contain UTF-8",
435 css::uno::Reference
< css::uno::XInterface
>());
441 BinaryAny
Unmarshal::readSequence(css::uno::TypeDescription
const & type
) {
442 assert(type
.is() && type
.get()->eTypeClass
== typelib_TypeClass_SEQUENCE
);
443 sal_uInt32 n
= readCompressed();
444 if (n
> SAL_MAX_INT32
) {
445 throw css::uno::RuntimeException(
446 "binaryurp::Unmarshal: sequence size too large",
447 css::uno::Reference
< css::uno::XInterface
>());
450 return BinaryAny(type
, 0);
452 css::uno::TypeDescription
ctd(
453 reinterpret_cast< typelib_IndirectTypeDescription
* >(
455 if (ctd
.get()->eTypeClass
== typelib_TypeClass_BYTE
) {
456 check(static_cast< sal_Int32
>(n
));
458 reinterpret_cast< sal_Int8
const * >(data_
),
459 static_cast< sal_Int32
>(n
));
461 sal_Sequence
* p
= s
.getHandle();
462 return BinaryAny(type
, &p
);
464 std::vector
< BinaryAny
> as
;
465 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
466 as
.push_back(readValue(ctd
));
468 assert(ctd
.get()->nSize
>= 0);
469 sal_uInt64 size
= static_cast< sal_uInt64
>(n
) *
470 static_cast< sal_uInt64
>(ctd
.get()->nSize
);
471 // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow
472 if (size
> SAL_MAX_SIZE
- SAL_SEQUENCE_HEADER_SIZE
) {
473 throw css::uno::RuntimeException(
474 "binaryurp::Unmarshal: sequence size too large",
475 css::uno::Reference
< css::uno::XInterface
>());
477 void * buf
= allocate(
478 SAL_SEQUENCE_HEADER_SIZE
+ static_cast< sal_Size
>(size
));
479 static_cast< sal_Sequence
* >(buf
)->nRefCount
= 0;
480 static_cast< sal_Sequence
* >(buf
)->nElements
=
481 static_cast< sal_Int32
>(n
);
482 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
484 static_cast< sal_Sequence
* >(buf
)->elements
+ i
* ctd
.get()->nSize
,
485 const_cast< void * >(as
[i
].getValue(ctd
)), ctd
.get(), 0);
487 return BinaryAny(type
, reinterpret_cast< sal_Sequence
** >(&buf
));
490 void Unmarshal::readMemberValues(
491 css::uno::TypeDescription
const & type
, std::vector
< BinaryAny
> * values
)
495 (type
.get()->eTypeClass
== typelib_TypeClass_STRUCT
||
496 type
.get()->eTypeClass
== typelib_TypeClass_EXCEPTION
) &&
499 typelib_CompoundTypeDescription
* ctd
=
500 reinterpret_cast< typelib_CompoundTypeDescription
* >(type
.get());
501 if (ctd
->pBaseTypeDescription
!= 0) {
503 css::uno::TypeDescription(&ctd
->pBaseTypeDescription
->aBase
),
506 for (sal_Int32 i
= 0; i
!= ctd
->nMembers
; ++i
) {
508 readValue(css::uno::TypeDescription(ctd
->ppTypeRefs
[i
])));
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */