LibreOffice Module binaryurp (master) 1
unmarshal.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <cassert>
23#include <cstdlib>
24#include <new>
25#include <utility>
26#include <vector>
27
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>
42#include <uno/any2.h>
43#include <uno/data.h>
44#include <uno/dispatcher.hxx>
45
46#include "binaryany.hxx"
47#include "bridge.hxx"
48#include "cache.hxx"
49#include "readerstate.hxx"
50#include "unmarshal.hxx"
51
52namespace binaryurp {
53
54namespace {
55
56void * allocate(sal_Size size) {
57 void * p = std::malloc(size);
58 if (p == nullptr) {
59 throw std::bad_alloc();
60 }
61 return p;
62}
63
64std::vector< BinaryAny >::iterator copyMemberValues(
65 css::uno::TypeDescription const & type,
66 std::vector< BinaryAny >::iterator const & it, void * buffer) noexcept
67{
68 assert(
69 type.is() &&
70 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
71 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
72 buffer != nullptr);
73 type.makeComplete();
74 std::vector< BinaryAny >::iterator i(it);
75 typelib_CompoundTypeDescription * ctd =
76 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
77 if (ctd->pBaseTypeDescription != nullptr) {
78 i = copyMemberValues(
79 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i,
80 buffer);
81 }
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);
87 }
88 return i;
89}
90
91}
92
94 rtl::Reference< Bridge > bridge, ReaderState & state,
95 css::uno::Sequence< sal_Int8 > const & buffer):
96 bridge_(std::move(bridge)), state_(state), buffer_(buffer)
97{
98 data_ = reinterpret_cast< sal_uInt8 const * >(buffer_.getConstArray());
99 end_ = data_ + buffer_.getLength();
100}
101
102Unmarshal::~Unmarshal() {}
103
104sal_uInt8 Unmarshal::read8() {
105 check(1);
106 return *data_++;
107}
108
109sal_uInt16 Unmarshal::read16() {
110 check(2);
111 sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8;
112 return n | *data_++;
113}
114
115sal_uInt32 Unmarshal::read32() {
116 check(4);
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;
120 return n | *data_++;
121}
122
123css::uno::TypeDescription Unmarshal::readType() {
124 sal_uInt8 flags = read8();
125 typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F);
126 switch (tc) {
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");
145 }
146 return css::uno::TypeDescription(
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:
153 {
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");
159 }
160 return state_.typeCache[idx];
161 } else {
162 OUString const str(readString());
163 css::uno::TypeDescription t(str);
164 if (!t.is() || t.get()->eTypeClass != tc) {
165
166 throw css::io::IOException(
167 "binaryurp::Unmarshal: type with unknown name: " + str);
168 }
169 for (css::uno::TypeDescription t2(t);
170 t2.get()->eTypeClass == typelib_TypeClass_SEQUENCE;)
171 {
172 t2.makeComplete();
173 t2 = css::uno::TypeDescription(
174 reinterpret_cast< typelib_IndirectTypeDescription * >(
175 t2.get())->pType);
176 if (!t2.is()) {
177 throw css::io::IOException(
178 "binaryurp::Unmarshal: sequence type with unknown"
179 " component type");
180 }
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"
186 " component type");
187 default:
188 break;
189 }
190 }
191 if (idx != cache::ignore) {
192 state_.typeCache[idx] = t;
193 }
194 return t;
195 }
196 }
197 default:
198 throw css::io::IOException(
199 "binaryurp::Unmarshal: type of unknown type class");
200 }
201}
202
203OUString Unmarshal::readOid() {
204 OUString oid(readString());
205 for (sal_Int32 i = 0; i != oid.getLength(); ++i) {
206 if (oid[i] > 0x7F) {
207 throw css::io::IOException(
208 "binaryurp::Unmarshal: OID contains non-ASCII character");
209 }
210 }
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");
216 }
217 return state_.oidCache[idx];
218 }
219 if (idx != cache::ignore) {
220 state_.oidCache[idx] = oid;
221 }
222 return oid;
223}
224
225rtl::ByteSequence Unmarshal::readTid() {
226 rtl::ByteSequence tid(
227 *static_cast< sal_Sequence * const * >(
228 readSequence(
229 css::uno::TypeDescription(
230 cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())).
231 getValue(
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");
239 }
240 return state_.tidCache[idx];
241 }
242 if (idx != cache::ignore) {
243 state_.tidCache[idx] = tid;
244 }
245 return tid;
246}
247
248BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) {
249 assert(type.is());
250 switch (type.get()->eTypeClass) {
251 default:
252 std::abort(); // this cannot happen
253 // pseudo fall-through to avoid compiler warnings
254 case typelib_TypeClass_VOID:
255 return BinaryAny();
256 case typelib_TypeClass_BOOLEAN:
257 {
258 sal_uInt8 v = read8();
259 if (v > 1) {
260 throw css::io::IOException(
261 "binaryurp::Unmarshal: boolean of unknown value");
262 }
263 return BinaryAny(type, &v);
264 }
265 case typelib_TypeClass_BYTE:
266 {
267 sal_uInt8 v = read8();
268 return BinaryAny(type, &v);
269 }
270 case typelib_TypeClass_SHORT:
271 case typelib_TypeClass_UNSIGNED_SHORT:
272 case typelib_TypeClass_CHAR:
273 {
274 sal_uInt16 v = read16();
275 return BinaryAny(type, &v);
276 }
277 case typelib_TypeClass_LONG:
278 case typelib_TypeClass_UNSIGNED_LONG:
279 case typelib_TypeClass_FLOAT:
280 {
281 sal_uInt32 v = read32();
282 return BinaryAny(type, &v);
283 }
284 case typelib_TypeClass_HYPER:
285 case typelib_TypeClass_UNSIGNED_HYPER:
286 case typelib_TypeClass_DOUBLE:
287 {
288 sal_uInt64 v = read64();
289 return BinaryAny(type, &v);
290 }
291 case typelib_TypeClass_STRING:
292 {
293 OUString v(readString());
294 return BinaryAny(type, &v.pData);
295 }
296 case typelib_TypeClass_TYPE:
297 {
298 css::uno::TypeDescription v(readType());
299 typelib_TypeDescription * p = v.get();
300 return BinaryAny(type, &p);
301 }
302 case typelib_TypeClass_ANY:
303 {
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");
308 }
309 return readValue(t);
310 }
311 case typelib_TypeClass_SEQUENCE:
312 type.makeComplete();
313 return readSequence(type);
314 case typelib_TypeClass_ENUM:
315 {
316 sal_Int32 v = static_cast< sal_Int32 >(read32());
317 type.makeComplete();
318 typelib_EnumTypeDescription * etd =
319 reinterpret_cast< typelib_EnumTypeDescription * >(type.get());
320 bool bFound = false;
321 for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) {
322 if (etd->pEnumValues[i] == v) {
323 bFound = true;
324 break;
325 }
326 }
327 if (!bFound) {
328 throw css::io::IOException(
329 "binaryurp::Unmarshal: unknown enum value");
330 }
331 return BinaryAny(type, &v);
332 }
333 case typelib_TypeClass_STRUCT:
334 case typelib_TypeClass_EXCEPTION:
335 {
336 std::vector< BinaryAny > as;
337 readMemberValues(type, &as);
338 void * buf = allocate(type.get()->nSize);
339 copyMemberValues(type, as.begin(), buf);
340 uno_Any raw;
341 raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >(
342 type.get());
343 raw.pData = buf;
344 raw.pReserved = nullptr;
345 return BinaryAny(raw);
346 }
347 case typelib_TypeClass_INTERFACE:
348 {
349 css::uno::UnoInterfaceReference obj(
350 bridge_->registerIncomingInterface(readOid(), type));
351 return BinaryAny(type, &obj.m_pUnoI);
352 }
353 }
354}
355
356void Unmarshal::done() const {
357 if (data_ != end_) {
358 throw css::io::IOException(
359 "binaryurp::Unmarshal: block contains excess data");
360 }
361}
362
363void 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");
367 }
368}
369
370sal_uInt32 Unmarshal::readCompressed() {
371 sal_uInt8 n = read8();
372 return n == 0xFF ? read32() : n;
373}
374
375sal_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");
380 }
381 return idx;
382}
383
384sal_uInt64 Unmarshal::read64() {
385 check(8);
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;
393 return n | *data_++;
394}
395
396OUString 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");
401 }
402 check(static_cast< sal_Int32 >(n));
403 OUString s;
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)))
410 {
411 throw css::io::IOException(
412 "binaryurp::Unmarshal: string does not contain UTF-8");
413 }
414 data_ += n;
415 return s;
416}
417
418BinaryAny 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");
424 }
425 if (n == 0) {
426 return BinaryAny(type, nullptr);
427 }
428 css::uno::TypeDescription ctd(
429 reinterpret_cast< typelib_IndirectTypeDescription * >(
430 type.get())->pType);
431 if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) {
432 check(static_cast< sal_Int32 >(n));
433 rtl::ByteSequence s(
434 reinterpret_cast< sal_Int8 const * >(data_),
435 static_cast< sal_Int32 >(n));
436 data_ += n;
437 sal_Sequence * p = s.getHandle();
438 return BinaryAny(type, &p);
439 }
440 std::vector< BinaryAny > as;
441 as.reserve(n);
442 for (sal_uInt32 i = 0; i != n; ++i) {
443 as.push_back(readValue(ctd));
444 }
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");
452 }
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);
462 }
463 return BinaryAny(type, &buf);
464}
465
466void Unmarshal::readMemberValues(
467 css::uno::TypeDescription const & type, std::vector< BinaryAny > * values)
468{
469 assert(
470 type.is() &&
471 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
472 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
473 values != nullptr);
474 type.makeComplete();
475 typelib_CompoundTypeDescription * ctd =
476 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
477 if (ctd->pBaseTypeDescription != nullptr) {
478 readMemberValues(
479 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase),
480 values);
481 }
482 values->reserve(values->size() + ctd->nMembers);
483 for (sal_Int32 i = 0; i != ctd->nMembers; ++i) {
484 values->push_back(
485 readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i])));
486 }
487}
488
489}
490
491/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
Unmarshal(rtl::Reference< Bridge > bridge, ReaderState &state, com::sun::star::uno::Sequence< sal_Int8 > const &buffer)
sal_Int32 nRefCount
sal_Int32 nElements
void SAL_CALL uno_type_copyData(void *pDest, void *pSource, typelib_TypeDescriptionReference *pType, uno_AcquireFunc acquire) SAL_THROW_EXTERN_C()
void SAL_CALL uno_copyData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_AcquireFunc acquire) SAL_THROW_EXTERN_C()
float v
const sal_uInt16 idx[]
void * p
sal_Int64 n
struct _typelib_TypeDescription typelib_TypeDescription
struct _uno_Any uno_Any
css::uno::UnoInterfaceReference get()
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > check(dp_misc::DescriptionInfoset const &infoset)
int i
css::beans::Optional< css::uno::Any > getValue(std::u16string_view id)
std::vector< char * > values
sal_uInt32 readString(const sal_uInt8 *buffer, sal_Unicode *v, sal_uInt32 maxSize)
typelib_TypeDescriptionReference **SAL_CALL typelib_static_type_getByTypeClass(typelib_TypeClass eTypeClass) SAL_THROW_EXTERN_C()
unsigned char sal_uInt8
#define SAL_MAX_INT32
#define SAL_SEQUENCE_HEADER_SIZE
signed char sal_Int8
ResultType type