LCOV - code coverage report
Current view: top level - unoidl/source - unoidlprovider.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 565 709 79.7 %
Date: 2015-06-13 12:38:46 Functions: 44 48 91.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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             :  */
       9             : 
      10             : #include "sal/config.h"
      11             : 
      12             : #include <algorithm>
      13             : #include <cassert>
      14             : #include <cstring>
      15             : #include <set>
      16             : #include <vector>
      17             : 
      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"
      29             : 
      30             : #include "unoidlprovider.hxx"
      31             : 
      32             : namespace unoidl { namespace detail {
      33             : 
      34             : class MappedFile: public salhelper::SimpleReferenceObject {
      35             : public:
      36             :     explicit MappedFile(OUString const & fileUrl);
      37             : 
      38             :     sal_uInt8 read8(sal_uInt32 offset) const;
      39             : 
      40             :     sal_uInt16 read16(sal_uInt32 offset) const;
      41             : 
      42             :     sal_uInt32 read32(sal_uInt32 offset) const;
      43             : 
      44             :     sal_uInt64 read64(sal_uInt32 offset) const;
      45             : 
      46             :     float readIso60599Binary32(sal_uInt32 offset) const;
      47             : 
      48             :     double readIso60599Binary64(sal_uInt32 offset) const;
      49             : 
      50             :     OUString readNulName(sal_uInt32 offset) /*const*/;
      51             : 
      52     9993432 :     OUString readIdxName(sal_uInt32 * offset) const
      53     9993432 :     { return readIdxString(offset, RTL_TEXTENCODING_ASCII_US); }
      54             : 
      55       17729 :     OUString readIdxString(sal_uInt32 * offset) const
      56       17729 :     { return readIdxString(offset, RTL_TEXTENCODING_UTF8); }
      57             : 
      58             :     OUString uri;
      59             :     oslFileHandle handle;
      60             :     sal_uInt64 size;
      61             :     void * address;
      62             : 
      63             : private:
      64             :     virtual ~MappedFile();
      65             : 
      66             :     sal_uInt8 get8(sal_uInt32 offset) const;
      67             : 
      68             :     sal_uInt16 get16(sal_uInt32 offset) const;
      69             : 
      70             :     sal_uInt32 get32(sal_uInt32 offset) const;
      71             : 
      72             :     sal_uInt64 get64(sal_uInt32 offset) const;
      73             : 
      74             :     float getIso60599Binary32(sal_uInt32 offset) const;
      75             : 
      76             :     double getIso60599Binary64(sal_uInt32 offset) const;
      77             : 
      78             :     OUString readIdxString(sal_uInt32 * offset, rtl_TextEncoding encoding)
      79             :         const;
      80             : };
      81             : 
      82             : namespace {
      83             : 
      84             : // sizeof (Memory16) == 2
      85             : struct Memory16 {
      86             :     unsigned char byte[2];
      87             : 
      88       71890 :     sal_uInt16 getUnsigned16() const {
      89       71890 :         return static_cast< sal_uInt16 >(byte[0])
      90       71890 :             | (static_cast< sal_uInt16 >(byte[1]) << 8);
      91             :     }
      92             : };
      93             : 
      94             : // sizeof (Memory32) == 4
      95             : struct Memory32 {
      96             :     unsigned char byte[4];
      97             : 
      98    52609206 :     sal_uInt32 getUnsigned32() const {
      99    52609206 :         return static_cast< sal_uInt32 >(byte[0])
     100    52609206 :             | (static_cast< sal_uInt32 >(byte[1]) << 8)
     101    52609206 :             | (static_cast< sal_uInt32 >(byte[2]) << 16)
     102    52609206 :             | (static_cast< sal_uInt32 >(byte[3]) << 24);
     103             :     }
     104             : 
     105         360 :     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         360 :         sa.buf[0] = byte[0];
     112         360 :         sa.buf[1] = byte[1];
     113         360 :         sa.buf[2] = byte[2];
     114         360 :         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         360 :         return sa.f;
     122             :     }
     123             : };
     124             : 
     125             : // sizeof (Memory64) == 8
     126             : struct Memory64 {
     127             :     unsigned char byte[8];
     128             : 
     129         455 :     sal_uInt64 getUnsigned64() const {
     130         455 :         return static_cast< sal_uInt64 >(byte[0])
     131         455 :             | (static_cast< sal_uInt64 >(byte[1]) << 8)
     132         455 :             | (static_cast< sal_uInt64 >(byte[2]) << 16)
     133         455 :             | (static_cast< sal_uInt64 >(byte[3]) << 24)
     134         455 :             | (static_cast< sal_uInt64 >(byte[4]) << 32)
     135         455 :             | (static_cast< sal_uInt64 >(byte[5]) << 40)
     136         455 :             | (static_cast< sal_uInt64 >(byte[6]) << 48)
     137         455 :             | (static_cast< sal_uInt64 >(byte[7]) << 56);
     138             :         }
     139             : 
     140           0 :     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           0 :         sa.buf[0] = byte[0];
     147           0 :         sa.buf[1] = byte[1];
     148           0 :         sa.buf[2] = byte[2];
     149           0 :         sa.buf[3] = byte[3];
     150           0 :         sa.buf[4] = byte[4];
     151           0 :         sa.buf[5] = byte[5];
     152           0 :         sa.buf[6] = byte[6];
     153           0 :         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           0 :         return sa.d;
     165             :     }
     166             : };
     167             : 
     168    10155524 : bool isSimpleType(OUString const & type) {
     169    19170859 :     return type == "void" || type == "boolean" || type == "byte"
     170     8669864 :         || type == "short" || type == "unsigned short" || type == "long"
     171     8323051 :         || type == "unsigned long" || type == "hyper"
     172     8247466 :         || type == "unsigned hyper" || type == "float" || type == "double"
     173     8210097 :         || type == "char" || type == "string" || type == "type"
     174    17439649 :         || type == "any";
     175             : }
     176             : 
     177             : // For backwards compatibility, does not strictly check segments to match
     178             : //
     179             : //  <segment> ::= <blocks> | <block>
     180             : //  <blocks> ::= <capital> <other>* ("_" <block>)*
     181             : //  <block> ::= <other>+
     182             : //  <other> ::= <capital> | "a"--"z" | "0"--"9"
     183             : //  <capital> ::= "A"--"Z"
     184             : //
     185     6779395 : bool isIdentifier(OUString const & type, bool scoped) {
     186     6779395 :     if (type.isEmpty()) {
     187           0 :         return false;
     188             :     }
     189   129850347 :     for (sal_Int32 i = 0; i != type.getLength(); ++i) {
     190   123070952 :         sal_Unicode c = type[i];
     191   123070952 :         if (c == '.') {
     192    27834090 :             if (!scoped || i == 0 || i == type.getLength() - 1
     193    18556060 :                 || type[i - 1] == '.')
     194             :             {
     195           0 :                 return false;
     196             :             }
     197   113792922 :         } else if (!rtl::isAsciiAlphanumeric(c) && c != '_') {
     198           0 :             return false;
     199             :         }
     200             :     }
     201     6779395 :     return true;
     202             : }
     203             : 
     204     5669429 : void checkTypeName(
     205             :     rtl::Reference< MappedFile > const & file, OUString const & type)
     206             : {
     207     5669429 :     OUString nucl(type);
     208     5669429 :     bool args = false;
     209     5669429 :     while (nucl.startsWith("[]", &nucl)) {}
     210     5669429 :     sal_Int32 i = nucl.indexOf('<');
     211     5669429 :     if (i != -1) {
     212        4910 :         OUString tmpl(nucl.copy(0, i));
     213        5741 :         do {
     214        5741 :             ++i; // skip '<' or ','
     215        5741 :             sal_Int32 j = i;
     216       79886 :             for (sal_Int32 level = 0; j != nucl.getLength(); ++j) {
     217       79886 :                 sal_Unicode c = nucl[j];
     218       79886 :                 if (c == ',') {
     219         987 :                     if (level == 0) {
     220         831 :                         break;
     221             :                     }
     222       78899 :                 } else if (c == '<') {
     223         607 :                     ++level;
     224       78292 :                 } else if (c == '>') {
     225        5517 :                     if (level == 0) {
     226        4910 :                         break;
     227             :                     }
     228         607 :                     --level;
     229             :                 }
     230             :             }
     231        5741 :             if (j != nucl.getLength()) {
     232        5741 :                 checkTypeName(file, nucl.copy(i, j - i));
     233        5741 :                 args = true;
     234             :             }
     235        5741 :             i = j;
     236        5741 :         } while (i != nucl.getLength() && nucl[i] != '>');
     237        4910 :         if (i != nucl.getLength() - 1 || nucl[i] != '>' || !args) {
     238           0 :             tmpl.clear(); // bad input
     239             :         }
     240        4910 :         nucl = tmpl;
     241             :     }
     242     5669429 :     if (isSimpleType(nucl) ? args : !isIdentifier(nucl, true)) {
     243             :         throw FileFormatException(
     244           0 :             file->uri, "UNOIDL format: bad type \"" + type + "\"");
     245     5669429 :     }
     246     5669429 : }
     247             : 
     248     4486095 : void checkEntityName(
     249             :     rtl::Reference< MappedFile > const & file, OUString const & name)
     250             : {
     251     4486095 :     if (isSimpleType(name) || !isIdentifier(name, false)) {
     252             :         throw FileFormatException(
     253           0 :             file->uri, "UNOIDL format: bad entity name \"" + name + "\"");
     254             :     }
     255     4486095 : }
     256             : 
     257             : }
     258             : 
     259         970 : MappedFile::MappedFile(OUString const & fileUrl): uri(fileUrl), handle(0) {
     260         970 :     oslFileError e = osl_openFile(uri.pData, &handle, osl_File_OpenFlag_Read);
     261         970 :     switch (e) {
     262             :     case osl_File_E_None:
     263         970 :         break;
     264             :     case osl_File_E_NOENT:
     265           0 :         throw NoSuchFileException(uri);
     266             :     default:
     267           0 :         throw FileFormatException(uri, "cannot open: " + OUString::number(e));
     268             :     }
     269         970 :     e = osl_getFileSize(handle, &size);
     270         970 :     if (e == osl_File_E_None) {
     271             :         e = osl_mapFile(
     272         970 :             handle, &address, size, 0, osl_File_MapFlag_RandomAccess);
     273             :     }
     274         970 :     if (e != osl_File_E_None) {
     275           0 :         oslFileError e2 = osl_closeFile(handle);
     276             :         SAL_WARN_IF(
     277             :             e2 != osl_File_E_None, "unoidl",
     278             :             "cannot close " << uri << ": " << +e2);
     279           0 :         throw FileFormatException(uri, "cannot mmap: " + OUString::number(e));
     280             :     }
     281         970 : }
     282             : 
     283     7910392 : sal_uInt8 MappedFile::read8(sal_uInt32 offset) const {
     284             :     assert(size >= 8);
     285     7910392 :     if (offset > size - 1) {
     286             :         throw FileFormatException(
     287           0 :             uri, "UNOIDL format: offset for 8-bit value too large");
     288             :     }
     289     7910392 :     return get8(offset);
     290             : }
     291             : 
     292       71890 : sal_uInt16 MappedFile::read16(sal_uInt32 offset) const {
     293             :     assert(size >= 8);
     294       71890 :     if (offset > size - 2) {
     295             :         throw FileFormatException(
     296           0 :             uri, "UNOIDL format: offset for 16-bit value too large");
     297             :     }
     298       71890 :     return get16(offset);
     299             : }
     300             : 
     301    30505610 : sal_uInt32 MappedFile::read32(sal_uInt32 offset) const {
     302             :     assert(size >= 8);
     303    30505610 :     if (offset > size - 4) {
     304             :         throw FileFormatException(
     305           0 :             uri, "UNOIDL format: offset for 32-bit value too large");
     306             :     }
     307    30505610 :     return get32(offset);
     308             : }
     309             : 
     310         455 : sal_uInt64 MappedFile::read64(sal_uInt32 offset) const {
     311             :     assert(size >= 8);
     312         455 :     if (offset > size - 8) {
     313             :         throw FileFormatException(
     314           0 :             uri, "UNOIDL format: offset for 64-bit value too large");
     315             :     }
     316         455 :     return get64(offset);
     317             : }
     318             : 
     319         360 : float MappedFile::readIso60599Binary32(sal_uInt32 offset) const {
     320             :     assert(size >= 8);
     321         360 :     if (offset > size - 4) {
     322             :         throw FileFormatException(
     323           0 :             uri, "UNOIDL format: offset for 32-bit value too large");
     324             :     }
     325         360 :     return getIso60599Binary32(offset);
     326             : }
     327             : 
     328           0 : double MappedFile::readIso60599Binary64(sal_uInt32 offset) const {
     329             :     assert(size >= 8);
     330           0 :     if (offset > size - 8) {
     331             :         throw FileFormatException(
     332           0 :             uri, "UNOIDL format: offset for 64-bit value too large");
     333             :     }
     334           0 :     return getIso60599Binary64(offset);
     335             : }
     336             : 
     337      156351 : OUString MappedFile::readNulName(sal_uInt32 offset) {
     338      156351 :     if (offset > size) {
     339             :         throw FileFormatException(
     340           0 :             uri, "UNOIDL format: offset for string too large");
     341             :     }
     342      156351 :     sal_uInt64 end = offset;
     343     2354962 :     for (;; ++end) {
     344     2511313 :         if (end == size) {
     345             :             throw FileFormatException(
     346           0 :                 uri, "UNOIDL format: string misses trailing NUL");
     347             :         }
     348     2511313 :         if (static_cast< char const * >(address)[end] == 0) {
     349      156351 :             break;
     350             :         }
     351             :     }
     352      156351 :     if (end - offset > SAL_MAX_INT32) {
     353           0 :         throw FileFormatException(uri, "UNOIDL format: string too long");
     354             :     }
     355      156351 :     OUString name;
     356      156351 :     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      156351 :              | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
     362             :     {
     363           0 :         throw FileFormatException(uri, "UNOIDL format: name is not ASCII");
     364             :     }
     365      156351 :     checkEntityName(this, name);
     366     2511313 :     return name;
     367             : }
     368             : 
     369        2643 : MappedFile::~MappedFile() {
     370         881 :     oslFileError e = osl_unmapMappedFile(handle, address, size);
     371             :     SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot unmap: " << +e);
     372         881 :     e = osl_closeFile(handle);
     373             :     SAL_WARN_IF(e != osl_File_E_None, "unoidl", "cannot close: " << +e);
     374        1762 : }
     375             : 
     376     7910392 : sal_uInt8 MappedFile::get8(sal_uInt32 offset) const {
     377             :     assert(size >= 8);
     378             :     assert(offset <= size - 1);
     379     7910392 :     return static_cast< char const * >(address)[offset];
     380             : }
     381             : 
     382       71890 : sal_uInt16 MappedFile::get16(sal_uInt32 offset) const {
     383             :     assert(size >= 8);
     384             :     assert(offset <= size - 2);
     385             :     return reinterpret_cast< Memory16 const * >(
     386       71890 :         static_cast< char const * >(address) + offset)->getUnsigned16();
     387             : }
     388             : 
     389    30505610 : sal_uInt32 MappedFile::get32(sal_uInt32 offset) const {
     390             :     assert(size >= 8);
     391             :     assert(offset <= size - 4);
     392             :     return reinterpret_cast< Memory32 const * >(
     393    30505610 :         static_cast< char const * >(address) + offset)->getUnsigned32();
     394             : }
     395             : 
     396         455 : sal_uInt64 MappedFile::get64(sal_uInt32 offset) const {
     397             :     assert(size >= 8);
     398             :     assert(offset <= size - 8);
     399             :     return reinterpret_cast< Memory64 const * >(
     400         455 :         static_cast< char const * >(address) + offset)->getUnsigned64();
     401             : }
     402             : 
     403         360 : float MappedFile::getIso60599Binary32(sal_uInt32 offset) const {
     404             :     assert(size >= 8);
     405             :     assert(offset <= size - 4);
     406             :     return reinterpret_cast< Memory32 const * >(
     407         360 :         static_cast< char const * >(address) + offset)->getIso60599Binary32();
     408             : }
     409             : 
     410           0 : double MappedFile::getIso60599Binary64(sal_uInt32 offset) const {
     411             :     assert(size >= 8);
     412             :     assert(offset <= size - 8);
     413             :     return reinterpret_cast< Memory64 const * >(
     414           0 :         static_cast< char const * >(address) + offset)->getIso60599Binary64();
     415             : }
     416             : 
     417    10011161 : OUString MappedFile::readIdxString(
     418             :     sal_uInt32 * offset, rtl_TextEncoding encoding) const
     419             : {
     420             :     assert(offset != 0);
     421    10011161 :     sal_uInt32 len = read32(*offset);
     422             :     sal_uInt32 off;
     423    10011161 :     if ((len & 0x80000000) == 0) {
     424     3016806 :         off = *offset;
     425     3016806 :         *offset += 4 + len;
     426             :     } else {
     427     6994355 :         *offset += 4;
     428     6994355 :         off = len & ~0x80000000;
     429     6994355 :         len = read32(off);
     430     6994355 :         if ((len & 0x80000000) != 0) {
     431             :             throw FileFormatException(
     432           0 :                 uri, "UNOIDL format: string length high bit set");
     433             :         }
     434             :     }
     435    10011161 :     if (len > SAL_MAX_INT32 || len > size - off - 4) {
     436             :         throw FileFormatException(
     437           0 :             uri, "UNOIDL format: size of string is too large");
     438             :     }
     439    10011161 :     OUString name;
     440    10011161 :     if (!rtl_convertStringToUString(
     441    10011161 :             &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    20022322 :              | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
     446             :     {
     447             :         throw FileFormatException(
     448           0 :             uri, "UNOIDL format: string bytes do not match encoding");
     449             :     }
     450    10011161 :     return name;
     451             : }
     452             : 
     453             : // sizeof (MapEntry) == 8
     454             : struct MapEntry {
     455             :     Memory32 name;
     456             :     Memory32 data;
     457             : };
     458             : 
     459    15247595 : bool operator <(const Map& map1, const Map& map2) {
     460    15247595 :     return map1.begin < map2.begin
     461    15247595 :         || (map1.begin == map2.begin && map1.size < map2.size);
     462             : }
     463             : 
     464             : namespace {
     465             : 
     466             : enum Compare { COMPARE_LESS, COMPARE_GREATER, COMPARE_EQUAL };
     467             : 
     468    15690628 : Compare compare(
     469             :     rtl::Reference< MappedFile > const & file, OUString const & name,
     470             :     sal_Int32 nameOffset, sal_Int32 nameLength, MapEntry const * entry)
     471             : {
     472             :     assert(file.is());
     473             :     assert(entry != 0);
     474    15690628 :     sal_uInt32 off = entry->name.getUnsigned32();
     475    15690628 :     if (off > file->size - 1) { // at least a trailing NUL
     476             :         throw FileFormatException(
     477           0 :             file->uri, "UNOIDL format: string offset too large");
     478             :     }
     479             :     assert(nameLength >= 0);
     480             :     sal_uInt64 min = std::min(
     481    15690628 :         static_cast< sal_uInt64 >(nameLength), file->size - off);
     482    52465589 :     for (sal_uInt64 i = 0; i != min; ++i) {
     483    46259931 :         sal_Unicode c1 = name[nameOffset + i];
     484    46259931 :         sal_Unicode c2 = static_cast< unsigned char const * >(file->address)[
     485    46259931 :             off + i];
     486    46259931 :         if (c1 < c2) {
     487     4567154 :             return COMPARE_LESS;
     488    41692777 :         } else if (c1 > c2 || c2 == 0) {
     489             :             // ...the "|| c2 == 0" is for the odd case where name erroneously
     490             :             // contains NUL characters
     491     4917816 :             return COMPARE_GREATER;
     492             :         }
     493             :     }
     494     6205658 :     if (static_cast< sal_uInt64 >(nameLength) == min) {
     495     6205658 :         if (file->size - off == min) {
     496             :             throw FileFormatException(
     497           0 :                 file->uri, "UNOIDL format: string misses trailing NUL");
     498             :         }
     499             :         return
     500     6205658 :             static_cast< unsigned char const * >(file->address)[off + min] == 0
     501     6205658 :             ? COMPARE_EQUAL : COMPARE_LESS;
     502             :     } else {
     503           0 :         return COMPARE_GREATER;
     504             :     }
     505             : }
     506             : 
     507    16474660 : 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)
     511             : {
     512    16474660 :     if (mapSize == 0) {
     513      784032 :         return 0;
     514             :     }
     515    15690628 :     sal_uInt32 n = mapSize / 2;
     516    15690628 :     MapEntry const * p = mapBegin + n;
     517    15690628 :     switch (compare(file, name, nameOffset, nameLength, p)) {
     518             :     case COMPARE_LESS:
     519     4672546 :         return findInMap(file, mapBegin, n, name, nameOffset, nameLength);
     520             :     case COMPARE_GREATER:
     521             :         return findInMap(
     522     4917816 :             file, p + 1, mapSize - n - 1, name, nameOffset, nameLength);
     523             :     default: // COMPARE_EQUAL
     524     6100266 :         break;
     525             :     }
     526     6100266 :     sal_uInt32 off = mapBegin[n].data.getUnsigned32();
     527     6100266 :     if (off == 0) {
     528             :         throw FileFormatException(
     529           0 :             file->uri, "UNOIDL format: map entry data offset is null");
     530             :     }
     531     6100266 :     return off;
     532             : }
     533             : 
     534     4300360 : std::vector< OUString > readAnnotations(
     535             :     bool annotated, rtl::Reference< MappedFile > const & file,
     536             :     sal_uInt32 offset, sal_uInt32 * newOffset = 0)
     537             : {
     538     4300360 :     std::vector< OUString > ans;
     539     4300360 :     if (annotated) {
     540       94018 :         sal_uInt32 n = file->read32(offset);
     541       94018 :         offset += 4;
     542      111747 :         for (sal_uInt32 i = 0; i != n; ++i) {
     543       17729 :             ans.push_back(file->readIdxString(&offset));
     544             :         }
     545             :     }
     546     4300360 :     if (newOffset != 0) {
     547     3321606 :         *newOffset = offset;
     548             :     }
     549     4300360 :     return ans;
     550             : }
     551             : 
     552      133695 : ConstantValue readConstant(
     553             :     rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
     554             :     sal_uInt32 * newOffset = 0, bool * annotated = 0)
     555             : {
     556             :     assert(file.is());
     557      133695 :     int v = file->read8(offset);
     558      133695 :     int type = v & 0x7F;
     559      133695 :     if (annotated != 0) {
     560      133695 :         *annotated = (v & 0x80) != 0;
     561             :     }
     562      133695 :     switch (type) {
     563             :     case 0: // BOOLEAN
     564           0 :         v = file->read8(offset + 1);
     565           0 :         if (newOffset != 0) {
     566           0 :             *newOffset = offset + 2;
     567             :         }
     568           0 :         switch (v) {
     569             :         case 0:
     570           0 :             return ConstantValue(false);
     571             :         case 1:
     572           0 :             return ConstantValue(true);
     573             :         default:
     574             :             throw FileFormatException(
     575           0 :                 file->uri,
     576             :                 ("UNOIDL format: bad boolean constant value "
     577           0 :                  + OUString::number(v)));
     578             :         }
     579             :     case 1: // BYTE
     580        3452 :         if (newOffset != 0) {
     581        3452 :             *newOffset = offset + 2;
     582             :         }
     583        3452 :         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       34779 :         if (newOffset != 0) {
     588       34779 :             *newOffset = offset + 3;
     589             :         }
     590             :         return ConstantValue(
     591       34779 :             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          10 :         if (newOffset != 0) {
     596          10 :             *newOffset = offset + 3;
     597             :         }
     598          10 :         return ConstantValue(file->read16(offset + 1));
     599             :     case 4: // LONG
     600       94629 :         if (newOffset != 0) {
     601       94629 :             *newOffset = offset + 5;
     602             :         }
     603             :         return ConstantValue(
     604       94629 :             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          10 :         if (newOffset != 0) {
     609          10 :             *newOffset = offset + 5;
     610             :         }
     611          10 :         return ConstantValue(file->read32(offset + 1));
     612             :     case 6: // HYPER
     613         445 :         if (newOffset != 0) {
     614         445 :             *newOffset = offset + 9;
     615             :         }
     616             :         return ConstantValue(
     617         445 :             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          10 :         if (newOffset != 0) {
     622          10 :             *newOffset = offset + 9;
     623             :         }
     624          10 :         return ConstantValue(file->read64(offset + 1));
     625             :     case 8: // FLOAT
     626         360 :         if (newOffset != 0) {
     627         360 :             *newOffset = offset + 5;
     628             :         }
     629         360 :         return ConstantValue(file->readIso60599Binary32(offset + 1));
     630             :     case 9: // DOUBLE
     631           0 :         if (newOffset != 0) {
     632           0 :             *newOffset = offset + 9;
     633             :         }
     634           0 :         return ConstantValue(file->readIso60599Binary64(offset + 1));
     635             :     default:
     636             :         throw FileFormatException(
     637           0 :             file->uri,
     638           0 :             "UNOIDL format: bad constant type byte " + OUString::number(v));
     639             :     }
     640             : }
     641             : 
     642             : rtl::Reference< Entity > readEntity(
     643             :     rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
     644             :     std::set<Map> const & trace);
     645             : 
     646             : class UnoidlModuleEntity;
     647             : 
     648             : class UnoidlCursor: public MapCursor {
     649             : public:
     650         690 :     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         690 :         map_(map), index_(0)
     657         690 :     {}
     658             : 
     659             : private:
     660        1380 :     virtual ~UnoidlCursor() throw () {}
     661             : 
     662             :     virtual rtl::Reference< Entity > getNext(OUString * name) SAL_OVERRIDE;
     663             : 
     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_;
     669             : };
     670             : 
     671       23346 : rtl::Reference< Entity > UnoidlCursor::getNext(OUString * name) {
     672             :     assert(name != 0);
     673       23346 :     rtl::Reference< Entity > ent;
     674       23346 :     if (index_ != map_.map.size) {
     675       22656 :         *name = file_->readNulName(map_.map.begin[index_].name.getUnsigned32());
     676       67968 :         ent = readEntity(
     677       45312 :             file_, map_.map.begin[index_].data.getUnsigned32(), map_.trace);
     678       22656 :         ++index_;
     679             :     }
     680       23346 :     return ent;
     681             : }
     682             : 
     683             : class UnoidlModuleEntity: public ModuleEntity {
     684             : public:
     685        2595 :     UnoidlModuleEntity(
     686             :         rtl::Reference< MappedFile > const & file, sal_uInt32 mapOffset,
     687             :         sal_uInt32 mapSize, std::set<Map> const & trace):
     688        2595 :         file_(file)
     689             :     {
     690             :         assert(file.is());
     691             :         map_.map.begin = reinterpret_cast<MapEntry const *>(
     692        2595 :             static_cast<char const *>(file_->address) + mapOffset);
     693        2595 :         map_.map.size = mapSize;
     694        2595 :         map_.trace = trace;
     695        2595 :         if (!map_.trace.insert(map_.map).second) {
     696             :             throw FileFormatException(
     697           0 :                 file_->uri, "UNOIDL format: recursive map");
     698             :         }
     699        2595 :     }
     700             : 
     701             : private:
     702        5190 :     virtual ~UnoidlModuleEntity() throw () {}
     703             : 
     704             :     virtual std::vector< OUString > getMemberNames() const SAL_OVERRIDE;
     705             : 
     706         657 :     virtual rtl::Reference< MapCursor > createCursor() const SAL_OVERRIDE {
     707             :         return new UnoidlCursor(
     708             :             file_, rtl::Reference<UnoidlProvider>(),
     709         657 :             const_cast<UnoidlModuleEntity *>(this), map_);
     710             :     }
     711             : 
     712             :     rtl::Reference< MappedFile > file_;
     713             :     NestedMap map_;
     714             : };
     715             : 
     716           0 : std::vector< OUString > UnoidlModuleEntity::getMemberNames() const {
     717           0 :     std::vector< OUString > names;
     718           0 :     for (sal_uInt32 i = 0; i != map_.map.size; ++i) {
     719             :         names.push_back(
     720           0 :             file_->readNulName(map_.map.begin[i].name.getUnsigned32()));
     721             :     }
     722           0 :     return names;
     723             : }
     724             : 
     725      847654 : rtl::Reference< Entity > readEntity(
     726             :     rtl::Reference< MappedFile > const & file, sal_uInt32 offset,
     727             :     std::set<Map> const & trace)
     728             : {
     729             :     assert(file.is());
     730      847654 :     int v = file->read8(offset);
     731      847654 :     int type = v & 0x3F;
     732      847654 :     bool published = (v & 0x80) != 0;
     733      847654 :     bool annotated = (v & 0x40) != 0;
     734      847654 :     bool flag = (v & 0x20) != 0;
     735      847654 :     switch (type) {
     736             :     case 0: // module
     737             :         {
     738        2595 :             if (v != 0) {
     739             :                 throw FileFormatException(
     740           0 :                     file->uri,
     741             :                     ("UNOIDL format: bad module type byte "
     742           0 :                      + OUString::number(v)));
     743             :             }
     744        2595 :             sal_uInt32 n = file->read32(offset + 1);
     745        2595 :             if (n > SAL_MAX_INT32) {
     746             :                 throw FileFormatException(
     747           0 :                     file->uri, "UNOIDL format: too many items in module");
     748             :             }
     749        2595 :             if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
     750             :                 // cannot overflow
     751             :             {
     752             :                 throw FileFormatException(
     753           0 :                     file->uri,
     754           0 :                     "UNOIDL format: module map offset + size too large");
     755             :             }
     756        2595 :             return new UnoidlModuleEntity(file, offset + 5, n, trace);
     757             :         }
     758             :     case 1: // enum type
     759             :         {
     760       14659 :             sal_uInt32 n = file->read32(offset + 1);
     761       14659 :             if (n == 0) {
     762             :                 throw FileFormatException(
     763           0 :                     file->uri, "UNOIDL format: enum type with no members");
     764             :             }
     765       14659 :             if (n > SAL_MAX_INT32) {
     766             :                 throw FileFormatException(
     767           0 :                     file->uri, "UNOIDL format: too many members of enum type");
     768             :             }
     769       14659 :             offset += 5;
     770       14659 :             std::vector< EnumTypeEntity::Member > mems;
     771      123679 :             for (sal_uInt32 i = 0; i != n; ++i) {
     772      109020 :                 OUString memName(file->readIdxName(&offset));
     773      109020 :                 checkEntityName(file, memName);
     774             :                 sal_Int32 memValue = static_cast< sal_Int32 >(
     775      109020 :                     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      109020 :                 offset += 4;
     780             :                 mems.push_back(
     781             :                     EnumTypeEntity::Member(
     782             :                         memName, memValue,
     783      109020 :                         readAnnotations(annotated, file, offset, &offset)));
     784      109020 :             }
     785             :             return new EnumTypeEntity(
     786       14659 :                 published, mems, readAnnotations(annotated, file, offset));
     787             :         }
     788             :     case 2: // plain struct type without base
     789             :     case 2 | 0x20: // plain struct type with base
     790             :         {
     791       46964 :             ++offset;
     792       46964 :             OUString base;
     793       46964 :             if (flag) {
     794        8031 :                 base = file->readIdxName(&offset);
     795        8031 :                 if (base.isEmpty()) {
     796             :                     throw FileFormatException(
     797           0 :                         file->uri,
     798             :                         ("UNOIDL format: empty base type name of plain struct"
     799           0 :                          " type"));
     800             :                 }
     801        8031 :                 checkTypeName(file, base);
     802             :             }
     803       46964 :             sal_uInt32 n = file->read32(offset);
     804       46964 :             if (n > SAL_MAX_INT32) {
     805             :                 throw FileFormatException(
     806           0 :                     file->uri,
     807             :                     ("UNOIDL format: too many direct members of plain struct"
     808           0 :                      " type"));
     809             :             }
     810       46964 :             offset += 4;
     811       93928 :             std::vector< PlainStructTypeEntity::Member > mems;
     812      213050 :             for (sal_uInt32 i = 0; i != n; ++i) {
     813      166086 :                 OUString memName(file->readIdxName(&offset));
     814      166086 :                 checkEntityName(file, memName);
     815      332172 :                 OUString memType(file->readIdxName(&offset));
     816      166086 :                 checkTypeName(file, memType);
     817             :                 mems.push_back(
     818             :                     PlainStructTypeEntity::Member(
     819             :                         memName, memType,
     820      166086 :                         readAnnotations(annotated, file, offset, &offset)));
     821      166086 :             }
     822             :             return new PlainStructTypeEntity(
     823             :                 published, base, mems,
     824       93928 :                 readAnnotations(annotated, file, offset));
     825             :         }
     826             :     case 3: // polymorphic struct type template
     827             :         {
     828        1254 :             sal_uInt32 n = file->read32(offset + 1);
     829        1254 :             if (n > SAL_MAX_INT32) {
     830             :                 throw FileFormatException(
     831           0 :                     file->uri,
     832             :                     ("UNOIDL format: too many type parameters of polymorphic"
     833           0 :                      " struct type template"));
     834             :             }
     835        1254 :             offset += 5;
     836        1254 :             std::vector< OUString > params;
     837        2866 :             for (sal_uInt32 i = 0; i != n; ++i) {
     838        1612 :                 OUString param(file->readIdxName(&offset));
     839        1612 :                 checkEntityName(file, param);
     840        1612 :                 params.push_back(param);
     841        1612 :             }
     842        1254 :             n = file->read32(offset);
     843        1254 :             if (n > SAL_MAX_INT32) {
     844             :                 throw FileFormatException(
     845           0 :                     file->uri,
     846             :                     ("UNOIDL format: too many members of polymorphic struct"
     847           0 :                      " type template"));
     848             :             }
     849        1254 :             offset += 4;
     850        2508 :             std::vector< PolymorphicStructTypeTemplateEntity::Member > mems;
     851        3399 :             for (sal_uInt32 i = 0; i != n; ++i) {
     852        2145 :                 v = file->read8(offset);
     853        2145 :                 ++offset;
     854        2145 :                 OUString memName(file->readIdxName(&offset));
     855        2145 :                 checkEntityName(file, memName);
     856        4290 :                 OUString memType(file->readIdxName(&offset));
     857        2145 :                 checkTypeName(file, memType);
     858        2145 :                 if (v > 1) {
     859             :                     throw FileFormatException(
     860           0 :                         file->uri,
     861           0 :                         ("UNOIDL format: bad flags " + OUString::number(v)
     862           0 :                          + " for member " + memName
     863           0 :                          + " of polymorphic struct type template"));
     864             :                 }
     865             :                 mems.push_back(
     866             :                     PolymorphicStructTypeTemplateEntity::Member(
     867             :                         memName, memType, v == 1,
     868        2145 :                         readAnnotations(annotated, file, offset, &offset)));
     869        2145 :             }
     870             :             return new PolymorphicStructTypeTemplateEntity(
     871             :                 published, params, mems,
     872        2508 :                 readAnnotations(annotated, file, offset));
     873             :         }
     874             :     case 4: // exception type without base
     875             :     case 4 | 0x20: // exception type with base
     876             :         {
     877       67346 :             ++offset;
     878       67346 :             OUString base;
     879       67346 :             if (flag) {
     880       59802 :                 base = file->readIdxName(&offset);
     881       59802 :                 if (base.isEmpty()) {
     882             :                     throw FileFormatException(
     883           0 :                         file->uri,
     884             :                         ("UNOIDL format: empty base type name of exception"
     885           0 :                          " type"));
     886             :                 }
     887       59802 :                 checkTypeName(file, base);
     888             :             }
     889       67346 :             sal_uInt32 n = file->read32(offset);
     890       67346 :             if (n > SAL_MAX_INT32) {
     891             :                 throw FileFormatException(
     892           0 :                     file->uri,
     893           0 :                     "UNOIDL format: too many direct members of exception type");
     894             :             }
     895       67346 :             offset += 4;
     896      134692 :             std::vector< ExceptionTypeEntity::Member > mems;
     897      112579 :             for (sal_uInt32 i = 0; i != n; ++i) {
     898       45233 :                 OUString memName(file->readIdxName(&offset));
     899       45233 :                 checkEntityName(file, memName);
     900       90466 :                 OUString memType(file->readIdxName(&offset));
     901       45233 :                 checkTypeName(file, memType);
     902             :                 mems.push_back(
     903             :                     ExceptionTypeEntity::Member(
     904             :                         memName, memType,
     905       45233 :                         readAnnotations(annotated, file, offset, &offset)));
     906       45233 :             }
     907             :             return new ExceptionTypeEntity(
     908             :                 published, base, mems,
     909      134692 :                 readAnnotations(annotated, file, offset));
     910             :         }
     911             :     case 5: // interface type
     912             :         {
     913      679166 :             sal_uInt32 n = file->read32(offset + 1);
     914      679166 :             if (n > SAL_MAX_INT32) {
     915             :                 throw FileFormatException(
     916           0 :                     file->uri,
     917             :                     ("UNOIDL format: too many direct mandatory bases of"
     918           0 :                      " interface type"));
     919             :             }
     920      679166 :             offset += 5;
     921      679166 :             std::vector< AnnotatedReference > mandBases;
     922     1077344 :             for (sal_uInt32 i = 0; i != n; ++i) {
     923      398178 :                 OUString base(file->readIdxName(&offset));
     924      398178 :                 checkTypeName(file, base);
     925             :                 mandBases.push_back(
     926             :                     AnnotatedReference(
     927             :                         base,
     928      398178 :                         readAnnotations(annotated, file, offset, &offset)));
     929      398178 :             }
     930      679166 :             n = file->read32(offset);
     931      679166 :             if (n > SAL_MAX_INT32) {
     932             :                 throw FileFormatException(
     933           0 :                     file->uri,
     934             :                     ("UNOIDL format: too many direct optional bases of"
     935           0 :                      " interface type"));
     936             :             }
     937      679166 :             offset += 4;
     938     1358332 :             std::vector< AnnotatedReference > optBases;
     939      679884 :             for (sal_uInt32 i = 0; i != n; ++i) {
     940         718 :                 OUString base(file->readIdxName(&offset));
     941         718 :                 checkTypeName(file, base);
     942             :                 optBases.push_back(
     943             :                     AnnotatedReference(
     944             :                         base,
     945         718 :                         readAnnotations(annotated, file, offset, &offset)));
     946         718 :             }
     947      679166 :             sal_uInt32 nAttrs = file->read32(offset);
     948      679166 :             if (nAttrs > SAL_MAX_INT32) {
     949             :                 throw FileFormatException(
     950           0 :                     file->uri,
     951             :                     ("UNOIDL format: too many direct attributes of interface"
     952           0 :                      " type"));
     953             :             }
     954      679166 :             offset += 4;
     955     1358332 :             std::vector< InterfaceTypeEntity::Attribute > attrs;
     956      891453 :             for (sal_uInt32 i = 0; i != nAttrs; ++i) {
     957      212287 :                 v = file->read8(offset);
     958      212287 :                 ++offset;
     959      212287 :                 OUString attrName(file->readIdxName(&offset));
     960      212287 :                 checkEntityName(file, attrName);
     961      424574 :                 OUString attrType(file->readIdxName(&offset));
     962      212287 :                 checkTypeName(file, attrType);
     963      212287 :                 if (v > 0x03) {
     964             :                     throw FileFormatException(
     965           0 :                         file->uri,
     966             :                         ("UNOIDL format: bad flags for direct attribute "
     967           0 :                          + attrName + " of interface type"));
     968             :                 }
     969      424574 :                 std::vector< OUString > getExcs;
     970      212287 :                 sal_uInt32 m = file->read32(offset);
     971      212287 :                 if (m > SAL_MAX_INT32) {
     972             :                     throw FileFormatException(
     973           0 :                         file->uri,
     974             :                         ("UNOIDL format: too many getter exceptions for direct"
     975           0 :                          " attribute " + attrName + " of interface type"));
     976             :                 }
     977      212287 :                 offset += 4;
     978      228000 :                 for (sal_uInt32 j = 0; j != m; ++j) {
     979       15713 :                     OUString exc(file->readIdxName(&offset));
     980       15713 :                     checkTypeName(file, exc);
     981       15713 :                     getExcs.push_back(exc);
     982       15713 :                 }
     983      424574 :                 std::vector< OUString > setExcs;
     984      212287 :                 if ((v & 0x02) == 0) {
     985      147218 :                     m = file->read32(offset);
     986      147218 :                     if (m > SAL_MAX_INT32) {
     987             :                         throw FileFormatException(
     988           0 :                             file->uri,
     989             :                             ("UNOIDL format: too many setter exceptions for"
     990           0 :                              " direct attribute " + attrName
     991           0 :                              + " of interface type"));
     992             :                     }
     993      147218 :                     offset += 4;
     994      173773 :                     for (sal_uInt32 j = 0; j != m; ++j) {
     995       26555 :                         OUString exc(file->readIdxName(&offset));
     996       26555 :                         checkTypeName(file, exc);
     997       26555 :                         setExcs.push_back(exc);
     998       26555 :                     }
     999             :                 }
    1000             :                 attrs.push_back(
    1001             :                     InterfaceTypeEntity::Attribute(
    1002      424574 :                         attrName, attrType, (v & 0x01) != 0, (v & 0x02) != 0,
    1003             :                         getExcs, setExcs,
    1004      636861 :                         readAnnotations(annotated, file, offset, &offset)));
    1005      212287 :             }
    1006      679166 :             sal_uInt32 nMeths = file->read32(offset);
    1007      679166 :             if (nMeths > SAL_MAX_INT32 - nAttrs) {
    1008             :                 throw FileFormatException(
    1009           0 :                     file->uri,
    1010             :                     ("UNOIDL format: too many direct attributes and methods of"
    1011           0 :                      " interface type"));
    1012             :             }
    1013      679166 :             offset += 4;
    1014     1358332 :             std::vector< InterfaceTypeEntity::Method > meths;
    1015     2996803 :             for (sal_uInt32 i = 0; i != nMeths; ++i) {
    1016     2317637 :                 OUString methName(file->readIdxName(&offset));
    1017     2317637 :                 checkEntityName(file, methName);
    1018     4635274 :                 OUString methType(file->readIdxName(&offset));
    1019     2317637 :                 checkTypeName(file, methType);
    1020     2317637 :                 sal_uInt32 m = file->read32(offset);
    1021     2317637 :                 if (m > SAL_MAX_INT32) {
    1022             :                     throw FileFormatException(
    1023           0 :                         file->uri,
    1024             :                         ("UNOIDL format: too many parameters for method "
    1025           0 :                          + methName + " of interface type"));
    1026             :                 }
    1027     2317637 :                 offset += 4;
    1028     4635274 :                 std::vector< InterfaceTypeEntity::Method::Parameter > params;
    1029     3749572 :                 for (sal_uInt32 j = 0; j != m; ++j) {
    1030     1431935 :                     v = file->read8(offset);
    1031     1431935 :                     ++offset;
    1032     1431935 :                     OUString paramName(file->readIdxName(&offset));
    1033     1431935 :                     checkEntityName(file, paramName);
    1034     2863870 :                     OUString paramType(file->readIdxName(&offset));
    1035     1431935 :                     checkTypeName(file, paramType);
    1036             :                     InterfaceTypeEntity::Method::Parameter::Direction dir;
    1037     1431935 :                     switch (v) {
    1038             :                     case 0:
    1039             :                         dir = InterfaceTypeEntity::Method::Parameter::
    1040     1415696 :                             DIRECTION_IN;
    1041     1415696 :                         break;
    1042             :                     case 1:
    1043             :                         dir = InterfaceTypeEntity::Method::Parameter::
    1044       11864 :                             DIRECTION_OUT;
    1045       11864 :                         break;
    1046             :                     case 2:
    1047             :                         dir = InterfaceTypeEntity::Method::Parameter::
    1048        4375 :                             DIRECTION_IN_OUT;
    1049        4375 :                         break;
    1050             :                     default:
    1051             :                         throw FileFormatException(
    1052           0 :                             file->uri,
    1053             :                             ("UNOIDL format: bad direction "
    1054           0 :                              + OUString::number(v) + " of parameter "
    1055           0 :                              + paramName + " for method " + methName
    1056           0 :                              + " of interface type"));
    1057             :                     }
    1058             :                     params.push_back(
    1059             :                         InterfaceTypeEntity::Method::Parameter(
    1060     1431935 :                             paramName, paramType, dir));
    1061     1431935 :                 }
    1062     2317637 :                 std::vector< OUString > excs;
    1063     2317637 :                 m = file->read32(offset);
    1064     2317637 :                 if (m > SAL_MAX_INT32) {
    1065             :                     throw FileFormatException(
    1066           0 :                         file->uri,
    1067             :                         ("UNOIDL format: too many exceptions for method "
    1068           0 :                          + methName + " of interface type"));
    1069             :                 }
    1070     2317637 :                 offset += 4;
    1071     3213649 :                 for (sal_uInt32 j = 0; j != m; ++j) {
    1072      896012 :                     OUString exc(file->readIdxName(&offset));
    1073      896012 :                     checkTypeName(file, exc);
    1074      896012 :                     excs.push_back(exc);
    1075      896012 :                 }
    1076             :                 meths.push_back(
    1077             :                     InterfaceTypeEntity::Method(
    1078             :                         methName, methType, params, excs,
    1079     2317637 :                         readAnnotations(annotated, file, offset, &offset)));
    1080     4635274 :             }
    1081             :             return new InterfaceTypeEntity(
    1082             :                 published, mandBases, optBases, attrs, meths,
    1083     1358332 :                 readAnnotations(annotated, file, offset));
    1084             :         }
    1085             :     case 6: // typedef
    1086             :         {
    1087        3959 :             ++offset;
    1088        3959 :             OUString base(file->readIdxName(&offset));
    1089        3959 :             checkTypeName(file, base);
    1090             :             return new TypedefEntity(
    1091        3959 :                 published, base, readAnnotations(annotated, file, offset));
    1092             :         }
    1093             :     case 7: // constant group
    1094             :         {
    1095       13137 :             sal_uInt32 n = file->read32(offset + 1);
    1096       13137 :             if (n > SAL_MAX_INT32) {
    1097             :                 throw FileFormatException(
    1098           0 :                     file->uri,
    1099           0 :                     "UNOIDL format: too many constants in constant group");
    1100             :             }
    1101       13137 :             if (sal_uInt64(offset) + 5 + 8 * sal_uInt64(n) > file->size)
    1102             :                 // cannot overflow
    1103             :             {
    1104             :                 throw FileFormatException(
    1105           0 :                     file->uri,
    1106             :                     ("UNOIDL format: constant group map offset + size too"
    1107           0 :                      " large"));
    1108             :             }
    1109             :             MapEntry const * p = reinterpret_cast< MapEntry const * >(
    1110       13137 :                 static_cast< char const * >(file->address) + offset + 5);
    1111       13137 :             std::vector< ConstantGroupEntity::Member > mems;
    1112      146832 :             for (sal_uInt32 i = 0; i != n; ++i) {
    1113      133695 :                 sal_uInt32 off = p[i].data.getUnsigned32();
    1114             :                 bool ann;
    1115      133695 :                 ConstantValue val(readConstant(file, off, &off, &ann));
    1116             :                 mems.push_back(
    1117             :                     ConstantGroupEntity::Member(
    1118      133695 :                         file->readNulName(p[i].name.getUnsigned32()), val,
    1119      267390 :                         readAnnotations(ann, file, off)));
    1120             :             }
    1121             :             return new ConstantGroupEntity(
    1122             :                 published, mems,
    1123       13137 :                 readAnnotations(annotated, file, offset + 5 + 8 * n));
    1124             :         }
    1125             :     case 8: // single-interface--based service without default constructor
    1126             :     case 8 | 0x20: // single-interface--based service with default constructor
    1127             :         {
    1128        5646 :             ++offset;
    1129        5646 :             OUString base(file->readIdxName(&offset));
    1130        5646 :             checkTypeName(file, base);
    1131       11292 :             std::vector< SingleInterfaceBasedServiceEntity::Constructor > ctors;
    1132        5646 :             if (flag) {
    1133             :                 ctors.push_back(
    1134        3521 :                     SingleInterfaceBasedServiceEntity::Constructor());
    1135             :             } else {
    1136        2125 :                 sal_uInt32 n = file->read32(offset);
    1137        2125 :                 if (n > SAL_MAX_INT32) {
    1138             :                     throw FileFormatException(
    1139           0 :                         file->uri,
    1140             :                         ("UNOIDL format: too many constructors of"
    1141           0 :                          " single-interface--based service"));
    1142             :                 }
    1143        2125 :                 offset += 4;
    1144        4634 :                 for (sal_uInt32 i = 0; i != n; ++i) {
    1145        2509 :                     OUString ctorName(file->readIdxName(&offset));
    1146        2509 :                     checkEntityName(file, ctorName);
    1147        2509 :                     sal_uInt32 m = file->read32(offset);
    1148        2509 :                     if (m > SAL_MAX_INT32) {
    1149             :                         throw FileFormatException(
    1150           0 :                             file->uri,
    1151             :                             ("UNOIDL format: too many parameters for"
    1152           0 :                              " constructor " + ctorName
    1153           0 :                              + " of single-interface--based service"));
    1154             :                     }
    1155        2509 :                     offset += 4;
    1156             :                     std::vector<
    1157             :                         SingleInterfaceBasedServiceEntity::Constructor::
    1158        5018 :                         Parameter > params;
    1159        6688 :                     for (sal_uInt32 j = 0; j != m; ++j) {
    1160        4179 :                         v = file->read8(offset);
    1161        4179 :                         ++offset;
    1162        4179 :                         OUString paramName(file->readIdxName(&offset));
    1163        4179 :                         checkEntityName(file, paramName);
    1164        8358 :                         OUString paramType(file->readIdxName(&offset));
    1165        4179 :                         checkTypeName(file, paramType);
    1166             :                         bool rest;
    1167        4179 :                         switch (v) {
    1168             :                         case 0:
    1169        4168 :                             rest = false;
    1170        4168 :                             break;
    1171             :                         case 0x04:
    1172          11 :                             rest = true;
    1173          11 :                             break;
    1174             :                         default:
    1175             :                             throw FileFormatException(
    1176           0 :                                 file->uri,
    1177             :                                 ("UNOIDL format: bad mode "
    1178           0 :                                  + OUString::number(v) + " of parameter "
    1179           0 :                                  + paramName + " for constructor " + ctorName
    1180           0 :                                  + " of single-interface--based service"));
    1181             :                         }
    1182             :                         params.push_back(
    1183             :                             SingleInterfaceBasedServiceEntity::Constructor::
    1184             :                             Parameter(
    1185        4179 :                                 paramName, paramType, rest));
    1186        4179 :                     }
    1187        2509 :                     std::vector< OUString > excs;
    1188        2509 :                     m = file->read32(offset);
    1189        2509 :                     if (m > SAL_MAX_INT32) {
    1190             :                         throw FileFormatException(
    1191           0 :                             file->uri,
    1192             :                             ("UNOIDL format: too many exceptions for"
    1193           0 :                              " constructor " + ctorName
    1194           0 :                              + " of single-interface--based service"));
    1195             :                     }
    1196        2509 :                     offset += 4;
    1197        3294 :                     for (sal_uInt32 j = 0; j != m; ++j) {
    1198         785 :                         OUString exc(file->readIdxName(&offset));
    1199         785 :                         checkTypeName(file, exc);
    1200         785 :                         excs.push_back(exc);
    1201         785 :                     }
    1202             :                     ctors.push_back(
    1203             :                         SingleInterfaceBasedServiceEntity::Constructor(
    1204             :                             ctorName, params, excs,
    1205        2509 :                             readAnnotations(annotated, file, offset, &offset)));
    1206        5018 :                 }
    1207             :             }
    1208             :             return new SingleInterfaceBasedServiceEntity(
    1209             :                 published, base, ctors,
    1210       11292 :                 readAnnotations(annotated, file, offset));
    1211             :         }
    1212             :     case 9: // accumulation-based service
    1213             :         {
    1214       11934 :             sal_uInt32 n = file->read32(offset + 1);
    1215       11934 :             if (n > SAL_MAX_INT32) {
    1216             :                 throw FileFormatException(
    1217           0 :                     file->uri,
    1218             :                     ("UNOIDL format: too many direct mandatory service bases of"
    1219           0 :                      " accumulation-based service"));
    1220             :             }
    1221       11934 :             offset += 5;
    1222       11934 :             std::vector< AnnotatedReference > mandServs;
    1223       20378 :             for (sal_uInt32 i = 0; i != n; ++i) {
    1224        8444 :                 OUString base(file->readIdxName(&offset));
    1225        8444 :                 checkTypeName(file, base);
    1226             :                 mandServs.push_back(
    1227             :                     AnnotatedReference(
    1228             :                         base,
    1229        8444 :                         readAnnotations(annotated, file, offset, &offset)));
    1230        8444 :             }
    1231       11934 :             n = file->read32(offset);
    1232       11934 :             if (n > SAL_MAX_INT32) {
    1233             :                 throw FileFormatException(
    1234           0 :                     file->uri,
    1235             :                     ("UNOIDL format: too many direct optional service bases of"
    1236           0 :                      " accumulation-based service"));
    1237             :             }
    1238       11934 :             offset += 4;
    1239       23868 :             std::vector< AnnotatedReference > optServs;
    1240       12638 :             for (sal_uInt32 i = 0; i != n; ++i) {
    1241         704 :                 OUString base(file->readIdxName(&offset));
    1242         704 :                 checkTypeName(file, base);
    1243             :                 optServs.push_back(
    1244             :                     AnnotatedReference(
    1245             :                         base,
    1246         704 :                         readAnnotations(annotated, file, offset, &offset)));
    1247         704 :             }
    1248       11934 :             n = file->read32(offset);
    1249       11934 :             if (n > SAL_MAX_INT32) {
    1250             :                 throw FileFormatException(
    1251           0 :                     file->uri,
    1252             :                     ("UNOIDL format: too many direct mandatory interface bases"
    1253           0 :                      " of accumulation-based service"));
    1254             :             }
    1255       11934 :             offset += 4;
    1256       23868 :             std::vector< AnnotatedReference > mandIfcs;
    1257       29991 :             for (sal_uInt32 i = 0; i != n; ++i) {
    1258       18057 :                 OUString base(file->readIdxName(&offset));
    1259       18057 :                 checkTypeName(file, base);
    1260             :                 mandIfcs.push_back(
    1261             :                     AnnotatedReference(
    1262             :                         base,
    1263       18057 :                         readAnnotations(annotated, file, offset, &offset)));
    1264       18057 :             }
    1265       11934 :             n = file->read32(offset);
    1266       11934 :             if (n > SAL_MAX_INT32) {
    1267             :                 throw FileFormatException(
    1268           0 :                     file->uri,
    1269             :                     ("UNOIDL format: too many direct optional interface bases"
    1270           0 :                      " of accumulation-based service"));
    1271             :             }
    1272       11934 :             offset += 4;
    1273       23868 :             std::vector< AnnotatedReference > optIfcs;
    1274       15421 :             for (sal_uInt32 i = 0; i != n; ++i) {
    1275        3487 :                 OUString base(file->readIdxName(&offset));
    1276        3487 :                 checkTypeName(file, base);
    1277             :                 optIfcs.push_back(
    1278             :                     AnnotatedReference(
    1279             :                         base,
    1280        3487 :                         readAnnotations(annotated, file, offset, &offset)));
    1281        3487 :             }
    1282       11934 :             n = file->read32(offset);
    1283       11934 :             if (n > SAL_MAX_INT32) {
    1284             :                 throw FileFormatException(
    1285           0 :                     file->uri,
    1286             :                     ("UNOIDL format: too many direct properties of"
    1287           0 :                      " accumulation-based service"));
    1288             :             }
    1289       11934 :             offset += 4;
    1290       23868 :             std::vector< AccumulationBasedServiceEntity::Property > props;
    1291       49035 :             for (sal_uInt32 i = 0; i != n; ++i) {
    1292       37101 :                 sal_uInt16 attrs = file->read16(offset);
    1293       37101 :                 offset += 2;
    1294       37101 :                 OUString propName(file->readIdxName(&offset));
    1295       37101 :                 checkEntityName(file, propName);
    1296       74202 :                 OUString propType(file->readIdxName(&offset));
    1297       37101 :                 checkTypeName(file, propType);
    1298       37101 :                 if (attrs > 0x01FF) { // see css.beans.PropertyAttribute
    1299             :                     throw FileFormatException(
    1300           0 :                         file->uri,
    1301           0 :                         ("UNOIDL format: bad mode " + OUString::number(v)
    1302           0 :                          + " of property " + propName
    1303           0 :                          + " for accumulation-based servcie"));
    1304             :                 }
    1305             :                 props.push_back(
    1306             :                     AccumulationBasedServiceEntity::Property(
    1307             :                         propName, propType,
    1308             :                         static_cast<
    1309             :                             AccumulationBasedServiceEntity::Property::
    1310             :                             Attributes >(
    1311             :                                 attrs),
    1312       37101 :                         readAnnotations(annotated, file, offset, &offset)));
    1313       37101 :             }
    1314             :             return new AccumulationBasedServiceEntity(
    1315             :                 published, mandServs, optServs, mandIfcs, optIfcs, props,
    1316       23868 :                 readAnnotations(annotated, file, offset));
    1317             :         }
    1318             :     case 10: // interface-based singleton
    1319             :         {
    1320         991 :             ++offset;
    1321         991 :             OUString base(file->readIdxName(&offset));
    1322         991 :             checkTypeName(file, base);
    1323             :             return new InterfaceBasedSingletonEntity(
    1324         991 :                 published, base, readAnnotations(annotated, file, offset));
    1325             :         }
    1326             :     case 11: // service-based singleton
    1327             :         {
    1328           3 :             ++offset;
    1329           3 :             OUString base(file->readIdxName(&offset));
    1330           3 :             checkTypeName(file, base);
    1331             :             return new ServiceBasedSingletonEntity(
    1332           3 :                 published, base, readAnnotations(annotated, file, offset));
    1333             :         }
    1334             :     default:
    1335             :         throw FileFormatException(
    1336           0 :             file->uri, "UNOIDL format: bad type byte " + OUString::number(v));
    1337             :     }
    1338             : }
    1339             : 
    1340             : }
    1341             : 
    1342         970 : UnoidlProvider::UnoidlProvider(OUString const & uri): file_(new MappedFile(uri))
    1343             : {
    1344         970 :     if (file_->size < 8 || std::memcmp(file_->address, "UNOIDL\xFF\0", 8) != 0)
    1345             :     {
    1346             :         throw FileFormatException(
    1347           0 :             file_->uri,
    1348             :             "UNOIDL format: does not begin with magic UNOIDL\\xFF and version"
    1349           0 :             " 0");
    1350             :     }
    1351         970 :     sal_uInt32 off = file_->read32(8);
    1352         970 :     map_.map.size = file_->read32(12);
    1353         970 :     if (off + 8 * sal_uInt64(map_.map.size) > file_->size) { // cannot overflow
    1354             :         throw FileFormatException(
    1355           0 :             file_->uri, "UNOIDL format: root map offset + size too large");
    1356             :     }
    1357             :     map_.map.begin = reinterpret_cast< MapEntry const * >(
    1358         970 :         static_cast< char const * >(file_->address) + off);
    1359         970 :     map_.trace.insert(map_.map);
    1360         970 : }
    1361             : 
    1362          33 : rtl::Reference< MapCursor > UnoidlProvider::createRootCursor() const {
    1363             :     return new UnoidlCursor(
    1364             :         file_, const_cast<UnoidlProvider *>(this),
    1365          33 :         rtl::Reference<UnoidlModuleEntity>(), map_);
    1366             : }
    1367             : 
    1368     1609286 : rtl::Reference< Entity > UnoidlProvider::findEntity(OUString const & name) const
    1369             : {
    1370     1609286 :     NestedMap map(map_);
    1371     1609286 :     bool cgroup = false;
    1372     1609286 :     for (sal_Int32 i = 0;;) {
    1373     6884298 :         sal_Int32 j = name.indexOf('.', i);
    1374     6884298 :         if (j == -1) {
    1375      861302 :             j = name.getLength();
    1376             :         }
    1377             :         sal_Int32 off = findInMap(
    1378     6884298 :             file_, map.map.begin, map.map.size, name, i, j - i);
    1379     6884298 :         if (off == 0) {
    1380      784032 :             return rtl::Reference< Entity >();
    1381             :         }
    1382     6100266 :         if (j == name.getLength()) {
    1383             :             return cgroup
    1384             :                 ? rtl::Reference< Entity >()
    1385      825221 :                 : readEntity(file_, off, map.trace);
    1386             :         }
    1387     5275045 :         if (cgroup) {
    1388           0 :             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?
    1392             :         }
    1393     5275045 :         int v = file_->read8(off);
    1394     5275045 :         if (v != 0) { // module
    1395         256 :             if ((v & 0x3F) == 7) { // constant group
    1396         223 :                 cgroup = true;
    1397             :             } else {
    1398          33 :                 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?
    1402             :             }
    1403             :         }
    1404     5275012 :         map.map.size = file_->read32(off + 1);
    1405     5275012 :         if (sal_uInt64(off) + 5 + 8 * sal_uInt64(map.map.size) > file_->size)
    1406             :             // cannot overflow
    1407             :         {
    1408             :             throw FileFormatException(
    1409           0 :                 file_->uri, "UNOIDL format: map offset + size too large");
    1410             :         }
    1411             :         map.map.begin = reinterpret_cast< MapEntry const * >(
    1412     5275012 :             static_cast< char const * >(file_->address) + off + 5);
    1413     5275012 :         if (!map.trace.insert(map.map).second) {
    1414             :             throw FileFormatException(
    1415           0 :                 file_->uri, "UNOIDL format: recursive map");
    1416             :         }
    1417     5275012 :         i = j + 1;
    1418     5275012 :     }
    1419             : }
    1420             : 
    1421        1762 : UnoidlProvider::~UnoidlProvider() throw () {}
    1422             : 
    1423             : } }
    1424             : 
    1425             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11