sw a11y: clang-format SidebarWinAccessible code
[LibreOffice.git] / unoidl / source / unoidlprovider.cxx
blob9b5dd2b28de5f6b14c49814ece56bde01c737910
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 <utility>
18 #include <vector>
20 #include <o3tl/string_view.hxx>
21 #include <osl/endian.h>
22 #include <osl/file.h>
23 #include <rtl/character.hxx>
24 #include <rtl/ref.hxx>
25 #include <rtl/textenc.h>
26 #include <rtl/textcvt.h>
27 #include <rtl/ustring.hxx>
28 #include <sal/log.hxx>
29 #include <sal/types.h>
30 #include <salhelper/simplereferenceobject.hxx>
31 #include <unoidl/unoidl.hxx>
33 #include "unoidlprovider.hxx"
35 namespace unoidl::detail {
37 class MappedFile: public salhelper::SimpleReferenceObject {
38 public:
39 explicit MappedFile(OUString fileUrl);
41 sal_uInt8 read8(sal_uInt32 offset) const;
43 sal_uInt16 read16(sal_uInt32 offset) const;
45 sal_uInt32 read32(sal_uInt32 offset) const;
47 sal_uInt64 read64(sal_uInt32 offset) const;
49 float readIso60599Binary32(sal_uInt32 offset) const;
51 double readIso60599Binary64(sal_uInt32 offset) const;
53 OUString readNulName(sal_uInt32 offset) /*const*/;
55 OUString readIdxName(sal_uInt32 * offset) const
56 { return readIdxString(offset, RTL_TEXTENCODING_ASCII_US); }
58 OUString readIdxString(sal_uInt32 * offset) const
59 { return readIdxString(offset, RTL_TEXTENCODING_UTF8); }
61 OUString uri;
62 oslFileHandle handle;
63 sal_uInt64 size;
64 void * address;
66 private:
67 virtual ~MappedFile() override;
69 sal_uInt8 get8(sal_uInt32 offset) const;
71 sal_uInt16 get16(sal_uInt32 offset) const;
73 sal_uInt32 get32(sal_uInt32 offset) const;
75 sal_uInt64 get64(sal_uInt32 offset) const;
77 float getIso60599Binary32(sal_uInt32 offset) const;
79 double getIso60599Binary64(sal_uInt32 offset) const;
81 OUString readIdxString(sal_uInt32 * offset, rtl_TextEncoding encoding)
82 const;
85 namespace {
87 // sizeof (Memory16) == 2
88 struct Memory16 {
89 unsigned char byte[2];
91 sal_uInt16 getUnsigned16() const {
92 return static_cast< sal_uInt16 >(byte[0])
93 | (static_cast< sal_uInt16 >(byte[1]) << 8);
97 // sizeof (Memory32) == 4
98 struct Memory32 {
99 unsigned char byte[4];
101 sal_uInt32 getUnsigned32() const {
102 return static_cast< sal_uInt32 >(byte[0])
103 | (static_cast< sal_uInt32 >(byte[1]) << 8)
104 | (static_cast< sal_uInt32 >(byte[2]) << 16)
105 | (static_cast< sal_uInt32 >(byte[3]) << 24);
108 float getIso60599Binary32() const {
109 union {
110 unsigned char buf[4];
111 float f; // assuming float is ISO 60599 binary32
112 } sa;
113 #if defined OSL_LITENDIAN
114 sa.buf[0] = byte[0];
115 sa.buf[1] = byte[1];
116 sa.buf[2] = byte[2];
117 sa.buf[3] = byte[3];
118 #else
119 sa.buf[0] = byte[3];
120 sa.buf[1] = byte[2];
121 sa.buf[2] = byte[1];
122 sa.buf[3] = byte[0];
123 #endif
124 return sa.f;
128 // sizeof (Memory64) == 8
129 struct Memory64 {
130 unsigned char byte[8];
132 sal_uInt64 getUnsigned64() const {
133 return static_cast< sal_uInt64 >(byte[0])
134 | (static_cast< sal_uInt64 >(byte[1]) << 8)
135 | (static_cast< sal_uInt64 >(byte[2]) << 16)
136 | (static_cast< sal_uInt64 >(byte[3]) << 24)
137 | (static_cast< sal_uInt64 >(byte[4]) << 32)
138 | (static_cast< sal_uInt64 >(byte[5]) << 40)
139 | (static_cast< sal_uInt64 >(byte[6]) << 48)
140 | (static_cast< sal_uInt64 >(byte[7]) << 56);
143 double getIso60599Binary64() const {
144 union {
145 unsigned char buf[8];
146 double d; // assuming double is ISO 60599 binary64
147 } sa;
148 #if defined OSL_LITENDIAN
149 sa.buf[0] = byte[0];
150 sa.buf[1] = byte[1];
151 sa.buf[2] = byte[2];
152 sa.buf[3] = byte[3];
153 sa.buf[4] = byte[4];
154 sa.buf[5] = byte[5];
155 sa.buf[6] = byte[6];
156 sa.buf[7] = byte[7];
157 #else
158 sa.buf[0] = byte[7];
159 sa.buf[1] = byte[6];
160 sa.buf[2] = byte[5];
161 sa.buf[3] = byte[4];
162 sa.buf[4] = byte[3];
163 sa.buf[5] = byte[2];
164 sa.buf[6] = byte[1];
165 sa.buf[7] = byte[0];
166 #endif
167 return sa.d;
171 bool isSimpleType(std::u16string_view type) {
172 return type == u"void" || type == u"boolean" || type == u"byte"
173 || type == u"short" || type == u"unsigned short" || type == u"long"
174 || type == u"unsigned long" || type == u"hyper"
175 || type == u"unsigned hyper" || type == u"float" || type == u"double"
176 || type == u"char" || type == u"string" || type == u"type"
177 || type == u"any";
180 // For backwards compatibility, does not strictly check segments to match
182 // <segment> ::= <blocks> | <block>
183 // <blocks> ::= <capital> <other>* ("_" <block>)*
184 // <block> ::= <other>+
185 // <other> ::= <capital> | "a"--"z" | "0"--"9"
186 // <capital> ::= "A"--"Z"
188 bool isIdentifier(std::u16string_view type, bool scoped) {
189 if (type.empty()) {
190 return false;
192 for (size_t i = 0; i != type.size(); ++i) {
193 sal_Unicode c = type[i];
194 if (c == '.') {
195 if (!scoped || i == 0 || i == type.size() - 1
196 || type[i - 1] == '.')
198 return false;
200 } else if (!rtl::isAsciiAlphanumeric(c) && c != '_') {
201 return false;
204 return true;
207 void checkTypeName(
208 rtl::Reference< MappedFile > const & file, std::u16string_view type)
210 std::u16string_view nucl(type);
211 bool args = false;
212 while (o3tl::starts_with(nucl, u"[]", &nucl)) {}
213 size_t i = nucl.find('<');
214 if (i != std::u16string_view::npos) {
215 std::u16string_view tmpl(nucl.substr(0, i));
216 do {
217 ++i; // skip '<' or ','
218 size_t j = i;
219 for (size_t level = 0; j != nucl.size(); ++j) {
220 sal_Unicode c = nucl[j];
221 if (c == ',') {
222 if (level == 0) {
223 break;
225 } else if (c == '<') {
226 ++level;
227 } else if (c == '>') {
228 if (level == 0) {
229 break;
231 --level;
234 if (j != nucl.size()) {
235 checkTypeName(file, nucl.substr(i, j - i));
236 args = true;
238 i = j;
239 } while (i != nucl.size() && nucl[i] != '>');
240 if (i != nucl.size() - 1 || nucl[i] != '>' || !args) {
241 tmpl = {}; // bad input
243 nucl = tmpl;
245 if (isSimpleType(nucl) ? args : !isIdentifier(nucl, true)) {
246 throw FileFormatException(
247 file->uri, OUString::Concat("UNOIDL format: bad type \"") + type + "\"");
251 void checkEntityName(
252 rtl::Reference< MappedFile > const & file, std::u16string_view name)
254 if (isSimpleType(name) || !isIdentifier(name, false)) {
255 throw FileFormatException(
256 file->uri, OUString::Concat("UNOIDL format: bad entity name \"") + name + "\"");
262 MappedFile::MappedFile(OUString fileUrl): uri(std::move(fileUrl)), handle(nullptr) {
263 oslFileError e = osl_openFile(uri.pData, &handle, osl_File_OpenFlag_Read);
264 switch (e) {
265 case osl_File_E_None:
266 break;
267 case osl_File_E_NOENT:
268 throw NoSuchFileException(uri);
269 default:
270 throw FileFormatException(uri, "cannot open: " + OUString::number(e));
272 e = osl_getFileSize(handle, &size);
273 if (e == osl_File_E_None) {
274 e = osl_mapFile(
275 handle, &address, size, 0, osl_File_MapFlag_RandomAccess);
277 if (e != osl_File_E_None) {
278 oslFileError e2 = osl_closeFile(handle);
279 SAL_WARN_IF(
280 e2 != osl_File_E_None, "unoidl",
281 "cannot close " << uri << ": " << +e2);
282 throw FileFormatException(uri, "cannot mmap: " + OUString::number(e));
286 sal_uInt8 MappedFile::read8(sal_uInt32 offset) const {
287 assert(size >= 8);
288 if (offset > size - 1) {
289 throw FileFormatException(
290 uri, u"UNOIDL format: offset for 8-bit value too large"_ustr);
292 return get8(offset);
295 sal_uInt16 MappedFile::read16(sal_uInt32 offset) const {
296 assert(size >= 8);
297 if (offset > size - 2) {
298 throw FileFormatException(
299 uri, u"UNOIDL format: offset for 16-bit value too large"_ustr);
301 return get16(offset);
304 sal_uInt32 MappedFile::read32(sal_uInt32 offset) const {
305 assert(size >= 8);
306 if (offset > size - 4) {
307 throw FileFormatException(
308 uri, u"UNOIDL format: offset for 32-bit value too large"_ustr);
310 return get32(offset);
313 sal_uInt64 MappedFile::read64(sal_uInt32 offset) const {
314 assert(size >= 8);
315 if (offset > size - 8) {
316 throw FileFormatException(
317 uri, u"UNOIDL format: offset for 64-bit value too large"_ustr);
319 return get64(offset);
322 float MappedFile::readIso60599Binary32(sal_uInt32 offset) const {
323 assert(size >= 8);
324 if (offset > size - 4) {
325 throw FileFormatException(
326 uri, u"UNOIDL format: offset for 32-bit value too large"_ustr);
328 return getIso60599Binary32(offset);
331 double MappedFile::readIso60599Binary64(sal_uInt32 offset) const {
332 assert(size >= 8);
333 if (offset > size - 8) {
334 throw FileFormatException(
335 uri, u"UNOIDL format: offset for 64-bit value too large"_ustr);
337 return getIso60599Binary64(offset);
340 OUString MappedFile::readNulName(sal_uInt32 offset) {
341 if (offset > size) {
342 throw FileFormatException(
343 uri, u"UNOIDL format: offset for string too large"_ustr);
345 sal_uInt64 end = offset;
346 for (;; ++end) {
347 if (end == size) {
348 throw FileFormatException(
349 uri, u"UNOIDL format: string misses trailing NUL"_ustr);
351 if (static_cast< char const * >(address)[end] == 0) {
352 break;
355 if (end - offset > SAL_MAX_INT32) {
356 throw FileFormatException(uri, u"UNOIDL format: string too long"_ustr);
358 OUString name;
359 if (!rtl_convertStringToUString(
360 &name.pData, static_cast< char const * >(address) + offset,
361 end - offset, RTL_TEXTENCODING_ASCII_US,
362 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
363 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
364 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
366 throw FileFormatException(uri, u"UNOIDL format: name is not ASCII"_ustr);
368 checkEntityName(this, name);
369 return name;
372 MappedFile::~MappedFile() {
373 oslFileError e = osl_unmapMappedFile(handle, address, size);
374 SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e);
375 e = osl_closeFile(handle);
376 SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e);
379 sal_uInt8 MappedFile::get8(sal_uInt32 offset) const {
380 assert(size >= 8);
381 assert(offset <= size - 1);
382 return static_cast< char const * >(address)[offset];
385 sal_uInt16 MappedFile::get16(sal_uInt32 offset) const {
386 assert(size >= 8);
387 assert(offset <= size - 2);
388 return reinterpret_cast< Memory16 const * >(
389 static_cast< char const * >(address) + offset)->getUnsigned16();
392 sal_uInt32 MappedFile::get32(sal_uInt32 offset) const {
393 assert(size >= 8);
394 assert(offset <= size - 4);
395 return reinterpret_cast< Memory32 const * >(
396 static_cast< char const * >(address) + offset)->getUnsigned32();
399 sal_uInt64 MappedFile::get64(sal_uInt32 offset) const {
400 assert(size >= 8);
401 assert(offset <= size - 8);
402 return reinterpret_cast< Memory64 const * >(
403 static_cast< char const * >(address) + offset)->getUnsigned64();
406 float MappedFile::getIso60599Binary32(sal_uInt32 offset) const {
407 assert(size >= 8);
408 assert(offset <= size - 4);
409 return reinterpret_cast< Memory32 const * >(
410 static_cast< char const * >(address) + offset)->getIso60599Binary32();
413 double MappedFile::getIso60599Binary64(sal_uInt32 offset) const {
414 assert(size >= 8);
415 assert(offset <= size - 8);
416 return reinterpret_cast< Memory64 const * >(
417 static_cast< char const * >(address) + offset)->getIso60599Binary64();
420 OUString MappedFile::readIdxString(
421 sal_uInt32 * offset, rtl_TextEncoding encoding) const
423 assert(offset != nullptr);
424 sal_uInt32 len = read32(*offset);
425 sal_uInt32 off;
426 if ((len & 0x80000000) == 0) {
427 off = *offset;
428 *offset += 4 + len;
429 } else {
430 *offset += 4;
431 off = len & ~0x80000000;
432 len = read32(off);
433 if ((len & 0x80000000) != 0) {
434 throw FileFormatException(
435 uri, u"UNOIDL format: string length high bit set"_ustr);
438 if (len > SAL_MAX_INT32 || len > size - off - 4) {
439 throw FileFormatException(
440 uri, u"UNOIDL format: size of string is too large"_ustr);
442 OUString name;
443 if (!rtl_convertStringToUString(
444 &name.pData, static_cast< char const * >(address) + off + 4, len,
445 encoding,
446 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
447 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
448 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
450 throw FileFormatException(
451 uri, u"UNOIDL format: string bytes do not match encoding"_ustr);
453 return name;
456 // sizeof (MapEntry) == 8
457 struct MapEntry {
458 Memory32 name;
459 Memory32 data;
462 static bool operator <(const Map& map1, const Map& map2) {
463 return map1.begin < map2.begin
464 || (map1.begin == map2.begin && map1.size < map2.size);
467 namespace {
469 enum Compare { COMPARE_LESS, COMPARE_GREATER, COMPARE_EQUAL };
471 Compare compare(
472 rtl::Reference< MappedFile > const & file, std::u16string_view name,
473 sal_Int32 nameOffset, sal_Int32 nameLength, MapEntry const * entry)
475 assert(file.is());
476 assert(entry != nullptr);
477 sal_uInt32 off = entry->name.getUnsigned32();
478 if (off > file->size - 1) { // at least a trailing NUL
479 throw FileFormatException(
480 file->uri, u"UNOIDL format: string offset too large"_ustr);
482 assert(nameLength >= 0);
483 sal_uInt64 min = std::min(
484 static_cast< sal_uInt64 >(nameLength), file->size - off);
485 for (sal_uInt64 i = 0; i != min; ++i) {
486 sal_Unicode c1 = name[nameOffset + i];
487 sal_Unicode c2 = static_cast< unsigned char const * >(file->address)[
488 off + i];
489 if (c1 < c2) {
490 return COMPARE_LESS;
491 } else if (c1 > c2 || c2 == 0) {
492 // ...the "|| c2 == 0" is for the odd case where name erroneously
493 // contains NUL characters
494 return COMPARE_GREATER;
497 if (static_cast< sal_uInt64 >(nameLength) == min) {
498 if (file->size - off == min) {
499 throw FileFormatException(
500 file->uri, u"UNOIDL format: string misses trailing NUL"_ustr);
502 return
503 static_cast< unsigned char const * >(file->address)[off + min] == 0
504 ? COMPARE_EQUAL : COMPARE_LESS;
505 } else {
506 return COMPARE_GREATER;
510 sal_uInt32 findInMap(
511 rtl::Reference< MappedFile > const & file, MapEntry const * mapBegin,
512 sal_uInt32 mapSize, OUString const & name, sal_Int32 nameOffset,
513 sal_Int32 nameLength)
515 if (mapSize == 0) {
516 return 0;
518 sal_uInt32 n = mapSize / 2;
519 MapEntry const * p = mapBegin + n;
520 switch (compare(file, name, nameOffset, nameLength, p)) {
521 case COMPARE_LESS:
522 return findInMap(file, mapBegin, n, name, nameOffset, nameLength);
523 case COMPARE_GREATER:
524 return findInMap(
525 file, p + 1, mapSize - n - 1, name, nameOffset, nameLength);
526 default: // COMPARE_EQUAL
527 break;
529 sal_uInt32 off = mapBegin[n].data.getUnsigned32();
530 if (off == 0) {
531 throw FileFormatException(
532 file->uri, u"UNOIDL format: map entry data offset is null"_ustr);
534 return off;
537 #if defined(__COVERITY__) && __COVERITY_MAJOR__ <= 2023
538 extern "C" void __coverity_tainted_data_sanitize__(void *);
539 #endif
541 std::vector< OUString > readAnnotations(
542 bool annotated, rtl::Reference< MappedFile > const & file,
543 sal_uInt32 offset, sal_uInt32 * newOffset = nullptr)
545 std::vector< OUString > ans;
546 if (annotated) {
547 sal_uInt32 n = file->read32(offset);
548 #if defined(__COVERITY__) && __COVERITY_MAJOR__ <= 2023
549 __coverity_tainted_data_sanitize__(&n);
550 #endif
551 offset += 4;
552 for (sal_uInt32 i = 0; i != n; ++i) {
553 ans.push_back(file->readIdxString(&offset));
556 if (newOffset != nullptr) {
557 *newOffset = offset;
559 return ans;
562 ConstantValue readConstant(
563 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
564 sal_uInt32 * newOffset, bool * annotated)
566 assert(file.is());
567 int v = file->read8(offset);
568 int type = v & 0x7F;
569 if (annotated != nullptr) {
570 *annotated = (v & 0x80) != 0;
572 switch (type) {
573 case 0: // BOOLEAN
574 v = file->read8(offset + 1);
575 if (newOffset != nullptr) {
576 *newOffset = offset + 2;
578 switch (v) {
579 case 0:
580 return ConstantValue(false);
581 case 1:
582 return ConstantValue(true);
583 default:
584 throw FileFormatException(
585 file->uri,
586 ("UNOIDL format: bad boolean constant value "
587 + OUString::number(v)));
589 case 1: // BYTE
590 if (newOffset != nullptr) {
591 *newOffset = offset + 2;
593 return ConstantValue(static_cast< sal_Int8 >(file->read8(offset + 1)));
594 //TODO: implementation-defined behavior of conversion from sal_uInt8
595 // to sal_Int8 relies on two's complement representation
596 case 2: // SHORT
597 if (newOffset != nullptr) {
598 *newOffset = offset + 3;
600 return ConstantValue(
601 static_cast< sal_Int16 >(file->read16(offset + 1)));
602 //TODO: implementation-defined behavior of conversion from
603 // sal_uInt16 to sal_Int16 relies on two's complement representation
604 case 3: // UNSIGNED SHORT
605 if (newOffset != nullptr) {
606 *newOffset = offset + 3;
608 return ConstantValue(file->read16(offset + 1));
609 case 4: // LONG
610 if (newOffset != nullptr) {
611 *newOffset = offset + 5;
613 return ConstantValue(
614 static_cast< sal_Int32 >(file->read32(offset + 1)));
615 //TODO: implementation-defined behavior of conversion from
616 // sal_uInt32 to sal_Int32 relies on two's complement representation
617 case 5: // UNSIGNED LONG
618 if (newOffset != nullptr) {
619 *newOffset = offset + 5;
621 return ConstantValue(file->read32(offset + 1));
622 case 6: // HYPER
623 if (newOffset != nullptr) {
624 *newOffset = offset + 9;
626 return ConstantValue(
627 static_cast< sal_Int64 >(file->read64(offset + 1)));
628 //TODO: implementation-defined behavior of conversion from
629 // sal_uInt64 to sal_Int64 relies on two's complement representation
630 case 7: // UNSIGNED HYPER
631 if (newOffset != nullptr) {
632 *newOffset = offset + 9;
634 return ConstantValue(file->read64(offset + 1));
635 case 8: // FLOAT
636 if (newOffset != nullptr) {
637 *newOffset = offset + 5;
639 return ConstantValue(file->readIso60599Binary32(offset + 1));
640 case 9: // DOUBLE
641 if (newOffset != nullptr) {
642 *newOffset = offset + 9;
644 return ConstantValue(file->readIso60599Binary64(offset + 1));
645 default:
646 throw FileFormatException(
647 file->uri,
648 "UNOIDL format: bad constant type byte " + OUString::number(v));
652 rtl::Reference< Entity > readEntity(
653 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
654 std::set<Map> && trace);
656 class UnoidlModuleEntity;
658 class UnoidlCursor: public MapCursor {
659 public:
660 UnoidlCursor(
661 rtl::Reference< MappedFile > file,
662 rtl::Reference<UnoidlProvider> reference1,
663 rtl::Reference<UnoidlModuleEntity> reference2,
664 NestedMap const & map):
665 file_(std::move(file)), reference1_(std::move(reference1)), reference2_(std::move(reference2)),
666 map_(map), index_(0)
669 private:
670 virtual ~UnoidlCursor() noexcept override {}
672 virtual rtl::Reference< Entity > getNext(OUString * name) override;
674 rtl::Reference< MappedFile > file_;
675 rtl::Reference<UnoidlProvider> reference1_; // HACK to keep alive whatever
676 rtl::Reference<UnoidlModuleEntity> reference2_; // owner of map_
677 NestedMap const & map_;
678 sal_uInt32 index_;
681 rtl::Reference< Entity > UnoidlCursor::getNext(OUString * name) {
682 assert(name != nullptr);
683 rtl::Reference< Entity > ent;
684 if (index_ != map_.map.size) {
685 *name = file_->readNulName(map_.map.begin[index_].name.getUnsigned32());
686 ent = readEntity(
687 file_, map_.map.begin[index_].data.getUnsigned32(), std::set(map_.trace));
688 ++index_;
690 return ent;
693 class UnoidlModuleEntity: public ModuleEntity {
694 public:
695 UnoidlModuleEntity(
696 rtl::Reference< MappedFile > const & file, sal_uInt32 mapOffset,
697 sal_uInt32 mapSize, std::set<Map> && trace):
698 file_(file)
700 assert(file.is());
701 map_.map.begin = reinterpret_cast<MapEntry const *>(
702 static_cast<char const *>(file_->address) + mapOffset);
703 map_.map.size = mapSize;
704 map_.trace = std::move(trace);
705 if (!map_.trace.insert(map_.map).second) {
706 throw FileFormatException(
707 file_->uri, u"UNOIDL format: recursive map"_ustr);
711 private:
712 virtual ~UnoidlModuleEntity() noexcept override {}
714 virtual std::vector< OUString > getMemberNames() const override;
716 virtual rtl::Reference< MapCursor > createCursor() const override {
717 return new UnoidlCursor(
718 file_, rtl::Reference<UnoidlProvider>(),
719 const_cast<UnoidlModuleEntity *>(this), map_);
722 rtl::Reference< MappedFile > file_;
723 NestedMap map_;
726 std::vector< OUString > UnoidlModuleEntity::getMemberNames() const {
727 std::vector< OUString > names;
728 for (sal_uInt32 i = 0; i != map_.map.size; ++i) {
729 names.push_back(
730 file_->readNulName(map_.map.begin[i].name.getUnsigned32()));
732 return names;
735 rtl::Reference< Entity > readEntity(
736 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
737 std::set<Map> && trace)
739 assert(file.is());
740 int v = file->read8(offset);
741 int type = v & 0x3F;
742 bool published = (v & 0x80) != 0;
743 bool annotated = (v & 0x40) != 0;
744 bool flag = (v & 0x20) != 0;
745 switch (type) {
746 case 0: // module
748 if (v != 0) {
749 throw FileFormatException(
750 file->uri,
751 ("UNOIDL format: bad module type byte "
752 + OUString::number(v)));
754 sal_uInt32 n = file->read32(offset + 1);
755 if (n > SAL_MAX_INT32) {
756 throw FileFormatException(
757 file->uri, u"UNOIDL format: too many items in module"_ustr);
759 if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
760 // cannot overflow
762 throw FileFormatException(
763 file->uri,
764 u"UNOIDL format: module map offset + size too large"_ustr);
766 return new UnoidlModuleEntity(file, offset + 5, n, std::move(trace));
768 case 1: // enum type
770 sal_uInt32 n = file->read32(offset + 1);
771 if (n == 0) {
772 throw FileFormatException(
773 file->uri, u"UNOIDL format: enum type with no members"_ustr);
775 if (n > SAL_MAX_INT32) {
776 throw FileFormatException(
777 file->uri, u"UNOIDL format: too many members of enum type"_ustr);
779 offset += 5;
780 std::vector< EnumTypeEntity::Member > mems;
781 mems.reserve(n);
782 for (sal_uInt32 i = 0; i != n; ++i) {
783 OUString memName(file->readIdxName(&offset));
784 checkEntityName(file, memName);
785 sal_Int32 memValue = static_cast< sal_Int32 >(
786 file->read32(offset));
787 //TODO: implementation-defined behavior of conversion from
788 // sal_uInt32 to sal_Int32 relies on two's complement
789 // representation
790 offset += 4;
791 mems.emplace_back(
792 memName, memValue,
793 readAnnotations(annotated, file, offset, &offset));
795 return new EnumTypeEntity(
796 published, std::move(mems), readAnnotations(annotated, file, offset));
798 case 2: // plain struct type without base
799 case 2 | 0x20: // plain struct type with base
801 ++offset;
802 OUString base;
803 if (flag) {
804 base = file->readIdxName(&offset);
805 if (base.isEmpty()) {
806 throw FileFormatException(
807 file->uri,
808 (u"UNOIDL format: empty base type name of plain struct"
809 " type"_ustr));
811 checkTypeName(file, base);
813 sal_uInt32 n = file->read32(offset);
814 if (n > SAL_MAX_INT32) {
815 throw FileFormatException(
816 file->uri,
817 (u"UNOIDL format: too many direct members of plain struct"
818 " type"_ustr));
820 offset += 4;
821 std::vector< PlainStructTypeEntity::Member > mems;
822 mems.reserve(n);
823 for (sal_uInt32 i = 0; i != n; ++i) {
824 OUString memName(file->readIdxName(&offset));
825 checkEntityName(file, memName);
826 OUString memType(file->readIdxName(&offset));
827 checkTypeName(file, memType);
828 mems.emplace_back(
829 memName, memType,
830 readAnnotations(annotated, file, offset, &offset));
832 return new PlainStructTypeEntity(
833 published, base, std::move(mems),
834 readAnnotations(annotated, file, offset));
836 case 3: // polymorphic struct type template
838 sal_uInt32 n = file->read32(offset + 1);
839 if (n > SAL_MAX_INT32) {
840 throw FileFormatException(
841 file->uri,
842 (u"UNOIDL format: too many type parameters of polymorphic"
843 " struct type template"_ustr));
845 offset += 5;
846 std::vector< OUString > params;
847 params.reserve(n);
848 for (sal_uInt32 i = 0; i != n; ++i) {
849 OUString param(file->readIdxName(&offset));
850 checkEntityName(file, param);
851 params.push_back(param);
853 n = file->read32(offset);
854 if (n > SAL_MAX_INT32) {
855 throw FileFormatException(
856 file->uri,
857 (u"UNOIDL format: too many members of polymorphic struct"
858 " type template"_ustr));
860 offset += 4;
861 std::vector< PolymorphicStructTypeTemplateEntity::Member > mems;
862 mems.reserve(n);
863 for (sal_uInt32 i = 0; i != n; ++i) {
864 v = file->read8(offset);
865 ++offset;
866 OUString memName(file->readIdxName(&offset));
867 checkEntityName(file, memName);
868 OUString memType(file->readIdxName(&offset));
869 checkTypeName(file, memType);
870 if (v > 1) {
871 throw FileFormatException(
872 file->uri,
873 ("UNOIDL format: bad flags " + OUString::number(v)
874 + " for member " + memName
875 + " of polymorphic struct type template"));
877 mems.emplace_back(
878 memName, memType, v == 1,
879 readAnnotations(annotated, file, offset, &offset));
881 return new PolymorphicStructTypeTemplateEntity(
882 published, std::move(params), std::move(mems),
883 readAnnotations(annotated, file, offset));
885 case 4: // exception type without base
886 case 4 | 0x20: // exception type with base
888 ++offset;
889 OUString base;
890 if (flag) {
891 base = file->readIdxName(&offset);
892 if (base.isEmpty()) {
893 throw FileFormatException(
894 file->uri,
895 (u"UNOIDL format: empty base type name of exception"
896 " type"_ustr));
898 checkTypeName(file, base);
900 sal_uInt32 n = file->read32(offset);
901 if (n > SAL_MAX_INT32) {
902 throw FileFormatException(
903 file->uri,
904 u"UNOIDL format: too many direct members of exception type"_ustr);
906 offset += 4;
907 std::vector< ExceptionTypeEntity::Member > mems;
908 mems.reserve(n);
909 for (sal_uInt32 i = 0; i != n; ++i) {
910 OUString memName(file->readIdxName(&offset));
911 checkEntityName(file, memName);
912 OUString memType(file->readIdxName(&offset));
913 checkTypeName(file, memType);
914 mems.emplace_back(
915 memName, memType,
916 readAnnotations(annotated, file, offset, &offset));
918 return new ExceptionTypeEntity(
919 published, base, std::move(mems),
920 readAnnotations(annotated, file, offset));
922 case 5: // interface type
924 sal_uInt32 n = file->read32(offset + 1);
925 if (n > SAL_MAX_INT32) {
926 throw FileFormatException(
927 file->uri,
928 (u"UNOIDL format: too many direct mandatory bases of"
929 " interface type"_ustr));
931 offset += 5;
932 std::vector< AnnotatedReference > mandBases;
933 mandBases.reserve(n);
934 for (sal_uInt32 i = 0; i != n; ++i) {
935 OUString base(file->readIdxName(&offset));
936 checkTypeName(file, base);
937 mandBases.emplace_back(
938 base, readAnnotations(annotated, file, offset, &offset));
940 n = file->read32(offset);
941 if (n > SAL_MAX_INT32) {
942 throw FileFormatException(
943 file->uri,
944 (u"UNOIDL format: too many direct optional bases of"
945 " interface type"_ustr));
947 offset += 4;
948 std::vector< AnnotatedReference > optBases;
949 optBases.reserve(n);
950 for (sal_uInt32 i = 0; i != n; ++i) {
951 OUString base(file->readIdxName(&offset));
952 checkTypeName(file, base);
953 optBases.emplace_back(
954 base, readAnnotations(annotated, file, offset, &offset));
956 sal_uInt32 nAttrs = file->read32(offset);
957 if (nAttrs > SAL_MAX_INT32) {
958 throw FileFormatException(
959 file->uri,
960 (u"UNOIDL format: too many direct attributes of interface"
961 " type"_ustr));
963 offset += 4;
964 std::vector< InterfaceTypeEntity::Attribute > attrs;
965 attrs.reserve(nAttrs);
966 for (sal_uInt32 i = 0; i != nAttrs; ++i) {
967 v = file->read8(offset);
968 ++offset;
969 OUString attrName(file->readIdxName(&offset));
970 checkEntityName(file, attrName);
971 OUString attrType(file->readIdxName(&offset));
972 checkTypeName(file, attrType);
973 if (v > 0x03) {
974 throw FileFormatException(
975 file->uri,
976 ("UNOIDL format: bad flags for direct attribute "
977 + attrName + " of interface type"));
979 std::vector< OUString > getExcs;
980 sal_uInt32 m = file->read32(offset);
981 if (m > SAL_MAX_INT32) {
982 throw FileFormatException(
983 file->uri,
984 ("UNOIDL format: too many getter exceptions for direct"
985 " attribute " + attrName + " of interface type"));
987 offset += 4;
988 getExcs.reserve(m);
989 for (sal_uInt32 j = 0; j != m; ++j) {
990 OUString exc(file->readIdxName(&offset));
991 checkTypeName(file, exc);
992 getExcs.push_back(exc);
994 std::vector< OUString > setExcs;
995 if ((v & 0x02) == 0) {
996 m = file->read32(offset);
997 if (m > SAL_MAX_INT32) {
998 throw FileFormatException(
999 file->uri,
1000 ("UNOIDL format: too many setter exceptions for"
1001 " direct attribute " + attrName
1002 + " of interface type"));
1004 offset += 4;
1005 setExcs.reserve(m);
1006 for (sal_uInt32 j = 0; j != m; ++j) {
1007 OUString exc(file->readIdxName(&offset));
1008 checkTypeName(file, exc);
1009 setExcs.push_back(exc);
1012 attrs.emplace_back(
1013 attrName, attrType, (v & 0x01) != 0, (v & 0x02) != 0,
1014 std::move(getExcs), std::move(setExcs),
1015 readAnnotations(annotated, file, offset, &offset));
1017 sal_uInt32 nMeths = file->read32(offset);
1018 if (nMeths > SAL_MAX_INT32 - nAttrs) {
1019 throw FileFormatException(
1020 file->uri,
1021 (u"UNOIDL format: too many direct attributes and methods of"
1022 " interface type"_ustr));
1024 offset += 4;
1025 std::vector< InterfaceTypeEntity::Method > meths;
1026 meths.reserve(nMeths);
1027 for (sal_uInt32 i = 0; i != nMeths; ++i) {
1028 OUString methName(file->readIdxName(&offset));
1029 checkEntityName(file, methName);
1030 OUString methType(file->readIdxName(&offset));
1031 checkTypeName(file, methType);
1032 sal_uInt32 m = file->read32(offset);
1033 if (m > SAL_MAX_INT32) {
1034 throw FileFormatException(
1035 file->uri,
1036 ("UNOIDL format: too many parameters for method "
1037 + methName + " of interface type"));
1039 offset += 4;
1040 std::vector< InterfaceTypeEntity::Method::Parameter > params;
1041 params.reserve(m);
1042 for (sal_uInt32 j = 0; j != m; ++j) {
1043 v = file->read8(offset);
1044 ++offset;
1045 OUString paramName(file->readIdxName(&offset));
1046 checkEntityName(file, paramName);
1047 OUString paramType(file->readIdxName(&offset));
1048 checkTypeName(file, paramType);
1049 InterfaceTypeEntity::Method::Parameter::Direction dir;
1050 switch (v) {
1051 case 0:
1052 dir = InterfaceTypeEntity::Method::Parameter::
1053 DIRECTION_IN;
1054 break;
1055 case 1:
1056 dir = InterfaceTypeEntity::Method::Parameter::
1057 DIRECTION_OUT;
1058 break;
1059 case 2:
1060 dir = InterfaceTypeEntity::Method::Parameter::
1061 DIRECTION_IN_OUT;
1062 break;
1063 default:
1064 throw FileFormatException(
1065 file->uri,
1066 ("UNOIDL format: bad direction "
1067 + OUString::number(v) + " of parameter "
1068 + paramName + " for method " + methName
1069 + " of interface type"));
1071 params.emplace_back(paramName, paramType, dir);
1073 std::vector< OUString > excs;
1074 m = file->read32(offset);
1075 if (m > SAL_MAX_INT32) {
1076 throw FileFormatException(
1077 file->uri,
1078 ("UNOIDL format: too many exceptions for method "
1079 + methName + " of interface type"));
1081 offset += 4;
1082 excs.reserve(m);
1083 for (sal_uInt32 j = 0; j != m; ++j) {
1084 OUString exc(file->readIdxName(&offset));
1085 checkTypeName(file, exc);
1086 excs.push_back(exc);
1088 meths.emplace_back(
1089 methName, methType, std::move(params), std::move(excs),
1090 readAnnotations(annotated, file, offset, &offset));
1092 return new InterfaceTypeEntity(
1093 published, std::move(mandBases), std::move(optBases), std::move(attrs), std::move(meths),
1094 readAnnotations(annotated, file, offset));
1096 case 6: // typedef
1098 ++offset;
1099 OUString base(file->readIdxName(&offset));
1100 checkTypeName(file, base);
1101 return new TypedefEntity(
1102 published, base, readAnnotations(annotated, file, offset));
1104 case 7: // constant group
1106 sal_uInt32 n = file->read32(offset + 1);
1107 if (n > SAL_MAX_INT32) {
1108 throw FileFormatException(
1109 file->uri,
1110 u"UNOIDL format: too many constants in constant group"_ustr);
1112 if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
1113 // cannot overflow
1115 throw FileFormatException(
1116 file->uri,
1117 (u"UNOIDL format: constant group map offset + size too"
1118 " large"_ustr));
1120 MapEntry const * p = reinterpret_cast< MapEntry const * >(
1121 static_cast< char const * >(file->address) + offset + 5);
1122 std::vector< ConstantGroupEntity::Member > mems;
1123 mems.reserve(n);
1124 for (sal_uInt32 i = 0; i != n; ++i) {
1125 sal_uInt32 off = p[i].data.getUnsigned32();
1126 bool ann;
1127 ConstantValue val(readConstant(file, off, &off, &ann));
1128 mems.emplace_back(
1129 file->readNulName(p[i].name.getUnsigned32()), val,
1130 readAnnotations(ann, file, off));
1132 return new ConstantGroupEntity(
1133 published, std::move(mems),
1134 readAnnotations(annotated, file, offset + 5 + 8 * n));
1136 case 8: // single-interface--based service without default constructor
1137 case 8 | 0x20: // single-interface--based service with default constructor
1139 ++offset;
1140 OUString base(file->readIdxName(&offset));
1141 checkTypeName(file, base);
1142 std::vector< SingleInterfaceBasedServiceEntity::Constructor > ctors;
1143 if (flag) {
1144 ctors.push_back(
1145 SingleInterfaceBasedServiceEntity::Constructor());
1146 } else {
1147 sal_uInt32 n = file->read32(offset);
1148 if (n > SAL_MAX_INT32) {
1149 throw FileFormatException(
1150 file->uri,
1151 (u"UNOIDL format: too many constructors of"
1152 " single-interface--based service"_ustr));
1154 offset += 4;
1155 ctors.reserve(n);
1156 for (sal_uInt32 i = 0; i != n; ++i) {
1157 OUString ctorName(file->readIdxName(&offset));
1158 checkEntityName(file, ctorName);
1159 sal_uInt32 m = file->read32(offset);
1160 if (m > SAL_MAX_INT32) {
1161 throw FileFormatException(
1162 file->uri,
1163 ("UNOIDL format: too many parameters for"
1164 " constructor " + ctorName
1165 + " of single-interface--based service"));
1167 offset += 4;
1168 std::vector<
1169 SingleInterfaceBasedServiceEntity::Constructor::
1170 Parameter > params;
1171 params.reserve(m);
1172 for (sal_uInt32 j = 0; j != m; ++j) {
1173 v = file->read8(offset);
1174 ++offset;
1175 OUString paramName(file->readIdxName(&offset));
1176 checkEntityName(file, paramName);
1177 OUString paramType(file->readIdxName(&offset));
1178 checkTypeName(file, paramType);
1179 bool rest;
1180 switch (v) {
1181 case 0:
1182 rest = false;
1183 break;
1184 case 0x04:
1185 rest = true;
1186 break;
1187 default:
1188 throw FileFormatException(
1189 file->uri,
1190 ("UNOIDL format: bad mode "
1191 + OUString::number(v) + " of parameter "
1192 + paramName + " for constructor " + ctorName
1193 + " of single-interface--based service"));
1195 params.emplace_back(paramName, paramType, rest);
1197 std::vector< OUString > excs;
1198 m = file->read32(offset);
1199 if (m > SAL_MAX_INT32) {
1200 throw FileFormatException(
1201 file->uri,
1202 ("UNOIDL format: too many exceptions for"
1203 " constructor " + ctorName
1204 + " of single-interface--based service"));
1206 offset += 4;
1207 excs.reserve(m);
1208 for (sal_uInt32 j = 0; j != m; ++j) {
1209 OUString exc(file->readIdxName(&offset));
1210 checkTypeName(file, exc);
1211 excs.push_back(exc);
1213 ctors.push_back(
1214 SingleInterfaceBasedServiceEntity::Constructor(
1215 ctorName, std::move(params), std::move(excs),
1216 readAnnotations(annotated, file, offset, &offset)));
1219 return new SingleInterfaceBasedServiceEntity(
1220 published, base, std::move(ctors),
1221 readAnnotations(annotated, file, offset));
1223 case 9: // accumulation-based service
1225 sal_uInt32 n = file->read32(offset + 1);
1226 if (n > SAL_MAX_INT32) {
1227 throw FileFormatException(
1228 file->uri,
1229 (u"UNOIDL format: too many direct mandatory service bases of"
1230 " accumulation-based service"_ustr));
1232 offset += 5;
1233 std::vector< AnnotatedReference > mandServs;
1234 mandServs.reserve(n);
1235 for (sal_uInt32 i = 0; i != n; ++i) {
1236 OUString base(file->readIdxName(&offset));
1237 checkTypeName(file, base);
1238 mandServs.emplace_back(
1239 base, readAnnotations(annotated, file, offset, &offset));
1241 n = file->read32(offset);
1242 if (n > SAL_MAX_INT32) {
1243 throw FileFormatException(
1244 file->uri,
1245 (u"UNOIDL format: too many direct optional service bases of"
1246 " accumulation-based service"_ustr));
1248 offset += 4;
1249 std::vector< AnnotatedReference > optServs;
1250 optServs.reserve(n);
1251 for (sal_uInt32 i = 0; i != n; ++i) {
1252 OUString base(file->readIdxName(&offset));
1253 checkTypeName(file, base);
1254 optServs.emplace_back(
1255 base, readAnnotations(annotated, file, offset, &offset));
1257 n = file->read32(offset);
1258 if (n > SAL_MAX_INT32) {
1259 throw FileFormatException(
1260 file->uri,
1261 (u"UNOIDL format: too many direct mandatory interface bases"
1262 " of accumulation-based service"_ustr));
1264 offset += 4;
1265 std::vector< AnnotatedReference > mandIfcs;
1266 mandIfcs.reserve(n);
1267 for (sal_uInt32 i = 0; i != n; ++i) {
1268 OUString base(file->readIdxName(&offset));
1269 checkTypeName(file, base);
1270 mandIfcs.emplace_back(
1271 base, readAnnotations(annotated, file, offset, &offset));
1273 n = file->read32(offset);
1274 if (n > SAL_MAX_INT32) {
1275 throw FileFormatException(
1276 file->uri,
1277 (u"UNOIDL format: too many direct optional interface bases"
1278 " of accumulation-based service"_ustr));
1280 offset += 4;
1281 std::vector< AnnotatedReference > optIfcs;
1282 optIfcs.reserve(n);
1283 for (sal_uInt32 i = 0; i != n; ++i) {
1284 OUString base(file->readIdxName(&offset));
1285 checkTypeName(file, base);
1286 optIfcs.emplace_back(
1287 base, readAnnotations(annotated, file, offset, &offset));
1289 n = file->read32(offset);
1290 if (n > SAL_MAX_INT32) {
1291 throw FileFormatException(
1292 file->uri,
1293 (u"UNOIDL format: too many direct properties of"
1294 " accumulation-based service"_ustr));
1296 offset += 4;
1297 std::vector< AccumulationBasedServiceEntity::Property > props;
1298 props.reserve(n);
1299 for (sal_uInt32 i = 0; i != n; ++i) {
1300 sal_uInt16 attrs = file->read16(offset);
1301 offset += 2;
1302 OUString propName(file->readIdxName(&offset));
1303 checkEntityName(file, propName);
1304 OUString propType(file->readIdxName(&offset));
1305 checkTypeName(file, propType);
1306 if (attrs > 0x01FF) { // see css.beans.PropertyAttribute
1307 throw FileFormatException(
1308 file->uri,
1309 ("UNOIDL format: bad mode " + OUString::number(v)
1310 + " of property " + propName
1311 + " for accumulation-based service"));
1313 props.emplace_back(
1314 propName, propType,
1315 static_cast<
1316 AccumulationBasedServiceEntity::Property::Attributes >(
1317 attrs),
1318 readAnnotations(annotated, file, offset, &offset));
1320 return new AccumulationBasedServiceEntity(
1321 published, std::move(mandServs), std::move(optServs), std::move(mandIfcs), std::move(optIfcs), std::move(props),
1322 readAnnotations(annotated, file, offset));
1324 case 10: // interface-based singleton
1326 ++offset;
1327 OUString base(file->readIdxName(&offset));
1328 checkTypeName(file, base);
1329 return new InterfaceBasedSingletonEntity(
1330 published, base, readAnnotations(annotated, file, offset));
1332 case 11: // service-based singleton
1334 ++offset;
1335 OUString base(file->readIdxName(&offset));
1336 checkTypeName(file, base);
1337 return new ServiceBasedSingletonEntity(
1338 published, base, readAnnotations(annotated, file, offset));
1340 default:
1341 throw FileFormatException(
1342 file->uri, "UNOIDL format: bad type byte " + OUString::number(v));
1348 UnoidlProvider::UnoidlProvider(OUString const & uri): file_(new MappedFile(uri))
1350 if (file_->size < 8 || std::memcmp(file_->address, "UNOIDL\xFF\0", 8) != 0)
1352 throw FileFormatException(
1353 file_->uri,
1354 u"UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1355 " 0"_ustr);
1357 sal_uInt32 off = file_->read32(8);
1358 map_.map.size = file_->read32(12);
1359 if (off + 8 * sal_uInt64(map_.map.size) > file_->size) { // cannot overflow
1360 throw FileFormatException(
1361 file_->uri, u"UNOIDL format: root map offset + size too large"_ustr);
1363 map_.map.begin = reinterpret_cast< MapEntry const * >(
1364 static_cast< char const * >(file_->address) + off);
1365 map_.trace.insert(map_.map);
1368 rtl::Reference< MapCursor > UnoidlProvider::createRootCursor() const {
1369 return new UnoidlCursor(
1370 file_, const_cast<UnoidlProvider *>(this),
1371 rtl::Reference<UnoidlModuleEntity>(), map_);
1374 rtl::Reference< Entity > UnoidlProvider::findEntity(OUString const & name) const
1376 NestedMap map(map_);
1377 bool cgroup = false;
1378 for (sal_Int32 i = 0;;) {
1379 sal_Int32 j = name.indexOf('.', i);
1380 if (j == -1) {
1381 j = name.getLength();
1383 sal_Int32 off = findInMap(
1384 file_, map.map.begin, map.map.size, name, i, j - i);
1385 if (off == 0) {
1386 return rtl::Reference< Entity >();
1388 if (j == name.getLength()) {
1389 return cgroup
1390 ? rtl::Reference< Entity >()
1391 : readEntity(file_, off, std::set(map.trace));
1393 if (cgroup) {
1394 return rtl::Reference< Entity >();
1395 //TODO: throw an exception instead here, where the segments of a
1396 // constant's name are a prefix of the requested name's
1397 // segments?
1399 int v = file_->read8(off);
1400 if (v != 0) { // module
1401 if ((v & 0x3F) == 7) { // constant group
1402 cgroup = true;
1403 } else {
1404 return rtl::Reference< Entity >();
1405 //TODO: throw an exception instead here, where the segments
1406 // of a non-module, non-constant-group entity's name are a
1407 // prefix of the requested name's segments?
1410 map.map.size = file_->read32(off + 1);
1411 if (sal_uInt64(off) + 5 + 8 * sal_uInt64(map.map.size) > file_->size)
1412 // cannot overflow
1414 throw FileFormatException(
1415 file_->uri, u"UNOIDL format: map offset + size too large"_ustr);
1417 map.map.begin = reinterpret_cast< MapEntry const * >(
1418 static_cast< char const * >(file_->address) + off + 5);
1419 if (!map.trace.insert(map.map).second) {
1420 throw FileFormatException(
1421 file_->uri, u"UNOIDL format: recursive map"_ustr);
1423 i = j + 1;
1427 UnoidlProvider::~UnoidlProvider() noexcept {}
1431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */