Slightly optimize truncateToLength and padToLength
[LibreOffice.git] / unoidl / source / unoidl-write.cxx
blob5ddd98468359dd28c0ed755c8123237cd1d9cb58
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <sal/config.h>
12 #include <algorithm>
13 #include <cassert>
14 #include <cstdlib>
15 #include <iostream>
16 #include <map>
17 #include <utility>
18 #include <vector>
20 #include <config_version.h>
21 #include <osl/endian.h>
22 #include <osl/file.h>
23 #include <osl/file.hxx>
24 #include <osl/process.h>
25 #include <rtl/byteseq.hxx>
26 #include <rtl/process.h>
27 #include <rtl/string.h>
28 #include <rtl/string.hxx>
29 #include <rtl/textenc.h>
30 #include <rtl/textcvt.h>
31 #include <rtl/ustring.hxx>
32 #include <sal/macros.h>
33 #include <sal/main.h>
34 #include <unoidl/unoidl.hxx>
36 namespace {
38 void badUsage() {
39 std::cerr
40 << "Usage:" << std::endl << std::endl
41 << " unoidl-write [<registries>] [@<entities file>] <unoidl file>"
42 << std::endl << std::endl
43 << ("where each <registry> is either a new- or legacy-format .rdb file,"
44 " a single .idl")
45 << std::endl
46 << ("file, or a root directory of an .idl file tree; and the UTF-8"
47 " encoded <entities")
48 << std::endl
49 << ("file> contains zero or more space-separated names of (non-module)"
50 " entities to")
51 << std::endl
52 << ("include in the output, and, if omitted, defaults to the complete"
53 " content of the")
54 << std::endl << "last <registry>, if any." << std::endl;
55 std::exit(EXIT_FAILURE);
58 OUString getArgumentUri(sal_uInt32 argument, bool * entities) {
59 OUString arg;
60 rtl_getAppCommandArg(argument, &arg.pData);
61 if (arg.startsWith("@", &arg)) {
62 if (entities == nullptr) {
63 badUsage();
65 *entities = true;
66 } else if (entities != nullptr) {
67 *entities = false;
69 OUString url;
70 osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
71 if (e1 != osl::FileBase::E_None) {
72 std::cerr
73 << "Cannot convert \"" << arg << "\" to file URL, error code "
74 << +e1 << std::endl;
75 std::exit(EXIT_FAILURE);
77 OUString cwd;
78 oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData);
79 if (e2 != osl_Process_E_None) {
80 std::cerr
81 << "Cannot obtain working directory, error code " << +e2
82 << std::endl;
83 std::exit(EXIT_FAILURE);
85 OUString abs;
86 e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs);
87 if (e1 != osl::FileBase::E_None) {
88 std::cerr
89 << "Cannot make \"" << url
90 << "\" into an absolute file URL, error code " << +e1 << std::endl;
91 std::exit(EXIT_FAILURE);
93 return abs;
96 sal_uInt64 getOffset(osl::File & file) {
97 sal_uInt64 off;
98 osl::FileBase::RC e = file.getPos(off);
99 if (e != osl::FileBase::E_None) {
100 std::cerr
101 << "Cannot determine current position in <" << file.getURL()
102 << ">, error code " << +e << std::endl;
103 std::exit(EXIT_FAILURE);
105 return off;
108 void write(osl::File & file, void const * buffer, sal_uInt64 size) {
109 sal_uInt64 n;
110 osl::FileBase::RC e = file.write(buffer, size, n);
111 if (e != osl::FileBase::E_None) {
112 std::cerr
113 << "Cannot write to <" << file.getURL() << ">, error code " << +e
114 << std::endl;
115 std::exit(EXIT_FAILURE);
117 if (n != size) {
118 std::cerr
119 << "Bad write of " << n << " instead of " << size << " bytes to <"
120 << file.getURL() << '>' << std::endl;
121 std::exit(EXIT_FAILURE);
125 void write8(osl::File & file, sal_uInt64 value) {
126 if (value > 0xFF) {
127 std::cerr
128 << "Cannot write value >= 2^8; input is too large" << std::endl;
129 std::exit(EXIT_FAILURE);
131 unsigned char buf[1];
132 buf[0] = value & 0xFF;
133 write(file, buf, SAL_N_ELEMENTS(buf));
136 void write16(osl::File & file, sal_uInt64 value) {
137 if (value > 0xFFFF) {
138 std::cerr
139 << "Cannot write value >= 2^16; input is too large" << std::endl;
140 std::exit(EXIT_FAILURE);
142 unsigned char buf[2];
143 buf[0] = value & 0xFF;
144 buf[1] = (value >> 8) & 0xFF;
145 write(file, buf, SAL_N_ELEMENTS(buf));
148 void write32(osl::File & file, sal_uInt64 value) {
149 if (value > 0xFFFFFFFF) {
150 std::cerr
151 << "Cannot write value >= 2^32; input is too large" << std::endl;
152 std::exit(EXIT_FAILURE);
154 unsigned char buf[4];
155 buf[0] = value & 0xFF;
156 buf[1] = (value >> 8) & 0xFF;
157 buf[2] = (value >> 16) & 0xFF;
158 buf[3] = (value >> 24) & 0xFF;
159 write(file, buf, SAL_N_ELEMENTS(buf));
162 void write64(osl::File & file, sal_uInt64 value) {
163 unsigned char buf[8];
164 buf[0] = value & 0xFF;
165 buf[1] = (value >> 8) & 0xFF;
166 buf[2] = (value >> 16) & 0xFF;
167 buf[3] = (value >> 24) & 0xFF;
168 buf[4] = (value >> 32) & 0xFF;
169 buf[5] = (value >> 40) & 0xFF;
170 buf[6] = (value >> 48) & 0xFF;
171 buf[7] = (value >> 56) & 0xFF;
172 write(file, buf, SAL_N_ELEMENTS(buf));
175 void writeIso60599Binary32(osl::File & file, float value) {
176 union {
177 unsigned char buf[4];
178 float f; // assuming float is ISO 60599 binary32
179 } sa;
180 sa.f = value;
181 #if defined OSL_BIGENDIAN
182 std::swap(sa.buf[0], sa.buf[3]);
183 std::swap(sa.buf[1], sa.buf[2]);
184 #endif
185 write(file, sa.buf, SAL_N_ELEMENTS(sa.buf));
188 void writeIso60599Binary64(osl::File & file, double value) {
189 union {
190 unsigned char buf[8];
191 float d; // assuming double is ISO 60599 binary64
192 } sa;
193 sa.d = value;
194 #if defined OSL_BIGENDIAN
195 std::swap(sa.buf[0], sa.buf[7]);
196 std::swap(sa.buf[1], sa.buf[6]);
197 std::swap(sa.buf[2], sa.buf[5]);
198 std::swap(sa.buf[3], sa.buf[4]);
199 #endif
200 write(file, sa.buf, SAL_N_ELEMENTS(sa.buf));
203 OString toAscii(OUString const & name) {
204 OString ascii;
205 if (!name.convertToString(
206 &ascii, RTL_TEXTENCODING_ASCII_US,
207 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
208 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
210 std::cerr
211 << "Cannot convert \"" << name << "\" to US ASCII" << std::endl;
212 std::exit(EXIT_FAILURE);
214 return ascii;
217 OString toUtf8(OUString const & string) {
218 OString ascii;
219 if (!string.convertToString(
220 &ascii, RTL_TEXTENCODING_UTF8,
221 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
222 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
224 std::cerr
225 << "Cannot convert \"" << string << "\" to UTF-8" << std::endl;
226 std::exit(EXIT_FAILURE);
228 return ascii;
231 sal_uInt64 writeNulName(osl::File & file, OUString const & name) {
232 OString ascii(toAscii(name));
233 if (ascii.indexOf('\0') != -1) {
234 std::cerr
235 << "Name \"" << ascii << "\" contains NUL characters" << std::endl;
236 std::exit(EXIT_FAILURE);
238 sal_uInt64 off = getOffset(file);
239 write(file, ascii.getStr(), ascii.getLength() + 1);
240 return off;
243 void writeIdxString(osl::File & file, OString const & string) {
244 static std::map< OString, sal_uInt64 > reuse;
245 std::map< OString, sal_uInt64 >::iterator i(reuse.find(string));
246 if (i == reuse.end()) {
247 reuse.insert(std::make_pair(string, getOffset(file)));
248 assert(
249 (static_cast< sal_uInt64 >(string.getLength()) & 0x80000000) == 0);
250 write32(file, static_cast< sal_uInt64 >(string.getLength()));
251 write(file, string.getStr(), string.getLength());
252 } else {
253 if ((i->second & 0x80000000) != 0) {
254 std::cerr
255 << "Cannot write index 0x" << std::hex << i->second << std::dec
256 << " of \"" << string << "\"; input is too large" << std::endl;
257 std::exit(EXIT_FAILURE);
259 write32(file, i->second | 0x80000000);
263 void writeIdxName(osl::File & file, OUString const & name) {
264 writeIdxString(file, toAscii(name));
267 void writeAnnotations(
268 osl::File & file, bool annotate,
269 std::vector< OUString > const & annotations)
271 assert(annotate || annotations.empty());
272 if (annotate) {
273 write32(file, annotations.size());
274 // overflow from std::vector::size_type -> sal_uInt64 is unrealistic
275 for (auto & i: annotations) {
276 writeIdxString(file, toUtf8(i));
281 void writeKind(
282 osl::File & file,
283 rtl::Reference< unoidl::PublishableEntity > const & entity,
284 bool annotated, bool flag = false)
286 assert(entity.is());
287 sal_uInt64 v = entity->getSort();
288 if (entity->isPublished()) {
289 v |= 0x80;
291 if (annotated) {
292 v |= 0x40;
294 if (flag) {
295 v |= 0x20;
297 write8(file, v);
300 struct Item {
301 explicit Item(rtl::Reference< unoidl::Entity > const & theEntity):
302 entity(theEntity), nameOffset(0), dataOffset(0)
305 rtl::Reference< unoidl::Entity > entity;
306 std::map< OUString, Item > module;
307 sal_uInt64 nameOffset;
308 sal_uInt64 dataOffset;
311 struct ConstItem {
312 ConstItem(
313 unoidl::ConstantValue const & theConstant,
314 std::vector< OUString >&& theAnnotations):
315 constant(theConstant), annotations(std::move(theAnnotations)), nameOffset(0),
316 dataOffset(0)
319 unoidl::ConstantValue constant;
320 std::vector< OUString > annotations;
321 sal_uInt64 nameOffset;
322 sal_uInt64 dataOffset;
325 void mapEntities(
326 rtl::Reference< unoidl::Manager > const & manager, OUString const & uri,
327 std::map< OUString, Item > & map)
329 assert(manager.is());
330 osl::File f(uri);
331 osl::FileBase::RC e = f.open(osl_File_OpenFlag_Read);
332 if (e != osl::FileBase::E_None) {
333 std::cerr
334 << "Cannot open <" << f.getURL() << "> for reading, error code "
335 << +e << std::endl;
336 std::exit(EXIT_FAILURE);
338 for (;;) {
339 sal_Bool eof;
340 e = f.isEndOfFile(&eof);
341 if (e != osl::FileBase::E_None) {
342 std::cerr
343 << "Cannot check <" << f.getURL() << "> for EOF, error code "
344 << +e << std::endl;
345 std::exit(EXIT_FAILURE);
347 if (eof) {
348 break;
350 rtl::ByteSequence s1;
351 e = f.readLine(s1);
352 if (e != osl::FileBase::E_None) {
353 std::cerr
354 << "Cannot read from <" << f.getURL() << ">, error code "
355 << +e << std::endl;
356 std::exit(EXIT_FAILURE);
358 OUString s2;
359 if (!rtl_convertStringToUString(
360 &s2.pData, reinterpret_cast< char const * >(s1.getConstArray()),
361 s1.getLength(), RTL_TEXTENCODING_UTF8,
362 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
363 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
364 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
366 std::cerr
367 << "Cannot interpret line read from <" << f.getURL()
368 << "> as UTF-8" << std::endl;
369 std::exit(EXIT_FAILURE);
371 for (sal_Int32 i = 0; i != -1;) {
372 OUString t(s2.getToken(0, ' ', i));
373 if (!t.isEmpty()) {
374 rtl::Reference< unoidl::Entity > ent(manager->findEntity(t));
375 if (!ent.is()) {
376 std::cerr
377 << "Unknown entity \"" << t << "\" read from <"
378 << f.getURL() << ">" << std::endl;
379 std::exit(EXIT_FAILURE);
381 if (ent->getSort() == unoidl::Entity::SORT_MODULE) {
382 std::cerr
383 << "Module entity \"" << t << "\" read from <"
384 << f.getURL() << ">" << std::endl;
385 std::exit(EXIT_FAILURE);
387 std::map< OUString, Item > * map2 = &map;
388 for (sal_Int32 j = 0;;) {
389 OUString id(t.getToken(0, '.', j));
390 if (j == -1) {
391 map2->insert(std::make_pair(id, Item(ent)));
392 break;
394 std::map< OUString, Item >::iterator k(map2->find(id));
395 if (k == map2->end()) {
396 rtl::Reference< unoidl::Entity > ent2(
397 manager->findEntity(t.copy(0, j - 1)));
398 assert(ent2.is());
399 k = map2->insert(std::make_pair(id, Item(ent2))).first;
401 assert(
402 k->second.entity->getSort()
403 == unoidl::Entity::SORT_MODULE);
404 map2 = &k->second.module;
409 e = f.close();
410 if (e != osl::FileBase::E_None) {
411 std::cerr
412 << "Cannot close <" << f.getURL() << "> after reading, error code "
413 << +e << std::endl;
414 std::exit(EXIT_FAILURE);
418 void mapCursor(
419 rtl::Reference< unoidl::MapCursor > const & cursor,
420 std::map< OUString, Item > & map)
422 if (!cursor.is())
423 return;
425 for (;;) {
426 OUString name;
427 rtl::Reference< unoidl::Entity > ent(cursor->getNext(&name));
428 if (!ent.is()) {
429 break;
431 std::pair< std::map< OUString, Item >::iterator, bool > i(
432 map.insert(std::make_pair(name, Item(ent))));
433 if (!i.second) {
434 std::cout << "Duplicate name \"" << name << '"' << std::endl;
435 std::exit(EXIT_FAILURE);
437 if (i.first->second.entity->getSort()
438 == unoidl::Entity::SORT_MODULE)
440 mapCursor(
441 rtl::Reference< unoidl::ModuleEntity >(
442 static_cast< unoidl::ModuleEntity * >(
443 i.first->second.entity.get()))->createCursor(),
444 i.first->second.module);
449 template<typename T>
450 bool hasNotEmptyAnnotations(const std::vector<T>& v)
452 return std::any_of(v.begin(), v.end(), [](const T& rItem) { return !rItem.annotations.empty(); });
455 sal_uInt64 writeMap(
456 osl::File & file, std::map< OUString, Item > & map, std::size_t * rootSize)
458 for (auto & i: map) {
459 switch (i.second.entity->getSort()) {
460 case unoidl::Entity::SORT_MODULE:
461 i.second.dataOffset = writeMap(file, i.second.module, nullptr);
462 break;
463 case unoidl::Entity::SORT_ENUM_TYPE:
465 rtl::Reference< unoidl::EnumTypeEntity > ent2(
466 static_cast< unoidl::EnumTypeEntity * >(
467 i.second.entity.get()));
468 bool ann = !ent2->getAnnotations().empty() ||
469 hasNotEmptyAnnotations(ent2->getMembers());
470 i.second.dataOffset = getOffset(file);
471 writeKind(file, ent2, ann);
472 write32(file, ent2->getMembers().size());
473 for (auto & j: ent2->getMembers()) {
474 writeIdxName(file, j.name);
475 write32(file, static_cast< sal_uInt32 >(j.value));
476 writeAnnotations(file, ann, j.annotations);
478 writeAnnotations(file, ann, ent2->getAnnotations());
479 break;
481 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
483 rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
484 static_cast< unoidl::PlainStructTypeEntity * >(
485 i.second.entity.get()));
486 bool ann = !ent2->getAnnotations().empty() ||
487 hasNotEmptyAnnotations(ent2->getDirectMembers());
488 i.second.dataOffset = getOffset(file);
489 writeKind(
490 file, ent2, ann, !ent2->getDirectBase().isEmpty());
491 if (!ent2->getDirectBase().isEmpty()) {
492 writeIdxName(file, ent2->getDirectBase());
494 write32(file, ent2->getDirectMembers().size());
495 for (auto & j: ent2->getDirectMembers()) {
496 writeIdxName(file, j.name);
497 writeIdxName(file, j.type);
498 writeAnnotations(file, ann, j.annotations);
500 writeAnnotations(file, ann, ent2->getAnnotations());
501 break;
503 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
505 rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity >
506 ent2(
507 static_cast<
508 unoidl::PolymorphicStructTypeTemplateEntity * >(
509 i.second.entity.get()));
510 bool ann = !ent2->getAnnotations().empty() ||
511 hasNotEmptyAnnotations(ent2->getMembers());
512 i.second.dataOffset = getOffset(file);
513 writeKind(file, ent2, ann);
514 write32(file, ent2->getTypeParameters().size());
515 for (auto & j: ent2->getTypeParameters()) {
516 writeIdxName(file, j);
518 write32(file, ent2->getMembers().size());
519 for (auto & j: ent2->getMembers()) {
520 sal_uInt64 f = 0;
521 if (j.parameterized) {
522 f |= 0x01;
524 write8(file, f);
525 writeIdxName(file, j.name);
526 writeIdxName(file, j.type);
527 writeAnnotations(file, ann, j.annotations);
529 writeAnnotations(file, ann, ent2->getAnnotations());
530 break;
532 case unoidl::Entity::SORT_EXCEPTION_TYPE:
534 rtl::Reference< unoidl::ExceptionTypeEntity > ent2(
535 static_cast< unoidl::ExceptionTypeEntity * >(
536 i.second.entity.get()));
537 bool ann = !ent2->getAnnotations().empty() ||
538 hasNotEmptyAnnotations(ent2->getDirectMembers());
539 i.second.dataOffset = getOffset(file);
540 writeKind(
541 file, ent2, ann, !ent2->getDirectBase().isEmpty());
542 if (!ent2->getDirectBase().isEmpty()) {
543 writeIdxName(file, ent2->getDirectBase());
545 write32(file, ent2->getDirectMembers().size());
546 for (auto & j: ent2->getDirectMembers()) {
547 writeIdxName(file, j.name);
548 writeIdxName(file, j.type);
549 writeAnnotations(file, ann, j.annotations);
551 writeAnnotations(file, ann, ent2->getAnnotations());
552 break;
554 case unoidl::Entity::SORT_INTERFACE_TYPE:
556 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
557 static_cast< unoidl::InterfaceTypeEntity * >(
558 i.second.entity.get()));
559 bool ann = !ent2->getAnnotations().empty() ||
560 hasNotEmptyAnnotations(ent2->getDirectMandatoryBases()) ||
561 hasNotEmptyAnnotations(ent2->getDirectOptionalBases()) ||
562 hasNotEmptyAnnotations(ent2->getDirectAttributes()) ||
563 hasNotEmptyAnnotations(ent2->getDirectMethods());
564 i.second.dataOffset = getOffset(file);
565 writeKind(file, ent2, ann);
566 write32(file, ent2->getDirectMandatoryBases().size());
567 for (auto & j: ent2->getDirectMandatoryBases()) {
568 writeIdxName(file, j.name);
569 writeAnnotations(file, ann, j.annotations);
571 write32(file, ent2->getDirectOptionalBases().size());
572 for (auto & j: ent2->getDirectOptionalBases()) {
573 writeIdxName(file, j.name);
574 writeAnnotations(file, ann, j.annotations);
576 write32(file, ent2->getDirectAttributes().size());
577 for (auto & j: ent2->getDirectAttributes()) {
578 sal_uInt64 f = 0;
579 if (j.bound) {
580 f |= 0x01;
582 if (j.readOnly) {
583 f |= 0x02;
585 write8(file, f);
586 writeIdxName(file, j.name);
587 writeIdxName(file, j.type);
588 write32(file, j.getExceptions.size());
589 for (auto & k: j.getExceptions) {
590 writeIdxName(file, k);
592 if (!j.readOnly) {
593 write32(file, j.setExceptions.size());
594 for (auto & k: j.setExceptions) {
595 writeIdxName(file, k);
598 writeAnnotations(file, ann, j.annotations);
600 write32(file, ent2->getDirectMethods().size());
601 for (auto & j: ent2->getDirectMethods()) {
602 writeIdxName(file, j.name);
603 writeIdxName(file, j.returnType);
604 write32(file, j.parameters.size());
605 for (auto & k: j.parameters) {
606 write8(file, k.direction);
607 writeIdxName(file, k.name);
608 writeIdxName(file, k.type);
610 write32(file, j.exceptions.size());
611 for (auto & k: j.exceptions) {
612 writeIdxName(file, k);
614 writeAnnotations(file, ann, j.annotations);
616 writeAnnotations(file, ann, ent2->getAnnotations());
617 break;
619 case unoidl::Entity::SORT_TYPEDEF:
621 rtl::Reference< unoidl::TypedefEntity > ent2(
622 static_cast< unoidl::TypedefEntity * >(
623 i.second.entity.get()));
624 bool ann = !ent2->getAnnotations().empty();
625 i.second.dataOffset = getOffset(file);
626 writeKind(file, ent2, ann);
627 writeIdxName(file, ent2->getType());
628 writeAnnotations(file, ann, ent2->getAnnotations());
629 break;
631 case unoidl::Entity::SORT_CONSTANT_GROUP:
633 rtl::Reference< unoidl::ConstantGroupEntity > ent2(
634 static_cast< unoidl::ConstantGroupEntity * >(
635 i.second.entity.get()));
636 std::map< OUString, ConstItem > cmap;
637 for (auto & j: ent2->getMembers()) {
638 if (!cmap.insert(
639 std::make_pair(
640 j.name, ConstItem(j.value, std::vector(j.annotations)))).
641 second)
643 std::cout
644 << "Duplicate constant group member name \""
645 << j.name << '"' << std::endl;
646 std::exit(EXIT_FAILURE);
649 for (auto & j: cmap) {
650 j.second.dataOffset = getOffset(file);
651 sal_uInt64 v = j.second.constant.type;
652 if (!j.second.annotations.empty()) {
653 v |= 0x80;
655 write8(file, v);
656 switch (j.second.constant.type) {
657 case unoidl::ConstantValue::TYPE_BOOLEAN:
658 write8(file, j.second.constant.booleanValue ? 1 : 0);
659 break;
660 case unoidl::ConstantValue::TYPE_BYTE:
661 write8(
662 file,
663 static_cast< sal_uInt8 >(
664 j.second.constant.byteValue));
665 break;
666 case unoidl::ConstantValue::TYPE_SHORT:
667 write16(
668 file,
669 static_cast< sal_uInt16 >(
670 j.second.constant.shortValue));
671 break;
672 case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
673 write16(file, j.second.constant.unsignedShortValue);
674 break;
675 case unoidl::ConstantValue::TYPE_LONG:
676 write32(
677 file,
678 static_cast< sal_uInt32 >(
679 j.second.constant.longValue));
680 break;
681 case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
682 write32(file, j.second.constant.unsignedLongValue);
683 break;
684 case unoidl::ConstantValue::TYPE_HYPER:
685 write64(
686 file,
687 static_cast< sal_uInt64 >(
688 j.second.constant.hyperValue));
689 break;
690 case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
691 write64(file, j.second.constant.unsignedHyperValue);
692 break;
693 case unoidl::ConstantValue::TYPE_FLOAT:
694 writeIso60599Binary32(
695 file, j.second.constant.floatValue);
696 break;
697 case unoidl::ConstantValue::TYPE_DOUBLE:
698 writeIso60599Binary64(
699 file, j.second.constant.doubleValue);
700 break;
701 default:
702 for (;;) { std::abort(); } // this cannot happen
704 writeAnnotations(
705 file, !j.second.annotations.empty(),
706 j.second.annotations);
708 for (auto & j: cmap) {
709 j.second.nameOffset = writeNulName(file, j.first);
711 bool ann = !ent2->getAnnotations().empty();
712 i.second.dataOffset = getOffset(file);
713 writeKind(file, ent2, ann);
714 write32(file, cmap.size());
715 // overflow from std::map::size_type -> sal_uInt64 is
716 // unrealistic
717 for (const auto & j: cmap) {
718 write32(file, j.second.nameOffset);
719 write32(file, j.second.dataOffset);
721 writeAnnotations(file, ann, ent2->getAnnotations());
722 break;
724 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
726 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity >
727 ent2(
728 static_cast<
729 unoidl::SingleInterfaceBasedServiceEntity * >(
730 i.second.entity.get()));
731 bool dfltCtor = ent2->getConstructors().size() == 1
732 && ent2->getConstructors()[0].defaultConstructor;
733 bool ann = !ent2->getAnnotations().empty();
734 if (!dfltCtor && !ann)
735 ann = hasNotEmptyAnnotations(ent2->getConstructors());
736 i.second.dataOffset = getOffset(file);
737 writeKind(file, ent2, ann, dfltCtor);
738 writeIdxName(file, ent2->getBase());
739 if (!dfltCtor) {
740 write32(file, ent2->getConstructors().size());
741 for (auto & j: ent2->getConstructors()) {
742 if (j.defaultConstructor) {
743 std::cout
744 << "Unexpected default constructor \""
745 << j.name << '"' << std::endl;
746 std::exit(EXIT_FAILURE);
748 writeIdxName(file, j.name);
749 write32(file, j.parameters.size());
750 for (auto & k: j.parameters) {
751 sal_uInt64 f = 0;
752 if (k.rest) {
753 f |= 0x04;
755 write8(file, f);
756 writeIdxName(file, k.name);
757 writeIdxName(file, k.type);
759 write32(file, j.exceptions.size());
760 for (auto & k: j.exceptions) {
761 writeIdxName(file, k);
763 writeAnnotations(file, ann, j.annotations);
766 writeAnnotations(file, ann, ent2->getAnnotations());
767 break;
769 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
771 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
772 static_cast< unoidl::AccumulationBasedServiceEntity * >(
773 i.second.entity.get()));
774 bool ann = !ent2->getAnnotations().empty() ||
775 hasNotEmptyAnnotations(ent2->getDirectMandatoryBaseServices()) ||
776 hasNotEmptyAnnotations(ent2->getDirectOptionalBaseServices()) ||
777 hasNotEmptyAnnotations(ent2->getDirectMandatoryBaseInterfaces()) ||
778 hasNotEmptyAnnotations(ent2->getDirectOptionalBaseInterfaces()) ||
779 hasNotEmptyAnnotations(ent2->getDirectProperties());
780 i.second.dataOffset = getOffset(file);
781 writeKind(file, ent2, ann);
782 write32(file, ent2->getDirectMandatoryBaseServices().size());
783 for (auto & j: ent2->getDirectMandatoryBaseServices()) {
784 writeIdxName(file, j.name);
785 writeAnnotations(file, ann, j.annotations);
787 write32(file, ent2->getDirectOptionalBaseServices().size());
788 for (auto & j: ent2->getDirectOptionalBaseServices()) {
789 writeIdxName(file, j.name);
790 writeAnnotations(file, ann, j.annotations);
792 write32(file, ent2->getDirectMandatoryBaseInterfaces().size());
793 for (auto & j: ent2->getDirectMandatoryBaseInterfaces()) {
794 writeIdxName(file, j.name);
795 writeAnnotations(file, ann, j.annotations);
797 write32(file, ent2->getDirectOptionalBaseInterfaces().size());
798 for (auto & j: ent2->getDirectOptionalBaseInterfaces()) {
799 writeIdxName(file, j.name);
800 writeAnnotations(file, ann, j.annotations);
802 write32(file, ent2->getDirectProperties().size());
803 for (auto & j: ent2->getDirectProperties()) {
804 write16(file, static_cast< sal_uInt16 >(j.attributes));
805 writeIdxName(file, j.name);
806 writeIdxName(file, j.type);
807 writeAnnotations(file, ann, j.annotations);
809 writeAnnotations(file, ann, ent2->getAnnotations());
810 break;
812 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
814 rtl::Reference< unoidl::InterfaceBasedSingletonEntity > ent2(
815 static_cast< unoidl::InterfaceBasedSingletonEntity * >(
816 i.second.entity.get()));
817 bool ann = !ent2->getAnnotations().empty();
818 i.second.dataOffset = getOffset(file);
819 writeKind(file, ent2, ann);
820 writeIdxName(file, ent2->getBase());
821 writeAnnotations(file, ann, ent2->getAnnotations());
822 break;
824 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
826 rtl::Reference< unoidl::ServiceBasedSingletonEntity > ent2(
827 static_cast< unoidl::ServiceBasedSingletonEntity * >(
828 i.second.entity.get()));
829 bool ann = !ent2->getAnnotations().empty();
830 i.second.dataOffset = getOffset(file);
831 writeKind(file, ent2, ann);
832 writeIdxName(file, ent2->getBase());
833 writeAnnotations(file, ann, ent2->getAnnotations());
834 break;
838 for (auto & i: map) {
839 i.second.nameOffset = writeNulName(file, i.first);
841 sal_uInt64 off = getOffset(file);
842 if (rootSize == nullptr) {
843 write8(file, 0); // SORT_MODULE
844 write32(file, map.size());
845 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
846 } else {
847 *rootSize = map.size();
848 // overflow from std::map::size_type -> std::size_t is unrealistic
850 for (const auto & i: map) {
851 write32(file, i.second.nameOffset);
852 write32(file, i.second.dataOffset);
854 return off;
859 SAL_IMPLEMENT_MAIN() {
860 try {
861 sal_uInt32 args = rtl_getAppCommandArgCount();
862 if (args == 0) {
863 badUsage();
865 rtl::Reference< unoidl::Manager > mgr(new unoidl::Manager);
866 bool entities = false;
867 rtl::Reference< unoidl::Provider > prov;
868 std::map< OUString, Item > map;
869 for (sal_uInt32 i = 0; i != args - 1; ++i) {
870 assert(args > 1);
871 OUString uri(getArgumentUri(i, i == args - 2 ? &entities : nullptr));
872 if (entities) {
873 mapEntities(mgr, uri, map);
874 } else {
875 try {
876 prov = mgr->addProvider(uri);
877 } catch (unoidl::NoSuchFileException &) {
878 std::cerr
879 << "Input <" << uri << "> does not exist" << std::endl;
880 std::exit(EXIT_FAILURE);
884 if (!entities) {
885 mapCursor(
886 (prov.is()
887 ? prov->createRootCursor()
888 : rtl::Reference< unoidl::MapCursor >()),
889 map);
891 osl::File f(getArgumentUri(args - 1, nullptr));
892 osl::FileBase::RC e = f.open(osl_File_OpenFlag_Write);
893 if (e == osl::FileBase::E_NOENT) {
894 e = f.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
896 if (e != osl::FileBase::E_None) {
897 std::cerr
898 << "Cannot open <" << f.getURL() << "> for writing, error code "
899 << +e << std::endl;
900 std::exit(EXIT_FAILURE);
902 write(f, "UNOIDL\xFF\0", 8);
903 write32(f, 0); // root map offset
904 write32(f, 0); // root map size
905 write(
907 RTL_CONSTASCII_STRINGPARAM(
908 "\0** Created by LibreOffice " LIBO_VERSION_DOTTED
909 " unoidl-write **\0"));
910 std::size_t size;
911 sal_uInt64 off = writeMap(f, map, &size);
912 e = f.setSize(getOffset(f)); // truncate in case it already existed
913 if (e != osl::FileBase::E_None) {
914 std::cerr
915 << "Cannot set size of <" << f.getURL() << ">, error code "
916 << +e << std::endl;
917 std::exit(EXIT_FAILURE);
919 e = f.setPos(osl_Pos_Absolut, 8);
920 if (e != osl::FileBase::E_None) {
921 std::cerr
922 << "Cannot rewind current position in <" << f.getURL()
923 << ">, error code " << +e << std::endl;
924 std::exit(EXIT_FAILURE);
926 write32(f, off);
927 write32(f, size);
928 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
929 e = f.close();
930 if (e != osl::FileBase::E_None) {
931 std::cerr
932 << "Cannot close <" << f.getURL()
933 << "> after writing, error code " << +e << std::endl;
934 std::exit(EXIT_FAILURE);
936 return EXIT_SUCCESS;
937 } catch (unoidl::FileFormatException & e1) {
938 std::cerr
939 << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
940 << std::endl;
941 std::exit(EXIT_FAILURE);
942 } catch (std::exception & e1) {
943 std::cerr
944 << "Failure: " << e1.what()
945 << std::endl;
946 std::exit(EXIT_FAILURE);
951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */