1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <sal/config.h>
16 #include <string_view>
20 #include <o3tl/string_view.hxx>
21 #include <osl/endian.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
{
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
); }
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
)
87 // sizeof (Memory16) == 2
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
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 {
110 unsigned char buf
[4];
111 float f
; // assuming float is ISO 60599 binary32
113 #if defined OSL_LITENDIAN
128 // sizeof (Memory64) == 8
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 {
145 unsigned char buf
[8];
146 double d
; // assuming double is ISO 60599 binary64
148 #if defined OSL_LITENDIAN
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"
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
) {
192 for (size_t i
= 0; i
!= type
.size(); ++i
) {
193 sal_Unicode c
= type
[i
];
195 if (!scoped
|| i
== 0 || i
== type
.size() - 1
196 || type
[i
- 1] == '.')
200 } else if (!rtl::isAsciiAlphanumeric(c
) && c
!= '_') {
208 rtl::Reference
< MappedFile
> const & file
, std::u16string_view type
)
210 std::u16string_view
nucl(type
);
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
));
217 ++i
; // skip '<' or ','
219 for (size_t level
= 0; j
!= nucl
.size(); ++j
) {
220 sal_Unicode c
= nucl
[j
];
225 } else if (c
== '<') {
227 } else if (c
== '>') {
234 if (j
!= nucl
.size()) {
235 checkTypeName(file
, nucl
.substr(i
, j
- i
));
239 } while (i
!= nucl
.size() && nucl
[i
] != '>');
240 if (i
!= nucl
.size() - 1 || nucl
[i
] != '>' || !args
) {
241 tmpl
= {}; // bad input
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
);
265 case osl_File_E_None
:
267 case osl_File_E_NOENT
:
268 throw NoSuchFileException(uri
);
270 throw FileFormatException(uri
, "cannot open: " + OUString::number(e
));
272 e
= osl_getFileSize(handle
, &size
);
273 if (e
== osl_File_E_None
) {
275 handle
, &address
, size
, 0, osl_File_MapFlag_RandomAccess
);
277 if (e
!= osl_File_E_None
) {
278 oslFileError e2
= osl_closeFile(handle
);
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 {
288 if (offset
> size
- 1) {
289 throw FileFormatException(
290 uri
, u
"UNOIDL format: offset for 8-bit value too large"_ustr
);
295 sal_uInt16
MappedFile::read16(sal_uInt32 offset
) const {
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 {
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 {
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 {
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 {
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
) {
342 throw FileFormatException(
343 uri
, u
"UNOIDL format: offset for string too large"_ustr
);
345 sal_uInt64 end
= offset
;
348 throw FileFormatException(
349 uri
, u
"UNOIDL format: string misses trailing NUL"_ustr
);
351 if (static_cast< char const * >(address
)[end
] == 0) {
355 if (end
- offset
> SAL_MAX_INT32
) {
356 throw FileFormatException(uri
, u
"UNOIDL format: string too long"_ustr
);
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
);
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 {
381 assert(offset
<= size
- 1);
382 return static_cast< char const * >(address
)[offset
];
385 sal_uInt16
MappedFile::get16(sal_uInt32 offset
) const {
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 {
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 {
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 {
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 {
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
);
426 if ((len
& 0x80000000) == 0) {
431 off
= len
& ~0x80000000;
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
);
443 if (!rtl_convertStringToUString(
444 &name
.pData
, static_cast< char const * >(address
) + off
+ 4, len
,
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
);
456 // sizeof (MapEntry) == 8
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
);
469 enum Compare
{ COMPARE_LESS
, COMPARE_GREATER
, COMPARE_EQUAL
};
472 rtl::Reference
< MappedFile
> const & file
, std::u16string_view name
,
473 sal_Int32 nameOffset
, sal_Int32 nameLength
, MapEntry
const * entry
)
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
)[
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
);
503 static_cast< unsigned char const * >(file
->address
)[off
+ min
] == 0
504 ? COMPARE_EQUAL
: COMPARE_LESS
;
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
)
518 sal_uInt32 n
= mapSize
/ 2;
519 MapEntry
const * p
= mapBegin
+ n
;
520 switch (compare(file
, name
, nameOffset
, nameLength
, p
)) {
522 return findInMap(file
, mapBegin
, n
, name
, nameOffset
, nameLength
);
523 case COMPARE_GREATER
:
525 file
, p
+ 1, mapSize
- n
- 1, name
, nameOffset
, nameLength
);
526 default: // COMPARE_EQUAL
529 sal_uInt32 off
= mapBegin
[n
].data
.getUnsigned32();
531 throw FileFormatException(
532 file
->uri
, u
"UNOIDL format: map entry data offset is null"_ustr
);
537 #if defined(__COVERITY__) && __COVERITY_MAJOR__ <= 2023
538 extern "C" void __coverity_tainted_data_sanitize__(void *);
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
;
547 sal_uInt32 n
= file
->read32(offset
);
548 #if defined(__COVERITY__) && __COVERITY_MAJOR__ <= 2023
549 __coverity_tainted_data_sanitize__(&n
);
552 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
553 ans
.push_back(file
->readIdxString(&offset
));
556 if (newOffset
!= nullptr) {
562 ConstantValue
readConstant(
563 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
564 sal_uInt32
* newOffset
, bool * annotated
)
567 int v
= file
->read8(offset
);
569 if (annotated
!= nullptr) {
570 *annotated
= (v
& 0x80) != 0;
574 v
= file
->read8(offset
+ 1);
575 if (newOffset
!= nullptr) {
576 *newOffset
= offset
+ 2;
580 return ConstantValue(false);
582 return ConstantValue(true);
584 throw FileFormatException(
586 ("UNOIDL format: bad boolean constant value "
587 + OUString::number(v
)));
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
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));
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));
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));
636 if (newOffset
!= nullptr) {
637 *newOffset
= offset
+ 5;
639 return ConstantValue(file
->readIso60599Binary32(offset
+ 1));
641 if (newOffset
!= nullptr) {
642 *newOffset
= offset
+ 9;
644 return ConstantValue(file
->readIso60599Binary64(offset
+ 1));
646 throw FileFormatException(
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
{
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
)),
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_
;
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());
687 file_
, map_
.map
.begin
[index_
].data
.getUnsigned32(), std::set(map_
.trace
));
693 class UnoidlModuleEntity
: public ModuleEntity
{
696 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 mapOffset
,
697 sal_uInt32 mapSize
, std::set
<Map
> && trace
):
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
);
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_
;
726 std::vector
< OUString
> UnoidlModuleEntity::getMemberNames() const {
727 std::vector
< OUString
> names
;
728 for (sal_uInt32 i
= 0; i
!= map_
.map
.size
; ++i
) {
730 file_
->readNulName(map_
.map
.begin
[i
].name
.getUnsigned32()));
735 rtl::Reference
< Entity
> readEntity(
736 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
737 std::set
<Map
> && trace
)
740 int v
= file
->read8(offset
);
742 bool published
= (v
& 0x80) != 0;
743 bool annotated
= (v
& 0x40) != 0;
744 bool flag
= (v
& 0x20) != 0;
749 throw FileFormatException(
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
)
762 throw FileFormatException(
764 u
"UNOIDL format: module map offset + size too large"_ustr
);
766 return new UnoidlModuleEntity(file
, offset
+ 5, n
, std::move(trace
));
770 sal_uInt32 n
= file
->read32(offset
+ 1);
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
);
780 std::vector
< EnumTypeEntity::Member
> mems
;
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
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
804 base
= file
->readIdxName(&offset
);
805 if (base
.isEmpty()) {
806 throw FileFormatException(
808 (u
"UNOIDL format: empty base type name of plain struct"
811 checkTypeName(file
, base
);
813 sal_uInt32 n
= file
->read32(offset
);
814 if (n
> SAL_MAX_INT32
) {
815 throw FileFormatException(
817 (u
"UNOIDL format: too many direct members of plain struct"
821 std::vector
< PlainStructTypeEntity::Member
> mems
;
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
);
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(
842 (u
"UNOIDL format: too many type parameters of polymorphic"
843 " struct type template"_ustr
));
846 std::vector
< OUString
> params
;
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(
857 (u
"UNOIDL format: too many members of polymorphic struct"
858 " type template"_ustr
));
861 std::vector
< PolymorphicStructTypeTemplateEntity::Member
> mems
;
863 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
864 v
= file
->read8(offset
);
866 OUString
memName(file
->readIdxName(&offset
));
867 checkEntityName(file
, memName
);
868 OUString
memType(file
->readIdxName(&offset
));
869 checkTypeName(file
, memType
);
871 throw FileFormatException(
873 ("UNOIDL format: bad flags " + OUString::number(v
)
874 + " for member " + memName
875 + " of polymorphic struct type template"));
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
891 base
= file
->readIdxName(&offset
);
892 if (base
.isEmpty()) {
893 throw FileFormatException(
895 (u
"UNOIDL format: empty base type name of exception"
898 checkTypeName(file
, base
);
900 sal_uInt32 n
= file
->read32(offset
);
901 if (n
> SAL_MAX_INT32
) {
902 throw FileFormatException(
904 u
"UNOIDL format: too many direct members of exception type"_ustr
);
907 std::vector
< ExceptionTypeEntity::Member
> mems
;
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
);
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(
928 (u
"UNOIDL format: too many direct mandatory bases of"
929 " interface type"_ustr
));
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(
944 (u
"UNOIDL format: too many direct optional bases of"
945 " interface type"_ustr
));
948 std::vector
< AnnotatedReference
> optBases
;
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(
960 (u
"UNOIDL format: too many direct attributes of interface"
964 std::vector
< InterfaceTypeEntity::Attribute
> attrs
;
965 attrs
.reserve(nAttrs
);
966 for (sal_uInt32 i
= 0; i
!= nAttrs
; ++i
) {
967 v
= file
->read8(offset
);
969 OUString
attrName(file
->readIdxName(&offset
));
970 checkEntityName(file
, attrName
);
971 OUString
attrType(file
->readIdxName(&offset
));
972 checkTypeName(file
, attrType
);
974 throw FileFormatException(
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(
984 ("UNOIDL format: too many getter exceptions for direct"
985 " attribute " + attrName
+ " of interface type"));
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(
1000 ("UNOIDL format: too many setter exceptions for"
1001 " direct attribute " + attrName
1002 + " of interface type"));
1006 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1007 OUString
exc(file
->readIdxName(&offset
));
1008 checkTypeName(file
, exc
);
1009 setExcs
.push_back(exc
);
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(
1021 (u
"UNOIDL format: too many direct attributes and methods of"
1022 " interface type"_ustr
));
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(
1036 ("UNOIDL format: too many parameters for method "
1037 + methName
+ " of interface type"));
1040 std::vector
< InterfaceTypeEntity::Method::Parameter
> params
;
1042 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1043 v
= file
->read8(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
;
1052 dir
= InterfaceTypeEntity::Method::Parameter::
1056 dir
= InterfaceTypeEntity::Method::Parameter::
1060 dir
= InterfaceTypeEntity::Method::Parameter::
1064 throw FileFormatException(
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(
1078 ("UNOIDL format: too many exceptions for method "
1079 + methName
+ " of interface type"));
1083 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1084 OUString
exc(file
->readIdxName(&offset
));
1085 checkTypeName(file
, exc
);
1086 excs
.push_back(exc
);
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
));
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(
1110 u
"UNOIDL format: too many constants in constant group"_ustr
);
1112 if (sal_uInt64(offset
) + 5 + 8 * sal_uInt64(n
) > file
->size
)
1115 throw FileFormatException(
1117 (u
"UNOIDL format: constant group map offset + size too"
1120 MapEntry
const * p
= reinterpret_cast< MapEntry
const * >(
1121 static_cast< char const * >(file
->address
) + offset
+ 5);
1122 std::vector
< ConstantGroupEntity::Member
> mems
;
1124 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1125 sal_uInt32 off
= p
[i
].data
.getUnsigned32();
1127 ConstantValue
val(readConstant(file
, off
, &off
, &ann
));
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
1140 OUString
base(file
->readIdxName(&offset
));
1141 checkTypeName(file
, base
);
1142 std::vector
< SingleInterfaceBasedServiceEntity::Constructor
> ctors
;
1145 SingleInterfaceBasedServiceEntity::Constructor());
1147 sal_uInt32 n
= file
->read32(offset
);
1148 if (n
> SAL_MAX_INT32
) {
1149 throw FileFormatException(
1151 (u
"UNOIDL format: too many constructors of"
1152 " single-interface--based service"_ustr
));
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(
1163 ("UNOIDL format: too many parameters for"
1164 " constructor " + ctorName
1165 + " of single-interface--based service"));
1169 SingleInterfaceBasedServiceEntity::Constructor::
1172 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1173 v
= file
->read8(offset
);
1175 OUString
paramName(file
->readIdxName(&offset
));
1176 checkEntityName(file
, paramName
);
1177 OUString
paramType(file
->readIdxName(&offset
));
1178 checkTypeName(file
, paramType
);
1188 throw FileFormatException(
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(
1202 ("UNOIDL format: too many exceptions for"
1203 " constructor " + ctorName
1204 + " of single-interface--based service"));
1208 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1209 OUString
exc(file
->readIdxName(&offset
));
1210 checkTypeName(file
, exc
);
1211 excs
.push_back(exc
);
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(
1229 (u
"UNOIDL format: too many direct mandatory service bases of"
1230 " accumulation-based service"_ustr
));
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(
1245 (u
"UNOIDL format: too many direct optional service bases of"
1246 " accumulation-based service"_ustr
));
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(
1261 (u
"UNOIDL format: too many direct mandatory interface bases"
1262 " of accumulation-based service"_ustr
));
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(
1277 (u
"UNOIDL format: too many direct optional interface bases"
1278 " of accumulation-based service"_ustr
));
1281 std::vector
< AnnotatedReference
> optIfcs
;
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(
1293 (u
"UNOIDL format: too many direct properties of"
1294 " accumulation-based service"_ustr
));
1297 std::vector
< AccumulationBasedServiceEntity::Property
> props
;
1299 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1300 sal_uInt16 attrs
= file
->read16(offset
);
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(
1309 ("UNOIDL format: bad mode " + OUString::number(v
)
1310 + " of property " + propName
1311 + " for accumulation-based service"));
1316 AccumulationBasedServiceEntity::Property::Attributes
>(
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
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
1335 OUString
base(file
->readIdxName(&offset
));
1336 checkTypeName(file
, base
);
1337 return new ServiceBasedSingletonEntity(
1338 published
, base
, readAnnotations(annotated
, file
, offset
));
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(
1354 u
"UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
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
);
1381 j
= name
.getLength();
1383 sal_Int32 off
= findInMap(
1384 file_
, map
.map
.begin
, map
.map
.size
, name
, i
, j
- i
);
1386 return rtl::Reference
< Entity
>();
1388 if (j
== name
.getLength()) {
1390 ? rtl::Reference
< Entity
>()
1391 : readEntity(file_
, off
, std::set(map
.trace
));
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
1399 int v
= file_
->read8(off
);
1400 if (v
!= 0) { // module
1401 if ((v
& 0x3F) == 7) { // constant group
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
)
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
);
1427 UnoidlProvider::~UnoidlProvider() noexcept
{}
1431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */