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>
18 #include <osl/endian.h>
20 #include <rtl/character.hxx>
21 #include <rtl/ref.hxx>
22 #include <rtl/textenc.h>
23 #include <rtl/textcvt.h>
24 #include <rtl/ustring.hxx>
25 #include <sal/log.hxx>
26 #include <sal/types.h>
27 #include <salhelper/simplereferenceobject.hxx>
28 #include <unoidl/unoidl.hxx>
30 #include "unoidlprovider.hxx"
32 namespace unoidl
{ namespace detail
{
34 class MappedFile
: public salhelper::SimpleReferenceObject
{
36 explicit MappedFile(OUString
const & fileUrl
);
38 sal_uInt8
read8(sal_uInt32 offset
) const;
40 sal_uInt16
read16(sal_uInt32 offset
) const;
42 sal_uInt32
read32(sal_uInt32 offset
) const;
44 sal_uInt64
read64(sal_uInt32 offset
) const;
46 float readIso60599Binary32(sal_uInt32 offset
) const;
48 double readIso60599Binary64(sal_uInt32 offset
) const;
50 OUString
readNulName(sal_uInt32 offset
) /*const*/;
52 OUString
readIdxName(sal_uInt32
* offset
) const
53 { return readIdxString(offset
, RTL_TEXTENCODING_ASCII_US
); }
55 OUString
readIdxString(sal_uInt32
* offset
) const
56 { return readIdxString(offset
, RTL_TEXTENCODING_UTF8
); }
64 virtual ~MappedFile() override
;
66 sal_uInt8
get8(sal_uInt32 offset
) const;
68 sal_uInt16
get16(sal_uInt32 offset
) const;
70 sal_uInt32
get32(sal_uInt32 offset
) const;
72 sal_uInt64
get64(sal_uInt32 offset
) const;
74 float getIso60599Binary32(sal_uInt32 offset
) const;
76 double getIso60599Binary64(sal_uInt32 offset
) const;
78 OUString
readIdxString(sal_uInt32
* offset
, rtl_TextEncoding encoding
)
84 // sizeof (Memory16) == 2
86 unsigned char const byte
[2];
88 sal_uInt16
getUnsigned16() const {
89 return static_cast< sal_uInt16
>(byte
[0])
90 | (static_cast< sal_uInt16
>(byte
[1]) << 8);
94 // sizeof (Memory32) == 4
96 unsigned char const byte
[4];
98 sal_uInt32
getUnsigned32() const {
99 return static_cast< sal_uInt32
>(byte
[0])
100 | (static_cast< sal_uInt32
>(byte
[1]) << 8)
101 | (static_cast< sal_uInt32
>(byte
[2]) << 16)
102 | (static_cast< sal_uInt32
>(byte
[3]) << 24);
105 float getIso60599Binary32() const {
107 unsigned char buf
[4];
108 float f
; // assuming float is ISO 60599 binary32
110 #if defined OSL_LITENDIAN
125 // sizeof (Memory64) == 8
127 unsigned char const byte
[8];
129 sal_uInt64
getUnsigned64() const {
130 return static_cast< sal_uInt64
>(byte
[0])
131 | (static_cast< sal_uInt64
>(byte
[1]) << 8)
132 | (static_cast< sal_uInt64
>(byte
[2]) << 16)
133 | (static_cast< sal_uInt64
>(byte
[3]) << 24)
134 | (static_cast< sal_uInt64
>(byte
[4]) << 32)
135 | (static_cast< sal_uInt64
>(byte
[5]) << 40)
136 | (static_cast< sal_uInt64
>(byte
[6]) << 48)
137 | (static_cast< sal_uInt64
>(byte
[7]) << 56);
140 double getIso60599Binary64() const {
142 unsigned char buf
[8];
143 double d
; // assuming double is ISO 60599 binary64
145 #if defined OSL_LITENDIAN
168 bool isSimpleType(OUString
const & type
) {
169 return type
== "void" || type
== "boolean" || type
== "byte"
170 || type
== "short" || type
== "unsigned short" || type
== "long"
171 || type
== "unsigned long" || type
== "hyper"
172 || type
== "unsigned hyper" || type
== "float" || type
== "double"
173 || type
== "char" || type
== "string" || type
== "type"
177 // For backwards compatibility, does not strictly check segments to match
179 // <segment> ::= <blocks> | <block>
180 // <blocks> ::= <capital> <other>* ("_" <block>)*
181 // <block> ::= <other>+
182 // <other> ::= <capital> | "a"--"z" | "0"--"9"
183 // <capital> ::= "A"--"Z"
185 bool isIdentifier(OUString
const & type
, bool scoped
) {
186 if (type
.isEmpty()) {
189 for (sal_Int32 i
= 0; i
!= type
.getLength(); ++i
) {
190 sal_Unicode c
= type
[i
];
192 if (!scoped
|| i
== 0 || i
== type
.getLength() - 1
193 || type
[i
- 1] == '.')
197 } else if (!rtl::isAsciiAlphanumeric(c
) && c
!= '_') {
205 rtl::Reference
< MappedFile
> const & file
, OUString
const & type
)
209 while (nucl
.startsWith("[]", &nucl
)) {}
210 sal_Int32 i
= nucl
.indexOf('<');
212 OUString
tmpl(nucl
.copy(0, i
));
214 ++i
; // skip '<' or ','
216 for (sal_Int32 level
= 0; j
!= nucl
.getLength(); ++j
) {
217 sal_Unicode c
= nucl
[j
];
222 } else if (c
== '<') {
224 } else if (c
== '>') {
231 if (j
!= nucl
.getLength()) {
232 checkTypeName(file
, nucl
.copy(i
, j
- i
));
236 } while (i
!= nucl
.getLength() && nucl
[i
] != '>');
237 if (i
!= nucl
.getLength() - 1 || nucl
[i
] != '>' || !args
) {
238 tmpl
.clear(); // bad input
242 if (isSimpleType(nucl
) ? args
: !isIdentifier(nucl
, true)) {
243 throw FileFormatException(
244 file
->uri
, "UNOIDL format: bad type \"" + type
+ "\"");
248 void checkEntityName(
249 rtl::Reference
< MappedFile
> const & file
, OUString
const & name
)
251 if (isSimpleType(name
) || !isIdentifier(name
, false)) {
252 throw FileFormatException(
253 file
->uri
, "UNOIDL format: bad entity name \"" + name
+ "\"");
259 MappedFile::MappedFile(OUString
const & fileUrl
): uri(fileUrl
), handle(nullptr) {
260 oslFileError e
= osl_openFile(uri
.pData
, &handle
, osl_File_OpenFlag_Read
);
262 case osl_File_E_None
:
264 case osl_File_E_NOENT
:
265 throw NoSuchFileException(uri
);
267 throw FileFormatException(uri
, "cannot open: " + OUString::number(e
));
269 e
= osl_getFileSize(handle
, &size
);
270 if (e
== osl_File_E_None
) {
272 handle
, &address
, size
, 0, osl_File_MapFlag_RandomAccess
);
274 if (e
!= osl_File_E_None
) {
275 oslFileError e2
= osl_closeFile(handle
);
277 e2
!= osl_File_E_None
, "unoidl",
278 "cannot close " << uri
<< ": " << +e2
);
279 throw FileFormatException(uri
, "cannot mmap: " + OUString::number(e
));
283 sal_uInt8
MappedFile::read8(sal_uInt32 offset
) const {
285 if (offset
> size
- 1) {
286 throw FileFormatException(
287 uri
, "UNOIDL format: offset for 8-bit value too large");
292 sal_uInt16
MappedFile::read16(sal_uInt32 offset
) const {
294 if (offset
> size
- 2) {
295 throw FileFormatException(
296 uri
, "UNOIDL format: offset for 16-bit value too large");
298 return get16(offset
);
301 sal_uInt32
MappedFile::read32(sal_uInt32 offset
) const {
303 if (offset
> size
- 4) {
304 throw FileFormatException(
305 uri
, "UNOIDL format: offset for 32-bit value too large");
307 return get32(offset
);
310 sal_uInt64
MappedFile::read64(sal_uInt32 offset
) const {
312 if (offset
> size
- 8) {
313 throw FileFormatException(
314 uri
, "UNOIDL format: offset for 64-bit value too large");
316 return get64(offset
);
319 float MappedFile::readIso60599Binary32(sal_uInt32 offset
) const {
321 if (offset
> size
- 4) {
322 throw FileFormatException(
323 uri
, "UNOIDL format: offset for 32-bit value too large");
325 return getIso60599Binary32(offset
);
328 double MappedFile::readIso60599Binary64(sal_uInt32 offset
) const {
330 if (offset
> size
- 8) {
331 throw FileFormatException(
332 uri
, "UNOIDL format: offset for 64-bit value too large");
334 return getIso60599Binary64(offset
);
337 OUString
MappedFile::readNulName(sal_uInt32 offset
) {
339 throw FileFormatException(
340 uri
, "UNOIDL format: offset for string too large");
342 sal_uInt64 end
= offset
;
345 throw FileFormatException(
346 uri
, "UNOIDL format: string misses trailing NUL");
348 if (static_cast< char const * >(address
)[end
] == 0) {
352 if (end
- offset
> SAL_MAX_INT32
) {
353 throw FileFormatException(uri
, "UNOIDL format: string too long");
356 if (!rtl_convertStringToUString(
357 &name
.pData
, static_cast< char const * >(address
) + offset
,
358 end
- offset
, RTL_TEXTENCODING_ASCII_US
,
359 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
360 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
361 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
363 throw FileFormatException(uri
, "UNOIDL format: name is not ASCII");
365 checkEntityName(this, name
);
369 MappedFile::~MappedFile() {
370 oslFileError e
= osl_unmapMappedFile(handle
, address
, size
);
371 SAL_WARN_IF(e
!= osl_File_E_None
, "unoidl", "cannot unmap: " << +e
);
372 e
= osl_closeFile(handle
);
373 SAL_WARN_IF(e
!= osl_File_E_None
, "unoidl", "cannot close: " << +e
);
376 sal_uInt8
MappedFile::get8(sal_uInt32 offset
) const {
378 assert(offset
<= size
- 1);
379 return static_cast< char const * >(address
)[offset
];
382 sal_uInt16
MappedFile::get16(sal_uInt32 offset
) const {
384 assert(offset
<= size
- 2);
385 return reinterpret_cast< Memory16
const * >(
386 static_cast< char const * >(address
) + offset
)->getUnsigned16();
389 sal_uInt32
MappedFile::get32(sal_uInt32 offset
) const {
391 assert(offset
<= size
- 4);
392 return reinterpret_cast< Memory32
const * >(
393 static_cast< char const * >(address
) + offset
)->getUnsigned32();
396 sal_uInt64
MappedFile::get64(sal_uInt32 offset
) const {
398 assert(offset
<= size
- 8);
399 return reinterpret_cast< Memory64
const * >(
400 static_cast< char const * >(address
) + offset
)->getUnsigned64();
403 float MappedFile::getIso60599Binary32(sal_uInt32 offset
) const {
405 assert(offset
<= size
- 4);
406 return reinterpret_cast< Memory32
const * >(
407 static_cast< char const * >(address
) + offset
)->getIso60599Binary32();
410 double MappedFile::getIso60599Binary64(sal_uInt32 offset
) const {
412 assert(offset
<= size
- 8);
413 return reinterpret_cast< Memory64
const * >(
414 static_cast< char const * >(address
) + offset
)->getIso60599Binary64();
417 OUString
MappedFile::readIdxString(
418 sal_uInt32
* offset
, rtl_TextEncoding encoding
) const
420 assert(offset
!= nullptr);
421 sal_uInt32 len
= read32(*offset
);
423 if ((len
& 0x80000000) == 0) {
428 off
= len
& ~0x80000000;
430 if ((len
& 0x80000000) != 0) {
431 throw FileFormatException(
432 uri
, "UNOIDL format: string length high bit set");
435 if (len
> SAL_MAX_INT32
|| len
> size
- off
- 4) {
436 throw FileFormatException(
437 uri
, "UNOIDL format: size of string is too large");
440 if (!rtl_convertStringToUString(
441 &name
.pData
, static_cast< char const * >(address
) + off
+ 4, len
,
443 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
444 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
445 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
447 throw FileFormatException(
448 uri
, "UNOIDL format: string bytes do not match encoding");
453 // sizeof (MapEntry) == 8
459 static bool operator <(const Map
& map1
, const Map
& map2
) {
460 return map1
.begin
< map2
.begin
461 || (map1
.begin
== map2
.begin
&& map1
.size
< map2
.size
);
466 enum Compare
{ COMPARE_LESS
, COMPARE_GREATER
, COMPARE_EQUAL
};
469 rtl::Reference
< MappedFile
> const & file
, OUString
const & name
,
470 sal_Int32 nameOffset
, sal_Int32 nameLength
, MapEntry
const * entry
)
473 assert(entry
!= nullptr);
474 sal_uInt32 off
= entry
->name
.getUnsigned32();
475 if (off
> file
->size
- 1) { // at least a trailing NUL
476 throw FileFormatException(
477 file
->uri
, "UNOIDL format: string offset too large");
479 assert(nameLength
>= 0);
480 sal_uInt64 min
= std::min(
481 static_cast< sal_uInt64
>(nameLength
), file
->size
- off
);
482 for (sal_uInt64 i
= 0; i
!= min
; ++i
) {
483 sal_Unicode c1
= name
[nameOffset
+ i
];
484 sal_Unicode c2
= static_cast< unsigned char const * >(file
->address
)[
488 } else if (c1
> c2
|| c2
== 0) {
489 // ...the "|| c2 == 0" is for the odd case where name erroneously
490 // contains NUL characters
491 return COMPARE_GREATER
;
494 if (static_cast< sal_uInt64
>(nameLength
) == min
) {
495 if (file
->size
- off
== min
) {
496 throw FileFormatException(
497 file
->uri
, "UNOIDL format: string misses trailing NUL");
500 static_cast< unsigned char const * >(file
->address
)[off
+ min
] == 0
501 ? COMPARE_EQUAL
: COMPARE_LESS
;
503 return COMPARE_GREATER
;
507 sal_uInt32
findInMap(
508 rtl::Reference
< MappedFile
> const & file
, MapEntry
const * mapBegin
,
509 sal_uInt32 mapSize
, OUString
const & name
, sal_Int32 nameOffset
,
510 sal_Int32 nameLength
)
515 sal_uInt32 n
= mapSize
/ 2;
516 MapEntry
const * p
= mapBegin
+ n
;
517 switch (compare(file
, name
, nameOffset
, nameLength
, p
)) {
519 return findInMap(file
, mapBegin
, n
, name
, nameOffset
, nameLength
);
520 case COMPARE_GREATER
:
522 file
, p
+ 1, mapSize
- n
- 1, name
, nameOffset
, nameLength
);
523 default: // COMPARE_EQUAL
526 sal_uInt32 off
= mapBegin
[n
].data
.getUnsigned32();
528 throw FileFormatException(
529 file
->uri
, "UNOIDL format: map entry data offset is null");
534 #if defined(__COVERITY__)
535 extern "C" void __coverity_tainted_data_sanitize__(void *);
538 std::vector
< OUString
> readAnnotations(
539 bool annotated
, rtl::Reference
< MappedFile
> const & file
,
540 sal_uInt32 offset
, sal_uInt32
* newOffset
= nullptr)
542 std::vector
< OUString
> ans
;
544 sal_uInt32 n
= file
->read32(offset
);
545 #if defined(__COVERITY__)
546 __coverity_tainted_data_sanitize__(&n
);
549 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
550 ans
.push_back(file
->readIdxString(&offset
));
553 if (newOffset
!= nullptr) {
559 ConstantValue
readConstant(
560 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
561 sal_uInt32
* newOffset
, bool * annotated
)
564 int v
= file
->read8(offset
);
566 if (annotated
!= nullptr) {
567 *annotated
= (v
& 0x80) != 0;
571 v
= file
->read8(offset
+ 1);
572 if (newOffset
!= nullptr) {
573 *newOffset
= offset
+ 2;
577 return ConstantValue(false);
579 return ConstantValue(true);
581 throw FileFormatException(
583 ("UNOIDL format: bad boolean constant value "
584 + OUString::number(v
)));
587 if (newOffset
!= nullptr) {
588 *newOffset
= offset
+ 2;
590 return ConstantValue(static_cast< sal_Int8
>(file
->read8(offset
+ 1)));
591 //TODO: implementation-defined behavior of conversion from sal_uInt8
592 // to sal_Int8 relies on two's complement representation
594 if (newOffset
!= nullptr) {
595 *newOffset
= offset
+ 3;
597 return ConstantValue(
598 static_cast< sal_Int16
>(file
->read16(offset
+ 1)));
599 //TODO: implementation-defined behavior of conversion from
600 // sal_uInt16 to sal_Int16 relies on two's complement representation
601 case 3: // UNSIGNED SHORT
602 if (newOffset
!= nullptr) {
603 *newOffset
= offset
+ 3;
605 return ConstantValue(file
->read16(offset
+ 1));
607 if (newOffset
!= nullptr) {
608 *newOffset
= offset
+ 5;
610 return ConstantValue(
611 static_cast< sal_Int32
>(file
->read32(offset
+ 1)));
612 //TODO: implementation-defined behavior of conversion from
613 // sal_uInt32 to sal_Int32 relies on two's complement representation
614 case 5: // UNSIGNED LONG
615 if (newOffset
!= nullptr) {
616 *newOffset
= offset
+ 5;
618 return ConstantValue(file
->read32(offset
+ 1));
620 if (newOffset
!= nullptr) {
621 *newOffset
= offset
+ 9;
623 return ConstantValue(
624 static_cast< sal_Int64
>(file
->read64(offset
+ 1)));
625 //TODO: implementation-defined behavior of conversion from
626 // sal_uInt64 to sal_Int64 relies on two's complement representation
627 case 7: // UNSIGNED HYPER
628 if (newOffset
!= nullptr) {
629 *newOffset
= offset
+ 9;
631 return ConstantValue(file
->read64(offset
+ 1));
633 if (newOffset
!= nullptr) {
634 *newOffset
= offset
+ 5;
636 return ConstantValue(file
->readIso60599Binary32(offset
+ 1));
638 if (newOffset
!= nullptr) {
639 *newOffset
= offset
+ 9;
641 return ConstantValue(file
->readIso60599Binary64(offset
+ 1));
643 throw FileFormatException(
645 "UNOIDL format: bad constant type byte " + OUString::number(v
));
649 rtl::Reference
< Entity
> readEntity(
650 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
651 std::set
<Map
> const & trace
);
653 class UnoidlModuleEntity
;
655 class UnoidlCursor
: public MapCursor
{
658 rtl::Reference
< MappedFile
> const & file
,
659 rtl::Reference
<UnoidlProvider
> const & reference1
,
660 rtl::Reference
<UnoidlModuleEntity
> const & reference2
,
661 NestedMap
const & map
):
662 file_(file
), reference1_(reference1
), reference2_(reference2
),
667 virtual ~UnoidlCursor() throw () override
{}
669 virtual rtl::Reference
< Entity
> getNext(OUString
* name
) override
;
671 rtl::Reference
< MappedFile
> file_
;
672 rtl::Reference
<UnoidlProvider
> reference1_
; // HACK to keep alive whatever
673 rtl::Reference
<UnoidlModuleEntity
> reference2_
; // owner of map_
674 NestedMap
const & map_
;
678 rtl::Reference
< Entity
> UnoidlCursor::getNext(OUString
* name
) {
679 assert(name
!= nullptr);
680 rtl::Reference
< Entity
> ent
;
681 if (index_
!= map_
.map
.size
) {
682 *name
= file_
->readNulName(map_
.map
.begin
[index_
].name
.getUnsigned32());
684 file_
, map_
.map
.begin
[index_
].data
.getUnsigned32(), map_
.trace
);
690 class UnoidlModuleEntity
: public ModuleEntity
{
693 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 mapOffset
,
694 sal_uInt32 mapSize
, std::set
<Map
> const & trace
):
698 map_
.map
.begin
= reinterpret_cast<MapEntry
const *>(
699 static_cast<char const *>(file_
->address
) + mapOffset
);
700 map_
.map
.size
= mapSize
;
702 if (!map_
.trace
.insert(map_
.map
).second
) {
703 throw FileFormatException(
704 file_
->uri
, "UNOIDL format: recursive map");
709 virtual ~UnoidlModuleEntity() throw () override
{}
711 virtual std::vector
< OUString
> getMemberNames() const override
;
713 virtual rtl::Reference
< MapCursor
> createCursor() const override
{
714 return new UnoidlCursor(
715 file_
, rtl::Reference
<UnoidlProvider
>(),
716 const_cast<UnoidlModuleEntity
*>(this), map_
);
719 rtl::Reference
< MappedFile
> file_
;
723 std::vector
< OUString
> UnoidlModuleEntity::getMemberNames() const {
724 std::vector
< OUString
> names
;
725 for (sal_uInt32 i
= 0; i
!= map_
.map
.size
; ++i
) {
727 file_
->readNulName(map_
.map
.begin
[i
].name
.getUnsigned32()));
732 rtl::Reference
< Entity
> readEntity(
733 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
734 std::set
<Map
> const & trace
)
737 int v
= file
->read8(offset
);
739 bool published
= (v
& 0x80) != 0;
740 bool annotated
= (v
& 0x40) != 0;
741 bool flag
= (v
& 0x20) != 0;
746 throw FileFormatException(
748 ("UNOIDL format: bad module type byte "
749 + OUString::number(v
)));
751 sal_uInt32 n
= file
->read32(offset
+ 1);
752 if (n
> SAL_MAX_INT32
) {
753 throw FileFormatException(
754 file
->uri
, "UNOIDL format: too many items in module");
756 if (sal_uInt64(offset
) + 5 + 8 * sal_uInt64(n
) > file
->size
)
759 throw FileFormatException(
761 "UNOIDL format: module map offset + size too large");
763 return new UnoidlModuleEntity(file
, offset
+ 5, n
, trace
);
767 sal_uInt32 n
= file
->read32(offset
+ 1);
769 throw FileFormatException(
770 file
->uri
, "UNOIDL format: enum type with no members");
772 if (n
> SAL_MAX_INT32
) {
773 throw FileFormatException(
774 file
->uri
, "UNOIDL format: too many members of enum type");
777 std::vector
< EnumTypeEntity::Member
> mems
;
778 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
779 OUString
memName(file
->readIdxName(&offset
));
780 checkEntityName(file
, memName
);
781 sal_Int32 memValue
= static_cast< sal_Int32
>(
782 file
->read32(offset
));
783 //TODO: implementation-defined behavior of conversion from
784 // sal_uInt32 to sal_Int32 relies on two's complement
789 readAnnotations(annotated
, file
, offset
, &offset
));
791 return new EnumTypeEntity(
792 published
, mems
, readAnnotations(annotated
, file
, offset
));
794 case 2: // plain struct type without base
795 case 2 | 0x20: // plain struct type with base
800 base
= file
->readIdxName(&offset
);
801 if (base
.isEmpty()) {
802 throw FileFormatException(
804 ("UNOIDL format: empty base type name of plain struct"
807 checkTypeName(file
, base
);
809 sal_uInt32 n
= file
->read32(offset
);
810 if (n
> SAL_MAX_INT32
) {
811 throw FileFormatException(
813 ("UNOIDL format: too many direct members of plain struct"
817 std::vector
< PlainStructTypeEntity::Member
> mems
;
818 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
819 OUString
memName(file
->readIdxName(&offset
));
820 checkEntityName(file
, memName
);
821 OUString
memType(file
->readIdxName(&offset
));
822 checkTypeName(file
, memType
);
825 readAnnotations(annotated
, file
, offset
, &offset
));
827 return new PlainStructTypeEntity(
828 published
, base
, mems
,
829 readAnnotations(annotated
, file
, offset
));
831 case 3: // polymorphic struct type template
833 sal_uInt32 n
= file
->read32(offset
+ 1);
834 if (n
> SAL_MAX_INT32
) {
835 throw FileFormatException(
837 ("UNOIDL format: too many type parameters of polymorphic"
838 " struct type template"));
841 std::vector
< OUString
> params
;
842 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
843 OUString
param(file
->readIdxName(&offset
));
844 checkEntityName(file
, param
);
845 params
.push_back(param
);
847 n
= file
->read32(offset
);
848 if (n
> SAL_MAX_INT32
) {
849 throw FileFormatException(
851 ("UNOIDL format: too many members of polymorphic struct"
855 std::vector
< PolymorphicStructTypeTemplateEntity::Member
> mems
;
856 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
857 v
= file
->read8(offset
);
859 OUString
memName(file
->readIdxName(&offset
));
860 checkEntityName(file
, memName
);
861 OUString
memType(file
->readIdxName(&offset
));
862 checkTypeName(file
, memType
);
864 throw FileFormatException(
866 ("UNOIDL format: bad flags " + OUString::number(v
)
867 + " for member " + memName
868 + " of polymorphic struct type template"));
871 memName
, memType
, v
== 1,
872 readAnnotations(annotated
, file
, offset
, &offset
));
874 return new PolymorphicStructTypeTemplateEntity(
875 published
, params
, mems
,
876 readAnnotations(annotated
, file
, offset
));
878 case 4: // exception type without base
879 case 4 | 0x20: // exception type with base
884 base
= file
->readIdxName(&offset
);
885 if (base
.isEmpty()) {
886 throw FileFormatException(
888 ("UNOIDL format: empty base type name of exception"
891 checkTypeName(file
, base
);
893 sal_uInt32 n
= file
->read32(offset
);
894 if (n
> SAL_MAX_INT32
) {
895 throw FileFormatException(
897 "UNOIDL format: too many direct members of exception type");
900 std::vector
< ExceptionTypeEntity::Member
> mems
;
901 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
902 OUString
memName(file
->readIdxName(&offset
));
903 checkEntityName(file
, memName
);
904 OUString
memType(file
->readIdxName(&offset
));
905 checkTypeName(file
, memType
);
908 readAnnotations(annotated
, file
, offset
, &offset
));
910 return new ExceptionTypeEntity(
911 published
, base
, mems
,
912 readAnnotations(annotated
, file
, offset
));
914 case 5: // interface type
916 sal_uInt32 n
= file
->read32(offset
+ 1);
917 if (n
> SAL_MAX_INT32
) {
918 throw FileFormatException(
920 ("UNOIDL format: too many direct mandatory bases of"
924 std::vector
< AnnotatedReference
> mandBases
;
925 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
926 OUString
base(file
->readIdxName(&offset
));
927 checkTypeName(file
, base
);
928 mandBases
.emplace_back(
929 base
, readAnnotations(annotated
, file
, offset
, &offset
));
931 n
= file
->read32(offset
);
932 if (n
> SAL_MAX_INT32
) {
933 throw FileFormatException(
935 ("UNOIDL format: too many direct optional bases of"
939 std::vector
< AnnotatedReference
> optBases
;
940 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
941 OUString
base(file
->readIdxName(&offset
));
942 checkTypeName(file
, base
);
943 optBases
.emplace_back(
944 base
, readAnnotations(annotated
, file
, offset
, &offset
));
946 sal_uInt32 nAttrs
= file
->read32(offset
);
947 if (nAttrs
> SAL_MAX_INT32
) {
948 throw FileFormatException(
950 ("UNOIDL format: too many direct attributes of interface"
954 std::vector
< InterfaceTypeEntity::Attribute
> attrs
;
955 for (sal_uInt32 i
= 0; i
!= nAttrs
; ++i
) {
956 v
= file
->read8(offset
);
958 OUString
attrName(file
->readIdxName(&offset
));
959 checkEntityName(file
, attrName
);
960 OUString
attrType(file
->readIdxName(&offset
));
961 checkTypeName(file
, attrType
);
963 throw FileFormatException(
965 ("UNOIDL format: bad flags for direct attribute "
966 + attrName
+ " of interface type"));
968 std::vector
< OUString
> getExcs
;
969 sal_uInt32 m
= file
->read32(offset
);
970 if (m
> SAL_MAX_INT32
) {
971 throw FileFormatException(
973 ("UNOIDL format: too many getter exceptions for direct"
974 " attribute " + attrName
+ " of interface type"));
977 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
978 OUString
exc(file
->readIdxName(&offset
));
979 checkTypeName(file
, exc
);
980 getExcs
.push_back(exc
);
982 std::vector
< OUString
> setExcs
;
983 if ((v
& 0x02) == 0) {
984 m
= file
->read32(offset
);
985 if (m
> SAL_MAX_INT32
) {
986 throw FileFormatException(
988 ("UNOIDL format: too many setter exceptions for"
989 " direct attribute " + attrName
990 + " of interface type"));
993 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
994 OUString
exc(file
->readIdxName(&offset
));
995 checkTypeName(file
, exc
);
996 setExcs
.push_back(exc
);
1000 attrName
, attrType
, (v
& 0x01) != 0, (v
& 0x02) != 0,
1002 readAnnotations(annotated
, file
, offset
, &offset
));
1004 sal_uInt32 nMeths
= file
->read32(offset
);
1005 if (nMeths
> SAL_MAX_INT32
- nAttrs
) {
1006 throw FileFormatException(
1008 ("UNOIDL format: too many direct attributes and methods of"
1009 " interface type"));
1012 std::vector
< InterfaceTypeEntity::Method
> meths
;
1013 meths
.reserve(nMeths
);
1014 for (sal_uInt32 i
= 0; i
!= nMeths
; ++i
) {
1015 OUString
methName(file
->readIdxName(&offset
));
1016 checkEntityName(file
, methName
);
1017 OUString
methType(file
->readIdxName(&offset
));
1018 checkTypeName(file
, methType
);
1019 sal_uInt32 m
= file
->read32(offset
);
1020 if (m
> SAL_MAX_INT32
) {
1021 throw FileFormatException(
1023 ("UNOIDL format: too many parameters for method "
1024 + methName
+ " of interface type"));
1027 std::vector
< InterfaceTypeEntity::Method::Parameter
> params
;
1028 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1029 v
= file
->read8(offset
);
1031 OUString
paramName(file
->readIdxName(&offset
));
1032 checkEntityName(file
, paramName
);
1033 OUString
paramType(file
->readIdxName(&offset
));
1034 checkTypeName(file
, paramType
);
1035 InterfaceTypeEntity::Method::Parameter::Direction dir
;
1038 dir
= InterfaceTypeEntity::Method::Parameter::
1042 dir
= InterfaceTypeEntity::Method::Parameter::
1046 dir
= InterfaceTypeEntity::Method::Parameter::
1050 throw FileFormatException(
1052 ("UNOIDL format: bad direction "
1053 + OUString::number(v
) + " of parameter "
1054 + paramName
+ " for method " + methName
1055 + " of interface type"));
1057 params
.emplace_back(paramName
, paramType
, dir
);
1059 std::vector
< OUString
> excs
;
1060 m
= file
->read32(offset
);
1061 if (m
> SAL_MAX_INT32
) {
1062 throw FileFormatException(
1064 ("UNOIDL format: too many exceptions for method "
1065 + methName
+ " of interface type"));
1068 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1069 OUString
exc(file
->readIdxName(&offset
));
1070 checkTypeName(file
, exc
);
1071 excs
.push_back(exc
);
1074 methName
, methType
, params
, excs
,
1075 readAnnotations(annotated
, file
, offset
, &offset
));
1077 return new InterfaceTypeEntity(
1078 published
, mandBases
, optBases
, attrs
, meths
,
1079 readAnnotations(annotated
, file
, offset
));
1084 OUString
base(file
->readIdxName(&offset
));
1085 checkTypeName(file
, base
);
1086 return new TypedefEntity(
1087 published
, base
, readAnnotations(annotated
, file
, offset
));
1089 case 7: // constant group
1091 sal_uInt32 n
= file
->read32(offset
+ 1);
1092 if (n
> SAL_MAX_INT32
) {
1093 throw FileFormatException(
1095 "UNOIDL format: too many constants in constant group");
1097 if (sal_uInt64(offset
) + 5 + 8 * sal_uInt64(n
) > file
->size
)
1100 throw FileFormatException(
1102 ("UNOIDL format: constant group map offset + size too"
1105 MapEntry
const * p
= reinterpret_cast< MapEntry
const * >(
1106 static_cast< char const * >(file
->address
) + offset
+ 5);
1107 std::vector
< ConstantGroupEntity::Member
> mems
;
1108 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1109 sal_uInt32 off
= p
[i
].data
.getUnsigned32();
1111 ConstantValue
val(readConstant(file
, off
, &off
, &ann
));
1113 file
->readNulName(p
[i
].name
.getUnsigned32()), val
,
1114 readAnnotations(ann
, file
, off
));
1116 return new ConstantGroupEntity(
1118 readAnnotations(annotated
, file
, offset
+ 5 + 8 * n
));
1120 case 8: // single-interface--based service without default constructor
1121 case 8 | 0x20: // single-interface--based service with default constructor
1124 OUString
base(file
->readIdxName(&offset
));
1125 checkTypeName(file
, base
);
1126 std::vector
< SingleInterfaceBasedServiceEntity::Constructor
> ctors
;
1129 SingleInterfaceBasedServiceEntity::Constructor());
1131 sal_uInt32 n
= file
->read32(offset
);
1132 if (n
> SAL_MAX_INT32
) {
1133 throw FileFormatException(
1135 ("UNOIDL format: too many constructors of"
1136 " single-interface--based service"));
1139 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1140 OUString
ctorName(file
->readIdxName(&offset
));
1141 checkEntityName(file
, ctorName
);
1142 sal_uInt32 m
= file
->read32(offset
);
1143 if (m
> SAL_MAX_INT32
) {
1144 throw FileFormatException(
1146 ("UNOIDL format: too many parameters for"
1147 " constructor " + ctorName
1148 + " of single-interface--based service"));
1152 SingleInterfaceBasedServiceEntity::Constructor::
1154 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1155 v
= file
->read8(offset
);
1157 OUString
paramName(file
->readIdxName(&offset
));
1158 checkEntityName(file
, paramName
);
1159 OUString
paramType(file
->readIdxName(&offset
));
1160 checkTypeName(file
, paramType
);
1170 throw FileFormatException(
1172 ("UNOIDL format: bad mode "
1173 + OUString::number(v
) + " of parameter "
1174 + paramName
+ " for constructor " + ctorName
1175 + " of single-interface--based service"));
1177 params
.emplace_back(paramName
, paramType
, rest
);
1179 std::vector
< OUString
> excs
;
1180 m
= file
->read32(offset
);
1181 if (m
> SAL_MAX_INT32
) {
1182 throw FileFormatException(
1184 ("UNOIDL format: too many exceptions for"
1185 " constructor " + ctorName
1186 + " of single-interface--based service"));
1189 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1190 OUString
exc(file
->readIdxName(&offset
));
1191 checkTypeName(file
, exc
);
1192 excs
.push_back(exc
);
1195 SingleInterfaceBasedServiceEntity::Constructor(
1196 ctorName
, params
, excs
,
1197 readAnnotations(annotated
, file
, offset
, &offset
)));
1200 return new SingleInterfaceBasedServiceEntity(
1201 published
, base
, ctors
,
1202 readAnnotations(annotated
, file
, offset
));
1204 case 9: // accumulation-based service
1206 sal_uInt32 n
= file
->read32(offset
+ 1);
1207 if (n
> SAL_MAX_INT32
) {
1208 throw FileFormatException(
1210 ("UNOIDL format: too many direct mandatory service bases of"
1211 " accumulation-based service"));
1214 std::vector
< AnnotatedReference
> mandServs
;
1215 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1216 OUString
base(file
->readIdxName(&offset
));
1217 checkTypeName(file
, base
);
1218 mandServs
.emplace_back(
1219 base
, readAnnotations(annotated
, file
, offset
, &offset
));
1221 n
= file
->read32(offset
);
1222 if (n
> SAL_MAX_INT32
) {
1223 throw FileFormatException(
1225 ("UNOIDL format: too many direct optional service bases of"
1226 " accumulation-based service"));
1229 std::vector
< AnnotatedReference
> optServs
;
1230 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1231 OUString
base(file
->readIdxName(&offset
));
1232 checkTypeName(file
, base
);
1233 optServs
.emplace_back(
1234 base
, readAnnotations(annotated
, file
, offset
, &offset
));
1236 n
= file
->read32(offset
);
1237 if (n
> SAL_MAX_INT32
) {
1238 throw FileFormatException(
1240 ("UNOIDL format: too many direct mandatory interface bases"
1241 " of accumulation-based service"));
1244 std::vector
< AnnotatedReference
> mandIfcs
;
1245 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1246 OUString
base(file
->readIdxName(&offset
));
1247 checkTypeName(file
, base
);
1248 mandIfcs
.emplace_back(
1249 base
, readAnnotations(annotated
, file
, offset
, &offset
));
1251 n
= file
->read32(offset
);
1252 if (n
> SAL_MAX_INT32
) {
1253 throw FileFormatException(
1255 ("UNOIDL format: too many direct optional interface bases"
1256 " of accumulation-based service"));
1259 std::vector
< AnnotatedReference
> optIfcs
;
1260 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1261 OUString
base(file
->readIdxName(&offset
));
1262 checkTypeName(file
, base
);
1263 optIfcs
.emplace_back(
1264 base
, readAnnotations(annotated
, file
, offset
, &offset
));
1266 n
= file
->read32(offset
);
1267 if (n
> SAL_MAX_INT32
) {
1268 throw FileFormatException(
1270 ("UNOIDL format: too many direct properties of"
1271 " accumulation-based service"));
1274 std::vector
< AccumulationBasedServiceEntity::Property
> props
;
1275 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1276 sal_uInt16 attrs
= file
->read16(offset
);
1278 OUString
propName(file
->readIdxName(&offset
));
1279 checkEntityName(file
, propName
);
1280 OUString
propType(file
->readIdxName(&offset
));
1281 checkTypeName(file
, propType
);
1282 if (attrs
> 0x01FF) { // see css.beans.PropertyAttribute
1283 throw FileFormatException(
1285 ("UNOIDL format: bad mode " + OUString::number(v
)
1286 + " of property " + propName
1287 + " for accumulation-based service"));
1292 AccumulationBasedServiceEntity::Property::Attributes
>(
1294 readAnnotations(annotated
, file
, offset
, &offset
));
1296 return new AccumulationBasedServiceEntity(
1297 published
, mandServs
, optServs
, mandIfcs
, optIfcs
, props
,
1298 readAnnotations(annotated
, file
, offset
));
1300 case 10: // interface-based singleton
1303 OUString
base(file
->readIdxName(&offset
));
1304 checkTypeName(file
, base
);
1305 return new InterfaceBasedSingletonEntity(
1306 published
, base
, readAnnotations(annotated
, file
, offset
));
1308 case 11: // service-based singleton
1311 OUString
base(file
->readIdxName(&offset
));
1312 checkTypeName(file
, base
);
1313 return new ServiceBasedSingletonEntity(
1314 published
, base
, readAnnotations(annotated
, file
, offset
));
1317 throw FileFormatException(
1318 file
->uri
, "UNOIDL format: bad type byte " + OUString::number(v
));
1324 UnoidlProvider::UnoidlProvider(OUString
const & uri
): file_(new MappedFile(uri
))
1326 if (file_
->size
< 8 || std::memcmp(file_
->address
, "UNOIDL\xFF\0", 8) != 0)
1328 throw FileFormatException(
1330 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1333 sal_uInt32 off
= file_
->read32(8);
1334 map_
.map
.size
= file_
->read32(12);
1335 if (off
+ 8 * sal_uInt64(map_
.map
.size
) > file_
->size
) { // cannot overflow
1336 throw FileFormatException(
1337 file_
->uri
, "UNOIDL format: root map offset + size too large");
1339 map_
.map
.begin
= reinterpret_cast< MapEntry
const * >(
1340 static_cast< char const * >(file_
->address
) + off
);
1341 map_
.trace
.insert(map_
.map
);
1344 rtl::Reference
< MapCursor
> UnoidlProvider::createRootCursor() const {
1345 return new UnoidlCursor(
1346 file_
, const_cast<UnoidlProvider
*>(this),
1347 rtl::Reference
<UnoidlModuleEntity
>(), map_
);
1350 rtl::Reference
< Entity
> UnoidlProvider::findEntity(OUString
const & name
) const
1352 NestedMap
map(map_
);
1353 bool cgroup
= false;
1354 for (sal_Int32 i
= 0;;) {
1355 sal_Int32 j
= name
.indexOf('.', i
);
1357 j
= name
.getLength();
1359 sal_Int32 off
= findInMap(
1360 file_
, map
.map
.begin
, map
.map
.size
, name
, i
, j
- i
);
1362 return rtl::Reference
< Entity
>();
1364 if (j
== name
.getLength()) {
1366 ? rtl::Reference
< Entity
>()
1367 : readEntity(file_
, off
, map
.trace
);
1370 return rtl::Reference
< Entity
>();
1371 //TODO: throw an exception instead here, where the segments of a
1372 // constant's name are a prefix of the requested name's
1375 int v
= file_
->read8(off
);
1376 if (v
!= 0) { // module
1377 if ((v
& 0x3F) == 7) { // constant group
1380 return rtl::Reference
< Entity
>();
1381 //TODO: throw an exception instead here, where the segments
1382 // of a non-module, non-constant-group entity's name are a
1383 // prefix of the requested name's segments?
1386 map
.map
.size
= file_
->read32(off
+ 1);
1387 if (sal_uInt64(off
) + 5 + 8 * sal_uInt64(map
.map
.size
) > file_
->size
)
1390 throw FileFormatException(
1391 file_
->uri
, "UNOIDL format: map offset + size too large");
1393 map
.map
.begin
= reinterpret_cast< MapEntry
const * >(
1394 static_cast< char const * >(file_
->address
) + off
+ 5);
1395 if (!map
.trace
.insert(map
.map
).second
) {
1396 throw FileFormatException(
1397 file_
->uri
, "UNOIDL format: recursive map");
1403 UnoidlProvider::~UnoidlProvider() throw () {}
1407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */