bump product version to 5.0.4.1
[LibreOffice.git] / unoidl / source / unoidlprovider.cxx
blob90f3b81ab9494fdd545858a97e74cec6d60b5bbe
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include "sal/config.h"
12 #include <algorithm>
13 #include <cassert>
14 #include <cstring>
15 #include <set>
16 #include <vector>
18 #include "osl/endian.h"
19 #include "osl/file.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 {
35 public:
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); }
58 OUString uri;
59 oslFileHandle handle;
60 sal_uInt64 size;
61 void * address;
63 private:
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)
79 const;
82 namespace {
84 // sizeof (Memory16) == 2
85 struct Memory16 {
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
95 struct Memory32 {
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 {
106 union {
107 unsigned char buf[4];
108 float f; // assuming float is ISO 60599 binary32
109 } sa;
110 #if defined OSL_LITENDIAN
111 sa.buf[0] = byte[0];
112 sa.buf[1] = byte[1];
113 sa.buf[2] = byte[2];
114 sa.buf[3] = byte[3];
115 #else
116 sa.buf[0] = byte[3];
117 sa.buf[1] = byte[2];
118 sa.buf[2] = byte[1];
119 sa.buf[3] = byte[0];
120 #endif
121 return sa.f;
125 // sizeof (Memory64) == 8
126 struct Memory64 {
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 {
141 union {
142 unsigned char buf[8];
143 double d; // assuming double is ISO 60599 binary64
144 } sa;
145 #if defined OSL_LITENDIAN
146 sa.buf[0] = byte[0];
147 sa.buf[1] = byte[1];
148 sa.buf[2] = byte[2];
149 sa.buf[3] = byte[3];
150 sa.buf[4] = byte[4];
151 sa.buf[5] = byte[5];
152 sa.buf[6] = byte[6];
153 sa.buf[7] = byte[7];
154 #else
155 sa.buf[0] = byte[7];
156 sa.buf[1] = byte[6];
157 sa.buf[2] = byte[5];
158 sa.buf[3] = byte[4];
159 sa.buf[4] = byte[3];
160 sa.buf[5] = byte[2];
161 sa.buf[6] = byte[1];
162 sa.buf[7] = byte[0];
163 #endif
164 return sa.d;
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"
174 || type == "any";
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()) {
187 return false;
189 for (sal_Int32 i = 0; i != type.getLength(); ++i) {
190 sal_Unicode c = type[i];
191 if (c == '.') {
192 if (!scoped || i == 0 || i == type.getLength() - 1
193 || type[i - 1] == '.')
195 return false;
197 } else if (!rtl::isAsciiAlphanumeric(c) && c != '_') {
198 return false;
201 return true;
204 void checkTypeName(
205 rtl::Reference< MappedFile > const & file, OUString const & type)
207 OUString nucl(type);
208 bool args = false;
209 while (nucl.startsWith("[]", &nucl)) {}
210 sal_Int32 i = nucl.indexOf('<');
211 if (i != -1) {
212 OUString tmpl(nucl.copy(0, i));
213 do {
214 ++i; // skip '<' or ','
215 sal_Int32 j = i;
216 for (sal_Int32 level = 0; j != nucl.getLength(); ++j) {
217 sal_Unicode c = nucl[j];
218 if (c == ',') {
219 if (level == 0) {
220 break;
222 } else if (c == '<') {
223 ++level;
224 } else if (c == '>') {
225 if (level == 0) {
226 break;
228 --level;
231 if (j != nucl.getLength()) {
232 checkTypeName(file, nucl.copy(i, j - i));
233 args = true;
235 i = j;
236 } while (i != nucl.getLength() && nucl[i] != '>');
237 if (i != nucl.getLength() - 1 || nucl[i] != '>' || !args) {
238 tmpl.clear(); // bad input
240 nucl = tmpl;
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);
261 switch (e) {
262 case osl_File_E_None:
263 break;
264 case osl_File_E_NOENT:
265 throw NoSuchFileException(uri);
266 default:
267 throw FileFormatException(uri, "cannot open: " + OUString::number(e));
269 e = osl_getFileSize(handle, &size);
270 if (e == osl_File_E_None) {
271 e = osl_mapFile(
272 handle, &address, size, 0, osl_File_MapFlag_RandomAccess);
274 if (e != osl_File_E_None) {
275 oslFileError e2 = osl_closeFile(handle);
276 SAL_WARN_IF(
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 {
284 assert(size >= 8);
285 if (offset > size - 1) {
286 throw FileFormatException(
287 uri, "UNOIDL format: offset for 8-bit value too large");
289 return get8(offset);
292 sal_uInt16 MappedFile::read16(sal_uInt32 offset) const {
293 assert(size >= 8);
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 {
302 assert(size >= 8);
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 {
311 assert(size >= 8);
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 {
320 assert(size >= 8);
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 {
329 assert(size >= 8);
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) {
338 if (offset > size) {
339 throw FileFormatException(
340 uri, "UNOIDL format: offset for string too large");
342 sal_uInt64 end = offset;
343 for (;; ++end) {
344 if (end == size) {
345 throw FileFormatException(
346 uri, "UNOIDL format: string misses trailing NUL");
348 if (static_cast< char const * >(address)[end] == 0) {
349 break;
352 if (end - offset > SAL_MAX_INT32) {
353 throw FileFormatException(uri, "UNOIDL format: string too long");
355 OUString name;
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);
366 return 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 {
377 assert(size >= 8);
378 assert(offset <= size - 1);
379 return static_cast< char const * >(address)[offset];
382 sal_uInt16 MappedFile::get16(sal_uInt32 offset) const {
383 assert(size >= 8);
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 {
390 assert(size >= 8);
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 {
397 assert(size >= 8);
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 {
404 assert(size >= 8);
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 {
411 assert(size >= 8);
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 != 0);
421 sal_uInt32 len = read32(*offset);
422 sal_uInt32 off;
423 if ((len & 0x80000000) == 0) {
424 off = *offset;
425 *offset += 4 + len;
426 } else {
427 *offset += 4;
428 off = len & ~0x80000000;
429 len = read32(off);
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");
439 OUString name;
440 if (!rtl_convertStringToUString(
441 &name.pData, static_cast< char const * >(address) + off + 4, len,
442 encoding,
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");
450 return name;
453 // sizeof (MapEntry) == 8
454 struct MapEntry {
455 Memory32 name;
456 Memory32 data;
459 bool operator <(const Map& map1, const Map& map2) {
460 return map1.begin < map2.begin
461 || (map1.begin == map2.begin && map1.size < map2.size);
464 namespace {
466 enum Compare { COMPARE_LESS, COMPARE_GREATER, COMPARE_EQUAL };
468 Compare compare(
469 rtl::Reference< MappedFile > const & file, OUString const & name,
470 sal_Int32 nameOffset, sal_Int32 nameLength, MapEntry const * entry)
472 assert(file.is());
473 assert(entry != 0);
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)[
485 off + i];
486 if (c1 < c2) {
487 return COMPARE_LESS;
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");
499 return
500 static_cast< unsigned char const * >(file->address)[off + min] == 0
501 ? COMPARE_EQUAL : COMPARE_LESS;
502 } else {
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)
512 if (mapSize == 0) {
513 return 0;
515 sal_uInt32 n = mapSize / 2;
516 MapEntry const * p = mapBegin + n;
517 switch (compare(file, name, nameOffset, nameLength, p)) {
518 case COMPARE_LESS:
519 return findInMap(file, mapBegin, n, name, nameOffset, nameLength);
520 case COMPARE_GREATER:
521 return findInMap(
522 file, p + 1, mapSize - n - 1, name, nameOffset, nameLength);
523 default: // COMPARE_EQUAL
524 break;
526 sal_uInt32 off = mapBegin[n].data.getUnsigned32();
527 if (off == 0) {
528 throw FileFormatException(
529 file->uri, "UNOIDL format: map entry data offset is null");
531 return off;
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;
539 if (annotated) {
540 sal_uInt32 n = file->read32(offset);
541 offset += 4;
542 for (sal_uInt32 i = 0; i != n; ++i) {
543 ans.push_back(file->readIdxString(&offset));
546 if (newOffset != 0) {
547 *newOffset = offset;
549 return ans;
552 ConstantValue readConstant(
553 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
554 sal_uInt32 * newOffset = 0, bool * annotated = 0)
556 assert(file.is());
557 int v = file->read8(offset);
558 int type = v & 0x7F;
559 if (annotated != 0) {
560 *annotated = (v & 0x80) != 0;
562 switch (type) {
563 case 0: // BOOLEAN
564 v = file->read8(offset + 1);
565 if (newOffset != 0) {
566 *newOffset = offset + 2;
568 switch (v) {
569 case 0:
570 return ConstantValue(false);
571 case 1:
572 return ConstantValue(true);
573 default:
574 throw FileFormatException(
575 file->uri,
576 ("UNOIDL format: bad boolean constant value "
577 + OUString::number(v)));
579 case 1: // BYTE
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
586 case 2: // SHORT
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));
599 case 4: // LONG
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));
612 case 6: // HYPER
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));
625 case 8: // FLOAT
626 if (newOffset != 0) {
627 *newOffset = offset + 5;
629 return ConstantValue(file->readIso60599Binary32(offset + 1));
630 case 9: // DOUBLE
631 if (newOffset != 0) {
632 *newOffset = offset + 9;
634 return ConstantValue(file->readIso60599Binary64(offset + 1));
635 default:
636 throw FileFormatException(
637 file->uri,
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 {
649 public:
650 UnoidlCursor(
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),
656 map_(map), index_(0)
659 private:
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_;
668 sal_uInt32 index_;
671 rtl::Reference< Entity > UnoidlCursor::getNext(OUString * name) {
672 assert(name != 0);
673 rtl::Reference< Entity > ent;
674 if (index_ != map_.map.size) {
675 *name = file_->readNulName(map_.map.begin[index_].name.getUnsigned32());
676 ent = readEntity(
677 file_, map_.map.begin[index_].data.getUnsigned32(), map_.trace);
678 ++index_;
680 return ent;
683 class UnoidlModuleEntity: public ModuleEntity {
684 public:
685 UnoidlModuleEntity(
686 rtl::Reference< MappedFile > const & file, sal_uInt32 mapOffset,
687 sal_uInt32 mapSize, std::set<Map> const & trace):
688 file_(file)
690 assert(file.is());
691 map_.map.begin = reinterpret_cast<MapEntry const *>(
692 static_cast<char const *>(file_->address) + mapOffset);
693 map_.map.size = mapSize;
694 map_.trace = trace;
695 if (!map_.trace.insert(map_.map).second) {
696 throw FileFormatException(
697 file_->uri, "UNOIDL format: recursive map");
701 private:
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_;
713 NestedMap map_;
716 std::vector< OUString > UnoidlModuleEntity::getMemberNames() const {
717 std::vector< OUString > names;
718 for (sal_uInt32 i = 0; i != map_.map.size; ++i) {
719 names.push_back(
720 file_->readNulName(map_.map.begin[i].name.getUnsigned32()));
722 return names;
725 rtl::Reference< Entity > readEntity(
726 rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
727 std::set<Map> const & trace)
729 assert(file.is());
730 int v = file->read8(offset);
731 int type = v & 0x3F;
732 bool published = (v & 0x80) != 0;
733 bool annotated = (v & 0x40) != 0;
734 bool flag = (v & 0x20) != 0;
735 switch (type) {
736 case 0: // module
738 if (v != 0) {
739 throw FileFormatException(
740 file->uri,
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)
750 // cannot overflow
752 throw FileFormatException(
753 file->uri,
754 "UNOIDL format: module map offset + size too large");
756 return new UnoidlModuleEntity(file, offset + 5, n, trace);
758 case 1: // enum type
760 sal_uInt32 n = file->read32(offset + 1);
761 if (n == 0) {
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");
769 offset += 5;
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
778 // representation
779 offset += 4;
780 mems.push_back(
781 EnumTypeEntity::Member(
782 memName, memValue,
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
791 ++offset;
792 OUString base;
793 if (flag) {
794 base = file->readIdxName(&offset);
795 if (base.isEmpty()) {
796 throw FileFormatException(
797 file->uri,
798 ("UNOIDL format: empty base type name of plain struct"
799 " type"));
801 checkTypeName(file, base);
803 sal_uInt32 n = file->read32(offset);
804 if (n > SAL_MAX_INT32) {
805 throw FileFormatException(
806 file->uri,
807 ("UNOIDL format: too many direct members of plain struct"
808 " type"));
810 offset += 4;
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);
817 mems.push_back(
818 PlainStructTypeEntity::Member(
819 memName, memType,
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(
831 file->uri,
832 ("UNOIDL format: too many type parameters of polymorphic"
833 " struct type template"));
835 offset += 5;
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(
845 file->uri,
846 ("UNOIDL format: too many members of polymorphic struct"
847 " type template"));
849 offset += 4;
850 std::vector< PolymorphicStructTypeTemplateEntity::Member > mems;
851 for (sal_uInt32 i = 0; i != n; ++i) {
852 v = file->read8(offset);
853 ++offset;
854 OUString memName(file->readIdxName(&offset));
855 checkEntityName(file, memName);
856 OUString memType(file->readIdxName(&offset));
857 checkTypeName(file, memType);
858 if (v > 1) {
859 throw FileFormatException(
860 file->uri,
861 ("UNOIDL format: bad flags " + OUString::number(v)
862 + " for member " + memName
863 + " of polymorphic struct type template"));
865 mems.push_back(
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
877 ++offset;
878 OUString base;
879 if (flag) {
880 base = file->readIdxName(&offset);
881 if (base.isEmpty()) {
882 throw FileFormatException(
883 file->uri,
884 ("UNOIDL format: empty base type name of exception"
885 " type"));
887 checkTypeName(file, base);
889 sal_uInt32 n = file->read32(offset);
890 if (n > SAL_MAX_INT32) {
891 throw FileFormatException(
892 file->uri,
893 "UNOIDL format: too many direct members of exception type");
895 offset += 4;
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);
902 mems.push_back(
903 ExceptionTypeEntity::Member(
904 memName, memType,
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(
916 file->uri,
917 ("UNOIDL format: too many direct mandatory bases of"
918 " interface type"));
920 offset += 5;
921 std::vector< AnnotatedReference > mandBases;
922 for (sal_uInt32 i = 0; i != n; ++i) {
923 OUString base(file->readIdxName(&offset));
924 checkTypeName(file, base);
925 mandBases.push_back(
926 AnnotatedReference(
927 base,
928 readAnnotations(annotated, file, offset, &offset)));
930 n = file->read32(offset);
931 if (n > SAL_MAX_INT32) {
932 throw FileFormatException(
933 file->uri,
934 ("UNOIDL format: too many direct optional bases of"
935 " interface type"));
937 offset += 4;
938 std::vector< AnnotatedReference > optBases;
939 for (sal_uInt32 i = 0; i != n; ++i) {
940 OUString base(file->readIdxName(&offset));
941 checkTypeName(file, base);
942 optBases.push_back(
943 AnnotatedReference(
944 base,
945 readAnnotations(annotated, file, offset, &offset)));
947 sal_uInt32 nAttrs = file->read32(offset);
948 if (nAttrs > SAL_MAX_INT32) {
949 throw FileFormatException(
950 file->uri,
951 ("UNOIDL format: too many direct attributes of interface"
952 " type"));
954 offset += 4;
955 std::vector< InterfaceTypeEntity::Attribute > attrs;
956 for (sal_uInt32 i = 0; i != nAttrs; ++i) {
957 v = file->read8(offset);
958 ++offset;
959 OUString attrName(file->readIdxName(&offset));
960 checkEntityName(file, attrName);
961 OUString attrType(file->readIdxName(&offset));
962 checkTypeName(file, attrType);
963 if (v > 0x03) {
964 throw FileFormatException(
965 file->uri,
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(
973 file->uri,
974 ("UNOIDL format: too many getter exceptions for direct"
975 " attribute " + attrName + " of interface type"));
977 offset += 4;
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(
988 file->uri,
989 ("UNOIDL format: too many setter exceptions for"
990 " direct attribute " + attrName
991 + " of interface type"));
993 offset += 4;
994 for (sal_uInt32 j = 0; j != m; ++j) {
995 OUString exc(file->readIdxName(&offset));
996 checkTypeName(file, exc);
997 setExcs.push_back(exc);
1000 attrs.push_back(
1001 InterfaceTypeEntity::Attribute(
1002 attrName, attrType, (v & 0x01) != 0, (v & 0x02) != 0,
1003 getExcs, setExcs,
1004 readAnnotations(annotated, file, offset, &offset)));
1006 sal_uInt32 nMeths = file->read32(offset);
1007 if (nMeths > SAL_MAX_INT32 - nAttrs) {
1008 throw FileFormatException(
1009 file->uri,
1010 ("UNOIDL format: too many direct attributes and methods of"
1011 " interface type"));
1013 offset += 4;
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(
1023 file->uri,
1024 ("UNOIDL format: too many parameters for method "
1025 + methName + " of interface type"));
1027 offset += 4;
1028 std::vector< InterfaceTypeEntity::Method::Parameter > params;
1029 for (sal_uInt32 j = 0; j != m; ++j) {
1030 v = file->read8(offset);
1031 ++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;
1037 switch (v) {
1038 case 0:
1039 dir = InterfaceTypeEntity::Method::Parameter::
1040 DIRECTION_IN;
1041 break;
1042 case 1:
1043 dir = InterfaceTypeEntity::Method::Parameter::
1044 DIRECTION_OUT;
1045 break;
1046 case 2:
1047 dir = InterfaceTypeEntity::Method::Parameter::
1048 DIRECTION_IN_OUT;
1049 break;
1050 default:
1051 throw FileFormatException(
1052 file->uri,
1053 ("UNOIDL format: bad direction "
1054 + OUString::number(v) + " of parameter "
1055 + paramName + " for method " + methName
1056 + " of interface type"));
1058 params.push_back(
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(
1066 file->uri,
1067 ("UNOIDL format: too many exceptions for method "
1068 + methName + " of interface type"));
1070 offset += 4;
1071 for (sal_uInt32 j = 0; j != m; ++j) {
1072 OUString exc(file->readIdxName(&offset));
1073 checkTypeName(file, exc);
1074 excs.push_back(exc);
1076 meths.push_back(
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));
1085 case 6: // typedef
1087 ++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(
1098 file->uri,
1099 "UNOIDL format: too many constants in constant group");
1101 if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
1102 // cannot overflow
1104 throw FileFormatException(
1105 file->uri,
1106 ("UNOIDL format: constant group map offset + size too"
1107 " large"));
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();
1114 bool ann;
1115 ConstantValue val(readConstant(file, off, &off, &ann));
1116 mems.push_back(
1117 ConstantGroupEntity::Member(
1118 file->readNulName(p[i].name.getUnsigned32()), val,
1119 readAnnotations(ann, file, off)));
1121 return new ConstantGroupEntity(
1122 published, mems,
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
1128 ++offset;
1129 OUString base(file->readIdxName(&offset));
1130 checkTypeName(file, base);
1131 std::vector< SingleInterfaceBasedServiceEntity::Constructor > ctors;
1132 if (flag) {
1133 ctors.push_back(
1134 SingleInterfaceBasedServiceEntity::Constructor());
1135 } else {
1136 sal_uInt32 n = file->read32(offset);
1137 if (n > SAL_MAX_INT32) {
1138 throw FileFormatException(
1139 file->uri,
1140 ("UNOIDL format: too many constructors of"
1141 " single-interface--based service"));
1143 offset += 4;
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(
1150 file->uri,
1151 ("UNOIDL format: too many parameters for"
1152 " constructor " + ctorName
1153 + " of single-interface--based service"));
1155 offset += 4;
1156 std::vector<
1157 SingleInterfaceBasedServiceEntity::Constructor::
1158 Parameter > params;
1159 for (sal_uInt32 j = 0; j != m; ++j) {
1160 v = file->read8(offset);
1161 ++offset;
1162 OUString paramName(file->readIdxName(&offset));
1163 checkEntityName(file, paramName);
1164 OUString paramType(file->readIdxName(&offset));
1165 checkTypeName(file, paramType);
1166 bool rest;
1167 switch (v) {
1168 case 0:
1169 rest = false;
1170 break;
1171 case 0x04:
1172 rest = true;
1173 break;
1174 default:
1175 throw FileFormatException(
1176 file->uri,
1177 ("UNOIDL format: bad mode "
1178 + OUString::number(v) + " of parameter "
1179 + paramName + " for constructor " + ctorName
1180 + " of single-interface--based service"));
1182 params.push_back(
1183 SingleInterfaceBasedServiceEntity::Constructor::
1184 Parameter(
1185 paramName, paramType, rest));
1187 std::vector< OUString > excs;
1188 m = file->read32(offset);
1189 if (m > SAL_MAX_INT32) {
1190 throw FileFormatException(
1191 file->uri,
1192 ("UNOIDL format: too many exceptions for"
1193 " constructor " + ctorName
1194 + " of single-interface--based service"));
1196 offset += 4;
1197 for (sal_uInt32 j = 0; j != m; ++j) {
1198 OUString exc(file->readIdxName(&offset));
1199 checkTypeName(file, exc);
1200 excs.push_back(exc);
1202 ctors.push_back(
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(
1217 file->uri,
1218 ("UNOIDL format: too many direct mandatory service bases of"
1219 " accumulation-based service"));
1221 offset += 5;
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(
1227 AnnotatedReference(
1228 base,
1229 readAnnotations(annotated, file, offset, &offset)));
1231 n = file->read32(offset);
1232 if (n > SAL_MAX_INT32) {
1233 throw FileFormatException(
1234 file->uri,
1235 ("UNOIDL format: too many direct optional service bases of"
1236 " accumulation-based service"));
1238 offset += 4;
1239 std::vector< AnnotatedReference > optServs;
1240 for (sal_uInt32 i = 0; i != n; ++i) {
1241 OUString base(file->readIdxName(&offset));
1242 checkTypeName(file, base);
1243 optServs.push_back(
1244 AnnotatedReference(
1245 base,
1246 readAnnotations(annotated, file, offset, &offset)));
1248 n = file->read32(offset);
1249 if (n > SAL_MAX_INT32) {
1250 throw FileFormatException(
1251 file->uri,
1252 ("UNOIDL format: too many direct mandatory interface bases"
1253 " of accumulation-based service"));
1255 offset += 4;
1256 std::vector< AnnotatedReference > mandIfcs;
1257 for (sal_uInt32 i = 0; i != n; ++i) {
1258 OUString base(file->readIdxName(&offset));
1259 checkTypeName(file, base);
1260 mandIfcs.push_back(
1261 AnnotatedReference(
1262 base,
1263 readAnnotations(annotated, file, offset, &offset)));
1265 n = file->read32(offset);
1266 if (n > SAL_MAX_INT32) {
1267 throw FileFormatException(
1268 file->uri,
1269 ("UNOIDL format: too many direct optional interface bases"
1270 " of accumulation-based service"));
1272 offset += 4;
1273 std::vector< AnnotatedReference > optIfcs;
1274 for (sal_uInt32 i = 0; i != n; ++i) {
1275 OUString base(file->readIdxName(&offset));
1276 checkTypeName(file, base);
1277 optIfcs.push_back(
1278 AnnotatedReference(
1279 base,
1280 readAnnotations(annotated, file, offset, &offset)));
1282 n = file->read32(offset);
1283 if (n > SAL_MAX_INT32) {
1284 throw FileFormatException(
1285 file->uri,
1286 ("UNOIDL format: too many direct properties of"
1287 " accumulation-based service"));
1289 offset += 4;
1290 std::vector< AccumulationBasedServiceEntity::Property > props;
1291 for (sal_uInt32 i = 0; i != n; ++i) {
1292 sal_uInt16 attrs = file->read16(offset);
1293 offset += 2;
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(
1300 file->uri,
1301 ("UNOIDL format: bad mode " + OUString::number(v)
1302 + " of property " + propName
1303 + " for accumulation-based servcie"));
1305 props.push_back(
1306 AccumulationBasedServiceEntity::Property(
1307 propName, propType,
1308 static_cast<
1309 AccumulationBasedServiceEntity::Property::
1310 Attributes >(
1311 attrs),
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
1320 ++offset;
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
1328 ++offset;
1329 OUString base(file->readIdxName(&offset));
1330 checkTypeName(file, base);
1331 return new ServiceBasedSingletonEntity(
1332 published, base, readAnnotations(annotated, file, offset));
1334 default:
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(
1347 file_->uri,
1348 "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
1349 " 0");
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);
1374 if (j == -1) {
1375 j = name.getLength();
1377 sal_Int32 off = findInMap(
1378 file_, map.map.begin, map.map.size, name, i, j - i);
1379 if (off == 0) {
1380 return rtl::Reference< Entity >();
1382 if (j == name.getLength()) {
1383 return cgroup
1384 ? rtl::Reference< Entity >()
1385 : readEntity(file_, off, map.trace);
1387 if (cgroup) {
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
1391 // segments?
1393 int v = file_->read8(off);
1394 if (v != 0) { // module
1395 if ((v & 0x3F) == 7) { // constant group
1396 cgroup = true;
1397 } else {
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)
1406 // cannot overflow
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");
1417 i = j + 1;
1421 UnoidlProvider::~UnoidlProvider() throw () {}
1425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */