lok: jsbuilder: avoid sending early id to client side
[LibreOffice.git] / binaryurp / source / unmarshal.cxx
blob8cf8676edad4a007456115f4226ac1c31d43a367
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/RuntimeException.hpp>
29 #include <com/sun/star/uno/Sequence.hxx>
30 #include <cppu/unotype.hxx>
31 #include <rtl/byteseq.hxx>
32 #include <rtl/ref.hxx>
33 #include <rtl/textcvt.h>
34 #include <rtl/textenc.h>
35 #include <rtl/ustring.h>
36 #include <rtl/ustring.hxx>
37 #include <sal/types.h>
38 #include <typelib/typeclass.h>
39 #include <typelib/typedescription.h>
40 #include <typelib/typedescription.hxx>
41 #include <uno/any2.h>
42 #include <uno/data.h>
43 #include <uno/dispatcher.hxx>
45 #include "binaryany.hxx"
46 #include "bridge.hxx"
47 #include "cache.hxx"
48 #include "readerstate.hxx"
49 #include "unmarshal.hxx"
51 namespace binaryurp {
53 namespace {
55 void * allocate(sal_Size size) {
56 void * p = std::malloc(size);
57 if (p == nullptr) {
58 throw std::bad_alloc();
60 return p;
63 std::vector< BinaryAny >::iterator copyMemberValues(
64 css::uno::TypeDescription const & type,
65 std::vector< BinaryAny >::iterator const & it, void * buffer) throw ()
67 assert(
68 type.is() &&
69 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
70 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
71 buffer != nullptr);
72 type.makeComplete();
73 std::vector< BinaryAny >::iterator i(it);
74 typelib_CompoundTypeDescription * ctd =
75 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
76 if (ctd->pBaseTypeDescription != nullptr) {
77 i = copyMemberValues(
78 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i,
79 buffer);
81 for (sal_Int32 j = 0; j != ctd->nMembers; ++j) {
82 uno_type_copyData(
83 static_cast< char * >(buffer) + ctd->pMemberOffsets[j],
84 i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j])),
85 ctd->ppTypeRefs[j], nullptr);
87 return i;
92 Unmarshal::Unmarshal(
93 rtl::Reference< Bridge > const & bridge, ReaderState & state,
94 css::uno::Sequence< sal_Int8 > const & buffer):
95 bridge_(bridge), state_(state), buffer_(buffer)
97 data_ = reinterpret_cast< sal_uInt8 const * >(buffer_.getConstArray());
98 end_ = data_ + buffer_.getLength();
101 Unmarshal::~Unmarshal() {}
103 sal_uInt8 Unmarshal::read8() {
104 check(1);
105 return *data_++;
108 sal_uInt16 Unmarshal::read16() {
109 check(2);
110 sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8;
111 return n | *data_++;
114 sal_uInt32 Unmarshal::read32() {
115 check(4);
116 sal_uInt32 n = static_cast< sal_uInt32 >(*data_++) << 24;
117 n |= static_cast< sal_uInt32 >(*data_++) << 16;
118 n |= static_cast< sal_uInt32 >(*data_++) << 8;
119 return n | *data_++;
122 css::uno::TypeDescription Unmarshal::readType() {
123 sal_uInt8 flags = read8();
124 typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F);
125 switch (tc) {
126 case typelib_TypeClass_VOID:
127 case typelib_TypeClass_BOOLEAN:
128 case typelib_TypeClass_BYTE:
129 case typelib_TypeClass_SHORT:
130 case typelib_TypeClass_UNSIGNED_SHORT:
131 case typelib_TypeClass_LONG:
132 case typelib_TypeClass_UNSIGNED_LONG:
133 case typelib_TypeClass_HYPER:
134 case typelib_TypeClass_UNSIGNED_HYPER:
135 case typelib_TypeClass_FLOAT:
136 case typelib_TypeClass_DOUBLE:
137 case typelib_TypeClass_CHAR:
138 case typelib_TypeClass_STRING:
139 case typelib_TypeClass_TYPE:
140 case typelib_TypeClass_ANY:
141 if ((flags & 0x80) != 0) {
142 throw css::io::IOException(
143 "binaryurp::Unmarshal: cache flag of simple type is set");
145 return css::uno::TypeDescription(
146 *typelib_static_type_getByTypeClass(tc));
147 case typelib_TypeClass_SEQUENCE:
148 case typelib_TypeClass_ENUM:
149 case typelib_TypeClass_STRUCT:
150 case typelib_TypeClass_EXCEPTION:
151 case typelib_TypeClass_INTERFACE:
153 sal_uInt16 idx = readCacheIndex();
154 if ((flags & 0x80) == 0) {
155 if (idx == cache::ignore || !state_.typeCache[idx].is()) {
156 throw css::io::IOException(
157 "binaryurp::Unmarshal: unknown type cache index");
159 return state_.typeCache[idx];
160 } else {
161 OUString const str(readString());
162 css::uno::TypeDescription t(str);
163 if (!t.is() || t.get()->eTypeClass != tc) {
165 throw css::io::IOException(
166 "binaryurp::Unmarshal: type with unknown name: " + str);
168 for (css::uno::TypeDescription t2(t);
169 t2.get()->eTypeClass == typelib_TypeClass_SEQUENCE;)
171 t2.makeComplete();
172 t2 = css::uno::TypeDescription(
173 reinterpret_cast< typelib_IndirectTypeDescription * >(
174 t2.get())->pType);
175 if (!t2.is()) {
176 throw css::io::IOException(
177 "binaryurp::Unmarshal: sequence type with unknown"
178 " component type");
180 switch (t2.get()->eTypeClass) {
181 case typelib_TypeClass_VOID:
182 case typelib_TypeClass_EXCEPTION:
183 throw css::io::IOException(
184 "binaryurp::Unmarshal: sequence type with bad"
185 " component type");
186 default:
187 break;
190 if (idx != cache::ignore) {
191 state_.typeCache[idx] = t;
193 return t;
196 default:
197 throw css::io::IOException(
198 "binaryurp::Unmarshal: type of unknown type class");
202 OUString Unmarshal::readOid() {
203 OUString oid(readString());
204 for (sal_Int32 i = 0; i != oid.getLength(); ++i) {
205 if (oid[i] > 0x7F) {
206 throw css::io::IOException(
207 "binaryurp::Unmarshal: OID contains non-ASCII character");
210 sal_uInt16 idx = readCacheIndex();
211 if (oid.isEmpty() && idx != cache::ignore) {
212 if (state_.oidCache[idx].isEmpty()) {
213 throw css::io::IOException(
214 "binaryurp::Unmarshal: unknown OID cache index");
216 return state_.oidCache[idx];
218 if (idx != cache::ignore) {
219 state_.oidCache[idx] = oid;
221 return oid;
224 rtl::ByteSequence Unmarshal::readTid() {
225 rtl::ByteSequence tid(
226 *static_cast< sal_Sequence * const * >(
227 readSequence(
228 css::uno::TypeDescription(
229 cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())).
230 getValue(
231 css::uno::TypeDescription(
232 cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get()))));
233 sal_uInt16 idx = readCacheIndex();
234 if (tid.getLength() == 0) {
235 if (idx == cache::ignore || state_.tidCache[idx].getLength() == 0) {
236 throw css::io::IOException(
237 "binaryurp::Unmarshal: unknown TID cache index");
239 return state_.tidCache[idx];
241 if (idx != cache::ignore) {
242 state_.tidCache[idx] = tid;
244 return tid;
247 BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) {
248 assert(type.is());
249 switch (type.get()->eTypeClass) {
250 default:
251 std::abort(); // this cannot happen
252 // pseudo fall-through to avoid compiler warnings
253 case typelib_TypeClass_VOID:
254 return BinaryAny();
255 case typelib_TypeClass_BOOLEAN:
257 sal_uInt8 v = read8();
258 if (v > 1) {
259 throw css::io::IOException(
260 "binaryurp::Unmarshal: boolean of unknown value");
262 return BinaryAny(type, &v);
264 case typelib_TypeClass_BYTE:
266 sal_uInt8 v = read8();
267 return BinaryAny(type, &v);
269 case typelib_TypeClass_SHORT:
270 case typelib_TypeClass_UNSIGNED_SHORT:
271 case typelib_TypeClass_CHAR:
273 sal_uInt16 v = read16();
274 return BinaryAny(type, &v);
276 case typelib_TypeClass_LONG:
277 case typelib_TypeClass_UNSIGNED_LONG:
278 case typelib_TypeClass_FLOAT:
280 sal_uInt32 v = read32();
281 return BinaryAny(type, &v);
283 case typelib_TypeClass_HYPER:
284 case typelib_TypeClass_UNSIGNED_HYPER:
285 case typelib_TypeClass_DOUBLE:
287 sal_uInt64 v = read64();
288 return BinaryAny(type, &v);
290 case typelib_TypeClass_STRING:
292 OUString v(readString());
293 return BinaryAny(type, &v.pData);
295 case typelib_TypeClass_TYPE:
297 css::uno::TypeDescription v(readType());
298 typelib_TypeDescription * p = v.get();
299 return BinaryAny(type, &p);
301 case typelib_TypeClass_ANY:
303 css::uno::TypeDescription t(readType());
304 if (t.get()->eTypeClass == typelib_TypeClass_ANY) {
305 throw css::io::IOException(
306 "binaryurp::Unmarshal: any of type ANY");
308 return readValue(t);
310 case typelib_TypeClass_SEQUENCE:
311 type.makeComplete();
312 return readSequence(type);
313 case typelib_TypeClass_ENUM:
315 sal_Int32 v = static_cast< sal_Int32 >(read32());
316 type.makeComplete();
317 typelib_EnumTypeDescription * etd =
318 reinterpret_cast< typelib_EnumTypeDescription * >(type.get());
319 bool bFound = false;
320 for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) {
321 if (etd->pEnumValues[i] == v) {
322 bFound = true;
323 break;
326 if (!bFound) {
327 throw css::io::IOException(
328 "binaryurp::Unmarshal: unknown enum value");
330 return BinaryAny(type, &v);
332 case typelib_TypeClass_STRUCT:
333 case typelib_TypeClass_EXCEPTION:
335 std::vector< BinaryAny > as;
336 readMemberValues(type, &as);
337 void * buf = allocate(type.get()->nSize);
338 copyMemberValues(type, as.begin(), buf);
339 uno_Any raw;
340 raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >(
341 type.get());
342 raw.pData = buf;
343 raw.pReserved = nullptr;
344 return BinaryAny(raw);
346 case typelib_TypeClass_INTERFACE:
348 css::uno::UnoInterfaceReference obj(
349 bridge_->registerIncomingInterface(readOid(), type));
350 return BinaryAny(type, &obj.m_pUnoI);
355 void Unmarshal::done() const {
356 if (data_ != end_) {
357 throw css::io::IOException(
358 "binaryurp::Unmarshal: block contains excess data");
362 void Unmarshal::check(sal_Int32 size) const {
363 if (end_ - data_ < size) {
364 throw css::io::IOException(
365 "binaryurp::Unmarshal: trying to read past end of block");
369 sal_uInt32 Unmarshal::readCompressed() {
370 sal_uInt8 n = read8();
371 return n == 0xFF ? read32() : n;
374 sal_uInt16 Unmarshal::readCacheIndex() {
375 sal_uInt16 idx = read16();
376 if (idx >= cache::size && idx != cache::ignore) {
377 throw css::io::IOException(
378 "binaryurp::Unmarshal: cache index out of range");
380 return idx;
383 sal_uInt64 Unmarshal::read64() {
384 check(8);
385 sal_uInt64 n = static_cast< sal_uInt64 >(*data_++) << 56;
386 n |= static_cast< sal_uInt64 >(*data_++) << 48;
387 n |= static_cast< sal_uInt64 >(*data_++) << 40;
388 n |= static_cast< sal_uInt64 >(*data_++) << 32;
389 n |= static_cast< sal_uInt64 >(*data_++) << 24;
390 n |= static_cast< sal_uInt64 >(*data_++) << 16;
391 n |= static_cast< sal_uInt64 >(*data_++) << 8;
392 return n | *data_++;
395 OUString Unmarshal::readString() {
396 sal_uInt32 n = readCompressed();
397 if (n > SAL_MAX_INT32) {
398 throw css::uno::RuntimeException(
399 "binaryurp::Unmarshal: string size too large");
401 check(static_cast< sal_Int32 >(n));
402 OUString s;
403 if (!rtl_convertStringToUString(
404 &s.pData, reinterpret_cast< char const * >(data_),
405 static_cast< sal_Int32 >(n), RTL_TEXTENCODING_UTF8,
406 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
407 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
408 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
410 throw css::io::IOException(
411 "binaryurp::Unmarshal: string does not contain UTF-8");
413 data_ += n;
414 return s;
417 BinaryAny Unmarshal::readSequence(css::uno::TypeDescription const & type) {
418 assert(type.is() && type.get()->eTypeClass == typelib_TypeClass_SEQUENCE);
419 sal_uInt32 n = readCompressed();
420 if (n > SAL_MAX_INT32) {
421 throw css::uno::RuntimeException(
422 "binaryurp::Unmarshal: sequence size too large");
424 if (n == 0) {
425 return BinaryAny(type, nullptr);
427 css::uno::TypeDescription ctd(
428 reinterpret_cast< typelib_IndirectTypeDescription * >(
429 type.get())->pType);
430 if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) {
431 check(static_cast< sal_Int32 >(n));
432 rtl::ByteSequence s(
433 reinterpret_cast< sal_Int8 const * >(data_),
434 static_cast< sal_Int32 >(n));
435 data_ += n;
436 sal_Sequence * p = s.getHandle();
437 return BinaryAny(type, &p);
439 std::vector< BinaryAny > as;
440 for (sal_uInt32 i = 0; i != n; ++i) {
441 as.push_back(readValue(ctd));
443 assert(ctd.get()->nSize >= 0);
444 sal_uInt64 size = static_cast< sal_uInt64 >(n) *
445 static_cast< sal_uInt64 >(ctd.get()->nSize);
446 // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow
447 if (size > SAL_MAX_SIZE - SAL_SEQUENCE_HEADER_SIZE) {
448 throw css::uno::RuntimeException(
449 "binaryurp::Unmarshal: sequence size too large");
451 void * buf = allocate(
452 SAL_SEQUENCE_HEADER_SIZE + static_cast< sal_Size >(size));
453 static_cast< sal_Sequence * >(buf)->nRefCount = 0;
454 static_cast< sal_Sequence * >(buf)->nElements =
455 static_cast< sal_Int32 >(n);
456 for (sal_uInt32 i = 0; i != n; ++i) {
457 uno_copyData(
458 static_cast< sal_Sequence * >(buf)->elements + i * ctd.get()->nSize,
459 as[i].getValue(ctd), ctd.get(), nullptr);
461 return BinaryAny(type, &buf);
464 void Unmarshal::readMemberValues(
465 css::uno::TypeDescription const & type, std::vector< BinaryAny > * values)
467 assert(
468 type.is() &&
469 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
470 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
471 values != nullptr);
472 type.makeComplete();
473 typelib_CompoundTypeDescription * ctd =
474 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
475 if (ctd->pBaseTypeDescription != nullptr) {
476 readMemberValues(
477 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase),
478 values);
480 for (sal_Int32 i = 0; i != ctd->nMembers; ++i) {
481 values->push_back(
482 readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i])));
488 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */