Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / binaryurp / source / unmarshal.cxx
blob41145ccffca545ce9d5dcdd7787f6e67a1415a05
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cassert>
23 #include <cstdlib>
24 #include <new>
25 #include <vector>
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>
43 #include <uno/any2.h>
44 #include <uno/data.h>
45 #include <uno/dispatcher.hxx>
47 #include "binaryany.hxx"
48 #include "bridge.hxx"
49 #include "cache.hxx"
50 #include "readerstate.hxx"
51 #include "unmarshal.hxx"
53 namespace binaryurp {
55 namespace {
57 void * allocate(sal_Size size) {
58 void * p = std::malloc(size);
59 if (p == nullptr) {
60 throw std::bad_alloc();
62 return p;
65 std::vector< BinaryAny >::iterator copyMemberValues(
66 css::uno::TypeDescription const & type,
67 std::vector< BinaryAny >::iterator const & it, void * buffer) throw ()
69 assert(
70 type.is() &&
71 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
72 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
73 buffer != nullptr);
74 type.makeComplete();
75 std::vector< BinaryAny >::iterator i(it);
76 typelib_CompoundTypeDescription * ctd =
77 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
78 if (ctd->pBaseTypeDescription != nullptr) {
79 i = copyMemberValues(
80 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i,
81 buffer);
83 for (sal_Int32 j = 0; j != ctd->nMembers; ++j) {
84 uno_type_copyData(
85 static_cast< char * >(buffer) + ctd->pMemberOffsets[j],
86 i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j])),
87 ctd->ppTypeRefs[j], nullptr);
89 return i;
94 Unmarshal::Unmarshal(
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() {
106 check(1);
107 return *data_++;
110 sal_uInt16 Unmarshal::read16() {
111 check(2);
112 sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8;
113 return n | *data_++;
116 sal_uInt32 Unmarshal::read32() {
117 check(4);
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;
121 return n | *data_++;
124 css::uno::TypeDescription Unmarshal::readType() {
125 sal_uInt8 flags = read8();
126 typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F);
127 switch (tc) {
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];
162 } else {
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;)
173 t2.makeComplete();
174 t2 = css::uno::TypeDescription(
175 reinterpret_cast< typelib_IndirectTypeDescription * >(
176 t2.get())->pType);
177 if (!t2.is()) {
178 throw css::io::IOException(
179 "binaryurp::Unmarshal: sequence type with unknown"
180 " component type");
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"
187 " component type");
188 default:
189 break;
192 if (idx != cache::ignore) {
193 state_.typeCache[idx] = t;
195 return t;
198 default:
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) {
207 if (oid[i] > 0x7F) {
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;
223 return oid;
226 rtl::ByteSequence Unmarshal::readTid() {
227 rtl::ByteSequence tid(
228 *static_cast< sal_Sequence * const * >(
229 readSequence(
230 css::uno::TypeDescription(
231 cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())).
232 getValue(
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;
246 return tid;
249 BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) {
250 assert(type.is());
251 switch (type.get()->eTypeClass) {
252 default:
253 std::abort(); // this cannot happen
254 // pseudo fall-through to avoid compiler warnings
255 case typelib_TypeClass_VOID:
256 return BinaryAny();
257 case typelib_TypeClass_BOOLEAN:
259 sal_uInt8 v = read8();
260 if (v > 1) {
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");
310 return readValue(t);
312 case typelib_TypeClass_SEQUENCE:
313 type.makeComplete();
314 return readSequence(type);
315 case typelib_TypeClass_ENUM:
317 sal_Int32 v = static_cast< sal_Int32 >(read32());
318 type.makeComplete();
319 typelib_EnumTypeDescription * etd =
320 reinterpret_cast< typelib_EnumTypeDescription * >(type.get());
321 bool bFound = false;
322 for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) {
323 if (etd->pEnumValues[i] == v) {
324 bFound = true;
325 break;
328 if (!bFound) {
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);
341 uno_Any raw;
342 raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >(
343 type.get());
344 raw.pData = buf;
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 {
358 if (data_ != end_) {
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");
382 return idx;
385 sal_uInt64 Unmarshal::read64() {
386 check(8);
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;
394 return n | *data_++;
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));
404 OUString s;
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");
415 data_ += n;
416 return s;
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");
426 if (n == 0) {
427 return BinaryAny(type, nullptr);
429 css::uno::TypeDescription ctd(
430 reinterpret_cast< typelib_IndirectTypeDescription * >(
431 type.get())->pType);
432 if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) {
433 check(static_cast< sal_Int32 >(n));
434 rtl::ByteSequence s(
435 reinterpret_cast< sal_Int8 const * >(data_),
436 static_cast< sal_Int32 >(n));
437 data_ += 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) {
459 uno_copyData(
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)
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);
482 for (sal_Int32 i = 0; i != ctd->nMembers; ++i) {
483 values->push_back(
484 readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i])));
490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */