xref: /trunk/main/binaryurp/source/unmarshal.cxx (revision cdf0e10c)
1 /*************************************************************************
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2000, 2011 Oracle and/or its affiliates.
6 *
7 * OpenOffice.org - a multi-platform office productivity suite
8 *
9 * This file is part of OpenOffice.org.
10 *
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
14 *
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org.  If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
25 *
26 ************************************************************************/
27 
28 #include "sal/config.h"
29 
30 #include <cstdlib>
31 #include <new>
32 #include <vector>
33 
34 #include "boost/noncopyable.hpp"
35 #include "com/sun/star/io/IOException.hpp"
36 #include "com/sun/star/uno/Reference.hxx"
37 #include "com/sun/star/uno/RuntimeException.hpp"
38 #include "com/sun/star/uno/Sequence.hxx"
39 #include "com/sun/star/uno/XInterface.hpp"
40 #include "cppu/unotype.hxx"
41 #include "osl/diagnose.h"
42 #include "rtl/byteseq.hxx"
43 #include "rtl/ref.hxx"
44 #include "rtl/textcvt.h"
45 #include "rtl/textenc.h"
46 #include "rtl/ustring.h"
47 #include "rtl/ustring.hxx"
48 #include "sal/types.h"
49 #include "typelib/typeclass.h"
50 #include "typelib/typedescription.h"
51 #include "typelib/typedescription.hxx"
52 #include "uno/any2.h"
53 #include "uno/data.h"
54 #include "uno/dispatcher.hxx"
55 
56 #include "binaryany.hxx"
57 #include "bridge.hxx"
58 #include "cache.hxx"
59 #include "readerstate.hxx"
60 #include "unmarshal.hxx"
61 
62 namespace binaryurp {
63 
64 namespace {
65 
66 namespace css = com::sun::star;
67 
68 void * allocate(sal_Size size) {
69     void * p = rtl_allocateMemory(size);
70     if (p == 0) {
71         throw std::bad_alloc();
72     }
73     return p;
74 }
75 
76 std::vector< BinaryAny >::iterator copyMemberValues(
77     css::uno::TypeDescription const & type,
78     std::vector< BinaryAny >::iterator const & it, void * buffer) throw ()
79 {
80     OSL_ASSERT(
81         type.is() &&
82         (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
83          type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
84         buffer != 0);
85     type.makeComplete();
86     std::vector< BinaryAny >::iterator i(it);
87     typelib_CompoundTypeDescription * ctd =
88         reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
89     if (ctd->pBaseTypeDescription != 0) {
90         i = copyMemberValues(
91             css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase), i,
92             buffer);
93     }
94     for (sal_Int32 j = 0; j != ctd->nMembers; ++j) {
95         uno_type_copyData(
96             static_cast< char * >(buffer) + ctd->pMemberOffsets[j],
97             const_cast< void * >(
98                 i++->getValue(css::uno::TypeDescription(ctd->ppTypeRefs[j]))),
99             ctd->ppTypeRefs[j], 0);
100     }
101     return i;
102 }
103 
104 }
105 
106 Unmarshal::Unmarshal(
107     rtl::Reference< Bridge > const & bridge, ReaderState & state,
108     css::uno::Sequence< sal_Int8 > const & buffer):
109     bridge_(bridge), state_(state), buffer_(buffer)
110 {
111     data_ = reinterpret_cast< sal_uInt8 const * >(buffer_.getConstArray());
112     end_ = data_ + buffer_.getLength();
113 }
114 
115 Unmarshal::~Unmarshal() {}
116 
117 sal_uInt8 Unmarshal::read8() {
118     check(1);
119     return *data_++;
120 }
121 
122 sal_uInt16 Unmarshal::read16() {
123     check(2);
124     sal_uInt16 n = static_cast< sal_uInt16 >(*data_++) << 8;
125     return n | *data_++;
126 }
127 
128 sal_uInt32 Unmarshal::read32() {
129     check(4);
130     sal_uInt32 n = static_cast< sal_uInt32 >(*data_++) << 24;
131     n |= static_cast< sal_uInt32 >(*data_++) << 16;
132     n |= static_cast< sal_uInt32 >(*data_++) << 8;
133     return n | *data_++;
134 }
135 
136 css::uno::TypeDescription Unmarshal::readType() {
137     sal_uInt8 flags = read8();
138     typelib_TypeClass tc = static_cast< typelib_TypeClass >(flags & 0x7F);
139     switch (tc) {
140     case typelib_TypeClass_VOID:
141     case typelib_TypeClass_BOOLEAN:
142     case typelib_TypeClass_BYTE:
143     case typelib_TypeClass_SHORT:
144     case typelib_TypeClass_UNSIGNED_SHORT:
145     case typelib_TypeClass_LONG:
146     case typelib_TypeClass_UNSIGNED_LONG:
147     case typelib_TypeClass_HYPER:
148     case typelib_TypeClass_UNSIGNED_HYPER:
149     case typelib_TypeClass_FLOAT:
150     case typelib_TypeClass_DOUBLE:
151     case typelib_TypeClass_CHAR:
152     case typelib_TypeClass_STRING:
153     case typelib_TypeClass_TYPE:
154     case typelib_TypeClass_ANY:
155         if ((flags & 0x80) != 0) {
156             throw css::io::IOException(
157                 rtl::OUString(
158                     RTL_CONSTASCII_USTRINGPARAM(
159                         "binaryurp::Unmarshal: cache flag of simple type is"
160                         " set")),
161                 css::uno::Reference< css::uno::XInterface >());
162         }
163         return css::uno::TypeDescription(
164             *typelib_static_type_getByTypeClass(
165                 static_cast< typelib_TypeClass >(tc)));
166     case typelib_TypeClass_SEQUENCE:
167     case typelib_TypeClass_ENUM:
168     case typelib_TypeClass_STRUCT:
169     case typelib_TypeClass_EXCEPTION:
170     case typelib_TypeClass_INTERFACE:
171         {
172             sal_uInt16 idx = readCacheIndex();
173             if ((flags & 0x80) == 0) {
174                 if (idx == cache::ignore || !state_.typeCache[idx].is()) {
175                     throw css::io::IOException(
176                         rtl::OUString(
177                             RTL_CONSTASCII_USTRINGPARAM(
178                                 "binaryurp::Unmarshal: unknown type cache"
179                                 " index")),
180                         css::uno::Reference< css::uno::XInterface >());
181                 }
182                 return state_.typeCache[idx];
183             } else {
184                 css::uno::TypeDescription t(readString());
185                 if (!t.is() ||
186                     t.get()->eTypeClass != static_cast< typelib_TypeClass >(tc))
187                 {
188                     throw css::io::IOException(
189                         rtl::OUString(
190                             RTL_CONSTASCII_USTRINGPARAM(
191                                 "binaryurp::Unmarshal: type with unknown"
192                                 " name")),
193                         css::uno::Reference< css::uno::XInterface >());
194                 }
195                 for (css::uno::TypeDescription t2(t);
196                      t2.get()->eTypeClass == typelib_TypeClass_SEQUENCE;)
197                 {
198                     t2.makeComplete();
199                     t2 = css::uno::TypeDescription(
200                         reinterpret_cast< typelib_IndirectTypeDescription * >(
201                             t2.get())->pType);
202                     if (!t2.is()) {
203                         throw css::io::IOException(
204                             rtl::OUString(
205                                 RTL_CONSTASCII_USTRINGPARAM(
206                                     "binaryurp::Unmarshal: sequence type with"
207                                     " unknown component type")),
208                             css::uno::Reference< css::uno::XInterface >());
209                     }
210                     switch (t2.get()->eTypeClass) {
211                     case typelib_TypeClass_VOID:
212                     case typelib_TypeClass_EXCEPTION:
213                         throw css::io::IOException(
214                             rtl::OUString(
215                                 RTL_CONSTASCII_USTRINGPARAM(
216                                     "binaryurp::Unmarshal: sequence type with"
217                                     " bad component type")),
218                             css::uno::Reference< css::uno::XInterface >());
219                     default:
220                         break;
221                     }
222                 }
223                 if (idx != cache::ignore) {
224                     state_.typeCache[idx] = t;
225                 }
226                 return t;
227             }
228         }
229     default:
230         throw css::io::IOException(
231             rtl::OUString(
232                 RTL_CONSTASCII_USTRINGPARAM(
233                     "binaryurp::Unmarshal: type of unknown type class")),
234             css::uno::Reference< css::uno::XInterface >());
235     }
236 }
237 
238 rtl::OUString Unmarshal::readOid() {
239     rtl::OUString oid(readString());
240     for (sal_Int32 i = 0; i != oid.getLength(); ++i) {
241         if (oid[i] > 0x7F) {
242             throw css::io::IOException(
243                 rtl::OUString(
244                     RTL_CONSTASCII_USTRINGPARAM(
245                         "binaryurp::Unmarshal: OID contains non-ASCII"
246                         " character")),
247                 css::uno::Reference< css::uno::XInterface >());
248         }
249     }
250     sal_uInt16 idx = readCacheIndex();
251     if (oid.getLength() == 0 && idx != cache::ignore) {
252         if (state_.oidCache[idx].getLength() == 0) {
253             throw css::io::IOException(
254                 rtl::OUString(
255                     RTL_CONSTASCII_USTRINGPARAM(
256                         "binaryurp::Unmarshal: unknown OID cache index")),
257                 css::uno::Reference< css::uno::XInterface >());
258         }
259         return state_.oidCache[idx];
260     }
261     if (idx != cache::ignore) {
262         state_.oidCache[idx] = oid;
263     }
264     return oid;
265 }
266 
267 rtl::ByteSequence Unmarshal::readTid() {
268     rtl::ByteSequence tid(
269         *static_cast< sal_Sequence * const * >(
270             readSequence(
271                 css::uno::TypeDescription(
272                     cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get())).
273             getValue(
274                 css::uno::TypeDescription(
275                     cppu::UnoType< css::uno::Sequence< sal_Int8 > >::get()))));
276     sal_uInt16 idx = readCacheIndex();
277     if (tid.getLength() == 0) {
278         if (idx == cache::ignore || state_.tidCache[idx].getLength() == 0) {
279             throw css::io::IOException(
280                 rtl::OUString(
281                     RTL_CONSTASCII_USTRINGPARAM(
282                         "binaryurp::Unmarshal: unknown TID cache index")),
283                 css::uno::Reference< css::uno::XInterface >());
284         }
285         return state_.tidCache[idx];
286     }
287     if (idx != cache::ignore) {
288         state_.tidCache[idx] = tid;
289     }
290     return tid;
291 }
292 
293 BinaryAny Unmarshal::readValue(css::uno::TypeDescription const & type) {
294     OSL_ASSERT(type.is());
295     switch (type.get()->eTypeClass) {
296     default:
297         std::abort(); // this cannot happen
298         // pseudo fall-through to avoid compiler warnings
299     case typelib_TypeClass_VOID:
300         return BinaryAny();
301     case typelib_TypeClass_BOOLEAN:
302         {
303             sal_uInt8 v = read8();
304             if (v > 1) {
305                 throw css::io::IOException(
306                     rtl::OUString(
307                         RTL_CONSTASCII_USTRINGPARAM(
308                             "binaryurp::Unmarshal: boolean of unknown value")),
309                     css::uno::Reference< css::uno::XInterface >());
310             }
311             return BinaryAny(type, &v);
312         }
313     case typelib_TypeClass_BYTE:
314         {
315             sal_uInt8 v = read8();
316             return BinaryAny(type, &v);
317         }
318     case typelib_TypeClass_SHORT:
319     case typelib_TypeClass_UNSIGNED_SHORT:
320     case typelib_TypeClass_CHAR:
321         {
322             sal_uInt16 v = read16();
323             return BinaryAny(type, &v);
324         }
325     case typelib_TypeClass_LONG:
326     case typelib_TypeClass_UNSIGNED_LONG:
327     case typelib_TypeClass_FLOAT:
328         {
329             sal_uInt32 v = read32();
330             return BinaryAny(type, &v);
331         }
332     case typelib_TypeClass_HYPER:
333     case typelib_TypeClass_UNSIGNED_HYPER:
334     case typelib_TypeClass_DOUBLE:
335         {
336             sal_uInt64 v = read64();
337             return BinaryAny(type, &v);
338         }
339     case typelib_TypeClass_STRING:
340         {
341             rtl::OUString v(readString());
342             return BinaryAny(type, &v.pData);
343         }
344     case typelib_TypeClass_TYPE:
345         {
346             css::uno::TypeDescription v(readType());
347             typelib_TypeDescription * p = v.get();
348             return BinaryAny(type, &p);
349         }
350     case typelib_TypeClass_ANY:
351         {
352             css::uno::TypeDescription t(readType());
353             if (t.get()->eTypeClass == typelib_TypeClass_ANY) {
354                 throw css::io::IOException(
355                     rtl::OUString(
356                         RTL_CONSTASCII_USTRINGPARAM(
357                             "binaryurp::Unmarshal: any of type ANY")),
358                     css::uno::Reference< css::uno::XInterface >());
359             }
360             return readValue(t);
361         }
362     case typelib_TypeClass_SEQUENCE:
363         type.makeComplete();
364         return readSequence(type);
365     case typelib_TypeClass_ENUM:
366         {
367             sal_Int32 v = static_cast< sal_Int32 >(read32());
368             type.makeComplete();
369             typelib_EnumTypeDescription * etd =
370                 reinterpret_cast< typelib_EnumTypeDescription * >(type.get());
371             bool found = false;
372             for (sal_Int32 i = 0; i != etd->nEnumValues; ++i) {
373                 if (etd->pEnumValues[i] == v) {
374                     found = true;
375                     break;
376                 }
377             }
378             if (!found) {
379                 throw css::io::IOException(
380                     rtl::OUString(
381                         RTL_CONSTASCII_USTRINGPARAM(
382                             "binaryurp::Unmarshal: unknown enum value")),
383                     css::uno::Reference< css::uno::XInterface >());
384             }
385             return BinaryAny(type, &v);
386         }
387     case typelib_TypeClass_STRUCT:
388     case typelib_TypeClass_EXCEPTION:
389         {
390             std::vector< BinaryAny > as;
391             readMemberValues(type, &as);
392             void * buf = allocate(type.get()->nSize);
393             copyMemberValues(type, as.begin(), buf);
394             uno_Any raw;
395             raw.pType = reinterpret_cast< typelib_TypeDescriptionReference * >(
396                 type.get());
397             raw.pData = buf;
398             raw.pReserved = 0;
399             return BinaryAny(raw);
400         }
401     case typelib_TypeClass_INTERFACE:
402         {
403             css::uno::UnoInterfaceReference obj(
404                 bridge_->registerIncomingInterface(readOid(), type));
405             return BinaryAny(type, &obj.m_pUnoI);
406         }
407     }
408 }
409 
410 void Unmarshal::done() const {
411     if (data_ != end_) {
412         throw css::io::IOException(
413             rtl::OUString(
414                 RTL_CONSTASCII_USTRINGPARAM(
415                     "binaryurp::Unmarshal: block contains excess data")),
416             css::uno::Reference< css::uno::XInterface >());
417     }
418 }
419 
420 void Unmarshal::check(sal_Int32 size) const {
421     if (end_ - data_ < size) {
422         throw css::io::IOException(
423             rtl::OUString(
424                 RTL_CONSTASCII_USTRINGPARAM(
425                     "binaryurp::Unmarshal: trying to read past end of block")),
426             css::uno::Reference< css::uno::XInterface >());
427     }
428 }
429 
430 sal_uInt32 Unmarshal::readCompressed() {
431     sal_uInt8 n = read8();
432     return n == 0xFF ? read32() : n;
433 }
434 
435 sal_uInt16 Unmarshal::readCacheIndex() {
436     sal_uInt16 idx = read16();
437     if (idx >= cache::size && idx != cache::ignore) {
438         throw css::io::IOException(
439             rtl::OUString(
440                 RTL_CONSTASCII_USTRINGPARAM(
441                     "binaryurp::Unmarshal: cache index out of range")),
442             css::uno::Reference< css::uno::XInterface >());
443     }
444     return idx;
445 }
446 
447 sal_uInt64 Unmarshal::read64() {
448     check(8);
449     sal_uInt64 n = static_cast< sal_uInt64 >(*data_++) << 56;
450     n |= static_cast< sal_uInt64 >(*data_++) << 48;
451     n |= static_cast< sal_uInt64 >(*data_++) << 40;
452     n |= static_cast< sal_uInt64 >(*data_++) << 32;
453     n |= static_cast< sal_uInt64 >(*data_++) << 24;
454     n |= static_cast< sal_uInt64 >(*data_++) << 16;
455     n |= static_cast< sal_uInt64 >(*data_++) << 8;
456     return n | *data_++;
457 }
458 
459 rtl::OUString Unmarshal::readString() {
460     sal_uInt32 n = readCompressed();
461     if (n > SAL_MAX_INT32) {
462         throw css::uno::RuntimeException(
463             rtl::OUString(
464                 RTL_CONSTASCII_USTRINGPARAM(
465                     "binaryurp::Unmarshal: string size too large")),
466             css::uno::Reference< css::uno::XInterface >());
467     }
468     check(static_cast< sal_Int32 >(n));
469     rtl::OUString s;
470     if (!rtl_convertStringToUString(
471             &s.pData, reinterpret_cast< char const * >(data_),
472             static_cast< sal_Int32 >(n), RTL_TEXTENCODING_UTF8,
473             (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
474              RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
475              RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
476     {
477         throw css::io::IOException(
478             rtl::OUString(
479                 RTL_CONSTASCII_USTRINGPARAM(
480                     "binaryurp::Unmarshal: string does not contain UTF-8")),
481             css::uno::Reference< css::uno::XInterface >());
482     }
483     data_ += n;
484     return s;
485 }
486 
487 BinaryAny Unmarshal::readSequence(css::uno::TypeDescription const & type) {
488     OSL_ASSERT(
489         type.is() && type.get()->eTypeClass == typelib_TypeClass_SEQUENCE);
490     sal_uInt32 n = readCompressed();
491     if (n > SAL_MAX_INT32) {
492         throw css::uno::RuntimeException(
493             rtl::OUString(
494                 RTL_CONSTASCII_USTRINGPARAM(
495                     "binaryurp::Unmarshal: sequence size too large")),
496             css::uno::Reference< css::uno::XInterface >());
497     }
498     if (n == 0) {
499         return BinaryAny(type, 0);
500     }
501     css::uno::TypeDescription ctd(
502         reinterpret_cast< typelib_IndirectTypeDescription * >(
503             type.get())->pType);
504     if (ctd.get()->eTypeClass == typelib_TypeClass_BYTE) {
505         check(static_cast< sal_Int32 >(n));
506         rtl::ByteSequence s(
507             reinterpret_cast< sal_Int8 const * >(data_),
508             static_cast< sal_Int32 >(n));
509         data_ += n;
510         sal_Sequence * p = s.getHandle();
511         return BinaryAny(type, &p);
512     }
513     std::vector< BinaryAny > as;
514     for (sal_uInt32 i = 0; i != n; ++i) {
515         as.push_back(readValue(ctd));
516     }
517     OSL_ASSERT(ctd.get()->nSize >= 0);
518     sal_uInt64 size = static_cast< sal_uInt64 >(n) *
519         static_cast< sal_uInt64 >(ctd.get()->nSize);
520         // sal_uInt32 * sal_Int32 -> sal_uInt64 cannot overflow
521     if (size > SAL_MAX_SIZE - SAL_SEQUENCE_HEADER_SIZE) {
522         throw css::uno::RuntimeException(
523             rtl::OUString(
524                 RTL_CONSTASCII_USTRINGPARAM(
525                     "binaryurp::Unmarshal: sequence size too large")),
526             css::uno::Reference< css::uno::XInterface >());
527     }
528     void * buf = allocate(
529         SAL_SEQUENCE_HEADER_SIZE + static_cast< sal_Size >(size));
530     static_cast< sal_Sequence * >(buf)->nRefCount = 0;
531     static_cast< sal_Sequence * >(buf)->nElements =
532         static_cast< sal_Int32 >(n);
533     for (sal_uInt32 i = 0; i != n; ++i) {
534         uno_copyData(
535             static_cast< sal_Sequence * >(buf)->elements + i * ctd.get()->nSize,
536             const_cast< void * >(as[i].getValue(ctd)), ctd.get(), 0);
537     }
538     return BinaryAny(type, reinterpret_cast< sal_Sequence ** >(&buf));
539 }
540 
541 void Unmarshal::readMemberValues(
542     css::uno::TypeDescription const & type, std::vector< BinaryAny > * values)
543 {
544     OSL_ASSERT(
545         type.is() &&
546         (type.get()->eTypeClass == typelib_TypeClass_STRUCT ||
547          type.get()->eTypeClass == typelib_TypeClass_EXCEPTION) &&
548         values != 0);
549     type.makeComplete();
550     typelib_CompoundTypeDescription * ctd =
551         reinterpret_cast< typelib_CompoundTypeDescription * >(type.get());
552     if (ctd->pBaseTypeDescription != 0) {
553         readMemberValues(
554             css::uno::TypeDescription(&ctd->pBaseTypeDescription->aBase),
555             values);
556     }
557     for (sal_Int32 i = 0; i != ctd->nMembers; ++i) {
558         values->push_back(
559             readValue(css::uno::TypeDescription(ctd->ppTypeRefs[i])));
560     }
561 }
562 
563 }
564