Use o3tl::convert in Math
[LibreOffice.git] / unoidl / source / unoidlprovider.cxx
blob217251dca053707ea0b145532887c23bc429c607
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 <set>
16 #include <string_view>
17 #include <vector>
19 #include <osl/endian.h>
20 #include <osl/file.h>
21 #include <rtl/character.hxx>
22 #include <rtl/ref.hxx>
23 #include <rtl/textenc.h>
24 #include <rtl/textcvt.h>
25 #include <rtl/ustring.hxx>
26 #include <sal/log.hxx>
27 #include <sal/types.h>
28 #include <salhelper/simplereferenceobject.hxx>
29 #include <unoidl/unoidl.hxx>
31 #include "unoidlprovider.hxx"
33 namespace unoidl::detail {
35 class MappedFile: public salhelper::SimpleReferenceObject {
36 public:
37 explicit MappedFile(OUString const & fileUrl);
39 sal_uInt8 read8(sal_uInt32 offset) const;
41 sal_uInt16 read16(sal_uInt32 offset) const;
43 sal_uInt32 read32(sal_uInt32 offset) const;
45 sal_uInt64 read64(sal_uInt32 offset) const;
47 float readIso60599Binary32(sal_uInt32 offset) const;
49 double readIso60599Binary64(sal_uInt32 offset) const;
51 OUString readNulName(sal_uInt32 offset) /*const*/;
53 OUString readIdxName(sal_uInt32 * offset) const
54 { return readIdxString(offset, RTL_TEXTENCODING_ASCII_US); }
56 OUString readIdxString(sal_uInt32 * offset) const
57 { return readIdxString(offset, RTL_TEXTENCODING_UTF8); }
59 OUString uri;
60 oslFileHandle handle;
61 sal_uInt64 size;
62 void * address;
64 private:
65 virtual ~MappedFile() override;
67 sal_uInt8 get8(sal_uInt32 offset) const;
69 sal_uInt16 get16(sal_uInt32 offset) const;
71 sal_uInt32 get32(sal_uInt32 offset) const;
73 sal_uInt64 get64(sal_uInt32 offset) const;
75 float getIso60599Binary32(sal_uInt32 offset) const;
77 double getIso60599Binary64(sal_uInt32 offset) const;
79 OUString readIdxString(sal_uInt32 * offset, rtl_TextEncoding encoding)
80 const;
83 namespace {
85 // sizeof (Memory16) == 2
86 struct Memory16 {
87 unsigned char byte[2];
89 sal_uInt16 getUnsigned16() const {
90 return static_cast< sal_uInt16 >(byte[0])
91 | (static_cast< sal_uInt16 >(byte[1]) << 8);
95 // sizeof (Memory32) == 4
96 struct Memory32 {
97 unsigned char byte[4];
99 sal_uInt32 getUnsigned32() const {
100 return static_cast< sal_uInt32 >(byte[0])
101 | (static_cast< sal_uInt32 >(byte[1]) << 8)
102 | (static_cast< sal_uInt32 >(byte[2]) << 16)
103 | (static_cast< sal_uInt32 >(byte[3]) << 24);
106 float getIso60599Binary32() const {
107 union {
108 unsigned char buf[4];
109 float f; // assuming float is ISO 60599 binary32
110 } sa;
111 #if defined OSL_LITENDIAN
112 sa.buf[0] = byte[0];
113 sa.buf[1] = byte[1];
114 sa.buf[2] = byte[2];
115 sa.buf[3] = byte[3];
116 #else
117 sa.buf[0] = byte[3];
118 sa.buf[1] = byte[2];
119 sa.buf[2] = byte[1];
120 sa.buf[3] = byte[0];
121 #endif
122 return sa.f;
126 // sizeof (Memory64) == 8
127 struct Memory64 {
128 unsigned char byte[8];
130 sal_uInt64 getUnsigned64() const {
131 return static_cast< sal_uInt64 >(byte[0])
132 | (static_cast< sal_uInt64 >(byte[1]) << 8)
133 | (static_cast< sal_uInt64 >(byte[2]) << 16)
134 | (static_cast< sal_uInt64 >(byte[3]) << 24)
135 | (static_cast< sal_uInt64 >(byte[4]) << 32)
136 | (static_cast< sal_uInt64 >(byte[5]) << 40)
137 | (static_cast< sal_uInt64 >(byte[6]) << 48)
138 | (static_cast< sal_uInt64 >(byte[7]) << 56);
141 double getIso60599Binary64() const {
142 union {
143 unsigned char buf[8];
144 double d; // assuming double is ISO 60599 binary64
145 } sa;
146 #if defined OSL_LITENDIAN
147 sa.buf[0] = byte[0];
148 sa.buf[1] = byte[1];
149 sa.buf[2] = byte[2];
150 sa.buf[3] = byte[3];
151 sa.buf[4] = byte[4];
152 sa.buf[5] = byte[5];
153 sa.buf[6] = byte[6];
154 sa.buf[7] = byte[7];
155 #else
156 sa.buf[0] = byte[7];
157 sa.buf[1] = byte[6];
158 sa.buf[2] = byte[5];
159 sa.buf[3] = byte[4];
160 sa.buf[4] = byte[3];
161 sa.buf[5] = byte[2];
162 sa.buf[6] = byte[1];
163 sa.buf[7] = byte[0];
164 #endif
165 return sa.d;
169 bool isSimpleType(std::u16string_view type) {
170 return type == u"void" || type == u"boolean" || type == u"byte"
171 || type == u"short" || type == u"unsigned short" || type == u"long"
172 || type == u"unsigned long" || type == u"hyper"
173 || type == u"unsigned hyper" || type == u"float" || type == u"double"
174 || type == u"char" || type == u"string" || type == u"type"
175 || type == u"any";
178 // For backwards compatibility, does not strictly check segments to match
180 // <segment> ::= <blocks> | <block>
181 // <blocks> ::= <capital> <other>* ("_" <block>)*
182 // <block> ::= <other>+
183 // <other> ::= <capital> | "a"--"z" | "0"--"9"
184 // <capital> ::= "A"--"Z"
186 bool isIdentifier(OUString const & type, bool scoped) {
187 if (type.isEmpty()) {
188 return false;
190 for (sal_Int32 i = 0; i != type.getLength(); ++i) {
191 sal_Unicode c = type[i];
192 if (c == '.') {
193 if (!scoped || i == 0 || i == type.getLength() - 1
194 || type[i - 1] == '.')
196 return false;
198 } else if (!rtl::isAsciiAlphanumeric(c) && c != '_') {
199 return false;
202 return true;
205 void checkTypeName(
206 rtl::Reference< MappedFile > const & file, OUString const & type)
208 OUString nucl(type);
209 bool args = false;
210 while (nucl.startsWith("[]", &nucl)) {}
211 sal_Int32 i = nucl.indexOf('<');
212 if (i != -1) {
213 OUString tmpl(nucl.copy(0, i));
214 do {
215 ++i; // skip '<' or ','
216 sal_Int32 j = i;
217 for (sal_Int32 level = 0; j != nucl.getLength(); ++j) {
218 sal_Unicode c = nucl[j];
219 if (c == ',') {
220 if (level == 0) {
221 break;
223 } else if (c == '<') {
224 ++level;
225 } else if (c == '>') {
226 if (level == 0) {
227 break;
229 --level;
232 if (j != nucl.getLength()) {
233 checkTypeName(file, nucl.copy(i, j - i));
234 args = true;
236 i = j;
237 } while (i != nucl.getLength() && nucl[i] != '>');
238 if (i != nucl.getLength() - 1 || nucl[i] != '>' || !args) {
239 tmpl.clear(); // bad input
241 nucl = tmpl;
243 if (isSimpleType(nucl) ? args : !isIdentifier(nucl, true)) {
244 throw FileFormatException(
245 file->uri, "UNOIDL format: bad type \"" + type + "\"");
249 void checkEntityName(
250 rtl::Reference< MappedFile > const & file, OUString const & name)
252 if (isSimpleType(name) || !isIdentifier(name, false)) {
253 throw FileFormatException(
254 file->uri, "UNOIDL format: bad entity name \"" + name + "\"");
260 MappedFile::MappedFile(OUString const & fileUrl): uri(fileUrl), handle(nullptr) {
261 oslFileError e = osl_openFile(uri.pData, &handle, osl_File_OpenFlag_Read);
262 switch (e) {
263 case osl_File_E_None:
264 break;
265 case osl_File_E_NOENT:
266 throw NoSuchFileException(uri);
267 default:
268 throw FileFormatException(uri, "cannot open: " + OUString::number(e));
270 e = osl_getFileSize(handle, &size);
271 if (e == osl_File_E_None) {
272 e = osl_mapFile(
273 handle, &address, size, 0, osl_File_MapFlag_RandomAccess);
275 if (e != osl_File_E_None) {
276 oslFileError e2 = osl_closeFile(handle);
277 SAL_WARN_IF(
278 e2 != osl_File_E_None, "unoidl",
279 "cannot close " << uri << ": " << +e2);
280 throw FileFormatException(uri, "cannot mmap: " + OUString::number(e));
284 sal_uInt8 MappedFile::read8(sal_uInt32 offset) const {
285 assert(size >= 8);
286 if (offset > size - 1) {
287 throw FileFormatException(
288 uri, "UNOIDL format: offset for 8-bit value too large");
290 return get8(offset);
293 sal_uInt16 MappedFile::read16(sal_uInt32 offset) const {
294 assert(size >= 8);
295 if (offset > size - 2) {
296 throw FileFormatException(
297 uri, "UNOIDL format: offset for 16-bit value too large");
299 return get16(offset);
302 sal_uInt32 MappedFile::read32(sal_uInt32 offset) const {
303 assert(size >= 8);
304 if (offset > size - 4) {
305 throw FileFormatException(
306 uri, "UNOIDL format: offset for 32-bit value too large");
308 return get32(offset);
311 sal_uInt64 MappedFile::read64(sal_uInt32 offset) const {
312 assert(size >= 8);
313 if (offset > size - 8) {
314 throw FileFormatException(
315 uri, "UNOIDL format: offset for 64-bit value too large");
317 return get64(offset);
320 float MappedFile::readIso60599Binary32(sal_uInt32 offset) const {
321 assert(size >= 8);
322 if (offset > size - 4) {
323 throw FileFormatException(
324 uri, "UNOIDL format: offset for 32-bit value too large");
326 return getIso60599Binary32(offset);
329 double MappedFile::readIso60599Binary64(sal_uInt32 offset) const {
330 assert(size >= 8);
331 if (offset > size - 8) {
332 throw FileFormatException(
333 uri, "UNOIDL format: offset for 64-bit value too large");
335 return getIso60599Binary64(offset);
338 OUString MappedFile::readNulName(sal_uInt32 offset) {
339 if (offset > size) {
340 throw FileFormatException(
341 uri, "UNOIDL format: offset for string too large");
343 sal_uInt64 end = offset;
344 for (;; ++end) {
345 if (end == size) {
346 throw FileFormatException(
347 uri, "UNOIDL format: string misses trailing NUL");
349 if (static_cast< char const * >(address)[end] == 0) {
350 break;
353 if (end - offset > SAL_MAX_INT32) {
354 throw FileFormatException(uri, "UNOIDL format: string too long");
356 OUString name;
357 if (!rtl_convertStringToUString(
358 &name.pData, static_cast< char const * >(address) + offset,
359 end - offset, RTL_TEXTENCODING_ASCII_US,
360 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
361 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
362 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
364 throw FileFormatException(uri, "UNOIDL format: name is not ASCII");
366 checkEntityName(this, name);
367 return name;
370 MappedFile::~MappedFile() {
371 oslFileError e = osl_unmapMappedFile(handle, address, size);
372 SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e);
373 e = osl_closeFile(handle);
374 SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e);
377 sal_uInt8 MappedFile::get8(sal_uInt32 offset) const {
378 assert(size >= 8);
379 assert(offset <= size - 1);
380 return static_cast< char const * >(address)[offset];
383 sal_uInt16 MappedFile::get16(sal_uInt32 offset) const {
384 assert(size >= 8);
385 assert(offset <= size - 2);
386 return reinterpret_cast< Memory16 const * >(
387 static_cast< char const * >(address) + offset)->getUnsigned16();
390 sal_uInt32 MappedFile::get32(sal_uInt32 offset) const {
391 assert(size >= 8);
392 assert(offset <= size - 4);
393 return reinterpret_cast< Memory32 const * >(
394 static_cast< char const * >(address) + offset)->getUnsigned32();
397 sal_uInt64 MappedFile::get64(sal_uInt32 offset) const {
398 assert(size >= 8);
399 assert(offset <= size - 8);
400 return reinterpret_cast< Memory64 const * >(
401 static_cast< char const * >(address) + offset)->getUnsigned64();
404 float MappedFile::getIso60599Binary32(sal_uInt32 offset) const {
405 assert(size >= 8);
406 assert(offset <= size - 4);
407 return reinterpret_cast< Memory32 const * >(
408 static_cast< char const * >(address) + offset)->getIso60599Binary32();
411 double MappedFile::getIso60599Binary64(sal_uInt32 offset) const {
412 assert(size >= 8);
413 assert(offset <= size - 8);
414 return reinterpret_cast< Memory64 const * >(
415 static_cast< char const * >(address) + offset)->getIso60599Binary64();
418 OUString MappedFile::readIdxString(
419 sal_uInt32 * offset, rtl_TextEncoding encoding) const
421 assert(offset != nullptr);
422 sal_uInt32 len = read32(*offset);
423 sal_uInt32 off;
424 if ((len & 0x80000000) == 0) {
425 off = *offset;
426 *offset += 4 + len;
427 } else {
428 *offset += 4;
429 off = len & ~0x80000000;
430 len = read32(off);
431 if ((len & 0x80000000) != 0) {
432 throw FileFormatException(
433 uri, "UNOIDL format: string length high bit set");
436 if (len > SAL_MAX_INT32 || len > size - off - 4) {
437 throw FileFormatException(
438 uri, "UNOIDL format: size of string is too large");
440 OUString name;
441 if (!rtl_convertStringToUString(
442 &name.pData, static_cast< char const * >(address) + off + 4, len,
443 encoding,
444 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
445 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
446 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
448 throw FileFormatException(
449 uri, "UNOIDL format: string bytes do not match encoding");
451 return name;
454 // sizeof (MapEntry) == 8
455 struct MapEntry {
456 Memory32 name;
457 Memory32 data;
460 static bool operator <(const Map& map1, const Map& map2) {
461 return map1.begin < map2.begin
462 || (map1.begin == map2.begin && map1.size < map2.size);
465 namespace {
467 enum Compare { COMPARE_LESS, COMPARE_GREATER, COMPARE_EQUAL };
469 Compare compare(
470 rtl::Reference< MappedFile > const & file, std::u16string_view name,
471 sal_Int32 nameOffset, sal_Int32 nameLength, MapEntry const * entry)
473 assert(file.is());
474 assert(entry != nullptr);
475 sal_uInt32 off = entry->name.getUnsigned32();
476 if (off > file->size - 1) { // at least a trailing NUL
477 throw FileFormatException(
478 file->uri, "UNOIDL format: string offset too large");
480 assert(nameLength >= 0);
481 sal_uInt64 min = std::min(
482 static_cast< sal_uInt64 >(nameLength), file->size - off);
483 for (sal_uInt64 i = 0; i != min; ++i) {
484 sal_Unicode c1 = name[nameOffset + i];
485 sal_Unicode c2 = static_cast< unsigned char const * >(file->address)[
486 off + i];
487 if (c1 < c2) {
488 return COMPARE_LESS;
489 } else if (c1 > c2 || c2 == 0) {
490 // ...the "|| c2 == 0" is for the odd case where name erroneously
491 // contains NUL characters
492 return COMPARE_GREATER;
495 if (static_cast< sal_uInt64 >(nameLength) == min) {
496 if (file->size - off == min) {
497 throw FileFormatException(
498 file->uri, "UNOIDL format: string misses trailing NUL");
500 return
501 static_cast< unsigned char const * >(file->address)[off + min] == 0
502 ? COMPARE_EQUAL : COMPARE_LESS;
503 } else {
504 return COMPARE_GREATER;
508 sal_uInt32 findInMap(
509 rtl::Reference< MappedFile > const & file, MapEntry const * mapBegin,
510 sal_uInt32 mapSize, OUString const & name, sal_Int32 nameOffset,
511 sal_Int32 nameLength)
513 if (mapSize == 0) {
514 return 0;
516 sal_uInt32 n = mapSize / 2;
517 MapEntry const * p = mapBegin + n;
518 switch (compare(file, name, nameOffset, nameLength, p)) {
519 case COMPARE_LESS:
520 return findInMap(file, mapBegin, n, name, nameOffset, nameLength);
521 case COMPARE_GREATER:
522 return findInMap(
523 file, p + 1, mapSize - n - 1, name, nameOffset, nameLength);
524 default: // COMPARE_EQUAL
525 break;
527 sal_uInt32 off = mapBegin[n].data.getUnsigned32();
528 if (off == 0) {
529 throw FileFormatException(
530 file->uri, "UNOIDL format: map entry data offset is null");
532 return off;
535 #if defined(__COVERITY__)
536 extern "C" void __coverity_tainted_data_sanitize__(void *);
537 #endif
539 std::vector< OUString > readAnnotations(
540 bool annotated, rtl::Reference< MappedFile > const & file,
541 sal_uInt32 offset, sal_uInt32 * newOffset = nullptr)
543 std::vector< OUString > ans;
544 if (annotated) {
545 sal_uInt32 n = file->read32(offset);
546 #if defined(__COVERITY__)
547 __coverity_tainted_data_sanitize__(&n);
548 #endif
549 offset += 4;
550 for (sal_uInt32 i = 0; i != n; ++i) {
551 ans.push_back(file->readIdxString(&offset));
554 if (newOffset != nullptr) {
555 *newOffset = offset;
557 return ans;
560 ConstantValue readConstant(
561 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
562 sal_uInt32 * newOffset, bool * annotated)
564 assert(file.is());
565 int v = file->read8(offset);
566 int type = v & 0x7F;
567 if (annotated != nullptr) {
568 *annotated = (v & 0x80) != 0;
570 switch (type) {
571 case 0: // BOOLEAN
572 v = file->read8(offset + 1);
573 if (newOffset != nullptr) {
574 *newOffset = offset + 2;
576 switch (v) {
577 case 0:
578 return ConstantValue(false);
579 case 1:
580 return ConstantValue(true);
581 default:
582 throw FileFormatException(
583 file->uri,
584 ("UNOIDL format: bad boolean constant value "
585 + OUString::number(v)));
587 case 1: // BYTE
588 if (newOffset != nullptr) {
589 *newOffset = offset + 2;
591 return ConstantValue(static_cast< sal_Int8 >(file->read8(offset + 1)));
592 //TODO: implementation-defined behavior of conversion from sal_uInt8
593 // to sal_Int8 relies on two's complement representation
594 case 2: // SHORT
595 if (newOffset != nullptr) {
596 *newOffset = offset + 3;
598 return ConstantValue(
599 static_cast< sal_Int16 >(file->read16(offset + 1)));
600 //TODO: implementation-defined behavior of conversion from
601 // sal_uInt16 to sal_Int16 relies on two's complement representation
602 case 3: // UNSIGNED SHORT
603 if (newOffset != nullptr) {
604 *newOffset = offset + 3;
606 return ConstantValue(file->read16(offset + 1));
607 case 4: // LONG
608 if (newOffset != nullptr) {
609 *newOffset = offset + 5;
611 return ConstantValue(
612 static_cast< sal_Int32 >(file->read32(offset + 1)));
613 //TODO: implementation-defined behavior of conversion from
614 // sal_uInt32 to sal_Int32 relies on two's complement representation
615 case 5: // UNSIGNED LONG
616 if (newOffset != nullptr) {
617 *newOffset = offset + 5;
619 return ConstantValue(file->read32(offset + 1));
620 case 6: // HYPER
621 if (newOffset != nullptr) {
622 *newOffset = offset + 9;
624 return ConstantValue(
625 static_cast< sal_Int64 >(file->read64(offset + 1)));
626 //TODO: implementation-defined behavior of conversion from
627 // sal_uInt64 to sal_Int64 relies on two's complement representation
628 case 7: // UNSIGNED HYPER
629 if (newOffset != nullptr) {
630 *newOffset = offset + 9;
632 return ConstantValue(file->read64(offset + 1));
633 case 8: // FLOAT
634 if (newOffset != nullptr) {
635 *newOffset = offset + 5;
637 return ConstantValue(file->readIso60599Binary32(offset + 1));
638 case 9: // DOUBLE
639 if (newOffset != nullptr) {
640 *newOffset = offset + 9;
642 return ConstantValue(file->readIso60599Binary64(offset + 1));
643 default:
644 throw FileFormatException(
645 file->uri,
646 "UNOIDL format: bad constant type byte " + OUString::number(v));
650 rtl::Reference< Entity > readEntity(
651 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
652 std::set<Map> && trace);
654 class UnoidlModuleEntity;
656 class UnoidlCursor: public MapCursor {
657 public:
658 UnoidlCursor(
659 rtl::Reference< MappedFile > const & file,
660 rtl::Reference<UnoidlProvider> const & reference1,
661 rtl::Reference<UnoidlModuleEntity> const & reference2,
662 NestedMap const & map):
663 file_(file), reference1_(reference1), reference2_(reference2),
664 map_(map), index_(0)
667 private:
668 virtual ~UnoidlCursor() noexcept override {}
670 virtual rtl::Reference< Entity > getNext(OUString * name) override;
672 rtl::Reference< MappedFile > file_;
673 rtl::Reference<UnoidlProvider> reference1_; // HACK to keep alive whatever
674 rtl::Reference<UnoidlModuleEntity> reference2_; // owner of map_
675 NestedMap const & map_;
676 sal_uInt32 index_;
679 rtl::Reference< Entity > UnoidlCursor::getNext(OUString * name) {
680 assert(name != nullptr);
681 rtl::Reference< Entity > ent;
682 if (index_ != map_.map.size) {
683 *name = file_->readNulName(map_.map.begin[index_].name.getUnsigned32());
684 ent = readEntity(
685 file_, map_.map.begin[index_].data.getUnsigned32(), std::set(map_.trace));
686 ++index_;
688 return ent;
691 class UnoidlModuleEntity: public ModuleEntity {
692 public:
693 UnoidlModuleEntity(
694 rtl::Reference< MappedFile > const & file, sal_uInt32 mapOffset,
695 sal_uInt32 mapSize, std::set<Map> && trace):
696 file_(file)
698 assert(file.is());
699 map_.map.begin = reinterpret_cast<MapEntry const *>(
700 static_cast<char const *>(file_->address) + mapOffset);
701 map_.map.size = mapSize;
702 map_.trace = std::move(trace);
703 if (!map_.trace.insert(map_.map).second) {
704 throw FileFormatException(
705 file_->uri, "UNOIDL format: recursive map");
709 private:
710 virtual ~UnoidlModuleEntity() noexcept override {}
712 virtual std::vector< OUString > getMemberNames() const override;
714 virtual rtl::Reference< MapCursor > createCursor() const override {
715 return new UnoidlCursor(
716 file_, rtl::Reference<UnoidlProvider>(),
717 const_cast<UnoidlModuleEntity *>(this), map_);
720 rtl::Reference< MappedFile > file_;
721 NestedMap map_;
724 std::vector< OUString > UnoidlModuleEntity::getMemberNames() const {
725 std::vector< OUString > names;
726 for (sal_uInt32 i = 0; i != map_.map.size; ++i) {
727 names.push_back(
728 file_->readNulName(map_.map.begin[i].name.getUnsigned32()));
730 return names;
733 rtl::Reference< Entity > readEntity(
734 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
735 std::set<Map> && trace)
737 assert(file.is());
738 int v = file->read8(offset);
739 int type = v & 0x3F;
740 bool published = (v & 0x80) != 0;
741 bool annotated = (v & 0x40) != 0;
742 bool flag = (v & 0x20) != 0;
743 switch (type) {
744 case 0: // module
746 if (v != 0) {
747 throw FileFormatException(
748 file->uri,
749 ("UNOIDL format: bad module type byte "
750 + OUString::number(v)));
752 sal_uInt32 n = file->read32(offset + 1);
753 if (n > SAL_MAX_INT32) {
754 throw FileFormatException(
755 file->uri, "UNOIDL format: too many items in module");
757 if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
758 // cannot overflow
760 throw FileFormatException(
761 file->uri,
762 "UNOIDL format: module map offset + size too large");
764 return new UnoidlModuleEntity(file, offset + 5, n, std::move(trace));
766 case 1: // enum type
768 sal_uInt32 n = file->read32(offset + 1);
769 if (n == 0) {
770 throw FileFormatException(
771 file->uri, "UNOIDL format: enum type with no members");
773 if (n > SAL_MAX_INT32) {
774 throw FileFormatException(
775 file->uri, "UNOIDL format: too many members of enum type");
777 offset += 5;
778 std::vector< EnumTypeEntity::Member > mems;
779 for (sal_uInt32 i = 0; i != n; ++i) {
780 OUString memName(file->readIdxName(&offset));
781 checkEntityName(file, memName);
782 sal_Int32 memValue = static_cast< sal_Int32 >(
783 file->read32(offset));
784 //TODO: implementation-defined behavior of conversion from
785 // sal_uInt32 to sal_Int32 relies on two's complement
786 // representation
787 offset += 4;
788 mems.emplace_back(
789 memName, memValue,
790 readAnnotations(annotated, file, offset, &offset));
792 return new EnumTypeEntity(
793 published, std::move(mems), readAnnotations(annotated, file, offset));
795 case 2: // plain struct type without base
796 case 2 | 0x20: // plain struct type with base
798 ++offset;
799 OUString base;
800 if (flag) {
801 base = file->readIdxName(&offset);
802 if (base.isEmpty()) {
803 throw FileFormatException(
804 file->uri,
805 ("UNOIDL format: empty base type name of plain struct"
806 " type"));
808 checkTypeName(file, base);
810 sal_uInt32 n = file->read32(offset);
811 if (n > SAL_MAX_INT32) {
812 throw FileFormatException(
813 file->uri,
814 ("UNOIDL format: too many direct members of plain struct"
815 " type"));
817 offset += 4;
818 std::vector< PlainStructTypeEntity::Member > mems;
819 for (sal_uInt32 i = 0; i != n; ++i) {
820 OUString memName(file->readIdxName(&offset));
821 checkEntityName(file, memName);
822 OUString memType(file->readIdxName(&offset));
823 checkTypeName(file, memType);
824 mems.emplace_back(
825 memName, memType,
826 readAnnotations(annotated, file, offset, &offset));
828 return new PlainStructTypeEntity(
829 published, base, std::move(mems),
830 readAnnotations(annotated, file, offset));
832 case 3: // polymorphic struct type template
834 sal_uInt32 n = file->read32(offset + 1);
835 if (n > SAL_MAX_INT32) {
836 throw FileFormatException(
837 file->uri,
838 ("UNOIDL format: too many type parameters of polymorphic"
839 " struct type template"));
841 offset += 5;
842 std::vector< OUString > params;
843 for (sal_uInt32 i = 0; i != n; ++i) {
844 OUString param(file->readIdxName(&offset));
845 checkEntityName(file, param);
846 params.push_back(param);
848 n = file->read32(offset);
849 if (n > SAL_MAX_INT32) {
850 throw FileFormatException(
851 file->uri,
852 ("UNOIDL format: too many members of polymorphic struct"
853 " type template"));
855 offset += 4;
856 std::vector< PolymorphicStructTypeTemplateEntity::Member > mems;
857 for (sal_uInt32 i = 0; i != n; ++i) {
858 v = file->read8(offset);
859 ++offset;
860 OUString memName(file->readIdxName(&offset));
861 checkEntityName(file, memName);
862 OUString memType(file->readIdxName(&offset));
863 checkTypeName(file, memType);
864 if (v > 1) {
865 throw FileFormatException(
866 file->uri,
867 ("UNOIDL format: bad flags " + OUString::number(v)
868 + " for member " + memName
869 + " of polymorphic struct type template"));
871 mems.emplace_back(
872 memName, memType, v == 1,
873 readAnnotations(annotated, file, offset, &offset));
875 return new PolymorphicStructTypeTemplateEntity(
876 published, std::move(params), std::move(mems),
877 readAnnotations(annotated, file, offset));
879 case 4: // exception type without base
880 case 4 | 0x20: // exception type with base
882 ++offset;
883 OUString base;
884 if (flag) {
885 base = file->readIdxName(&offset);
886 if (base.isEmpty()) {
887 throw FileFormatException(
888 file->uri,
889 ("UNOIDL format: empty base type name of exception"
890 " type"));
892 checkTypeName(file, base);
894 sal_uInt32 n = file->read32(offset);
895 if (n > SAL_MAX_INT32) {
896 throw FileFormatException(
897 file->uri,
898 "UNOIDL format: too many direct members of exception type");
900 offset += 4;
901 std::vector< ExceptionTypeEntity::Member > mems;
902 for (sal_uInt32 i = 0; i != n; ++i) {
903 OUString memName(file->readIdxName(&offset));
904 checkEntityName(file, memName);
905 OUString memType(file->readIdxName(&offset));
906 checkTypeName(file, memType);
907 mems.emplace_back(
908 memName, memType,
909 readAnnotations(annotated, file, offset, &offset));
911 return new ExceptionTypeEntity(
912 published, base, std::move(mems),
913 readAnnotations(annotated, file, offset));
915 case 5: // interface type
917 sal_uInt32 n = file->read32(offset + 1);
918 if (n > SAL_MAX_INT32) {
919 throw FileFormatException(
920 file->uri,
921 ("UNOIDL format: too many direct mandatory bases of"
922 " interface type"));
924 offset += 5;
925 std::vector< AnnotatedReference > mandBases;
926 for (sal_uInt32 i = 0; i != n; ++i) {
927 OUString base(file->readIdxName(&offset));
928 checkTypeName(file, base);
929 mandBases.emplace_back(
930 base, readAnnotations(annotated, file, offset, &offset));
932 n = file->read32(offset);
933 if (n > SAL_MAX_INT32) {
934 throw FileFormatException(
935 file->uri,
936 ("UNOIDL format: too many direct optional bases of"
937 " interface type"));
939 offset += 4;
940 std::vector< AnnotatedReference > optBases;
941 for (sal_uInt32 i = 0; i != n; ++i) {
942 OUString base(file->readIdxName(&offset));
943 checkTypeName(file, base);
944 optBases.emplace_back(
945 base, readAnnotations(annotated, file, offset, &offset));
947 sal_uInt32 nAttrs = file->read32(offset);
948 if (nAttrs > SAL_MAX_INT32) {
949 throw FileFormatException(
950 file->uri,
951 ("UNOIDL format: too many direct attributes of interface"
952 " type"));
954 offset += 4;
955 std::vector< InterfaceTypeEntity::Attribute > attrs;
956 for (sal_uInt32 i = 0; i != nAttrs; ++i) {
957 v = file->read8(offset);
958 ++offset;
959 OUString attrName(file->readIdxName(&offset));
960 checkEntityName(file, attrName);
961 OUString attrType(file->readIdxName(&offset));
962 checkTypeName(file, attrType);
963 if (v > 0x03) {
964 throw FileFormatException(
965 file->uri,
966 ("UNOIDL format: bad flags for direct attribute "
967 + attrName + " of interface type"));
969 std::vector< OUString > getExcs;
970 sal_uInt32 m = file->read32(offset);
971 if (m > SAL_MAX_INT32) {
972 throw FileFormatException(
973 file->uri,
974 ("UNOIDL format: too many getter exceptions for direct"
975 " attribute " + attrName + " of interface type"));
977 offset += 4;
978 for (sal_uInt32 j = 0; j != m; ++j) {
979 OUString exc(file->readIdxName(&offset));
980 checkTypeName(file, exc);
981 getExcs.push_back(exc);
983 std::vector< OUString > setExcs;
984 if ((v & 0x02) == 0) {
985 m = file->read32(offset);
986 if (m > SAL_MAX_INT32) {
987 throw FileFormatException(
988 file->uri,
989 ("UNOIDL format: too many setter exceptions for"
990 " direct attribute " + attrName
991 + " of interface type"));
993 offset += 4;
994 for (sal_uInt32 j = 0; j != m; ++j) {
995 OUString exc(file->readIdxName(&offset));
996 checkTypeName(file, exc);
997 setExcs.push_back(exc);
1000 attrs.emplace_back(
1001 attrName, attrType, (v & 0x01) != 0, (v & 0x02) != 0,
1002 std::move(getExcs), std::move(setExcs),
1003 readAnnotations(annotated, file, offset, &offset));
1005 sal_uInt32 nMeths = file->read32(offset);
1006 if (nMeths > SAL_MAX_INT32 - nAttrs) {
1007 throw FileFormatException(
1008 file->uri,
1009 ("UNOIDL format: too many direct attributes and methods of"
1010 " interface type"));
1012 offset += 4;
1013 std::vector< InterfaceTypeEntity::Method > meths;
1014 meths.reserve(nMeths);
1015 for (sal_uInt32 i = 0; i != nMeths; ++i) {
1016 OUString methName(file->readIdxName(&offset));
1017 checkEntityName(file, methName);
1018 OUString methType(file->readIdxName(&offset));
1019 checkTypeName(file, methType);
1020 sal_uInt32 m = file->read32(offset);
1021 if (m > SAL_MAX_INT32) {
1022 throw FileFormatException(
1023 file->uri,
1024 ("UNOIDL format: too many parameters for method "
1025 + methName + " of interface type"));
1027 offset += 4;
1028 std::vector< InterfaceTypeEntity::Method::Parameter > params;
1029 for (sal_uInt32 j = 0; j != m; ++j) {
1030 v = file->read8(offset);
1031 ++offset;
1032 OUString paramName(file->readIdxName(&offset));
1033 checkEntityName(file, paramName);
1034 OUString paramType(file->readIdxName(&offset));
1035 checkTypeName(file, paramType);
1036 InterfaceTypeEntity::Method::Parameter::Direction dir;
1037 switch (v) {
1038 case 0:
1039 dir = InterfaceTypeEntity::Method::Parameter::
1040 DIRECTION_IN;
1041 break;
1042 case 1:
1043 dir = InterfaceTypeEntity::Method::Parameter::
1044 DIRECTION_OUT;
1045 break;
1046 case 2:
1047 dir = InterfaceTypeEntity::Method::Parameter::
1048 DIRECTION_IN_OUT;
1049 break;
1050 default:
1051 throw FileFormatException(
1052 file->uri,
1053 ("UNOIDL format: bad direction "
1054 + OUString::number(v) + " of parameter "
1055 + paramName + " for method " + methName
1056 + " of interface type"));
1058 params.emplace_back(paramName, paramType, dir);
1060 std::vector< OUString > excs;
1061 m = file->read32(offset);
1062 if (m > SAL_MAX_INT32) {
1063 throw FileFormatException(
1064 file->uri,
1065 ("UNOIDL format: too many exceptions for method "
1066 + methName + " of interface type"));
1068 offset += 4;
1069 for (sal_uInt32 j = 0; j != m; ++j) {
1070 OUString exc(file->readIdxName(&offset));
1071 checkTypeName(file, exc);
1072 excs.push_back(exc);
1074 meths.emplace_back(
1075 methName, methType, std::move(params), std::move(excs),
1076 readAnnotations(annotated, file, offset, &offset));
1078 return new InterfaceTypeEntity(
1079 published, std::move(mandBases), std::move(optBases), std::move(attrs), std::move(meths),
1080 readAnnotations(annotated, file, offset));
1082 case 6: // typedef
1084 ++offset;
1085 OUString base(file->readIdxName(&offset));
1086 checkTypeName(file, base);
1087 return new TypedefEntity(
1088 published, base, readAnnotations(annotated, file, offset));
1090 case 7: // constant group
1092 sal_uInt32 n = file->read32(offset + 1);
1093 if (n > SAL_MAX_INT32) {
1094 throw FileFormatException(
1095 file->uri,
1096 "UNOIDL format: too many constants in constant group");
1098 if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
1099 // cannot overflow
1101 throw FileFormatException(
1102 file->uri,
1103 ("UNOIDL format: constant group map offset + size too"
1104 " large"));
1106 MapEntry const * p = reinterpret_cast< MapEntry const * >(
1107 static_cast< char const * >(file->address) + offset + 5);
1108 std::vector< ConstantGroupEntity::Member > mems;
1109 for (sal_uInt32 i = 0; i != n; ++i) {
1110 sal_uInt32 off = p[i].data.getUnsigned32();
1111 bool ann;
1112 ConstantValue val(readConstant(file, off, &off, &ann));
1113 mems.emplace_back(
1114 file->readNulName(p[i].name.getUnsigned32()), val,
1115 readAnnotations(ann, file, off));
1117 return new ConstantGroupEntity(
1118 published, std::move(mems),
1119 readAnnotations(annotated, file, offset + 5 + 8 * n));
1121 case 8: // single-interface--based service without default constructor
1122 case 8 | 0x20: // single-interface--based service with default constructor
1124 ++offset;
1125 OUString base(file->readIdxName(&offset));
1126 checkTypeName(file, base);
1127 std::vector< SingleInterfaceBasedServiceEntity::Constructor > ctors;
1128 if (flag) {
1129 ctors.push_back(
1130 SingleInterfaceBasedServiceEntity::Constructor());
1131 } else {
1132 sal_uInt32 n = file->read32(offset);
1133 if (n > SAL_MAX_INT32) {
1134 throw FileFormatException(
1135 file->uri,
1136 ("UNOIDL format: too many constructors of"
1137 " single-interface--based service"));
1139 offset += 4;
1140 for (sal_uInt32 i = 0; i != n; ++i) {
1141 OUString ctorName(file->readIdxName(&offset));
1142 checkEntityName(file, ctorName);
1143 sal_uInt32 m = file->read32(offset);
1144 if (m > SAL_MAX_INT32) {
1145 throw FileFormatException(
1146 file->uri,
1147 ("UNOIDL format: too many parameters for"
1148 " constructor " + ctorName
1149 + " of single-interface--based service"));
1151 offset += 4;
1152 std::vector<
1153 SingleInterfaceBasedServiceEntity::Constructor::
1154 Parameter > params;
1155 for (sal_uInt32 j = 0; j != m; ++j) {
1156 v = file->read8(offset);
1157 ++offset;
1158 OUString paramName(file->readIdxName(&offset));
1159 checkEntityName(file, paramName);
1160 OUString paramType(file->readIdxName(&offset));
1161 checkTypeName(file, paramType);
1162 bool rest;
1163 switch (v) {
1164 case 0:
1165 rest = false;
1166 break;
1167 case 0x04:
1168 rest = true;
1169 break;
1170 default:
1171 throw FileFormatException(
1172 file->uri,
1173 ("UNOIDL format: bad mode "
1174 + OUString::number(v) + " of parameter "
1175 + paramName + " for constructor " + ctorName
1176 + " of single-interface--based service"));
1178 params.emplace_back(paramName, paramType, rest);
1180 std::vector< OUString > excs;
1181 m = file->read32(offset);
1182 if (m > SAL_MAX_INT32) {
1183 throw FileFormatException(
1184 file->uri,
1185 ("UNOIDL format: too many exceptions for"
1186 " constructor " + ctorName
1187 + " of single-interface--based service"));
1189 offset += 4;
1190 for (sal_uInt32 j = 0; j != m; ++j) {
1191 OUString exc(file->readIdxName(&offset));
1192 checkTypeName(file, exc);
1193 excs.push_back(exc);
1195 ctors.push_back(
1196 SingleInterfaceBasedServiceEntity::Constructor(
1197 ctorName, std::move(params), std::move(excs),
1198 readAnnotations(annotated, file, offset, &offset)));
1201 return new SingleInterfaceBasedServiceEntity(
1202 published, base, std::move(ctors),
1203 readAnnotations(annotated, file, offset));
1205 case 9: // accumulation-based service
1207 sal_uInt32 n = file->read32(offset + 1);
1208 if (n > SAL_MAX_INT32) {
1209 throw FileFormatException(
1210 file->uri,
1211 ("UNOIDL format: too many direct mandatory service bases of"
1212 " accumulation-based service"));
1214 offset += 5;
1215 std::vector< AnnotatedReference > mandServs;
1216 for (sal_uInt32 i = 0; i != n; ++i) {
1217 OUString base(file->readIdxName(&offset));
1218 checkTypeName(file, base);
1219 mandServs.emplace_back(
1220 base, readAnnotations(annotated, file, offset, &offset));
1222 n = file->read32(offset);
1223 if (n > SAL_MAX_INT32) {
1224 throw FileFormatException(
1225 file->uri,
1226 ("UNOIDL format: too many direct optional service bases of"
1227 " accumulation-based service"));
1229 offset += 4;
1230 std::vector< AnnotatedReference > optServs;
1231 for (sal_uInt32 i = 0; i != n; ++i) {
1232 OUString base(file->readIdxName(&offset));
1233 checkTypeName(file, base);
1234 optServs.emplace_back(
1235 base, readAnnotations(annotated, file, offset, &offset));
1237 n = file->read32(offset);
1238 if (n > SAL_MAX_INT32) {
1239 throw FileFormatException(
1240 file->uri,
1241 ("UNOIDL format: too many direct mandatory interface bases"
1242 " of accumulation-based service"));
1244 offset += 4;
1245 std::vector< AnnotatedReference > mandIfcs;
1246 for (sal_uInt32 i = 0; i != n; ++i) {
1247 OUString base(file->readIdxName(&offset));
1248 checkTypeName(file, base);
1249 mandIfcs.emplace_back(
1250 base, readAnnotations(annotated, file, offset, &offset));
1252 n = file->read32(offset);
1253 if (n > SAL_MAX_INT32) {
1254 throw FileFormatException(
1255 file->uri,
1256 ("UNOIDL format: too many direct optional interface bases"
1257 " of accumulation-based service"));
1259 offset += 4;
1260 std::vector< AnnotatedReference > optIfcs;
1261 for (sal_uInt32 i = 0; i != n; ++i) {
1262 OUString base(file->readIdxName(&offset));
1263 checkTypeName(file, base);
1264 optIfcs.emplace_back(
1265 base, readAnnotations(annotated, file, offset, &offset));
1267 n = file->read32(offset);
1268 if (n > SAL_MAX_INT32) {
1269 throw FileFormatException(
1270 file->uri,
1271 ("UNOIDL format: too many direct properties of"
1272 " accumulation-based service"));
1274 offset += 4;
1275 std::vector< AccumulationBasedServiceEntity::Property > props;
1276 for (sal_uInt32 i = 0; i != n; ++i) {
1277 sal_uInt16 attrs = file->read16(offset);
1278 offset += 2;
1279 OUString propName(file->readIdxName(&offset));
1280 checkEntityName(file, propName);
1281 OUString propType(file->readIdxName(&offset));
1282 checkTypeName(file, propType);
1283 if (attrs > 0x01FF) { // see css.beans.PropertyAttribute
1284 throw FileFormatException(
1285 file->uri,
1286 ("UNOIDL format: bad mode " + OUString::number(v)
1287 + " of property " + propName
1288 + " for accumulation-based service"));
1290 props.emplace_back(
1291 propName, propType,
1292 static_cast<
1293 AccumulationBasedServiceEntity::Property::Attributes >(
1294 attrs),
1295 readAnnotations(annotated, file, offset, &offset));
1297 return new AccumulationBasedServiceEntity(
1298 published, std::move(mandServs), std::move(optServs), std::move(mandIfcs), std::move(optIfcs), std::move(props),
1299 readAnnotations(annotated, file, offset));
1301 case 10: // interface-based singleton
1303 ++offset;
1304 OUString base(file->readIdxName(&offset));
1305 checkTypeName(file, base);
1306 return new InterfaceBasedSingletonEntity(
1307 published, base, readAnnotations(annotated, file, offset));
1309 case 11: // service-based singleton
1311 ++offset;
1312 OUString base(file->readIdxName(&offset));
1313 checkTypeName(file, base);
1314 return new ServiceBasedSingletonEntity(
1315 published, base, readAnnotations(annotated, file, offset));
1317 default:
1318 throw FileFormatException(
1319 file->uri, "UNOIDL format: bad type byte " + OUString::number(v));
1325 UnoidlProvider::UnoidlProvider(OUString const & uri): file_(new MappedFile(uri))
1327 if (file_->size < 8 || std::memcmp(file_->address, "UNOIDL\xFF\0", 8) != 0)
1329 throw FileFormatException(
1330 file_->uri,
1331 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1332 " 0");
1334 sal_uInt32 off = file_->read32(8);
1335 map_.map.size = file_->read32(12);
1336 if (off + 8 * sal_uInt64(map_.map.size) > file_->size) { // cannot overflow
1337 throw FileFormatException(
1338 file_->uri, "UNOIDL format: root map offset + size too large");
1340 map_.map.begin = reinterpret_cast< MapEntry const * >(
1341 static_cast< char const * >(file_->address) + off);
1342 map_.trace.insert(map_.map);
1345 rtl::Reference< MapCursor > UnoidlProvider::createRootCursor() const {
1346 return new UnoidlCursor(
1347 file_, const_cast<UnoidlProvider *>(this),
1348 rtl::Reference<UnoidlModuleEntity>(), map_);
1351 rtl::Reference< Entity > UnoidlProvider::findEntity(OUString const & name) const
1353 NestedMap map(map_);
1354 bool cgroup = false;
1355 for (sal_Int32 i = 0;;) {
1356 sal_Int32 j = name.indexOf('.', i);
1357 if (j == -1) {
1358 j = name.getLength();
1360 sal_Int32 off = findInMap(
1361 file_, map.map.begin, map.map.size, name, i, j - i);
1362 if (off == 0) {
1363 return rtl::Reference< Entity >();
1365 if (j == name.getLength()) {
1366 return cgroup
1367 ? rtl::Reference< Entity >()
1368 : readEntity(file_, off, std::set(map.trace));
1370 if (cgroup) {
1371 return rtl::Reference< Entity >();
1372 //TODO: throw an exception instead here, where the segments of a
1373 // constant's name are a prefix of the requested name's
1374 // segments?
1376 int v = file_->read8(off);
1377 if (v != 0) { // module
1378 if ((v & 0x3F) == 7) { // constant group
1379 cgroup = true;
1380 } else {
1381 return rtl::Reference< Entity >();
1382 //TODO: throw an exception instead here, where the segments
1383 // of a non-module, non-constant-group entity's name are a
1384 // prefix of the requested name's segments?
1387 map.map.size = file_->read32(off + 1);
1388 if (sal_uInt64(off) + 5 + 8 * sal_uInt64(map.map.size) > file_->size)
1389 // cannot overflow
1391 throw FileFormatException(
1392 file_->uri, "UNOIDL format: map offset + size too large");
1394 map.map.begin = reinterpret_cast< MapEntry const * >(
1395 static_cast< char const * >(file_->address) + off + 5);
1396 if (!map.trace.insert(map.map).second) {
1397 throw FileFormatException(
1398 file_->uri, "UNOIDL format: recursive map");
1400 i = j + 1;
1404 UnoidlProvider::~UnoidlProvider() noexcept {}
1408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */