Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / binaryurp / source / unmarshal.cxx
blobd413e5f84e7802b74b8549de238da830635c7c5b
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 "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"
44 #include "uno/any2.h"
45 #include "uno/data.h"
46 #include "uno/dispatcher.hxx"
48 #include "binaryany.hxx"
49 #include "bridge.hxx"
50 #include "cache.hxx"
51 #include "readerstate.hxx"
52 #include "unmarshal.hxx"
54 namespace binaryurp {
56 namespace {
58 void * allocate(sal_Size size) {
59 void * p = rtl_allocateMemory(size);
60 if (p == 0) {
61 throw std::bad_alloc();
63 return p;
66 std::vector< BinaryAny >::iterator copyMemberValues(
67 css::uno::TypeDescription const & type,
68 std::vector< BinaryAny >::iterator const & it, void * buffer) throw ()
70 assert(
71 type.is() &&
72 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
73 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
74 buffer != 0);
75 type.makeComplete();
76 std::vector< BinaryAny >::iterator i(it);
77 typelib_CompoundTypeDescription * ctd =
78 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
79 if (ctd->pBaseTypeDescription != 0) {
80 i = copyMemberValues(
81 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i,
82 buffer);
84 for (sal_Int32 j = 0; j != ctd->nMembers; ++j) {
85 uno_type_copyData(
86 static_cast< char * >(buffer) + ctd->pMemberOffsets[j],
87 const_cast< void * >(
88 i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j]))),
89 ctd->ppTypeRefs[j], 0);
91 return i;
96 Unmarshal::Unmarshal(
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() {
108 check(1);
109 return *data_++;
112 sal_uInt16 Unmarshal::read16() {
113 check(2);
114 sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8;
115 return n | *data_++;
118 sal_uInt32 Unmarshal::read32() {
119 check(4);
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;
123 return n | *data_++;
126 css::uno::TypeDescription Unmarshal::readType() {
127 sal_uInt8 flags = read8();
128 typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F);
129 switch (tc) {
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];
167 } else {
168 OUString const str(readString());
169 css::uno::TypeDescription t(str);
170 if (!t.is() ||
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;)
181 t2.makeComplete();
182 t2 = css::uno::TypeDescription(
183 reinterpret_cast< typelib_IndirectTypeDescription * >(
184 t2.get())->pType);
185 if (!t2.is()) {
186 throw css::io::IOException(
187 ("binaryurp::Unmarshal: sequence type with unknown"
188 " component type"),
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"
196 " component type"),
197 css::uno::Reference< css::uno::XInterface >());
198 default:
199 break;
202 if (idx != cache::ignore) {
203 state_.typeCache[idx] = t;
205 return t;
208 default:
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) {
218 if (oid[i] > 0x7F) {
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;
236 return oid;
239 rtl::ByteSequence Unmarshal::readTid() {
240 rtl::ByteSequence tid(
241 *static_cast< sal_Sequence * const * >(
242 readSequence(
243 css::uno::TypeDescription(
244 cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())).
245 getValue(
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;
260 return tid;
263 BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) {
264 assert(type.is());
265 switch (type.get()->eTypeClass) {
266 default:
267 std::abort(); // this cannot happen
268 // pseudo fall-through to avoid compiler warnings
269 case typelib_TypeClass_VOID:
270 return BinaryAny();
271 case typelib_TypeClass_BOOLEAN:
273 sal_uInt8 v = read8();
274 if (v > 1) {
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 >());
326 return readValue(t);
328 case typelib_TypeClass_SEQUENCE:
329 type.makeComplete();
330 return readSequence(type);
331 case typelib_TypeClass_ENUM:
333 sal_Int32 v = static_cast< sal_Int32 >(read32());
334 type.makeComplete();
335 typelib_EnumTypeDescription * etd =
336 reinterpret_cast< typelib_EnumTypeDescription * >(type.get());
337 bool found = false;
338 for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) {
339 if (etd->pEnumValues[i] == v) {
340 found = true;
341 break;
344 if (!found) {
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);
358 uno_Any raw;
359 raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >(
360 type.get());
361 raw.pData = buf;
362 raw.pReserved = 0;
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 {
375 if (data_ != end_) {
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 >());
402 return idx;
405 sal_uInt64 Unmarshal::read64() {
406 check(8);
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;
414 return n | *data_++;
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));
425 OUString s;
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 >());
437 data_ += n;
438 return s;
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 >());
449 if (n == 0) {
450 return BinaryAny(type, 0);
452 css::uno::TypeDescription ctd(
453 reinterpret_cast< typelib_IndirectTypeDescription * >(
454 type.get())->pType);
455 if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) {
456 check(static_cast< sal_Int32 >(n));
457 rtl::ByteSequence s(
458 reinterpret_cast< sal_Int8 const * >(data_),
459 static_cast< sal_Int32 >(n));
460 data_ += 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) {
483 uno_copyData(
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)
493 assert(
494 type.is() &&
495 (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
496 type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
497 values != 0);
498 type.makeComplete();
499 typelib_CompoundTypeDescription * ctd =
500 reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
501 if (ctd->pBaseTypeDescription != 0) {
502 readMemberValues(
503 css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase),
504 values);
506 for (sal_Int32 i = 0; i != ctd->nMembers; ++i) {
507 values->push_back(
508 readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i])));
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */