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();
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 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 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 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(0) {
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
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 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
)
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 std::vector
< OUString
> readAnnotations(
535 bool annotated
, rtl::Reference
< MappedFile
> const & file
,
536 sal_uInt32 offset
, sal_uInt32
* newOffset
= 0)
538 std::vector
< OUString
> ans
;
540 sal_uInt32 n
= file
->read32(offset
);
542 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
543 ans
.push_back(file
->readIdxString(&offset
));
546 if (newOffset
!= 0) {
552 ConstantValue
readConstant(
553 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
554 sal_uInt32
* newOffset
= 0, bool * annotated
= 0)
557 int v
= file
->read8(offset
);
559 if (annotated
!= 0) {
560 *annotated
= (v
& 0x80) != 0;
564 v
= file
->read8(offset
+ 1);
565 if (newOffset
!= 0) {
566 *newOffset
= offset
+ 2;
570 return ConstantValue(false);
572 return ConstantValue(true);
574 throw FileFormatException(
576 ("UNOIDL format: bad boolean constant value "
577 + OUString::number(v
)));
580 if (newOffset
!= 0) {
581 *newOffset
= offset
+ 2;
583 return ConstantValue(static_cast< sal_Int8
>(file
->read8(offset
+ 1)));
584 //TODO: implementation-defined behavior of conversion from sal_uInt8
585 // to sal_Int8 relies on two's complement representation
587 if (newOffset
!= 0) {
588 *newOffset
= offset
+ 3;
590 return ConstantValue(
591 static_cast< sal_Int16
>(file
->read16(offset
+ 1)));
592 //TODO: implementation-defined behavior of conversion from
593 // sal_uInt16 to sal_Int16 relies on two's complement representation
594 case 3: // UNSIGNED SHORT
595 if (newOffset
!= 0) {
596 *newOffset
= offset
+ 3;
598 return ConstantValue(file
->read16(offset
+ 1));
600 if (newOffset
!= 0) {
601 *newOffset
= offset
+ 5;
603 return ConstantValue(
604 static_cast< sal_Int32
>(file
->read32(offset
+ 1)));
605 //TODO: implementation-defined behavior of conversion from
606 // sal_uInt32 to sal_Int32 relies on two's complement representation
607 case 5: // UNSIGNED LONG
608 if (newOffset
!= 0) {
609 *newOffset
= offset
+ 5;
611 return ConstantValue(file
->read32(offset
+ 1));
613 if (newOffset
!= 0) {
614 *newOffset
= offset
+ 9;
616 return ConstantValue(
617 static_cast< sal_Int64
>(file
->read64(offset
+ 1)));
618 //TODO: implementation-defined behavior of conversion from
619 // sal_uInt64 to sal_Int64 relies on two's complement representation
620 case 7: // UNSIGNED HYPER
621 if (newOffset
!= 0) {
622 *newOffset
= offset
+ 9;
624 return ConstantValue(file
->read64(offset
+ 1));
626 if (newOffset
!= 0) {
627 *newOffset
= offset
+ 5;
629 return ConstantValue(file
->readIso60599Binary32(offset
+ 1));
631 if (newOffset
!= 0) {
632 *newOffset
= offset
+ 9;
634 return ConstantValue(file
->readIso60599Binary64(offset
+ 1));
636 throw FileFormatException(
638 "UNOIDL format: bad constant type byte " + OUString::number(v
));
642 rtl::Reference
< Entity
> readEntity(
643 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
644 std::set
<Map
> const & trace
);
646 class UnoidlModuleEntity
;
648 class UnoidlCursor
: public MapCursor
{
651 rtl::Reference
< MappedFile
> file
,
652 rtl::Reference
<UnoidlProvider
> const & reference1
,
653 rtl::Reference
<UnoidlModuleEntity
> const & reference2
,
654 NestedMap
const & map
):
655 file_(file
), reference1_(reference1
), reference2_(reference2
),
660 virtual ~UnoidlCursor() throw () {}
662 virtual rtl::Reference
< Entity
> getNext(OUString
* name
) SAL_OVERRIDE
;
664 rtl::Reference
< MappedFile
> file_
;
665 rtl::Reference
<UnoidlProvider
> reference1_
; // HACK to keep alive whatever
666 rtl::Reference
<UnoidlModuleEntity
> reference2_
; // owner of map_
667 NestedMap
const & map_
;
671 rtl::Reference
< Entity
> UnoidlCursor::getNext(OUString
* name
) {
673 rtl::Reference
< Entity
> ent
;
674 if (index_
!= map_
.map
.size
) {
675 *name
= file_
->readNulName(map_
.map
.begin
[index_
].name
.getUnsigned32());
677 file_
, map_
.map
.begin
[index_
].data
.getUnsigned32(), map_
.trace
);
683 class UnoidlModuleEntity
: public ModuleEntity
{
686 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 mapOffset
,
687 sal_uInt32 mapSize
, std::set
<Map
> const & trace
):
691 map_
.map
.begin
= reinterpret_cast<MapEntry
const *>(
692 static_cast<char const *>(file_
->address
) + mapOffset
);
693 map_
.map
.size
= mapSize
;
695 if (!map_
.trace
.insert(map_
.map
).second
) {
696 throw FileFormatException(
697 file_
->uri
, "UNOIDL format: recursive map");
702 virtual ~UnoidlModuleEntity() throw () {}
704 virtual std::vector
< OUString
> getMemberNames() const SAL_OVERRIDE
;
706 virtual rtl::Reference
< MapCursor
> createCursor() const SAL_OVERRIDE
{
707 return new UnoidlCursor(
708 file_
, rtl::Reference
<UnoidlProvider
>(),
709 const_cast<UnoidlModuleEntity
*>(this), map_
);
712 rtl::Reference
< MappedFile
> file_
;
716 std::vector
< OUString
> UnoidlModuleEntity::getMemberNames() const {
717 std::vector
< OUString
> names
;
718 for (sal_uInt32 i
= 0; i
!= map_
.map
.size
; ++i
) {
720 file_
->readNulName(map_
.map
.begin
[i
].name
.getUnsigned32()));
725 rtl::Reference
< Entity
> readEntity(
726 rtl::Reference
< MappedFile
> const & file
, sal_uInt32 offset
,
727 std::set
<Map
> const & trace
)
730 int v
= file
->read8(offset
);
732 bool published
= (v
& 0x80) != 0;
733 bool annotated
= (v
& 0x40) != 0;
734 bool flag
= (v
& 0x20) != 0;
739 throw FileFormatException(
741 ("UNOIDL format: bad module type byte "
742 + OUString::number(v
)));
744 sal_uInt32 n
= file
->read32(offset
+ 1);
745 if (n
> SAL_MAX_INT32
) {
746 throw FileFormatException(
747 file
->uri
, "UNOIDL format: too many items in module");
749 if (sal_uInt64(offset
) + 5 + 8 * sal_uInt64(n
) > file
->size
)
752 throw FileFormatException(
754 "UNOIDL format: module map offset + size too large");
756 return new UnoidlModuleEntity(file
, offset
+ 5, n
, trace
);
760 sal_uInt32 n
= file
->read32(offset
+ 1);
762 throw FileFormatException(
763 file
->uri
, "UNOIDL format: enum type with no members");
765 if (n
> SAL_MAX_INT32
) {
766 throw FileFormatException(
767 file
->uri
, "UNOIDL format: too many members of enum type");
770 std::vector
< EnumTypeEntity::Member
> mems
;
771 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
772 OUString
memName(file
->readIdxName(&offset
));
773 checkEntityName(file
, memName
);
774 sal_Int32 memValue
= static_cast< sal_Int32
>(
775 file
->read32(offset
));
776 //TODO: implementation-defined behavior of conversion from
777 // sal_uInt32 to sal_Int32 relies on two's complement
781 EnumTypeEntity::Member(
783 readAnnotations(annotated
, file
, offset
, &offset
)));
785 return new EnumTypeEntity(
786 published
, mems
, readAnnotations(annotated
, file
, offset
));
788 case 2: // plain struct type without base
789 case 2 | 0x20: // plain struct type with base
794 base
= file
->readIdxName(&offset
);
795 if (base
.isEmpty()) {
796 throw FileFormatException(
798 ("UNOIDL format: empty base type name of plain struct"
801 checkTypeName(file
, base
);
803 sal_uInt32 n
= file
->read32(offset
);
804 if (n
> SAL_MAX_INT32
) {
805 throw FileFormatException(
807 ("UNOIDL format: too many direct members of plain struct"
811 std::vector
< PlainStructTypeEntity::Member
> mems
;
812 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
813 OUString
memName(file
->readIdxName(&offset
));
814 checkEntityName(file
, memName
);
815 OUString
memType(file
->readIdxName(&offset
));
816 checkTypeName(file
, memType
);
818 PlainStructTypeEntity::Member(
820 readAnnotations(annotated
, file
, offset
, &offset
)));
822 return new PlainStructTypeEntity(
823 published
, base
, mems
,
824 readAnnotations(annotated
, file
, offset
));
826 case 3: // polymorphic struct type template
828 sal_uInt32 n
= file
->read32(offset
+ 1);
829 if (n
> SAL_MAX_INT32
) {
830 throw FileFormatException(
832 ("UNOIDL format: too many type parameters of polymorphic"
833 " struct type template"));
836 std::vector
< OUString
> params
;
837 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
838 OUString
param(file
->readIdxName(&offset
));
839 checkEntityName(file
, param
);
840 params
.push_back(param
);
842 n
= file
->read32(offset
);
843 if (n
> SAL_MAX_INT32
) {
844 throw FileFormatException(
846 ("UNOIDL format: too many members of polymorphic struct"
850 std::vector
< PolymorphicStructTypeTemplateEntity::Member
> mems
;
851 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
852 v
= file
->read8(offset
);
854 OUString
memName(file
->readIdxName(&offset
));
855 checkEntityName(file
, memName
);
856 OUString
memType(file
->readIdxName(&offset
));
857 checkTypeName(file
, memType
);
859 throw FileFormatException(
861 ("UNOIDL format: bad flags " + OUString::number(v
)
862 + " for member " + memName
863 + " of polymorphic struct type template"));
866 PolymorphicStructTypeTemplateEntity::Member(
867 memName
, memType
, v
== 1,
868 readAnnotations(annotated
, file
, offset
, &offset
)));
870 return new PolymorphicStructTypeTemplateEntity(
871 published
, params
, mems
,
872 readAnnotations(annotated
, file
, offset
));
874 case 4: // exception type without base
875 case 4 | 0x20: // exception type with base
880 base
= file
->readIdxName(&offset
);
881 if (base
.isEmpty()) {
882 throw FileFormatException(
884 ("UNOIDL format: empty base type name of exception"
887 checkTypeName(file
, base
);
889 sal_uInt32 n
= file
->read32(offset
);
890 if (n
> SAL_MAX_INT32
) {
891 throw FileFormatException(
893 "UNOIDL format: too many direct members of exception type");
896 std::vector
< ExceptionTypeEntity::Member
> mems
;
897 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
898 OUString
memName(file
->readIdxName(&offset
));
899 checkEntityName(file
, memName
);
900 OUString
memType(file
->readIdxName(&offset
));
901 checkTypeName(file
, memType
);
903 ExceptionTypeEntity::Member(
905 readAnnotations(annotated
, file
, offset
, &offset
)));
907 return new ExceptionTypeEntity(
908 published
, base
, mems
,
909 readAnnotations(annotated
, file
, offset
));
911 case 5: // interface type
913 sal_uInt32 n
= file
->read32(offset
+ 1);
914 if (n
> SAL_MAX_INT32
) {
915 throw FileFormatException(
917 ("UNOIDL format: too many direct mandatory bases of"
921 std::vector
< AnnotatedReference
> mandBases
;
922 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
923 OUString
base(file
->readIdxName(&offset
));
924 checkTypeName(file
, base
);
928 readAnnotations(annotated
, file
, offset
, &offset
)));
930 n
= file
->read32(offset
);
931 if (n
> SAL_MAX_INT32
) {
932 throw FileFormatException(
934 ("UNOIDL format: too many direct optional bases of"
938 std::vector
< AnnotatedReference
> optBases
;
939 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
940 OUString
base(file
->readIdxName(&offset
));
941 checkTypeName(file
, base
);
945 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 InterfaceTypeEntity::Attribute(
1002 attrName
, attrType
, (v
& 0x01) != 0, (v
& 0x02) != 0,
1004 readAnnotations(annotated
, file
, offset
, &offset
)));
1006 sal_uInt32 nMeths
= file
->read32(offset
);
1007 if (nMeths
> SAL_MAX_INT32
- nAttrs
) {
1008 throw FileFormatException(
1010 ("UNOIDL format: too many direct attributes and methods of"
1011 " interface type"));
1014 std::vector
< InterfaceTypeEntity::Method
> meths
;
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"));
1059 InterfaceTypeEntity::Method::Parameter(
1060 paramName
, paramType
, dir
));
1062 std::vector
< OUString
> excs
;
1063 m
= file
->read32(offset
);
1064 if (m
> SAL_MAX_INT32
) {
1065 throw FileFormatException(
1067 ("UNOIDL format: too many exceptions for method "
1068 + methName
+ " of interface type"));
1071 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1072 OUString
exc(file
->readIdxName(&offset
));
1073 checkTypeName(file
, exc
);
1074 excs
.push_back(exc
);
1077 InterfaceTypeEntity::Method(
1078 methName
, methType
, params
, excs
,
1079 readAnnotations(annotated
, file
, offset
, &offset
)));
1081 return new InterfaceTypeEntity(
1082 published
, mandBases
, optBases
, attrs
, meths
,
1083 readAnnotations(annotated
, file
, offset
));
1088 OUString
base(file
->readIdxName(&offset
));
1089 checkTypeName(file
, base
);
1090 return new TypedefEntity(
1091 published
, base
, readAnnotations(annotated
, file
, offset
));
1093 case 7: // constant group
1095 sal_uInt32 n
= file
->read32(offset
+ 1);
1096 if (n
> SAL_MAX_INT32
) {
1097 throw FileFormatException(
1099 "UNOIDL format: too many constants in constant group");
1101 if (sal_uInt64(offset
) + 5 + 8 * sal_uInt64(n
) > file
->size
)
1104 throw FileFormatException(
1106 ("UNOIDL format: constant group map offset + size too"
1109 MapEntry
const * p
= reinterpret_cast< MapEntry
const * >(
1110 static_cast< char const * >(file
->address
) + offset
+ 5);
1111 std::vector
< ConstantGroupEntity::Member
> mems
;
1112 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1113 sal_uInt32 off
= p
[i
].data
.getUnsigned32();
1115 ConstantValue
val(readConstant(file
, off
, &off
, &ann
));
1117 ConstantGroupEntity::Member(
1118 file
->readNulName(p
[i
].name
.getUnsigned32()), val
,
1119 readAnnotations(ann
, file
, off
)));
1121 return new ConstantGroupEntity(
1123 readAnnotations(annotated
, file
, offset
+ 5 + 8 * n
));
1125 case 8: // single-interface--based service without default constructor
1126 case 8 | 0x20: // single-interface--based service with default constructor
1129 OUString
base(file
->readIdxName(&offset
));
1130 checkTypeName(file
, base
);
1131 std::vector
< SingleInterfaceBasedServiceEntity::Constructor
> ctors
;
1134 SingleInterfaceBasedServiceEntity::Constructor());
1136 sal_uInt32 n
= file
->read32(offset
);
1137 if (n
> SAL_MAX_INT32
) {
1138 throw FileFormatException(
1140 ("UNOIDL format: too many constructors of"
1141 " single-interface--based service"));
1144 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1145 OUString
ctorName(file
->readIdxName(&offset
));
1146 checkEntityName(file
, ctorName
);
1147 sal_uInt32 m
= file
->read32(offset
);
1148 if (m
> SAL_MAX_INT32
) {
1149 throw FileFormatException(
1151 ("UNOIDL format: too many parameters for"
1152 " constructor " + ctorName
1153 + " of single-interface--based service"));
1157 SingleInterfaceBasedServiceEntity::Constructor::
1159 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1160 v
= file
->read8(offset
);
1162 OUString
paramName(file
->readIdxName(&offset
));
1163 checkEntityName(file
, paramName
);
1164 OUString
paramType(file
->readIdxName(&offset
));
1165 checkTypeName(file
, paramType
);
1175 throw FileFormatException(
1177 ("UNOIDL format: bad mode "
1178 + OUString::number(v
) + " of parameter "
1179 + paramName
+ " for constructor " + ctorName
1180 + " of single-interface--based service"));
1183 SingleInterfaceBasedServiceEntity::Constructor::
1185 paramName
, paramType
, rest
));
1187 std::vector
< OUString
> excs
;
1188 m
= file
->read32(offset
);
1189 if (m
> SAL_MAX_INT32
) {
1190 throw FileFormatException(
1192 ("UNOIDL format: too many exceptions for"
1193 " constructor " + ctorName
1194 + " of single-interface--based service"));
1197 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1198 OUString
exc(file
->readIdxName(&offset
));
1199 checkTypeName(file
, exc
);
1200 excs
.push_back(exc
);
1203 SingleInterfaceBasedServiceEntity::Constructor(
1204 ctorName
, params
, excs
,
1205 readAnnotations(annotated
, file
, offset
, &offset
)));
1208 return new SingleInterfaceBasedServiceEntity(
1209 published
, base
, ctors
,
1210 readAnnotations(annotated
, file
, offset
));
1212 case 9: // accumulation-based service
1214 sal_uInt32 n
= file
->read32(offset
+ 1);
1215 if (n
> SAL_MAX_INT32
) {
1216 throw FileFormatException(
1218 ("UNOIDL format: too many direct mandatory service bases of"
1219 " accumulation-based service"));
1222 std::vector
< AnnotatedReference
> mandServs
;
1223 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1224 OUString
base(file
->readIdxName(&offset
));
1225 checkTypeName(file
, base
);
1226 mandServs
.push_back(
1229 readAnnotations(annotated
, file
, offset
, &offset
)));
1231 n
= file
->read32(offset
);
1232 if (n
> SAL_MAX_INT32
) {
1233 throw FileFormatException(
1235 ("UNOIDL format: too many direct optional service bases of"
1236 " accumulation-based service"));
1239 std::vector
< AnnotatedReference
> optServs
;
1240 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1241 OUString
base(file
->readIdxName(&offset
));
1242 checkTypeName(file
, base
);
1246 readAnnotations(annotated
, file
, offset
, &offset
)));
1248 n
= file
->read32(offset
);
1249 if (n
> SAL_MAX_INT32
) {
1250 throw FileFormatException(
1252 ("UNOIDL format: too many direct mandatory interface bases"
1253 " of accumulation-based service"));
1256 std::vector
< AnnotatedReference
> mandIfcs
;
1257 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1258 OUString
base(file
->readIdxName(&offset
));
1259 checkTypeName(file
, base
);
1263 readAnnotations(annotated
, file
, offset
, &offset
)));
1265 n
= file
->read32(offset
);
1266 if (n
> SAL_MAX_INT32
) {
1267 throw FileFormatException(
1269 ("UNOIDL format: too many direct optional interface bases"
1270 " of accumulation-based service"));
1273 std::vector
< AnnotatedReference
> optIfcs
;
1274 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1275 OUString
base(file
->readIdxName(&offset
));
1276 checkTypeName(file
, base
);
1280 readAnnotations(annotated
, file
, offset
, &offset
)));
1282 n
= file
->read32(offset
);
1283 if (n
> SAL_MAX_INT32
) {
1284 throw FileFormatException(
1286 ("UNOIDL format: too many direct properties of"
1287 " accumulation-based service"));
1290 std::vector
< AccumulationBasedServiceEntity::Property
> props
;
1291 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1292 sal_uInt16 attrs
= file
->read16(offset
);
1294 OUString
propName(file
->readIdxName(&offset
));
1295 checkEntityName(file
, propName
);
1296 OUString
propType(file
->readIdxName(&offset
));
1297 checkTypeName(file
, propType
);
1298 if (attrs
> 0x01FF) { // see css.beans.PropertyAttribute
1299 throw FileFormatException(
1301 ("UNOIDL format: bad mode " + OUString::number(v
)
1302 + " of property " + propName
1303 + " for accumulation-based servcie"));
1306 AccumulationBasedServiceEntity::Property(
1309 AccumulationBasedServiceEntity::Property::
1312 readAnnotations(annotated
, file
, offset
, &offset
)));
1314 return new AccumulationBasedServiceEntity(
1315 published
, mandServs
, optServs
, mandIfcs
, optIfcs
, props
,
1316 readAnnotations(annotated
, file
, offset
));
1318 case 10: // interface-based singleton
1321 OUString
base(file
->readIdxName(&offset
));
1322 checkTypeName(file
, base
);
1323 return new InterfaceBasedSingletonEntity(
1324 published
, base
, readAnnotations(annotated
, file
, offset
));
1326 case 11: // service-based singleton
1329 OUString
base(file
->readIdxName(&offset
));
1330 checkTypeName(file
, base
);
1331 return new ServiceBasedSingletonEntity(
1332 published
, base
, readAnnotations(annotated
, file
, offset
));
1335 throw FileFormatException(
1336 file
->uri
, "UNOIDL format: bad type byte " + OUString::number(v
));
1342 UnoidlProvider::UnoidlProvider(OUString
const & uri
): file_(new MappedFile(uri
))
1344 if (file_
->size
< 8 || std::memcmp(file_
->address
, "UNOIDL\xFF\0", 8) != 0)
1346 throw FileFormatException(
1348 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1351 sal_uInt32 off
= file_
->read32(8);
1352 map_
.map
.size
= file_
->read32(12);
1353 if (off
+ 8 * sal_uInt64(map_
.map
.size
) > file_
->size
) { // cannot overflow
1354 throw FileFormatException(
1355 file_
->uri
, "UNOIDL format: root map offset + size too large");
1357 map_
.map
.begin
= reinterpret_cast< MapEntry
const * >(
1358 static_cast< char const * >(file_
->address
) + off
);
1359 map_
.trace
.insert(map_
.map
);
1362 rtl::Reference
< MapCursor
> UnoidlProvider::createRootCursor() const {
1363 return new UnoidlCursor(
1364 file_
, const_cast<UnoidlProvider
*>(this),
1365 rtl::Reference
<UnoidlModuleEntity
>(), map_
);
1368 rtl::Reference
< Entity
> UnoidlProvider::findEntity(OUString
const & name
) const
1370 NestedMap
map(map_
);
1371 bool cgroup
= false;
1372 for (sal_Int32 i
= 0;;) {
1373 sal_Int32 j
= name
.indexOf('.', i
);
1375 j
= name
.getLength();
1377 sal_Int32 off
= findInMap(
1378 file_
, map
.map
.begin
, map
.map
.size
, name
, i
, j
- i
);
1380 return rtl::Reference
< Entity
>();
1382 if (j
== name
.getLength()) {
1384 ? rtl::Reference
< Entity
>()
1385 : readEntity(file_
, off
, map
.trace
);
1388 return rtl::Reference
< Entity
>();
1389 //TODO: throw an exception instead here, where the segments of a
1390 // constant's name are a prefix of the requested name's
1393 int v
= file_
->read8(off
);
1394 if (v
!= 0) { // module
1395 if ((v
& 0x3F) == 7) { // constant group
1398 return rtl::Reference
< Entity
>();
1399 //TODO: throw an exception instead here, where the segments
1400 // of a non-module, non-constant-group entity's name are a
1401 // prefix of the requested name's segments?
1404 map
.map
.size
= file_
->read32(off
+ 1);
1405 if (sal_uInt64(off
) + 5 + 8 * sal_uInt64(map
.map
.size
) > file_
->size
)
1408 throw FileFormatException(
1409 file_
->uri
, "UNOIDL format: map offset + size too large");
1411 map
.map
.begin
= reinterpret_cast< MapEntry
const * >(
1412 static_cast< char const * >(file_
->address
) + off
+ 5);
1413 if (!map
.trace
.insert(map
.map
).second
) {
1414 throw FileFormatException(
1415 file_
->uri
, "UNOIDL format: recursive map");
1421 UnoidlProvider::~UnoidlProvider() throw () {}
1425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */