update credits
[LibreOffice.git] / unoidl / source / unoidlprovider.cxx
blob47b6f9eb0399ca7c606533c5cc0d90eece54f655
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/.
8 */
10 #include "sal/config.h"
12 #include <algorithm>
13 #include <cassert>
14 #include <cstring>
15 #include <vector>
17 #include "osl/endian.h"
18 #include "osl/file.h"
19 #include "rtl/ref.hxx"
20 #include "rtl/textenc.h"
21 #include "rtl/textcvt.h"
22 #include "rtl/ustring.hxx"
23 #include "sal/log.hxx"
24 #include "sal/types.h"
25 #include "salhelper/simplereferenceobject.hxx"
26 #include "unoidl/unoidl.hxx"
27 #include "unoidl/unoidlprovider.hxx"
29 namespace {
31 // sizeof (Memory16) == 2
32 struct Memory16 {
33 unsigned char byte[2];
35 sal_uInt16 getUnsigned16() const {
36 return static_cast< sal_uInt16 >(byte[0])
37 | (static_cast< sal_uInt16 >(byte[1]) << 8);
41 // sizeof (Memory32) == 4
42 struct Memory32 {
43 unsigned char byte[4];
45 sal_uInt32 getUnsigned32() const {
46 return static_cast< sal_uInt32 >(byte[0])
47 | (static_cast< sal_uInt32 >(byte[1]) << 8)
48 | (static_cast< sal_uInt32 >(byte[2]) << 16)
49 | (static_cast< sal_uInt32 >(byte[3]) << 24);
52 float getIso60599Binary32() const {
53 union {
54 unsigned char buf[4];
55 float f; // assuming float is ISO 60599 binary32
56 } sa;
57 #if defined OSL_LITENDIAN
58 sa.buf[0] = byte[0];
59 sa.buf[1] = byte[1];
60 sa.buf[2] = byte[2];
61 sa.buf[3] = byte[3];
62 #else
63 sa.buf[0] = byte[3];
64 sa.buf[1] = byte[2];
65 sa.buf[2] = byte[1];
66 sa.buf[3] = byte[0];
67 #endif
68 return sa.f;
72 // sizeof (Memory64) == 8
73 struct Memory64 {
74 unsigned char byte[8];
76 sal_uInt64 getUnsigned64() const {
77 return static_cast< sal_uInt64 >(byte[0])
78 | (static_cast< sal_uInt64 >(byte[1]) << 8)
79 | (static_cast< sal_uInt64 >(byte[2]) << 16)
80 | (static_cast< sal_uInt64 >(byte[3]) << 24)
81 | (static_cast< sal_uInt64 >(byte[4]) << 32)
82 | (static_cast< sal_uInt64 >(byte[5]) << 40)
83 | (static_cast< sal_uInt64 >(byte[6]) << 48)
84 | (static_cast< sal_uInt64 >(byte[7]) << 56);
87 double getIso60599Binary64() const {
88 union {
89 unsigned char buf[8];
90 double d; // assuming double is ISO 60599 binary64
91 } sa;
92 #if defined OSL_LITENDIAN
93 sa.buf[0] = byte[0];
94 sa.buf[1] = byte[1];
95 sa.buf[2] = byte[2];
96 sa.buf[3] = byte[3];
97 sa.buf[4] = byte[4];
98 sa.buf[5] = byte[5];
99 sa.buf[6] = byte[6];
100 sa.buf[7] = byte[7];
101 #else
102 sa.buf[0] = byte[7];
103 sa.buf[1] = byte[6];
104 sa.buf[2] = byte[5];
105 sa.buf[3] = byte[4];
106 sa.buf[4] = byte[3];
107 sa.buf[5] = byte[2];
108 sa.buf[6] = byte[1];
109 sa.buf[7] = byte[0];
110 #endif
111 return sa.d;
117 namespace unoidl {
119 namespace detail {
121 class MappedFile: public salhelper::SimpleReferenceObject {
122 public:
123 explicit MappedFile(OUString const & fileUrl);
125 sal_uInt8 read8(sal_uInt32 offset) const;
127 sal_uInt16 read16(sal_uInt32 offset) const;
129 sal_uInt32 read32(sal_uInt32 offset) const;
131 sal_uInt64 read64(sal_uInt32 offset) const;
133 float readIso60599Binary32(sal_uInt32 offset) const;
135 double readIso60599Binary64(sal_uInt32 offset) const;
137 OUString readNulName(sal_uInt32 offset) const;
139 OUString readIdxName(sal_uInt32 * offset) const
140 { return readIdxString(offset, RTL_TEXTENCODING_ASCII_US); }
142 OUString readIdxString(sal_uInt32 * offset) const
143 { return readIdxString(offset, RTL_TEXTENCODING_UTF8); }
145 OUString uri;
146 oslFileHandle handle;
147 sal_uInt64 size;
148 void * address;
150 private:
151 virtual ~MappedFile();
153 sal_uInt8 get8(sal_uInt32 offset) const;
155 sal_uInt16 get16(sal_uInt32 offset) const;
157 sal_uInt32 get32(sal_uInt32 offset) const;
159 sal_uInt64 get64(sal_uInt32 offset) const;
161 float getIso60599Binary32(sal_uInt32 offset) const;
163 double getIso60599Binary64(sal_uInt32 offset) const;
165 OUString readIdxString(sal_uInt32 * offset, rtl_TextEncoding encoding)
166 const;
169 MappedFile::MappedFile(OUString const & fileUrl): uri(fileUrl) {
170 oslFileError e = osl_openFile(uri.pData, &handle, osl_File_OpenFlag_Read);
171 switch (e) {
172 case osl_File_E_None:
173 break;
174 case osl_File_E_NOENT:
175 throw NoSuchFileException(uri);
176 default:
177 throw FileFormatException(uri, "cannot open: " + OUString::number(e));
179 e = osl_getFileSize(handle, &size);
180 if (e == osl_File_E_None) {
181 e = osl_mapFile(
182 handle, &address, size, 0, osl_File_MapFlag_RandomAccess);
184 if (e != osl_File_E_None) {
185 oslFileError e2 = osl_closeFile(handle);
186 SAL_WARN_IF(
187 e2 != osl_File_E_None, "unoidl",
188 "cannot close " << uri << ": " << +e2);
189 throw FileFormatException(uri, "cannot mmap: " + OUString::number(e));
193 sal_uInt8 MappedFile::read8(sal_uInt32 offset) const {
194 assert(size >= 8);
195 if (offset > size - 1) {
196 throw FileFormatException(
197 uri, "UNOIDL format: offset for 8-bit value too large");
199 return get8(offset);
202 sal_uInt16 MappedFile::read16(sal_uInt32 offset) const {
203 assert(size >= 8);
204 if (offset > size - 2) {
205 throw FileFormatException(
206 uri, "UNOIDL format: offset for 16-bit value too large");
208 return get16(offset);
211 sal_uInt32 MappedFile::read32(sal_uInt32 offset) const {
212 assert(size >= 8);
213 if (offset > size - 4) {
214 throw FileFormatException(
215 uri, "UNOIDL format: offset for 32-bit value too large");
217 return get32(offset);
220 sal_uInt64 MappedFile::read64(sal_uInt32 offset) const {
221 assert(size >= 8);
222 if (offset > size - 8) {
223 throw FileFormatException(
224 uri, "UNOIDL format: offset for 64-bit value too large");
226 return get64(offset);
229 float MappedFile::readIso60599Binary32(sal_uInt32 offset) const {
230 assert(size >= 8);
231 if (offset > size - 4) {
232 throw FileFormatException(
233 uri, "UNOIDL format: offset for 32-bit value too large");
235 return getIso60599Binary32(offset);
238 double MappedFile::readIso60599Binary64(sal_uInt32 offset) const {
239 assert(size >= 8);
240 if (offset > size - 8) {
241 throw FileFormatException(
242 uri, "UNOIDL format: offset for 64-bit value too large");
244 return getIso60599Binary64(offset);
247 OUString MappedFile::readNulName(sal_uInt32 offset) const {
248 if (offset > size) {
249 throw FileFormatException(
250 uri, "UNOIDL format: offset for string too large");
252 sal_uInt64 end = offset;
253 for (;; ++end) {
254 if (end == size) {
255 throw FileFormatException(
256 uri, "UNOIDL format: string misses trailing NUL");
258 if (static_cast< char const * >(address)[end] == 0) {
259 break;
262 if (end - offset > SAL_MAX_INT32) {
263 throw FileFormatException(uri, "UNOIDL format: string too long");
265 OUString name;
266 if (!rtl_convertStringToUString(
267 &name.pData, static_cast< char const * >(address) + offset,
268 end - offset, RTL_TEXTENCODING_ASCII_US,
269 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
270 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
271 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
273 throw FileFormatException(uri, "UNOIDL format: name is not ASCII");
275 return name;
278 MappedFile::~MappedFile() {
279 oslFileError e = osl_unmapMappedFile(handle, address, size);
280 SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e);
281 e = osl_closeFile(handle);
282 SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e);
285 sal_uInt8 MappedFile::get8(sal_uInt32 offset) const {
286 assert(size >= 8);
287 assert(offset <= size - 1);
288 return static_cast< char const * >(address)[offset];
291 sal_uInt16 MappedFile::get16(sal_uInt32 offset) const {
292 assert(size >= 8);
293 assert(offset <= size - 2);
294 return reinterpret_cast< Memory16 const * >(
295 static_cast< char const * >(address) + offset)->getUnsigned16();
298 sal_uInt32 MappedFile::get32(sal_uInt32 offset) const {
299 assert(size >= 8);
300 assert(offset <= size - 4);
301 return reinterpret_cast< Memory32 const * >(
302 static_cast< char const * >(address) + offset)->getUnsigned32();
305 sal_uInt64 MappedFile::get64(sal_uInt32 offset) const {
306 assert(size >= 8);
307 assert(offset <= size - 8);
308 return reinterpret_cast< Memory64 const * >(
309 static_cast< char const * >(address) + offset)->getUnsigned64();
312 float MappedFile::getIso60599Binary32(sal_uInt32 offset) const {
313 assert(size >= 8);
314 assert(offset <= size - 4);
315 return reinterpret_cast< Memory32 const * >(
316 static_cast< char const * >(address) + offset)->getIso60599Binary32();
319 double MappedFile::getIso60599Binary64(sal_uInt32 offset) const {
320 assert(size >= 8);
321 assert(offset <= size - 8);
322 return reinterpret_cast< Memory64 const * >(
323 static_cast< char const * >(address) + offset)->getIso60599Binary64();
326 OUString MappedFile::readIdxString(
327 sal_uInt32 * offset, rtl_TextEncoding encoding) const
329 assert(offset != 0);
330 sal_uInt32 len = read32(*offset);
331 sal_uInt32 off;
332 if ((len & 0x80000000) == 0) {
333 off = *offset;
334 *offset += 4 + len;
335 } else {
336 *offset += 4;
337 off = len & ~0x80000000;
338 len = read32(off);
339 if ((len & 0x80000000) != 0) {
340 throw FileFormatException(
341 uri, "UNOIDL format: string length high bit set");
344 if (len > SAL_MAX_INT32 || len > size - off - 4) {
345 throw FileFormatException(
346 uri, "UNOIDL format: size of string is too large");
348 OUString name;
349 if (!rtl_convertStringToUString(
350 &name.pData, static_cast< char const * >(address) + off + 4, len,
351 encoding,
352 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
353 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
354 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
356 throw FileFormatException(
357 uri, "UNOIDL format: string bytes do not match encoding");
359 return name;
362 // sizeof (MapEntry) == 8
363 struct MapEntry {
364 Memory32 name;
365 Memory32 data;
370 namespace {
372 enum Compare { COMPARE_LESS, COMPARE_GREATER, COMPARE_EQUAL };
374 Compare compare(
375 rtl::Reference< detail::MappedFile > const & file, OUString const & name,
376 sal_Int32 nameOffset, sal_Int32 nameLength, detail::MapEntry const * entry)
378 assert(file.is());
379 assert(entry != 0);
380 sal_uInt32 off = entry->name.getUnsigned32();
381 if (off > file->size - 1) { // at least a trailing NUL
382 throw FileFormatException(
383 file->uri, "UNOIDL format: string offset too large");
385 assert(nameLength >= 0);
386 sal_uInt64 min = std::min(
387 static_cast< sal_uInt64 >(nameLength), file->size - off);
388 for (sal_uInt64 i = 0; i != min; ++i) {
389 sal_Unicode c1 = name[nameOffset + i];
390 sal_Unicode c2 = static_cast< unsigned char const * >(file->address)[
391 off + i];
392 if (c1 < c2) {
393 return COMPARE_LESS;
394 } else if (c1 > c2 || c2 == 0) {
395 // ...the "|| c2 == 0" is for the odd case where name erroneously
396 // contains NUL characters
397 return COMPARE_GREATER;
400 if (static_cast< sal_uInt64 >(nameLength) == min) {
401 if (file->size - off == min) {
402 throw FileFormatException(
403 file->uri, "UNOIDL format: string misses trailing NUL");
405 return
406 static_cast< unsigned char const * >(file->address)[off + min] == 0
407 ? COMPARE_EQUAL : COMPARE_LESS;
408 } else {
409 return COMPARE_GREATER;
413 sal_uInt32 findInMap(
414 rtl::Reference< detail::MappedFile > const & file,
415 detail::MapEntry const * mapBegin, sal_uInt32 mapSize,
416 OUString const & name, sal_Int32 nameOffset, sal_Int32 nameLength)
418 if (mapSize == 0) {
419 return 0;
421 sal_uInt32 n = mapSize / 2;
422 detail::MapEntry const * p = mapBegin + n;
423 switch (compare(file, name, nameOffset, nameLength, p)) {
424 case COMPARE_LESS:
425 return findInMap(file, mapBegin, n, name, nameOffset, nameLength);
426 case COMPARE_GREATER:
427 return findInMap(
428 file, p + 1, mapSize - n - 1, name, nameOffset, nameLength);
429 default: // COMPARE_EQUAL
430 break;
432 sal_uInt32 off = mapBegin[n].data.getUnsigned32();
433 if (off == 0) {
434 throw FileFormatException(
435 file->uri, "UNOIDL format: map entry data offset is null");
437 return off;
440 std::vector< OUString > readAnnotations(
441 bool annotated, rtl::Reference< detail::MappedFile > const & file,
442 sal_uInt32 offset, sal_uInt32 * newOffset = 0)
444 std::vector< OUString > ans;
445 if (annotated) {
446 sal_uInt32 n = file->read32(offset);
447 offset += 4;
448 for (sal_uInt32 i = 0; i != n; ++i) {
449 ans.push_back(file->readIdxString(&offset));
452 if (newOffset != 0) {
453 *newOffset = offset;
455 return ans;
458 ConstantValue readConstant(
459 rtl::Reference< detail::MappedFile > const & file, sal_uInt32 offset,
460 sal_uInt32 * newOffset = 0, bool * annotated = 0)
462 assert(file.is());
463 int v = file->read8(offset);
464 int type = v & 0x7F;
465 if (annotated != 0) {
466 *annotated = (v & 0x80) != 0;
468 switch (type) {
469 case 0: // BOOLEAN
470 v = file->read8(offset + 1);
471 if (newOffset != 0) {
472 *newOffset = offset + 2;
474 switch (v) {
475 case 0:
476 return ConstantValue(false);
477 case 1:
478 return ConstantValue(true);
479 default:
480 throw FileFormatException(
481 file->uri,
482 ("UNOIDL format: bad boolean constant value "
483 + OUString::number(v)));
485 case 1: // BYTE
486 if (newOffset != 0) {
487 *newOffset = offset + 2;
489 return ConstantValue(static_cast< sal_Int8 >(file->read8(offset + 1)));
490 //TODO: implementation-defined behavior of conversion from sal_uInt8
491 // to sal_Int8 relies on two's complement representation
492 case 2: // SHORT
493 if (newOffset != 0) {
494 *newOffset = offset + 3;
496 return ConstantValue(
497 static_cast< sal_Int16 >(file->read16(offset + 1)));
498 //TODO: implementation-defined behavior of conversion from
499 // sal_uInt16 to sal_Int16 relies on two's complement representation
500 case 3: // UNSIGNED SHORT
501 if (newOffset != 0) {
502 *newOffset = offset + 3;
504 return ConstantValue(file->read16(offset + 1));
505 case 4: // LONG
506 if (newOffset != 0) {
507 *newOffset = offset + 5;
509 return ConstantValue(
510 static_cast< sal_Int32 >(file->read32(offset + 1)));
511 //TODO: implementation-defined behavior of conversion from
512 // sal_uInt32 to sal_Int32 relies on two's complement representation
513 case 5: // UNSIGNED LONG
514 if (newOffset != 0) {
515 *newOffset = offset + 5;
517 return ConstantValue(file->read32(offset + 1));
518 case 6: // HYPER
519 if (newOffset != 0) {
520 *newOffset = offset + 9;
522 return ConstantValue(
523 static_cast< sal_Int64 >(file->read64(offset + 1)));
524 //TODO: implementation-defined behavior of conversion from
525 // sal_uInt64 to sal_Int64 relies on two's complement representation
526 case 7: // UNSIGNED HYPER
527 if (newOffset != 0) {
528 *newOffset = offset + 9;
530 return ConstantValue(file->read64(offset + 1));
531 case 8: // FLOAT
532 if (newOffset != 0) {
533 *newOffset = offset + 5;
535 return ConstantValue(file->readIso60599Binary32(offset + 1));
536 case 9: // DOUBLE
537 if (newOffset != 0) {
538 *newOffset = offset + 9;
540 return ConstantValue(file->readIso60599Binary64(offset + 1));
541 default:
542 throw FileFormatException(
543 file->uri,
544 "UNOIDL format: bad constant type byte " + OUString::number(v));
548 rtl::Reference< Entity > readEntity(
549 rtl::Reference< detail::MappedFile > const & file, sal_uInt32 offset);
551 class UnoidlCursor: public MapCursor {
552 public:
553 UnoidlCursor(
554 rtl::Reference< detail::MappedFile > file,
555 detail::MapEntry const * mapBegin, sal_uInt32 mapSize):
556 file_(file), mapIndex_(mapBegin), mapEnd_(mapBegin + mapSize)
559 private:
560 virtual ~UnoidlCursor() throw () {}
562 virtual rtl::Reference< Entity > getNext(OUString * name);
564 rtl::Reference< detail::MappedFile > file_;
565 detail::MapEntry const * mapIndex_;
566 detail::MapEntry const * mapEnd_;
569 rtl::Reference< Entity > UnoidlCursor::getNext(OUString * name) {
570 assert(name != 0);
571 rtl::Reference< Entity > ent;
572 if (mapIndex_ != mapEnd_) {
573 *name = file_->readNulName(mapIndex_->name.getUnsigned32());
574 ent = readEntity(file_, mapIndex_->data.getUnsigned32());
575 ++mapIndex_;
577 return ent;
580 class UnoidlModuleEntity: public ModuleEntity {
581 public:
582 UnoidlModuleEntity(
583 rtl::Reference< detail::MappedFile > const & file, sal_uInt32 mapOffset,
584 sal_uInt32 mapSize):
585 file_(file),
586 mapBegin_(
587 reinterpret_cast< detail::MapEntry const * >(
588 static_cast< char const * >(file_->address) + mapOffset)),
589 mapSize_(mapSize)
590 { assert(file.is()); }
592 private:
593 virtual ~UnoidlModuleEntity() throw () {}
595 virtual std::vector< OUString > getMemberNames() const;
597 virtual rtl::Reference< MapCursor > createCursor() const
598 { return new UnoidlCursor(file_, mapBegin_, mapSize_); }
600 rtl::Reference< detail::MappedFile > file_;
601 detail::MapEntry const * mapBegin_;
602 sal_uInt32 mapSize_;
605 std::vector< OUString > UnoidlModuleEntity::getMemberNames() const {
606 std::vector< OUString > names;
607 for (sal_uInt32 i = 0; i != mapSize_; ++i) {
608 names.push_back(file_->readNulName(mapBegin_[i].name.getUnsigned32()));
610 return names;
613 rtl::Reference< Entity > readEntity(
614 rtl::Reference< detail::MappedFile > const & file, sal_uInt32 offset)
616 assert(file.is());
617 int v = file->read8(offset);
618 int type = v & 0x3F;
619 bool published = (v & 0x80) != 0;
620 bool annotated = (v & 0x40) != 0;
621 bool flag = (v & 0x20) != 0;
622 switch (type) {
623 case 0: // module
625 if (v != 0) {
626 throw FileFormatException(
627 file->uri,
628 ("UNOIDL format: bad module type byte "
629 + OUString::number(v)));
631 sal_uInt32 n = file->read32(offset + 1);
632 if (n > SAL_MAX_INT32) {
633 throw FileFormatException(
634 file->uri, "UNOIDL format: too many items in module");
636 if (offset + 5 + 8 * n > file->size) { //TODO: overflow
637 throw FileFormatException(
638 file->uri,
639 "UNOIDL format: module map offset + size too large");
641 return new UnoidlModuleEntity(file, offset + 5, n);
643 case 1: // enum type
645 sal_uInt32 n = file->read32(offset + 1);
646 if (n > SAL_MAX_INT32) {
647 throw FileFormatException(
648 file->uri, "UNOIDL format: too many members of enum type");
650 offset += 5;
651 std::vector< EnumTypeEntity::Member > mems;
652 for (sal_uInt32 i = 0; i != n; ++i) {
653 OUString memName(file->readIdxName(&offset));
654 sal_Int32 memValue = static_cast< sal_Int32 >(
655 file->read32(offset));
656 //TODO: implementation-defined behavior of conversion from
657 // sal_uInt32 to sal_Int32 relies on two's complement
658 // representation
659 offset += 4;
660 mems.push_back(
661 EnumTypeEntity::Member(
662 memName, memValue,
663 readAnnotations(annotated, file, offset, &offset)));
665 return new EnumTypeEntity(
666 published, mems, readAnnotations(annotated, file, offset));
668 case 2: // plain struct type without base
669 case 2 | 0x20: // plain struct type with base
671 ++offset;
672 OUString base;
673 if (flag) {
674 base = file->readIdxName(&offset);
675 if (base.isEmpty()) {
676 throw FileFormatException(
677 file->uri,
678 ("UNOIDL format: empty base type name of plain struct"
679 " type"));
682 sal_uInt32 n = file->read32(offset);
683 if (n > SAL_MAX_INT32) {
684 throw FileFormatException(
685 file->uri,
686 ("UNOIDL format: too many direct members of plain struct"
687 " type"));
689 offset += 4;
690 std::vector< PlainStructTypeEntity::Member > mems;
691 for (sal_uInt32 i = 0; i != n; ++i) {
692 OUString memName(file->readIdxName(&offset));
693 OUString memType(file->readIdxName(&offset));
694 mems.push_back(
695 PlainStructTypeEntity::Member(
696 memName, memType,
697 readAnnotations(annotated, file, offset, &offset)));
699 return new PlainStructTypeEntity(
700 published, base, mems,
701 readAnnotations(annotated, file, offset));
703 case 3: // polymorphic struct type template
705 sal_uInt32 n = file->read32(offset + 1);
706 if (n > SAL_MAX_INT32) {
707 throw FileFormatException(
708 file->uri,
709 ("UNOIDL format: too many type parameters of polymorphic"
710 " struct type template"));
712 offset += 5;
713 std::vector< OUString > params;
714 for (sal_uInt32 i = 0; i != n; ++i) {
715 params.push_back(file->readIdxName(&offset));
717 n = file->read32(offset);
718 if (n > SAL_MAX_INT32) {
719 throw FileFormatException(
720 file->uri,
721 ("UNOIDL format: too many members of polymorphic struct"
722 " type template"));
724 offset += 4;
725 std::vector< PolymorphicStructTypeTemplateEntity::Member > mems;
726 for (sal_uInt32 i = 0; i != n; ++i) {
727 v = file->read8(offset);
728 ++offset;
729 OUString memName(file->readIdxName(&offset));
730 OUString memType(file->readIdxName(&offset));
731 if (v > 1) {
732 throw FileFormatException(
733 file->uri,
734 ("UNOIDL format: bad flags " + OUString::number(v)
735 + " for member " + memName
736 + " of polymorphic struct type template"));
738 mems.push_back(
739 PolymorphicStructTypeTemplateEntity::Member(
740 memName, memType, v == 1,
741 readAnnotations(annotated, file, offset, &offset)));
743 return new PolymorphicStructTypeTemplateEntity(
744 published, params, mems,
745 readAnnotations(annotated, file, offset));
747 case 4: // exception type without base
748 case 4 | 0x20: // exception type with base
750 ++offset;
751 OUString base;
752 if (flag) {
753 base = file->readIdxName(&offset);
754 if (base.isEmpty()) {
755 throw FileFormatException(
756 file->uri,
757 ("UNOIDL format: empty base type name of exception"
758 " type"));
761 sal_uInt32 n = file->read32(offset);
762 if (n > SAL_MAX_INT32) {
763 throw FileFormatException(
764 file->uri,
765 "UNOIDL format: too many direct members of exception type");
767 offset += 4;
768 std::vector< ExceptionTypeEntity::Member > mems;
769 for (sal_uInt32 i = 0; i != n; ++i) {
770 OUString memName(file->readIdxName(&offset));
771 OUString memType(file->readIdxName(&offset));
772 mems.push_back(
773 ExceptionTypeEntity::Member(
774 memName, memType,
775 readAnnotations(annotated, file, offset, &offset)));
777 return new ExceptionTypeEntity(
778 published, base, mems,
779 readAnnotations(annotated, file, offset));
781 case 5: // interface type
783 sal_uInt32 n = file->read32(offset + 1);
784 if (n > SAL_MAX_INT32) {
785 throw FileFormatException(
786 file->uri,
787 ("UNOIDL format: too many direct mandatory bases of"
788 " interface type"));
790 offset += 5;
791 std::vector< AnnotatedReference > mandBases;
792 for (sal_uInt32 i = 0; i != n; ++i) {
793 OUString base(file->readIdxName(&offset));
794 mandBases.push_back(
795 AnnotatedReference(
796 base,
797 readAnnotations(annotated, file, offset, &offset)));
799 n = file->read32(offset);
800 if (n > SAL_MAX_INT32) {
801 throw FileFormatException(
802 file->uri,
803 ("UNOIDL format: too many direct optional bases of"
804 " interface type"));
806 offset += 4;
807 std::vector< AnnotatedReference > optBases;
808 for (sal_uInt32 i = 0; i != n; ++i) {
809 OUString base(file->readIdxName(&offset));
810 optBases.push_back(
811 AnnotatedReference(
812 base,
813 readAnnotations(annotated, file, offset, &offset)));
815 sal_uInt32 nAttrs = file->read32(offset);
816 if (nAttrs > SAL_MAX_INT32) {
817 throw FileFormatException(
818 file->uri,
819 ("UNOIDL format: too many direct attributes of interface"
820 " type"));
822 offset += 4;
823 std::vector< InterfaceTypeEntity::Attribute > attrs;
824 for (sal_uInt32 i = 0; i != nAttrs; ++i) {
825 v = file->read8(offset);
826 ++offset;
827 OUString attrName(file->readIdxName(&offset));
828 OUString attrType(file->readIdxName(&offset));
829 if (v > 0x03) {
830 throw FileFormatException(
831 file->uri,
832 ("UNOIDL format: bad flags for direct attribute "
833 + attrName + " of interface type"));
835 std::vector< OUString > getExcs;
836 sal_uInt32 m = file->read32(offset);
837 if (m > SAL_MAX_INT32) {
838 throw FileFormatException(
839 file->uri,
840 ("UNOIDL format: too many getter exceptions for direct"
841 " attribute " + attrName + " of interface type"));
843 offset += 4;
844 for (sal_uInt32 j = 0; j != m; ++j) {
845 getExcs.push_back(file->readIdxName(&offset));
847 std::vector< OUString > setExcs;
848 if ((v & 0x02) == 0) {
849 m = file->read32(offset);
850 if (m > SAL_MAX_INT32) {
851 throw FileFormatException(
852 file->uri,
853 ("UNOIDL format: too many setter exceptions for"
854 " direct attribute " + attrName
855 + " of interface type"));
857 offset += 4;
858 for (sal_uInt32 j = 0; j != m; ++j) {
859 setExcs.push_back(file->readIdxName(&offset));
862 attrs.push_back(
863 InterfaceTypeEntity::Attribute(
864 attrName, attrType, (v & 0x01) != 0, (v & 0x02) != 0,
865 getExcs, setExcs,
866 readAnnotations(annotated, file, offset, &offset)));
868 sal_uInt32 nMeths = file->read32(offset);
869 if (nMeths > SAL_MAX_INT32 - nAttrs) {
870 throw FileFormatException(
871 file->uri,
872 ("UNOIDL format: too many direct attributes and methods of"
873 " interface type"));
875 offset += 4;
876 std::vector< InterfaceTypeEntity::Method > meths;
877 for (sal_uInt32 i = 0; i != nMeths; ++i) {
878 OUString methName(file->readIdxName(&offset));
879 OUString methType(file->readIdxName(&offset));
880 sal_uInt32 m = file->read32(offset);
881 if (m > SAL_MAX_INT32) {
882 throw FileFormatException(
883 file->uri,
884 ("UNOIDL format: too many parameters for method "
885 + methName + " of interface type"));
887 offset += 4;
888 std::vector< InterfaceTypeEntity::Method::Parameter > params;
889 for (sal_uInt32 j = 0; j != m; ++j) {
890 v = file->read8(offset);
891 ++offset;
892 OUString paramName(file->readIdxName(&offset));
893 OUString paramType(file->readIdxName(&offset));
894 InterfaceTypeEntity::Method::Parameter::Direction dir;
895 switch (v) {
896 case 0:
897 dir = InterfaceTypeEntity::Method::Parameter::
898 DIRECTION_IN;
899 break;
900 case 1:
901 dir = InterfaceTypeEntity::Method::Parameter::
902 DIRECTION_OUT;
903 break;
904 case 2:
905 dir = InterfaceTypeEntity::Method::Parameter::
906 DIRECTION_IN_OUT;
907 break;
908 default:
909 throw FileFormatException(
910 file->uri,
911 ("UNOIDL format: bad direction "
912 + OUString::number(v) + " of parameter "
913 + paramName + " for method " + methName
914 + " of interface type"));
916 params.push_back(
917 InterfaceTypeEntity::Method::Parameter(
918 paramName, paramType, dir));
920 std::vector< OUString > excs;
921 m = file->read32(offset);
922 if (m > SAL_MAX_INT32) {
923 throw FileFormatException(
924 file->uri,
925 ("UNOIDL format: too many exceptions for method "
926 + methName + " of interface type"));
928 offset += 4;
929 for (sal_uInt32 j = 0; j != m; ++j) {
930 excs.push_back(file->readIdxName(&offset));
932 meths.push_back(
933 InterfaceTypeEntity::Method(
934 methName, methType, params, excs,
935 readAnnotations(annotated, file, offset, &offset)));
937 return new InterfaceTypeEntity(
938 published, mandBases, optBases, attrs, meths,
939 readAnnotations(annotated, file, offset));
941 case 6: // typedef
943 ++offset;
944 OUString base(file->readIdxName(&offset));
945 return new TypedefEntity(
946 published, base, readAnnotations(annotated, file, offset));
948 case 7: // constant group
950 sal_uInt32 n = file->read32(offset + 1);
951 if (n > SAL_MAX_INT32) {
952 throw FileFormatException(
953 file->uri,
954 "UNOIDL format: too many constants in constant group");
956 if (offset + 5 + 8 * n > file->size) { //TODO: overflow
957 throw FileFormatException(
958 file->uri,
959 ("UNOIDL format: constant group map offset + size too"
960 " large"));
962 detail::MapEntry const * p
963 = reinterpret_cast< detail::MapEntry const * >(
964 static_cast< char const * >(file->address) + offset + 5);
965 std::vector< ConstantGroupEntity::Member > mems;
966 for (sal_uInt32 i = 0; i != n; ++i) {
967 sal_uInt32 off = p[i].data.getUnsigned32();
968 bool ann;
969 ConstantValue val(readConstant(file, off, &off, &ann));
970 mems.push_back(
971 ConstantGroupEntity::Member(
972 file->readNulName(p[i].name.getUnsigned32()), val,
973 readAnnotations(ann, file, off)));
975 return new ConstantGroupEntity(
976 published, mems,
977 readAnnotations(annotated, file, offset + 5 + 8 * n));
979 case 8: // single-interface--based service without default constructor
980 case 8 | 0x20: // single-interface--based service with default constructor
982 ++offset;
983 OUString base(file->readIdxName(&offset));
984 std::vector< SingleInterfaceBasedServiceEntity::Constructor > ctors;
985 if (flag) {
986 ctors.push_back(
987 SingleInterfaceBasedServiceEntity::Constructor());
988 } else {
989 sal_uInt32 n = file->read32(offset);
990 if (n > SAL_MAX_INT32) {
991 throw FileFormatException(
992 file->uri,
993 ("UNOIDL format: too many constructors of"
994 " single-interface--based service"));
996 offset += 4;
997 for (sal_uInt32 i = 0; i != n; ++i) {
998 OUString ctorName(file->readIdxName(&offset));
999 sal_uInt32 m = file->read32(offset);
1000 if (m > SAL_MAX_INT32) {
1001 throw FileFormatException(
1002 file->uri,
1003 ("UNOIDL format: too many parameters for"
1004 " constructor " + ctorName
1005 + " of single-interface--based service"));
1007 offset += 4;
1008 std::vector<
1009 SingleInterfaceBasedServiceEntity::Constructor::
1010 Parameter > params;
1011 for (sal_uInt32 j = 0; j != m; ++j) {
1012 v = file->read8(offset);
1013 ++offset;
1014 OUString paramName(file->readIdxName(&offset));
1015 OUString paramType(file->readIdxName(&offset));
1016 bool rest;
1017 switch (v) {
1018 case 0:
1019 rest = false;
1020 break;
1021 case 0x04:
1022 rest = true;
1023 break;
1024 default:
1025 throw FileFormatException(
1026 file->uri,
1027 ("UNOIDL format: bad mode "
1028 + OUString::number(v) + " of parameter "
1029 + paramName + " for constructor " + ctorName
1030 + " of single-interface--based service"));
1032 params.push_back(
1033 SingleInterfaceBasedServiceEntity::Constructor::
1034 Parameter(
1035 paramName, paramType, rest));
1037 std::vector< OUString > excs;
1038 m = file->read32(offset);
1039 if (m > SAL_MAX_INT32) {
1040 throw FileFormatException(
1041 file->uri,
1042 ("UNOIDL format: too many exceptions for"
1043 " constructor " + ctorName
1044 + " of single-interface--based service"));
1046 offset += 4;
1047 for (sal_uInt32 j = 0; j != m; ++j) {
1048 excs.push_back(file->readIdxName(&offset));
1050 ctors.push_back(
1051 SingleInterfaceBasedServiceEntity::Constructor(
1052 ctorName, params, excs,
1053 readAnnotations(annotated, file, offset, &offset)));
1056 return new SingleInterfaceBasedServiceEntity(
1057 published, base, ctors,
1058 readAnnotations(annotated, file, offset));
1060 case 9: // accumulation-based service
1062 sal_uInt32 n = file->read32(offset + 1);
1063 if (n > SAL_MAX_INT32) {
1064 throw FileFormatException(
1065 file->uri,
1066 ("UNOIDL format: too many direct mandatory service bases of"
1067 " accumulation-based service"));
1069 offset += 5;
1070 std::vector< AnnotatedReference > mandServs;
1071 for (sal_uInt32 i = 0; i != n; ++i) {
1072 OUString base(file->readIdxName(&offset));
1073 mandServs.push_back(
1074 AnnotatedReference(
1075 base,
1076 readAnnotations(annotated, file, offset, &offset)));
1078 n = file->read32(offset);
1079 if (n > SAL_MAX_INT32) {
1080 throw FileFormatException(
1081 file->uri,
1082 ("UNOIDL format: too many direct optional service bases of"
1083 " accumulation-based service"));
1085 offset += 4;
1086 std::vector< AnnotatedReference > optServs;
1087 for (sal_uInt32 i = 0; i != n; ++i) {
1088 OUString base(file->readIdxName(&offset));
1089 optServs.push_back(
1090 AnnotatedReference(
1091 base,
1092 readAnnotations(annotated, file, offset, &offset)));
1094 n = file->read32(offset);
1095 if (n > SAL_MAX_INT32) {
1096 throw FileFormatException(
1097 file->uri,
1098 ("UNOIDL format: too many direct mandatory interface bases"
1099 " of accumulation-based service"));
1101 offset += 4;
1102 std::vector< AnnotatedReference > mandIfcs;
1103 for (sal_uInt32 i = 0; i != n; ++i) {
1104 OUString base(file->readIdxName(&offset));
1105 mandIfcs.push_back(
1106 AnnotatedReference(
1107 base,
1108 readAnnotations(annotated, file, offset, &offset)));
1110 n = file->read32(offset);
1111 if (n > SAL_MAX_INT32) {
1112 throw FileFormatException(
1113 file->uri,
1114 ("UNOIDL format: too many direct optional interface bases"
1115 " of accumulation-based service"));
1117 offset += 4;
1118 std::vector< AnnotatedReference > optIfcs;
1119 for (sal_uInt32 i = 0; i != n; ++i) {
1120 OUString base(file->readIdxName(&offset));
1121 optIfcs.push_back(
1122 AnnotatedReference(
1123 base,
1124 readAnnotations(annotated, file, offset, &offset)));
1126 n = file->read32(offset);
1127 if (n > SAL_MAX_INT32) {
1128 throw FileFormatException(
1129 file->uri,
1130 ("UNOIDL format: too many direct properties of"
1131 " accumulation-based service"));
1133 offset += 4;
1134 std::vector< AccumulationBasedServiceEntity::Property > props;
1135 for (sal_uInt32 i = 0; i != n; ++i) {
1136 sal_uInt16 attrs = file->read16(offset);
1137 offset += 2;
1138 OUString propName(file->readIdxName(&offset));
1139 OUString propType(file->readIdxName(&offset));
1140 if (attrs > 0x01FF) { // see css.beans.PropertyAttribute
1141 throw FileFormatException(
1142 file->uri,
1143 ("UNOIDL format: bad mode " + OUString::number(v)
1144 + " of property " + propName
1145 + " for accumulation-based servcie"));
1147 props.push_back(
1148 AccumulationBasedServiceEntity::Property(
1149 propName, propType,
1150 static_cast<
1151 AccumulationBasedServiceEntity::Property::
1152 Attributes >(
1153 attrs),
1154 readAnnotations(annotated, file, offset, &offset)));
1156 return new AccumulationBasedServiceEntity(
1157 published, mandServs, optServs, mandIfcs, optIfcs, props,
1158 readAnnotations(annotated, file, offset));
1160 case 10: // interface-based singleton
1162 ++offset;
1163 OUString base(file->readIdxName(&offset));
1164 return new InterfaceBasedSingletonEntity(
1165 published, base, readAnnotations(annotated, file, offset));
1167 case 11: // service-based singleton
1169 ++offset;
1170 OUString base(file->readIdxName(&offset));
1171 return new ServiceBasedSingletonEntity(
1172 published, base, readAnnotations(annotated, file, offset));
1174 default:
1175 throw FileFormatException(
1176 file->uri, "UNOIDL format: bad type byte " + OUString::number(v));
1182 UnoidlProvider::UnoidlProvider(OUString const & uri):
1183 file_(new detail::MappedFile(uri))
1185 if (file_->size < 8 || std::memcmp(file_->address, "UNOIDL\xFF\0", 8) != 0)
1187 throw FileFormatException(
1188 file_->uri,
1189 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1190 " 0");
1192 sal_uInt32 off = file_->read32(8);
1193 mapSize_ = file_->read32(12);
1194 if (off + 8 * mapSize_ > file_->size) { //TODO: overflow
1195 throw FileFormatException(
1196 file_->uri, "UNOIDL format: root map offset + size too large");
1198 mapBegin_ = reinterpret_cast< detail::MapEntry const * >(
1199 static_cast< char const * >(file_->address) + off);
1202 rtl::Reference< MapCursor > UnoidlProvider::createRootCursor() const {
1203 return new UnoidlCursor(file_, mapBegin_, mapSize_);
1206 rtl::Reference< Entity > UnoidlProvider::findEntity(OUString const & name) const
1208 bool cnst;
1209 sal_uInt32 off = find(name, &cnst);
1210 return off == 0 || cnst ? rtl::Reference< Entity >() : getEntity(off);
1213 sal_uInt32 UnoidlProvider::find(OUString const & name, bool * constant) const {
1214 detail::MapEntry const * mapBegin = mapBegin_;
1215 sal_uInt32 mapSize = mapSize_;
1216 bool cgroup = false;
1217 for (sal_Int32 i = 0;;) {
1218 sal_Int32 j = name.indexOf('.', i);
1219 if (j == -1) {
1220 j = name.getLength();
1222 sal_Int32 off = findInMap(file_, mapBegin, mapSize, name, i, j - i);
1223 if (off == 0) {
1224 return 0;
1226 if (j == name.getLength()) {
1227 if (constant != 0) {
1228 *constant = cgroup;
1230 return off;
1232 if (cgroup) {
1233 return 0;
1234 //TODO: throw an exception instead here, where the segments of a
1235 // constant's name are a prefix of the requested name's
1236 // segments?
1238 int v = file_->read8(off);
1239 if (v != 0) { // module
1240 if ((v & 0x3F) == 7) { // constant group
1241 cgroup = true;
1242 } else {
1243 return 0;
1244 //TODO: throw an exception instead here, where the segments
1245 // of a non-module, non-constant-group entity's name are a
1246 // prefix of the requested name's segments?
1249 mapSize = file_->read32(off + 1);
1250 if (8 * mapSize > file_->size - off - 5) { //TODO: overflow
1251 throw FileFormatException(
1252 file_->uri, "UNOIDL format: map offset + size too large");
1254 mapBegin = reinterpret_cast< detail::MapEntry const * >(
1255 static_cast< char const * >(file_->address) + off + 5);
1256 i = j + 1;
1260 rtl::Reference< Entity > UnoidlProvider::getEntity(sal_uInt32 offset) const {
1261 return readEntity(file_, offset);
1264 ConstantValue UnoidlProvider::getConstant(sal_uInt32 offset) const {
1265 return readConstant(file_, offset);
1268 UnoidlProvider::~UnoidlProvider() throw () {}
1272 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */