Coverage Report

Created: 2025-07-07 10:01

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