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