/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: */ |