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>
19 #include <osl/endian.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
{
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
); }
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
)
85 // sizeof (Memory16) == 2
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
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 {
108 unsigned char buf
[4];
109 float f
; // assuming float is ISO 60599 binary32
111 #if defined OSL_LITENDIAN
126 // sizeof (Memory64) == 8
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 {
143 unsigned char buf
[8];
144 double d
; // assuming double is ISO 60599 binary64
146 #if defined OSL_LITENDIAN
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"
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()) {
190 for (sal_Int32 i
= 0; i
!= type
.getLength(); ++i
) {
191 sal_Unicode c
= type
[i
];
193 if (!scoped
|| i
== 0 || i
== type
.getLength() - 1
194 || type
[i
- 1] == '.')
198 } else if (!rtl::isAsciiAlphanumeric(c
) && c
!= '_') {
206 rtl::Reference
< MappedFile
> const & file
, OUString
const & type
)
210 while (nucl
.startsWith("[]", &nucl
)) {}
211 sal_Int32 i
= nucl
.indexOf('<');
213 OUString
tmpl(nucl
.copy(0, i
));
215 ++i
; // skip '<' or ','
217 for (sal_Int32 level
= 0; j
!= nucl
.getLength(); ++j
) {
218 sal_Unicode c
= nucl
[j
];
223 } else if (c
== '<') {
225 } else if (c
== '>') {
232 if (j
!= nucl
.getLength()) {
233 checkTypeName(file
, nucl
.copy(i
, j
- i
));
237 } while (i
!= nucl
.getLength() && nucl
[i
] != '>');
238 if (i
!= nucl
.getLength() - 1 || nucl
[i
] != '>' || !args
) {
239 tmpl
.clear(); // bad input
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
);
263 case osl_File_E_None
:
265 case osl_File_E_NOENT
:
266 throw NoSuchFileException(uri
);
268 throw FileFormatException(uri
, "cannot open: " + OUString::number(e
));
270 e
= osl_getFileSize(handle
, &size
);
271 if (e
== osl_File_E_None
) {
273 handle
, &address
, size
, 0, osl_File_MapFlag_RandomAccess
);
275 if (e
!= osl_File_E_None
) {
276 oslFileError e2
= osl_closeFile(handle
);
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 {
286 if (offset
> size
- 1) {
287 throw FileFormatException(
288 uri
, "UNOIDL format: offset for 8-bit value too large");
293 sal_uInt16
MappedFile::read16(sal_uInt32 offset
) const {
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 {
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 {
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 {
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 {
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
) {
340 throw FileFormatException(
341 uri
, "UNOIDL format: offset for string too large");
343 sal_uInt64 end
= offset
;
346 throw FileFormatException(
347 uri
, "UNOIDL format: string misses trailing NUL");
349 if (static_cast< char const * >(address
)[end
] == 0) {
353 if (end
- offset
> SAL_MAX_INT32
) {
354 throw FileFormatException(uri
, "UNOIDL format: string too long");
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
);
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 {
379 assert(offset
<= size
- 1);
380 return static_cast< char const * >(address
)[offset
];
383 sal_uInt16
MappedFile::get16(sal_uInt32 offset
) const {
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 {
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 {
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 {
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 {
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
);
424 if ((len
& 0x80000000) == 0) {
429 off
= len
& ~0x80000000;
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");
441 if (!rtl_convertStringToUString(
442 &name
.pData
, static_cast< char const * >(address
) + off
+ 4, len
,
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");
454 // sizeof (MapEntry) == 8
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
);
467 enum Compare
{ COMPARE_LESS
, COMPARE_GREATER
, COMPARE_EQUAL
};
470 rtl::Reference
< MappedFile
> const & file
, std::u16string_view name
,
471 sal_Int32 nameOffset
, sal_Int32 nameLength
, MapEntry
const * entry
)
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
)[
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");
501 static_cast< unsigned char const * >(file
->address
)[off
+ min
] == 0
502 ? COMPARE_EQUAL
: COMPARE_LESS
;
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
)
516 sal_uInt32 n
= mapSize
/ 2;
517 MapEntry
const * p
= mapBegin
+ n
;
518 switch (compare(file
, name
, nameOffset
, nameLength
, p
)) {
520 return findInMap(file
, mapBegin
, n
, name
, nameOffset
, nameLength
);
521 case COMPARE_GREATER
:
523 file
, p
+ 1, mapSize
- n
- 1, name
, nameOffset
, nameLength
);
524 default: // COMPARE_EQUAL
527 sal_uInt32 off
= mapBegin
[n
].data
.getUnsigned32();
529 throw FileFormatException(
530 file
->uri
, "UNOIDL format: map entry data offset is null");
535 #if defined(__COVERITY__)
536 extern "C" void __coverity_tainted_data_sanitize__(void *);
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
;
545 sal_uInt32 n
= file
->read32(offset
);
546 #if defined(__COVERITY__)
547 __coverity_tainted_data_sanitize__(&n
);
550 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
551 ans
.push_back(file
->readIdxString(&offset
));
554 if (newOffset
!= nullptr) {
560 ConstantValue
readConstant(
561 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
562 sal_uInt32
* newOffset
, bool * annotated
)
565 int v
= file
->read8(offset
);
567 if (annotated
!= nullptr) {
568 *annotated
= (v
& 0x80) != 0;
572 v
= file
->read8(offset
+ 1);
573 if (newOffset
!= nullptr) {
574 *newOffset
= offset
+ 2;
578 return ConstantValue(false);
580 return ConstantValue(true);
582 throw FileFormatException(
584 ("UNOIDL format: bad boolean constant value "
585 + OUString::number(v
)));
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
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));
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));
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));
634 if (newOffset
!= nullptr) {
635 *newOffset
= offset
+ 5;
637 return ConstantValue(file
->readIso60599Binary32(offset
+ 1));
639 if (newOffset
!= nullptr) {
640 *newOffset
= offset
+ 9;
642 return ConstantValue(file
->readIso60599Binary64(offset
+ 1));
644 throw FileFormatException(
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
{
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
),
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_
;
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());
685 file_
, map_
.map
.begin
[index_
].data
.getUnsigned32(), std::set(map_
.trace
));
691 class UnoidlModuleEntity
: public ModuleEntity
{
694 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 mapOffset
,
695 sal_uInt32 mapSize
, std::set
<Map
> && trace
):
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");
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_
;
724 std::vector
< OUString
> UnoidlModuleEntity::getMemberNames() const {
725 std::vector
< OUString
> names
;
726 for (sal_uInt32 i
= 0; i
!= map_
.map
.size
; ++i
) {
728 file_
->readNulName(map_
.map
.begin
[i
].name
.getUnsigned32()));
733 rtl::Reference
< Entity
> readEntity(
734 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
735 std::set
<Map
> && trace
)
738 int v
= file
->read8(offset
);
740 bool published
= (v
& 0x80) != 0;
741 bool annotated
= (v
& 0x40) != 0;
742 bool flag
= (v
& 0x20) != 0;
747 throw FileFormatException(
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
)
760 throw FileFormatException(
762 "UNOIDL format: module map offset + size too large");
764 return new UnoidlModuleEntity(file
, offset
+ 5, n
, std::move(trace
));
768 sal_uInt32 n
= file
->read32(offset
+ 1);
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");
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
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
801 base
= file
->readIdxName(&offset
);
802 if (base
.isEmpty()) {
803 throw FileFormatException(
805 ("UNOIDL format: empty base type name of plain struct"
808 checkTypeName(file
, base
);
810 sal_uInt32 n
= file
->read32(offset
);
811 if (n
> SAL_MAX_INT32
) {
812 throw FileFormatException(
814 ("UNOIDL format: too many direct members of plain struct"
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
);
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(
838 ("UNOIDL format: too many type parameters of polymorphic"
839 " struct type template"));
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(
852 ("UNOIDL format: too many members of polymorphic struct"
856 std::vector
< PolymorphicStructTypeTemplateEntity::Member
> mems
;
857 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
858 v
= file
->read8(offset
);
860 OUString
memName(file
->readIdxName(&offset
));
861 checkEntityName(file
, memName
);
862 OUString
memType(file
->readIdxName(&offset
));
863 checkTypeName(file
, memType
);
865 throw FileFormatException(
867 ("UNOIDL format: bad flags " + OUString::number(v
)
868 + " for member " + memName
869 + " of polymorphic struct type template"));
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
885 base
= file
->readIdxName(&offset
);
886 if (base
.isEmpty()) {
887 throw FileFormatException(
889 ("UNOIDL format: empty base type name of exception"
892 checkTypeName(file
, base
);
894 sal_uInt32 n
= file
->read32(offset
);
895 if (n
> SAL_MAX_INT32
) {
896 throw FileFormatException(
898 "UNOIDL format: too many direct members of exception type");
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
);
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(
921 ("UNOIDL format: too many direct mandatory bases of"
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(
936 ("UNOIDL format: too many direct optional bases of"
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(
951 ("UNOIDL format: too many direct attributes of interface"
955 std::vector
< InterfaceTypeEntity::Attribute
> attrs
;
956 for (sal_uInt32 i
= 0; i
!= nAttrs
; ++i
) {
957 v
= file
->read8(offset
);
959 OUString
attrName(file
->readIdxName(&offset
));
960 checkEntityName(file
, attrName
);
961 OUString
attrType(file
->readIdxName(&offset
));
962 checkTypeName(file
, attrType
);
964 throw FileFormatException(
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(
974 ("UNOIDL format: too many getter exceptions for direct"
975 " attribute " + attrName
+ " of interface type"));
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(
989 ("UNOIDL format: too many setter exceptions for"
990 " direct attribute " + attrName
991 + " of interface type"));
994 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
995 OUString
exc(file
->readIdxName(&offset
));
996 checkTypeName(file
, exc
);
997 setExcs
.push_back(exc
);
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(
1009 ("UNOIDL format: too many direct attributes and methods of"
1010 " interface type"));
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(
1024 ("UNOIDL format: too many parameters for method "
1025 + methName
+ " of interface type"));
1028 std::vector
< InterfaceTypeEntity::Method::Parameter
> params
;
1029 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1030 v
= file
->read8(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
;
1039 dir
= InterfaceTypeEntity::Method::Parameter::
1043 dir
= InterfaceTypeEntity::Method::Parameter::
1047 dir
= InterfaceTypeEntity::Method::Parameter::
1051 throw FileFormatException(
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(
1065 ("UNOIDL format: too many exceptions for method "
1066 + methName
+ " of interface type"));
1069 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1070 OUString
exc(file
->readIdxName(&offset
));
1071 checkTypeName(file
, exc
);
1072 excs
.push_back(exc
);
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
));
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(
1096 "UNOIDL format: too many constants in constant group");
1098 if (sal_uInt64(offset
) + 5 + 8 * sal_uInt64(n
) > file
->size
)
1101 throw FileFormatException(
1103 ("UNOIDL format: constant group map offset + size too"
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();
1112 ConstantValue
val(readConstant(file
, off
, &off
, &ann
));
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
1125 OUString
base(file
->readIdxName(&offset
));
1126 checkTypeName(file
, base
);
1127 std::vector
< SingleInterfaceBasedServiceEntity::Constructor
> ctors
;
1130 SingleInterfaceBasedServiceEntity::Constructor());
1132 sal_uInt32 n
= file
->read32(offset
);
1133 if (n
> SAL_MAX_INT32
) {
1134 throw FileFormatException(
1136 ("UNOIDL format: too many constructors of"
1137 " single-interface--based service"));
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(
1147 ("UNOIDL format: too many parameters for"
1148 " constructor " + ctorName
1149 + " of single-interface--based service"));
1153 SingleInterfaceBasedServiceEntity::Constructor::
1155 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1156 v
= file
->read8(offset
);
1158 OUString
paramName(file
->readIdxName(&offset
));
1159 checkEntityName(file
, paramName
);
1160 OUString
paramType(file
->readIdxName(&offset
));
1161 checkTypeName(file
, paramType
);
1171 throw FileFormatException(
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(
1185 ("UNOIDL format: too many exceptions for"
1186 " constructor " + ctorName
1187 + " of single-interface--based service"));
1190 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1191 OUString
exc(file
->readIdxName(&offset
));
1192 checkTypeName(file
, exc
);
1193 excs
.push_back(exc
);
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(
1211 ("UNOIDL format: too many direct mandatory service bases of"
1212 " accumulation-based service"));
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(
1226 ("UNOIDL format: too many direct optional service bases of"
1227 " accumulation-based service"));
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(
1241 ("UNOIDL format: too many direct mandatory interface bases"
1242 " of accumulation-based service"));
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(
1256 ("UNOIDL format: too many direct optional interface bases"
1257 " of accumulation-based service"));
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(
1271 ("UNOIDL format: too many direct properties of"
1272 " accumulation-based service"));
1275 std::vector
< AccumulationBasedServiceEntity::Property
> props
;
1276 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1277 sal_uInt16 attrs
= file
->read16(offset
);
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(
1286 ("UNOIDL format: bad mode " + OUString::number(v
)
1287 + " of property " + propName
1288 + " for accumulation-based service"));
1293 AccumulationBasedServiceEntity::Property::Attributes
>(
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
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
1312 OUString
base(file
->readIdxName(&offset
));
1313 checkTypeName(file
, base
);
1314 return new ServiceBasedSingletonEntity(
1315 published
, base
, readAnnotations(annotated
, file
, offset
));
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(
1331 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
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
);
1358 j
= name
.getLength();
1360 sal_Int32 off
= findInMap(
1361 file_
, map
.map
.begin
, map
.map
.size
, name
, i
, j
- i
);
1363 return rtl::Reference
< Entity
>();
1365 if (j
== name
.getLength()) {
1367 ? rtl::Reference
< Entity
>()
1368 : readEntity(file_
, off
, std::set(map
.trace
));
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
1376 int v
= file_
->read8(off
);
1377 if (v
!= 0) { // module
1378 if ((v
& 0x3F) == 7) { // constant group
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
)
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");
1404 UnoidlProvider::~UnoidlProvider() noexcept
{}
1408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */