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"
17 #include "osl/endian.h"
19 #include "rtl/ref.hxx"
20 #include "rtl/textenc.h"
21 #include "rtl/textcvt.h"
22 #include "rtl/ustring.hxx"
23 #include "sal/log.hxx"
24 #include "sal/types.h"
25 #include "salhelper/simplereferenceobject.hxx"
26 #include "unoidl/unoidl.hxx"
27 #include "unoidl/unoidlprovider.hxx"
31 // sizeof (Memory16) == 2
33 unsigned char byte
[2];
35 sal_uInt16
getUnsigned16() const {
36 return static_cast< sal_uInt16
>(byte
[0])
37 | (static_cast< sal_uInt16
>(byte
[1]) << 8);
41 // sizeof (Memory32) == 4
43 unsigned char byte
[4];
45 sal_uInt32
getUnsigned32() const {
46 return static_cast< sal_uInt32
>(byte
[0])
47 | (static_cast< sal_uInt32
>(byte
[1]) << 8)
48 | (static_cast< sal_uInt32
>(byte
[2]) << 16)
49 | (static_cast< sal_uInt32
>(byte
[3]) << 24);
52 float getIso60599Binary32() const {
55 float f
; // assuming float is ISO 60599 binary32
57 #if defined OSL_LITENDIAN
72 // sizeof (Memory64) == 8
74 unsigned char byte
[8];
76 sal_uInt64
getUnsigned64() const {
77 return static_cast< sal_uInt64
>(byte
[0])
78 | (static_cast< sal_uInt64
>(byte
[1]) << 8)
79 | (static_cast< sal_uInt64
>(byte
[2]) << 16)
80 | (static_cast< sal_uInt64
>(byte
[3]) << 24)
81 | (static_cast< sal_uInt64
>(byte
[4]) << 32)
82 | (static_cast< sal_uInt64
>(byte
[5]) << 40)
83 | (static_cast< sal_uInt64
>(byte
[6]) << 48)
84 | (static_cast< sal_uInt64
>(byte
[7]) << 56);
87 double getIso60599Binary64() const {
90 double d
; // assuming double is ISO 60599 binary64
92 #if defined OSL_LITENDIAN
121 class MappedFile
: public salhelper::SimpleReferenceObject
{
123 explicit MappedFile(OUString
const & fileUrl
);
125 sal_uInt8
read8(sal_uInt32 offset
) const;
127 sal_uInt16
read16(sal_uInt32 offset
) const;
129 sal_uInt32
read32(sal_uInt32 offset
) const;
131 sal_uInt64
read64(sal_uInt32 offset
) const;
133 float readIso60599Binary32(sal_uInt32 offset
) const;
135 double readIso60599Binary64(sal_uInt32 offset
) const;
137 OUString
readNulName(sal_uInt32 offset
) const;
139 OUString
readIdxName(sal_uInt32
* offset
) const
140 { return readIdxString(offset
, RTL_TEXTENCODING_ASCII_US
); }
142 OUString
readIdxString(sal_uInt32
* offset
) const
143 { return readIdxString(offset
, RTL_TEXTENCODING_UTF8
); }
146 oslFileHandle handle
;
151 virtual ~MappedFile();
153 sal_uInt8
get8(sal_uInt32 offset
) const;
155 sal_uInt16
get16(sal_uInt32 offset
) const;
157 sal_uInt32
get32(sal_uInt32 offset
) const;
159 sal_uInt64
get64(sal_uInt32 offset
) const;
161 float getIso60599Binary32(sal_uInt32 offset
) const;
163 double getIso60599Binary64(sal_uInt32 offset
) const;
165 OUString
readIdxString(sal_uInt32
* offset
, rtl_TextEncoding encoding
)
169 MappedFile::MappedFile(OUString
const & fileUrl
): uri(fileUrl
) {
170 oslFileError e
= osl_openFile(uri
.pData
, &handle
, osl_File_OpenFlag_Read
);
172 case osl_File_E_None
:
174 case osl_File_E_NOENT
:
175 throw NoSuchFileException(uri
);
177 throw FileFormatException(uri
, "cannot open: " + OUString::number(e
));
179 e
= osl_getFileSize(handle
, &size
);
180 if (e
== osl_File_E_None
) {
182 handle
, &address
, size
, 0, osl_File_MapFlag_RandomAccess
);
184 if (e
!= osl_File_E_None
) {
185 oslFileError e2
= osl_closeFile(handle
);
187 e2
!= osl_File_E_None
, "unoidl",
188 "cannot close " << uri
<< ": " << +e2
);
189 throw FileFormatException(uri
, "cannot mmap: " + OUString::number(e
));
193 sal_uInt8
MappedFile::read8(sal_uInt32 offset
) const {
195 if (offset
> size
- 1) {
196 throw FileFormatException(
197 uri
, "UNOIDL format: offset for 8-bit value too large");
202 sal_uInt16
MappedFile::read16(sal_uInt32 offset
) const {
204 if (offset
> size
- 2) {
205 throw FileFormatException(
206 uri
, "UNOIDL format: offset for 16-bit value too large");
208 return get16(offset
);
211 sal_uInt32
MappedFile::read32(sal_uInt32 offset
) const {
213 if (offset
> size
- 4) {
214 throw FileFormatException(
215 uri
, "UNOIDL format: offset for 32-bit value too large");
217 return get32(offset
);
220 sal_uInt64
MappedFile::read64(sal_uInt32 offset
) const {
222 if (offset
> size
- 8) {
223 throw FileFormatException(
224 uri
, "UNOIDL format: offset for 64-bit value too large");
226 return get64(offset
);
229 float MappedFile::readIso60599Binary32(sal_uInt32 offset
) const {
231 if (offset
> size
- 4) {
232 throw FileFormatException(
233 uri
, "UNOIDL format: offset for 32-bit value too large");
235 return getIso60599Binary32(offset
);
238 double MappedFile::readIso60599Binary64(sal_uInt32 offset
) const {
240 if (offset
> size
- 8) {
241 throw FileFormatException(
242 uri
, "UNOIDL format: offset for 64-bit value too large");
244 return getIso60599Binary64(offset
);
247 OUString
MappedFile::readNulName(sal_uInt32 offset
) const {
249 throw FileFormatException(
250 uri
, "UNOIDL format: offset for string too large");
252 sal_uInt64 end
= offset
;
255 throw FileFormatException(
256 uri
, "UNOIDL format: string misses trailing NUL");
258 if (static_cast< char const * >(address
)[end
] == 0) {
262 if (end
- offset
> SAL_MAX_INT32
) {
263 throw FileFormatException(uri
, "UNOIDL format: string too long");
266 if (!rtl_convertStringToUString(
267 &name
.pData
, static_cast< char const * >(address
) + offset
,
268 end
- offset
, RTL_TEXTENCODING_ASCII_US
,
269 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
270 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
271 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
273 throw FileFormatException(uri
, "UNOIDL format: name is not ASCII");
278 MappedFile::~MappedFile() {
279 oslFileError e
= osl_unmapMappedFile(handle
, address
, size
);
280 SAL_WARN_IF(e
!= osl_File_E_None
, "unoidl", "cannot unmap: " << +e
);
281 e
= osl_closeFile(handle
);
282 SAL_WARN_IF(e
!= osl_File_E_None
, "unoidl", "cannot close: " << +e
);
285 sal_uInt8
MappedFile::get8(sal_uInt32 offset
) const {
287 assert(offset
<= size
- 1);
288 return static_cast< char const * >(address
)[offset
];
291 sal_uInt16
MappedFile::get16(sal_uInt32 offset
) const {
293 assert(offset
<= size
- 2);
294 return reinterpret_cast< Memory16
const * >(
295 static_cast< char const * >(address
) + offset
)->getUnsigned16();
298 sal_uInt32
MappedFile::get32(sal_uInt32 offset
) const {
300 assert(offset
<= size
- 4);
301 return reinterpret_cast< Memory32
const * >(
302 static_cast< char const * >(address
) + offset
)->getUnsigned32();
305 sal_uInt64
MappedFile::get64(sal_uInt32 offset
) const {
307 assert(offset
<= size
- 8);
308 return reinterpret_cast< Memory64
const * >(
309 static_cast< char const * >(address
) + offset
)->getUnsigned64();
312 float MappedFile::getIso60599Binary32(sal_uInt32 offset
) const {
314 assert(offset
<= size
- 4);
315 return reinterpret_cast< Memory32
const * >(
316 static_cast< char const * >(address
) + offset
)->getIso60599Binary32();
319 double MappedFile::getIso60599Binary64(sal_uInt32 offset
) const {
321 assert(offset
<= size
- 8);
322 return reinterpret_cast< Memory64
const * >(
323 static_cast< char const * >(address
) + offset
)->getIso60599Binary64();
326 OUString
MappedFile::readIdxString(
327 sal_uInt32
* offset
, rtl_TextEncoding encoding
) const
330 sal_uInt32 len
= read32(*offset
);
332 if ((len
& 0x80000000) == 0) {
337 off
= len
& ~0x80000000;
339 if ((len
& 0x80000000) != 0) {
340 throw FileFormatException(
341 uri
, "UNOIDL format: string length high bit set");
344 if (len
> SAL_MAX_INT32
|| len
> size
- off
- 4) {
345 throw FileFormatException(
346 uri
, "UNOIDL format: size of string is too large");
349 if (!rtl_convertStringToUString(
350 &name
.pData
, static_cast< char const * >(address
) + off
+ 4, len
,
352 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
353 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
354 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
356 throw FileFormatException(
357 uri
, "UNOIDL format: string bytes do not match encoding");
362 // sizeof (MapEntry) == 8
372 enum Compare
{ COMPARE_LESS
, COMPARE_GREATER
, COMPARE_EQUAL
};
375 rtl::Reference
< detail::MappedFile
> const & file
, OUString
const & name
,
376 sal_Int32 nameOffset
, sal_Int32 nameLength
, detail::MapEntry
const * entry
)
380 sal_uInt32 off
= entry
->name
.getUnsigned32();
381 if (off
> file
->size
- 1) { // at least a trailing NUL
382 throw FileFormatException(
383 file
->uri
, "UNOIDL format: string offset too large");
385 assert(nameLength
>= 0);
386 sal_uInt64 min
= std::min(
387 static_cast< sal_uInt64
>(nameLength
), file
->size
- off
);
388 for (sal_uInt64 i
= 0; i
!= min
; ++i
) {
389 sal_Unicode c1
= name
[nameOffset
+ i
];
390 sal_Unicode c2
= static_cast< unsigned char const * >(file
->address
)[
394 } else if (c1
> c2
|| c2
== 0) {
395 // ...the "|| c2 == 0" is for the odd case where name erroneously
396 // contains NUL characters
397 return COMPARE_GREATER
;
400 if (static_cast< sal_uInt64
>(nameLength
) == min
) {
401 if (file
->size
- off
== min
) {
402 throw FileFormatException(
403 file
->uri
, "UNOIDL format: string misses trailing NUL");
406 static_cast< unsigned char const * >(file
->address
)[off
+ min
] == 0
407 ? COMPARE_EQUAL
: COMPARE_LESS
;
409 return COMPARE_GREATER
;
413 sal_uInt32
findInMap(
414 rtl::Reference
< detail::MappedFile
> const & file
,
415 detail::MapEntry
const * mapBegin
, sal_uInt32 mapSize
,
416 OUString
const & name
, sal_Int32 nameOffset
, sal_Int32 nameLength
)
421 sal_uInt32 n
= mapSize
/ 2;
422 detail::MapEntry
const * p
= mapBegin
+ n
;
423 switch (compare(file
, name
, nameOffset
, nameLength
, p
)) {
425 return findInMap(file
, mapBegin
, n
, name
, nameOffset
, nameLength
);
426 case COMPARE_GREATER
:
428 file
, p
+ 1, mapSize
- n
- 1, name
, nameOffset
, nameLength
);
429 default: // COMPARE_EQUAL
432 sal_uInt32 off
= mapBegin
[n
].data
.getUnsigned32();
434 throw FileFormatException(
435 file
->uri
, "UNOIDL format: map entry data offset is null");
440 std::vector
< OUString
> readAnnotations(
441 bool annotated
, rtl::Reference
< detail::MappedFile
> const & file
,
442 sal_uInt32 offset
, sal_uInt32
* newOffset
= 0)
444 std::vector
< OUString
> ans
;
446 sal_uInt32 n
= file
->read32(offset
);
448 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
449 ans
.push_back(file
->readIdxString(&offset
));
452 if (newOffset
!= 0) {
458 ConstantValue
readConstant(
459 rtl::Reference
< detail::MappedFile
> const & file
, sal_uInt32 offset
,
460 sal_uInt32
* newOffset
= 0, bool * annotated
= 0)
463 int v
= file
->read8(offset
);
465 if (annotated
!= 0) {
466 *annotated
= (v
& 0x80) != 0;
470 v
= file
->read8(offset
+ 1);
471 if (newOffset
!= 0) {
472 *newOffset
= offset
+ 2;
476 return ConstantValue(false);
478 return ConstantValue(true);
480 throw FileFormatException(
482 ("UNOIDL format: bad boolean constant value "
483 + OUString::number(v
)));
486 if (newOffset
!= 0) {
487 *newOffset
= offset
+ 2;
489 return ConstantValue(static_cast< sal_Int8
>(file
->read8(offset
+ 1)));
490 //TODO: implementation-defined behavior of conversion from sal_uInt8
491 // to sal_Int8 relies on two's complement representation
493 if (newOffset
!= 0) {
494 *newOffset
= offset
+ 3;
496 return ConstantValue(
497 static_cast< sal_Int16
>(file
->read16(offset
+ 1)));
498 //TODO: implementation-defined behavior of conversion from
499 // sal_uInt16 to sal_Int16 relies on two's complement representation
500 case 3: // UNSIGNED SHORT
501 if (newOffset
!= 0) {
502 *newOffset
= offset
+ 3;
504 return ConstantValue(file
->read16(offset
+ 1));
506 if (newOffset
!= 0) {
507 *newOffset
= offset
+ 5;
509 return ConstantValue(
510 static_cast< sal_Int32
>(file
->read32(offset
+ 1)));
511 //TODO: implementation-defined behavior of conversion from
512 // sal_uInt32 to sal_Int32 relies on two's complement representation
513 case 5: // UNSIGNED LONG
514 if (newOffset
!= 0) {
515 *newOffset
= offset
+ 5;
517 return ConstantValue(file
->read32(offset
+ 1));
519 if (newOffset
!= 0) {
520 *newOffset
= offset
+ 9;
522 return ConstantValue(
523 static_cast< sal_Int64
>(file
->read64(offset
+ 1)));
524 //TODO: implementation-defined behavior of conversion from
525 // sal_uInt64 to sal_Int64 relies on two's complement representation
526 case 7: // UNSIGNED HYPER
527 if (newOffset
!= 0) {
528 *newOffset
= offset
+ 9;
530 return ConstantValue(file
->read64(offset
+ 1));
532 if (newOffset
!= 0) {
533 *newOffset
= offset
+ 5;
535 return ConstantValue(file
->readIso60599Binary32(offset
+ 1));
537 if (newOffset
!= 0) {
538 *newOffset
= offset
+ 9;
540 return ConstantValue(file
->readIso60599Binary64(offset
+ 1));
542 throw FileFormatException(
544 "UNOIDL format: bad constant type byte " + OUString::number(v
));
548 rtl::Reference
< Entity
> readEntity(
549 rtl::Reference
< detail::MappedFile
> const & file
, sal_uInt32 offset
);
551 class UnoidlCursor
: public MapCursor
{
554 rtl::Reference
< detail::MappedFile
> file
,
555 detail::MapEntry
const * mapBegin
, sal_uInt32 mapSize
):
556 file_(file
), mapIndex_(mapBegin
), mapEnd_(mapBegin
+ mapSize
)
560 virtual ~UnoidlCursor() throw () {}
562 virtual rtl::Reference
< Entity
> getNext(OUString
* name
);
564 rtl::Reference
< detail::MappedFile
> file_
;
565 detail::MapEntry
const * mapIndex_
;
566 detail::MapEntry
const * mapEnd_
;
569 rtl::Reference
< Entity
> UnoidlCursor::getNext(OUString
* name
) {
571 rtl::Reference
< Entity
> ent
;
572 if (mapIndex_
!= mapEnd_
) {
573 *name
= file_
->readNulName(mapIndex_
->name
.getUnsigned32());
574 ent
= readEntity(file_
, mapIndex_
->data
.getUnsigned32());
580 class UnoidlModuleEntity
: public ModuleEntity
{
583 rtl::Reference
< detail::MappedFile
> const & file
, sal_uInt32 mapOffset
,
587 reinterpret_cast< detail::MapEntry
const * >(
588 static_cast< char const * >(file_
->address
) + mapOffset
)),
590 { assert(file
.is()); }
593 virtual ~UnoidlModuleEntity() throw () {}
595 virtual std::vector
< OUString
> getMemberNames() const;
597 virtual rtl::Reference
< MapCursor
> createCursor() const
598 { return new UnoidlCursor(file_
, mapBegin_
, mapSize_
); }
600 rtl::Reference
< detail::MappedFile
> file_
;
601 detail::MapEntry
const * mapBegin_
;
605 std::vector
< OUString
> UnoidlModuleEntity::getMemberNames() const {
606 std::vector
< OUString
> names
;
607 for (sal_uInt32 i
= 0; i
!= mapSize_
; ++i
) {
608 names
.push_back(file_
->readNulName(mapBegin_
[i
].name
.getUnsigned32()));
613 rtl::Reference
< Entity
> readEntity(
614 rtl::Reference
< detail::MappedFile
> const & file
, sal_uInt32 offset
)
617 int v
= file
->read8(offset
);
619 bool published
= (v
& 0x80) != 0;
620 bool annotated
= (v
& 0x40) != 0;
621 bool flag
= (v
& 0x20) != 0;
626 throw FileFormatException(
628 ("UNOIDL format: bad module type byte "
629 + OUString::number(v
)));
631 sal_uInt32 n
= file
->read32(offset
+ 1);
632 if (n
> SAL_MAX_INT32
) {
633 throw FileFormatException(
634 file
->uri
, "UNOIDL format: too many items in module");
636 if (offset
+ 5 + 8 * n
> file
->size
) { //TODO: overflow
637 throw FileFormatException(
639 "UNOIDL format: module map offset + size too large");
641 return new UnoidlModuleEntity(file
, offset
+ 5, n
);
645 sal_uInt32 n
= file
->read32(offset
+ 1);
646 if (n
> SAL_MAX_INT32
) {
647 throw FileFormatException(
648 file
->uri
, "UNOIDL format: too many members of enum type");
651 std::vector
< EnumTypeEntity::Member
> mems
;
652 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
653 OUString
memName(file
->readIdxName(&offset
));
654 sal_Int32 memValue
= static_cast< sal_Int32
>(
655 file
->read32(offset
));
656 //TODO: implementation-defined behavior of conversion from
657 // sal_uInt32 to sal_Int32 relies on two's complement
661 EnumTypeEntity::Member(
663 readAnnotations(annotated
, file
, offset
, &offset
)));
665 return new EnumTypeEntity(
666 published
, mems
, readAnnotations(annotated
, file
, offset
));
668 case 2: // plain struct type without base
669 case 2 | 0x20: // plain struct type with base
674 base
= file
->readIdxName(&offset
);
675 if (base
.isEmpty()) {
676 throw FileFormatException(
678 ("UNOIDL format: empty base type name of plain struct"
682 sal_uInt32 n
= file
->read32(offset
);
683 if (n
> SAL_MAX_INT32
) {
684 throw FileFormatException(
686 ("UNOIDL format: too many direct members of plain struct"
690 std::vector
< PlainStructTypeEntity::Member
> mems
;
691 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
692 OUString
memName(file
->readIdxName(&offset
));
693 OUString
memType(file
->readIdxName(&offset
));
695 PlainStructTypeEntity::Member(
697 readAnnotations(annotated
, file
, offset
, &offset
)));
699 return new PlainStructTypeEntity(
700 published
, base
, mems
,
701 readAnnotations(annotated
, file
, offset
));
703 case 3: // polymorphic struct type template
705 sal_uInt32 n
= file
->read32(offset
+ 1);
706 if (n
> SAL_MAX_INT32
) {
707 throw FileFormatException(
709 ("UNOIDL format: too many type parameters of polymorphic"
710 " struct type template"));
713 std::vector
< OUString
> params
;
714 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
715 params
.push_back(file
->readIdxName(&offset
));
717 n
= file
->read32(offset
);
718 if (n
> SAL_MAX_INT32
) {
719 throw FileFormatException(
721 ("UNOIDL format: too many members of polymorphic struct"
725 std::vector
< PolymorphicStructTypeTemplateEntity::Member
> mems
;
726 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
727 v
= file
->read8(offset
);
729 OUString
memName(file
->readIdxName(&offset
));
730 OUString
memType(file
->readIdxName(&offset
));
732 throw FileFormatException(
734 ("UNOIDL format: bad flags " + OUString::number(v
)
735 + " for member " + memName
736 + " of polymorphic struct type template"));
739 PolymorphicStructTypeTemplateEntity::Member(
740 memName
, memType
, v
== 1,
741 readAnnotations(annotated
, file
, offset
, &offset
)));
743 return new PolymorphicStructTypeTemplateEntity(
744 published
, params
, mems
,
745 readAnnotations(annotated
, file
, offset
));
747 case 4: // exception type without base
748 case 4 | 0x20: // exception type with base
753 base
= file
->readIdxName(&offset
);
754 if (base
.isEmpty()) {
755 throw FileFormatException(
757 ("UNOIDL format: empty base type name of exception"
761 sal_uInt32 n
= file
->read32(offset
);
762 if (n
> SAL_MAX_INT32
) {
763 throw FileFormatException(
765 "UNOIDL format: too many direct members of exception type");
768 std::vector
< ExceptionTypeEntity::Member
> mems
;
769 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
770 OUString
memName(file
->readIdxName(&offset
));
771 OUString
memType(file
->readIdxName(&offset
));
773 ExceptionTypeEntity::Member(
775 readAnnotations(annotated
, file
, offset
, &offset
)));
777 return new ExceptionTypeEntity(
778 published
, base
, mems
,
779 readAnnotations(annotated
, file
, offset
));
781 case 5: // interface type
783 sal_uInt32 n
= file
->read32(offset
+ 1);
784 if (n
> SAL_MAX_INT32
) {
785 throw FileFormatException(
787 ("UNOIDL format: too many direct mandatory bases of"
791 std::vector
< AnnotatedReference
> mandBases
;
792 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
793 OUString
base(file
->readIdxName(&offset
));
797 readAnnotations(annotated
, file
, offset
, &offset
)));
799 n
= file
->read32(offset
);
800 if (n
> SAL_MAX_INT32
) {
801 throw FileFormatException(
803 ("UNOIDL format: too many direct optional bases of"
807 std::vector
< AnnotatedReference
> optBases
;
808 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
809 OUString
base(file
->readIdxName(&offset
));
813 readAnnotations(annotated
, file
, offset
, &offset
)));
815 sal_uInt32 nAttrs
= file
->read32(offset
);
816 if (nAttrs
> SAL_MAX_INT32
) {
817 throw FileFormatException(
819 ("UNOIDL format: too many direct attributes of interface"
823 std::vector
< InterfaceTypeEntity::Attribute
> attrs
;
824 for (sal_uInt32 i
= 0; i
!= nAttrs
; ++i
) {
825 v
= file
->read8(offset
);
827 OUString
attrName(file
->readIdxName(&offset
));
828 OUString
attrType(file
->readIdxName(&offset
));
830 throw FileFormatException(
832 ("UNOIDL format: bad flags for direct attribute "
833 + attrName
+ " of interface type"));
835 std::vector
< OUString
> getExcs
;
836 sal_uInt32 m
= file
->read32(offset
);
837 if (m
> SAL_MAX_INT32
) {
838 throw FileFormatException(
840 ("UNOIDL format: too many getter exceptions for direct"
841 " attribute " + attrName
+ " of interface type"));
844 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
845 getExcs
.push_back(file
->readIdxName(&offset
));
847 std::vector
< OUString
> setExcs
;
848 if ((v
& 0x02) == 0) {
849 m
= file
->read32(offset
);
850 if (m
> SAL_MAX_INT32
) {
851 throw FileFormatException(
853 ("UNOIDL format: too many setter exceptions for"
854 " direct attribute " + attrName
855 + " of interface type"));
858 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
859 setExcs
.push_back(file
->readIdxName(&offset
));
863 InterfaceTypeEntity::Attribute(
864 attrName
, attrType
, (v
& 0x01) != 0, (v
& 0x02) != 0,
866 readAnnotations(annotated
, file
, offset
, &offset
)));
868 sal_uInt32 nMeths
= file
->read32(offset
);
869 if (nMeths
> SAL_MAX_INT32
- nAttrs
) {
870 throw FileFormatException(
872 ("UNOIDL format: too many direct attributes and methods of"
876 std::vector
< InterfaceTypeEntity::Method
> meths
;
877 for (sal_uInt32 i
= 0; i
!= nMeths
; ++i
) {
878 OUString
methName(file
->readIdxName(&offset
));
879 OUString
methType(file
->readIdxName(&offset
));
880 sal_uInt32 m
= file
->read32(offset
);
881 if (m
> SAL_MAX_INT32
) {
882 throw FileFormatException(
884 ("UNOIDL format: too many parameters for method "
885 + methName
+ " of interface type"));
888 std::vector
< InterfaceTypeEntity::Method::Parameter
> params
;
889 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
890 v
= file
->read8(offset
);
892 OUString
paramName(file
->readIdxName(&offset
));
893 OUString
paramType(file
->readIdxName(&offset
));
894 InterfaceTypeEntity::Method::Parameter::Direction dir
;
897 dir
= InterfaceTypeEntity::Method::Parameter::
901 dir
= InterfaceTypeEntity::Method::Parameter::
905 dir
= InterfaceTypeEntity::Method::Parameter::
909 throw FileFormatException(
911 ("UNOIDL format: bad direction "
912 + OUString::number(v
) + " of parameter "
913 + paramName
+ " for method " + methName
914 + " of interface type"));
917 InterfaceTypeEntity::Method::Parameter(
918 paramName
, paramType
, dir
));
920 std::vector
< OUString
> excs
;
921 m
= file
->read32(offset
);
922 if (m
> SAL_MAX_INT32
) {
923 throw FileFormatException(
925 ("UNOIDL format: too many exceptions for method "
926 + methName
+ " of interface type"));
929 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
930 excs
.push_back(file
->readIdxName(&offset
));
933 InterfaceTypeEntity::Method(
934 methName
, methType
, params
, excs
,
935 readAnnotations(annotated
, file
, offset
, &offset
)));
937 return new InterfaceTypeEntity(
938 published
, mandBases
, optBases
, attrs
, meths
,
939 readAnnotations(annotated
, file
, offset
));
944 OUString
base(file
->readIdxName(&offset
));
945 return new TypedefEntity(
946 published
, base
, readAnnotations(annotated
, file
, offset
));
948 case 7: // constant group
950 sal_uInt32 n
= file
->read32(offset
+ 1);
951 if (n
> SAL_MAX_INT32
) {
952 throw FileFormatException(
954 "UNOIDL format: too many constants in constant group");
956 if (offset
+ 5 + 8 * n
> file
->size
) { //TODO: overflow
957 throw FileFormatException(
959 ("UNOIDL format: constant group map offset + size too"
962 detail::MapEntry
const * p
963 = reinterpret_cast< detail::MapEntry
const * >(
964 static_cast< char const * >(file
->address
) + offset
+ 5);
965 std::vector
< ConstantGroupEntity::Member
> mems
;
966 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
967 sal_uInt32 off
= p
[i
].data
.getUnsigned32();
969 ConstantValue
val(readConstant(file
, off
, &off
, &ann
));
971 ConstantGroupEntity::Member(
972 file
->readNulName(p
[i
].name
.getUnsigned32()), val
,
973 readAnnotations(ann
, file
, off
)));
975 return new ConstantGroupEntity(
977 readAnnotations(annotated
, file
, offset
+ 5 + 8 * n
));
979 case 8: // single-interface--based service without default constructor
980 case 8 | 0x20: // single-interface--based service with default constructor
983 OUString
base(file
->readIdxName(&offset
));
984 std::vector
< SingleInterfaceBasedServiceEntity::Constructor
> ctors
;
987 SingleInterfaceBasedServiceEntity::Constructor());
989 sal_uInt32 n
= file
->read32(offset
);
990 if (n
> SAL_MAX_INT32
) {
991 throw FileFormatException(
993 ("UNOIDL format: too many constructors of"
994 " single-interface--based service"));
997 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
998 OUString
ctorName(file
->readIdxName(&offset
));
999 sal_uInt32 m
= file
->read32(offset
);
1000 if (m
> SAL_MAX_INT32
) {
1001 throw FileFormatException(
1003 ("UNOIDL format: too many parameters for"
1004 " constructor " + ctorName
1005 + " of single-interface--based service"));
1009 SingleInterfaceBasedServiceEntity::Constructor::
1011 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1012 v
= file
->read8(offset
);
1014 OUString
paramName(file
->readIdxName(&offset
));
1015 OUString
paramType(file
->readIdxName(&offset
));
1025 throw FileFormatException(
1027 ("UNOIDL format: bad mode "
1028 + OUString::number(v
) + " of parameter "
1029 + paramName
+ " for constructor " + ctorName
1030 + " of single-interface--based service"));
1033 SingleInterfaceBasedServiceEntity::Constructor::
1035 paramName
, paramType
, rest
));
1037 std::vector
< OUString
> excs
;
1038 m
= file
->read32(offset
);
1039 if (m
> SAL_MAX_INT32
) {
1040 throw FileFormatException(
1042 ("UNOIDL format: too many exceptions for"
1043 " constructor " + ctorName
1044 + " of single-interface--based service"));
1047 for (sal_uInt32 j
= 0; j
!= m
; ++j
) {
1048 excs
.push_back(file
->readIdxName(&offset
));
1051 SingleInterfaceBasedServiceEntity::Constructor(
1052 ctorName
, params
, excs
,
1053 readAnnotations(annotated
, file
, offset
, &offset
)));
1056 return new SingleInterfaceBasedServiceEntity(
1057 published
, base
, ctors
,
1058 readAnnotations(annotated
, file
, offset
));
1060 case 9: // accumulation-based service
1062 sal_uInt32 n
= file
->read32(offset
+ 1);
1063 if (n
> SAL_MAX_INT32
) {
1064 throw FileFormatException(
1066 ("UNOIDL format: too many direct mandatory service bases of"
1067 " accumulation-based service"));
1070 std::vector
< AnnotatedReference
> mandServs
;
1071 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1072 OUString
base(file
->readIdxName(&offset
));
1073 mandServs
.push_back(
1076 readAnnotations(annotated
, file
, offset
, &offset
)));
1078 n
= file
->read32(offset
);
1079 if (n
> SAL_MAX_INT32
) {
1080 throw FileFormatException(
1082 ("UNOIDL format: too many direct optional service bases of"
1083 " accumulation-based service"));
1086 std::vector
< AnnotatedReference
> optServs
;
1087 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1088 OUString
base(file
->readIdxName(&offset
));
1092 readAnnotations(annotated
, file
, offset
, &offset
)));
1094 n
= file
->read32(offset
);
1095 if (n
> SAL_MAX_INT32
) {
1096 throw FileFormatException(
1098 ("UNOIDL format: too many direct mandatory interface bases"
1099 " of accumulation-based service"));
1102 std::vector
< AnnotatedReference
> mandIfcs
;
1103 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1104 OUString
base(file
->readIdxName(&offset
));
1108 readAnnotations(annotated
, file
, offset
, &offset
)));
1110 n
= file
->read32(offset
);
1111 if (n
> SAL_MAX_INT32
) {
1112 throw FileFormatException(
1114 ("UNOIDL format: too many direct optional interface bases"
1115 " of accumulation-based service"));
1118 std::vector
< AnnotatedReference
> optIfcs
;
1119 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1120 OUString
base(file
->readIdxName(&offset
));
1124 readAnnotations(annotated
, file
, offset
, &offset
)));
1126 n
= file
->read32(offset
);
1127 if (n
> SAL_MAX_INT32
) {
1128 throw FileFormatException(
1130 ("UNOIDL format: too many direct properties of"
1131 " accumulation-based service"));
1134 std::vector
< AccumulationBasedServiceEntity::Property
> props
;
1135 for (sal_uInt32 i
= 0; i
!= n
; ++i
) {
1136 sal_uInt16 attrs
= file
->read16(offset
);
1138 OUString
propName(file
->readIdxName(&offset
));
1139 OUString
propType(file
->readIdxName(&offset
));
1140 if (attrs
> 0x01FF) { // see css.beans.PropertyAttribute
1141 throw FileFormatException(
1143 ("UNOIDL format: bad mode " + OUString::number(v
)
1144 + " of property " + propName
1145 + " for accumulation-based servcie"));
1148 AccumulationBasedServiceEntity::Property(
1151 AccumulationBasedServiceEntity::Property::
1154 readAnnotations(annotated
, file
, offset
, &offset
)));
1156 return new AccumulationBasedServiceEntity(
1157 published
, mandServs
, optServs
, mandIfcs
, optIfcs
, props
,
1158 readAnnotations(annotated
, file
, offset
));
1160 case 10: // interface-based singleton
1163 OUString
base(file
->readIdxName(&offset
));
1164 return new InterfaceBasedSingletonEntity(
1165 published
, base
, readAnnotations(annotated
, file
, offset
));
1167 case 11: // service-based singleton
1170 OUString
base(file
->readIdxName(&offset
));
1171 return new ServiceBasedSingletonEntity(
1172 published
, base
, readAnnotations(annotated
, file
, offset
));
1175 throw FileFormatException(
1176 file
->uri
, "UNOIDL format: bad type byte " + OUString::number(v
));
1182 UnoidlProvider::UnoidlProvider(OUString
const & uri
):
1183 file_(new detail::MappedFile(uri
))
1185 if (file_
->size
< 8 || std::memcmp(file_
->address
, "UNOIDL\xFF\0", 8) != 0)
1187 throw FileFormatException(
1189 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1192 sal_uInt32 off
= file_
->read32(8);
1193 mapSize_
= file_
->read32(12);
1194 if (off
+ 8 * mapSize_
> file_
->size
) { //TODO: overflow
1195 throw FileFormatException(
1196 file_
->uri
, "UNOIDL format: root map offset + size too large");
1198 mapBegin_
= reinterpret_cast< detail::MapEntry
const * >(
1199 static_cast< char const * >(file_
->address
) + off
);
1202 rtl::Reference
< MapCursor
> UnoidlProvider::createRootCursor() const {
1203 return new UnoidlCursor(file_
, mapBegin_
, mapSize_
);
1206 rtl::Reference
< Entity
> UnoidlProvider::findEntity(OUString
const & name
) const
1209 sal_uInt32 off
= find(name
, &cnst
);
1210 return off
== 0 || cnst
? rtl::Reference
< Entity
>() : getEntity(off
);
1213 sal_uInt32
UnoidlProvider::find(OUString
const & name
, bool * constant
) const {
1214 detail::MapEntry
const * mapBegin
= mapBegin_
;
1215 sal_uInt32 mapSize
= mapSize_
;
1216 bool cgroup
= false;
1217 for (sal_Int32 i
= 0;;) {
1218 sal_Int32 j
= name
.indexOf('.', i
);
1220 j
= name
.getLength();
1222 sal_Int32 off
= findInMap(file_
, mapBegin
, mapSize
, name
, i
, j
- i
);
1226 if (j
== name
.getLength()) {
1227 if (constant
!= 0) {
1234 //TODO: throw an exception instead here, where the segments of a
1235 // constant's name are a prefix of the requested name's
1238 int v
= file_
->read8(off
);
1239 if (v
!= 0) { // module
1240 if ((v
& 0x3F) == 7) { // constant group
1244 //TODO: throw an exception instead here, where the segments
1245 // of a non-module, non-constant-group entity's name are a
1246 // prefix of the requested name's segments?
1249 mapSize
= file_
->read32(off
+ 1);
1250 if (8 * mapSize
> file_
->size
- off
- 5) { //TODO: overflow
1251 throw FileFormatException(
1252 file_
->uri
, "UNOIDL format: map offset + size too large");
1254 mapBegin
= reinterpret_cast< detail::MapEntry
const * >(
1255 static_cast< char const * >(file_
->address
) + off
+ 5);
1260 rtl::Reference
< Entity
> UnoidlProvider::getEntity(sal_uInt32 offset
) const {
1261 return readEntity(file_
, offset
);
1264 ConstantValue
UnoidlProvider::getConstant(sal_uInt32 offset
) const {
1265 return readConstant(file_
, offset
);
1268 UnoidlProvider::~UnoidlProvider() throw () {}
1272 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */