further winget configuration files to complete the setup
[LibreOffice.git] / binaryurp / source / unmarshal.cxx
blob10eb4e780f3f41ffd2bebce40434451d891bbc4f
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 <utility>
26 #include <vector>
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>
46 #include "binaryany.hxx"
47 #include "bridge.hxx"
48 #include "cache.hxx"
49 #include "readerstate.hxx"
50 #include "unmarshal.hxx"
52 namespace binaryurp {
54 namespace {
56 void * allocate(sal_Size size) {
57 void * p = std::malloc(size);
58 if (p == nullptr) {
59 throw std::bad_alloc();
61 return p;
64 std::vector< BinaryAny >::iterator copyMemberValues(
65 css::uno::TypeDescription const & type,
66 std::vector< BinaryAny >::iterator const & it, void * buffer) noexcept
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);
82 for (sal_Int32 j = 0; j != ctd->nMembers; ++j) {
83 uno_type_copyData(
84 static_cast< char * >(buffer) + ctd->pMemberOffsets[j],
85 i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j])),
86 ctd->ppTypeRefs[j], nullptr);
88 return i;
93 Unmarshal::Unmarshal(
94 rtl::Reference< Bridge > bridge, ReaderState & state,
95 css::uno::Sequence< sal_Int8 > const & buffer):
96 bridge_(std::move(bridge)), state_(state), buffer_(buffer)
98 data_ = reinterpret_cast< sal_uInt8 const * >(buffer_.getConstArray());
99 end_ = data_ + buffer_.getLength();
102 Unmarshal::~Unmarshal() {}
104 sal_uInt8 Unmarshal::read8() {
105 check(1);
106 return *data_++;
109 sal_uInt16 Unmarshal::read16() {
110 check(2);
111 sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8;
112 return n | *data_++;
115 sal_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_++;
123 css::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 u"binaryurp::Unmarshal: cache flag of simple type is set"_ustr);
146 return css::uno::TypeDescription(
147 *typelib_static_type_getByTypeClass(tc));
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:
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 u"binaryurp::Unmarshal: unknown type cache index"_ustr);
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) {
166 throw css::io::IOException(
167 "binaryurp::Unmarshal: type with unknown name: " + str);
169 for (css::uno::TypeDescription t2(t);
170 t2.get()->eTypeClass == typelib_TypeClass_SEQUENCE;)
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 u"binaryurp::Unmarshal: sequence type with unknown"
179 " component type"_ustr);
181 switch (t2.get()->eTypeClass) {
182 case typelib_TypeClass_VOID:
183 case typelib_TypeClass_EXCEPTION:
184 throw css::io::IOException(
185 u"binaryurp::Unmarshal: sequence type with bad"
186 " component type"_ustr);
187 default:
188 break;
191 if (idx != cache::ignore) {
192 state_.typeCache[idx] = t;
194 return t;
197 default:
198 throw css::io::IOException(
199 u"binaryurp::Unmarshal: type of unknown type class"_ustr);
203 OUString 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 u"binaryurp::Unmarshal: OID contains non-ASCII character"_ustr);
211 sal_uInt16 idx = readCacheIndex();
212 if (oid.isEmpty() && idx != cache::ignore) {
213 if (state_.oidCache[idx].isEmpty()) {
214 throw css::io::IOException(
215 u"binaryurp::Unmarshal: unknown OID cache index"_ustr);
217 return state_.oidCache[idx];
219 if (idx != cache::ignore) {
220 state_.oidCache[idx] = oid;
222 return oid;
225 rtl::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 u"binaryurp::Unmarshal: unknown TID cache index"_ustr);
240 return state_.tidCache[idx];
242 if (idx != cache::ignore) {
243 state_.tidCache[idx] = tid;
245 return tid;
248 BinaryAny 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:
258 sal_uInt8 v = read8();
259 if (v > 1) {
260 throw css::io::IOException(
261 u"binaryurp::Unmarshal: boolean of unknown value"_ustr);
263 return BinaryAny(type, &v);
265 case typelib_TypeClass_BYTE:
267 sal_uInt8 v = read8();
268 return BinaryAny(type, &v);
270 case typelib_TypeClass_SHORT:
271 case typelib_TypeClass_UNSIGNED_SHORT:
272 case typelib_TypeClass_CHAR:
274 sal_uInt16 v = read16();
275 return BinaryAny(type, &v);
277 case typelib_TypeClass_LONG:
278 case typelib_TypeClass_UNSIGNED_LONG:
279 case typelib_TypeClass_FLOAT:
281 sal_uInt32 v = read32();
282 return BinaryAny(type, &v);
284 case typelib_TypeClass_HYPER:
285 case typelib_TypeClass_UNSIGNED_HYPER:
286 case typelib_TypeClass_DOUBLE:
288 sal_uInt64 v = read64();
289 return BinaryAny(type, &v);
291 case typelib_TypeClass_STRING:
293 OUString v(readString());
294 return BinaryAny(type, &v.pData);
296 case typelib_TypeClass_TYPE:
298 css::uno::TypeDescription v(readType());
299 typelib_TypeDescription * p = v.get();
300 return BinaryAny(type, &p);
302 case typelib_TypeClass_ANY:
304 css::uno::TypeDescription t(readType());
305 if (t.get()->eTypeClass == typelib_TypeClass_ANY) {
306 throw css::io::IOException(
307 u"binaryurp::Unmarshal: any of type ANY"_ustr);
309 return readValue(t);
311 case typelib_TypeClass_SEQUENCE:
312 type.makeComplete();
313 return readSequence(type);
314 case typelib_TypeClass_ENUM:
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;
327 if (!bFound) {
328 throw css::io::IOException(
329 u"binaryurp::Unmarshal: unknown enum value"_ustr);
331 return BinaryAny(type, &v);
333 case typelib_TypeClass_STRUCT:
334 case typelib_TypeClass_EXCEPTION:
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);
347 case typelib_TypeClass_INTERFACE:
349 css::uno::UnoInterfaceReference obj(
350 bridge_->registerIncomingInterface(readOid(), type));
351 return BinaryAny(type, &obj.m_pUnoI);
356 void Unmarshal::done() const {
357 if (data_ != end_) {
358 throw css::io::IOException(
359 u"binaryurp::Unmarshal: block contains excess data"_ustr);
363 void Unmarshal::check(sal_Int32 size) const {
364 if (end_ - data_ < size) {
365 throw css::io::IOException(
366 u"binaryurp::Unmarshal: trying to read past end of block"_ustr);
370 sal_uInt32 Unmarshal::readCompressed() {
371 sal_uInt8 n = read8();
372 return n == 0xFF ? read32() : n;
375 sal_uInt16 Unmarshal::readCacheIndex() {
376 sal_uInt16 idx = read16();
377 if (idx >= cache::size && idx != cache::ignore) {
378 throw css::io::IOException(
379 u"binaryurp::Unmarshal: cache index out of range"_ustr);
381 return idx;
384 sal_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_++;
396 OUString Unmarshal::readString() {
397 sal_uInt32 n = readCompressed();
398 if (n > SAL_MAX_INT32) {
399 throw css::uno::RuntimeException(
400 u"binaryurp::Unmarshal: string size too large"_ustr);
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)))
411 throw css::io::IOException(
412 u"binaryurp::Unmarshal: string does not contain UTF-8"_ustr);
414 data_ += n;
415 return s;
418 BinaryAny 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 u"binaryurp::Unmarshal: sequence size too large"_ustr);
425 if (n == 0) {
426 return BinaryAny(type, nullptr);
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);
440 std::vector< BinaryAny > as;
441 as.reserve(n);
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 u"binaryurp::Unmarshal: sequence size too large"_ustr);
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 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])));
491 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */