bump product version to 6.4.0.3
[LibreOffice.git] / unoidl / source / unoidl-write.cxx
blob3f51b68c07dd08ad5660c14c04c99da9bc9a51f6
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 > const & theAnnotations):
315 constant(theConstant), annotations(theAnnotations), nameOffset(0),
316 dataOffset(0)
319 unoidl::ConstantValue const constant;
320 std::vector< OUString > const 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 for (;;) {
424 OUString name;
425 rtl::Reference< unoidl::Entity > ent(cursor->getNext(&name));
426 if (!ent.is()) {
427 break;
429 std::pair< std::map< OUString, Item >::iterator, bool > i(
430 map.insert(std::make_pair(name, Item(ent))));
431 if (!i.second) {
432 std::cout << "Duplicate name \"" << name << '"' << std::endl;
433 std::exit(EXIT_FAILURE);
435 if (i.first->second.entity->getSort()
436 == unoidl::Entity::SORT_MODULE)
438 mapCursor(
439 rtl::Reference< unoidl::ModuleEntity >(
440 static_cast< unoidl::ModuleEntity * >(
441 i.first->second.entity.get()))->createCursor(),
442 i.first->second.module);
448 template<typename T>
449 bool hasNotEmptyAnnotations(const std::vector<T>& v)
451 return std::any_of(v.begin(), v.end(), [](const T& rItem) { return !rItem.annotations.empty(); });
454 sal_uInt64 writeMap(
455 osl::File & file, std::map< OUString, Item > & map, std::size_t * rootSize)
457 for (auto & i: map) {
458 switch (i.second.entity->getSort()) {
459 case unoidl::Entity::SORT_MODULE:
460 i.second.dataOffset = writeMap(file, i.second.module, nullptr);
461 break;
462 case unoidl::Entity::SORT_ENUM_TYPE:
464 rtl::Reference< unoidl::EnumTypeEntity > ent2(
465 static_cast< unoidl::EnumTypeEntity * >(
466 i.second.entity.get()));
467 bool ann = !ent2->getAnnotations().empty() ||
468 hasNotEmptyAnnotations(ent2->getMembers());
469 i.second.dataOffset = getOffset(file);
470 writeKind(file, ent2.get(), ann);
471 write32(file, ent2->getMembers().size());
472 for (auto & j: ent2->getMembers()) {
473 writeIdxName(file, j.name);
474 write32(file, static_cast< sal_uInt32 >(j.value));
475 writeAnnotations(file, ann, j.annotations);
477 writeAnnotations(file, ann, ent2->getAnnotations());
478 break;
480 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
482 rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
483 static_cast< unoidl::PlainStructTypeEntity * >(
484 i.second.entity.get()));
485 bool ann = !ent2->getAnnotations().empty() ||
486 hasNotEmptyAnnotations(ent2->getDirectMembers());
487 i.second.dataOffset = getOffset(file);
488 writeKind(
489 file, ent2.get(), ann, !ent2->getDirectBase().isEmpty());
490 if (!ent2->getDirectBase().isEmpty()) {
491 writeIdxName(file, ent2->getDirectBase());
493 write32(file, ent2->getDirectMembers().size());
494 for (auto & j: ent2->getDirectMembers()) {
495 writeIdxName(file, j.name);
496 writeIdxName(file, j.type);
497 writeAnnotations(file, ann, j.annotations);
499 writeAnnotations(file, ann, ent2->getAnnotations());
500 break;
502 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
504 rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity >
505 ent2(
506 static_cast<
507 unoidl::PolymorphicStructTypeTemplateEntity * >(
508 i.second.entity.get()));
509 bool ann = !ent2->getAnnotations().empty() ||
510 hasNotEmptyAnnotations(ent2->getMembers());
511 i.second.dataOffset = getOffset(file);
512 writeKind(file, ent2.get(), ann);
513 write32(file, ent2->getTypeParameters().size());
514 for (auto & j: ent2->getTypeParameters()) {
515 writeIdxName(file, j);
517 write32(file, ent2->getMembers().size());
518 for (auto & j: ent2->getMembers()) {
519 sal_uInt64 f = 0;
520 if (j.parameterized) {
521 f |= 0x01;
523 write8(file, f);
524 writeIdxName(file, j.name);
525 writeIdxName(file, j.type);
526 writeAnnotations(file, ann, j.annotations);
528 writeAnnotations(file, ann, ent2->getAnnotations());
529 break;
531 case unoidl::Entity::SORT_EXCEPTION_TYPE:
533 rtl::Reference< unoidl::ExceptionTypeEntity > ent2(
534 static_cast< unoidl::ExceptionTypeEntity * >(
535 i.second.entity.get()));
536 bool ann = !ent2->getAnnotations().empty() ||
537 hasNotEmptyAnnotations(ent2->getDirectMembers());
538 i.second.dataOffset = getOffset(file);
539 writeKind(
540 file, ent2.get(), ann, !ent2->getDirectBase().isEmpty());
541 if (!ent2->getDirectBase().isEmpty()) {
542 writeIdxName(file, ent2->getDirectBase());
544 write32(file, ent2->getDirectMembers().size());
545 for (auto & j: ent2->getDirectMembers()) {
546 writeIdxName(file, j.name);
547 writeIdxName(file, j.type);
548 writeAnnotations(file, ann, j.annotations);
550 writeAnnotations(file, ann, ent2->getAnnotations());
551 break;
553 case unoidl::Entity::SORT_INTERFACE_TYPE:
555 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
556 static_cast< unoidl::InterfaceTypeEntity * >(
557 i.second.entity.get()));
558 bool ann = !ent2->getAnnotations().empty() ||
559 hasNotEmptyAnnotations(ent2->getDirectMandatoryBases()) ||
560 hasNotEmptyAnnotations(ent2->getDirectOptionalBases()) ||
561 hasNotEmptyAnnotations(ent2->getDirectAttributes()) ||
562 hasNotEmptyAnnotations(ent2->getDirectMethods());
563 i.second.dataOffset = getOffset(file);
564 writeKind(file, ent2.get(), ann);
565 write32(file, ent2->getDirectMandatoryBases().size());
566 for (auto & j: ent2->getDirectMandatoryBases()) {
567 writeIdxName(file, j.name);
568 writeAnnotations(file, ann, j.annotations);
570 write32(file, ent2->getDirectOptionalBases().size());
571 for (auto & j: ent2->getDirectOptionalBases()) {
572 writeIdxName(file, j.name);
573 writeAnnotations(file, ann, j.annotations);
575 write32(file, ent2->getDirectAttributes().size());
576 for (auto & j: ent2->getDirectAttributes()) {
577 sal_uInt64 f = 0;
578 if (j.bound) {
579 f |= 0x01;
581 if (j.readOnly) {
582 f |= 0x02;
584 write8(file, f);
585 writeIdxName(file, j.name);
586 writeIdxName(file, j.type);
587 write32(file, j.getExceptions.size());
588 for (auto & k: j.getExceptions) {
589 writeIdxName(file, k);
591 if (!j.readOnly) {
592 write32(file, j.setExceptions.size());
593 for (auto & k: j.setExceptions) {
594 writeIdxName(file, k);
597 writeAnnotations(file, ann, j.annotations);
599 write32(file, ent2->getDirectMethods().size());
600 for (auto & j: ent2->getDirectMethods()) {
601 writeIdxName(file, j.name);
602 writeIdxName(file, j.returnType);
603 write32(file, j.parameters.size());
604 for (auto & k: j.parameters) {
605 write8(file, k.direction);
606 writeIdxName(file, k.name);
607 writeIdxName(file, k.type);
609 write32(file, j.exceptions.size());
610 for (auto & k: j.exceptions) {
611 writeIdxName(file, k);
613 writeAnnotations(file, ann, j.annotations);
615 writeAnnotations(file, ann, ent2->getAnnotations());
616 break;
618 case unoidl::Entity::SORT_TYPEDEF:
620 rtl::Reference< unoidl::TypedefEntity > ent2(
621 static_cast< unoidl::TypedefEntity * >(
622 i.second.entity.get()));
623 bool ann = !ent2->getAnnotations().empty();
624 i.second.dataOffset = getOffset(file);
625 writeKind(file, ent2.get(), ann);
626 writeIdxName(file, ent2->getType());
627 writeAnnotations(file, ann, ent2->getAnnotations());
628 break;
630 case unoidl::Entity::SORT_CONSTANT_GROUP:
632 rtl::Reference< unoidl::ConstantGroupEntity > ent2(
633 static_cast< unoidl::ConstantGroupEntity * >(
634 i.second.entity.get()));
635 std::map< OUString, ConstItem > cmap;
636 for (auto & j: ent2->getMembers()) {
637 if (!cmap.insert(
638 std::make_pair(
639 j.name, ConstItem(j.value, j.annotations))).
640 second)
642 std::cout
643 << "Duplicate constant group member name \""
644 << j.name << '"' << std::endl;
645 std::exit(EXIT_FAILURE);
648 for (auto & j: cmap) {
649 j.second.dataOffset = getOffset(file);
650 sal_uInt64 v = j.second.constant.type;
651 if (!j.second.annotations.empty()) {
652 v |= 0x80;
654 write8(file, v);
655 switch (j.second.constant.type) {
656 case unoidl::ConstantValue::TYPE_BOOLEAN:
657 write8(file, j.second.constant.booleanValue ? 1 : 0);
658 break;
659 case unoidl::ConstantValue::TYPE_BYTE:
660 write8(
661 file,
662 static_cast< sal_uInt8 >(
663 j.second.constant.byteValue));
664 break;
665 case unoidl::ConstantValue::TYPE_SHORT:
666 write16(
667 file,
668 static_cast< sal_uInt16 >(
669 j.second.constant.shortValue));
670 break;
671 case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
672 write16(file, j.second.constant.unsignedShortValue);
673 break;
674 case unoidl::ConstantValue::TYPE_LONG:
675 write32(
676 file,
677 static_cast< sal_uInt32 >(
678 j.second.constant.longValue));
679 break;
680 case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
681 write32(file, j.second.constant.unsignedLongValue);
682 break;
683 case unoidl::ConstantValue::TYPE_HYPER:
684 write64(
685 file,
686 static_cast< sal_uInt64 >(
687 j.second.constant.hyperValue));
688 break;
689 case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
690 write64(file, j.second.constant.unsignedHyperValue);
691 break;
692 case unoidl::ConstantValue::TYPE_FLOAT:
693 writeIso60599Binary32(
694 file, j.second.constant.floatValue);
695 break;
696 case unoidl::ConstantValue::TYPE_DOUBLE:
697 writeIso60599Binary64(
698 file, j.second.constant.doubleValue);
699 break;
700 default:
701 for (;;) { std::abort(); } // this cannot happen
703 writeAnnotations(
704 file, !j.second.annotations.empty(),
705 j.second.annotations);
707 for (auto & j: cmap) {
708 j.second.nameOffset = writeNulName(file, j.first);
710 bool ann = !ent2->getAnnotations().empty();
711 i.second.dataOffset = getOffset(file);
712 writeKind(file, ent2.get(), ann);
713 write32(file, cmap.size());
714 // overflow from std::map::size_type -> sal_uInt64 is
715 // unrealistic
716 for (const auto & j: cmap) {
717 write32(file, j.second.nameOffset);
718 write32(file, j.second.dataOffset);
720 writeAnnotations(file, ann, ent2->getAnnotations());
721 break;
723 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
725 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity >
726 ent2(
727 static_cast<
728 unoidl::SingleInterfaceBasedServiceEntity * >(
729 i.second.entity.get()));
730 bool dfltCtor = ent2->getConstructors().size() == 1
731 && ent2->getConstructors()[0].defaultConstructor;
732 bool ann = !ent2->getAnnotations().empty();
733 if (!dfltCtor && !ann)
734 ann = hasNotEmptyAnnotations(ent2->getConstructors());
735 i.second.dataOffset = getOffset(file);
736 writeKind(file, ent2.get(), ann, dfltCtor);
737 writeIdxName(file, ent2->getBase());
738 if (!dfltCtor) {
739 write32(file, ent2->getConstructors().size());
740 for (auto & j: ent2->getConstructors()) {
741 if (j.defaultConstructor) {
742 std::cout
743 << "Unexpected default constructor \""
744 << j.name << '"' << std::endl;
745 std::exit(EXIT_FAILURE);
747 writeIdxName(file, j.name);
748 write32(file, j.parameters.size());
749 for (auto & k: j.parameters) {
750 sal_uInt64 f = 0;
751 if (k.rest) {
752 f |= 0x04;
754 write8(file, f);
755 writeIdxName(file, k.name);
756 writeIdxName(file, k.type);
758 write32(file, j.exceptions.size());
759 for (auto & k: j.exceptions) {
760 writeIdxName(file, k);
762 writeAnnotations(file, ann, j.annotations);
765 writeAnnotations(file, ann, ent2->getAnnotations());
766 break;
768 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
770 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
771 static_cast< unoidl::AccumulationBasedServiceEntity * >(
772 i.second.entity.get()));
773 bool ann = !ent2->getAnnotations().empty() ||
774 hasNotEmptyAnnotations(ent2->getDirectMandatoryBaseServices()) ||
775 hasNotEmptyAnnotations(ent2->getDirectOptionalBaseServices()) ||
776 hasNotEmptyAnnotations(ent2->getDirectMandatoryBaseInterfaces()) ||
777 hasNotEmptyAnnotations(ent2->getDirectOptionalBaseInterfaces()) ||
778 hasNotEmptyAnnotations(ent2->getDirectProperties());
779 i.second.dataOffset = getOffset(file);
780 writeKind(file, ent2.get(), ann);
781 write32(file, ent2->getDirectMandatoryBaseServices().size());
782 for (auto & j: ent2->getDirectMandatoryBaseServices()) {
783 writeIdxName(file, j.name);
784 writeAnnotations(file, ann, j.annotations);
786 write32(file, ent2->getDirectOptionalBaseServices().size());
787 for (auto & j: ent2->getDirectOptionalBaseServices()) {
788 writeIdxName(file, j.name);
789 writeAnnotations(file, ann, j.annotations);
791 write32(file, ent2->getDirectMandatoryBaseInterfaces().size());
792 for (auto & j: ent2->getDirectMandatoryBaseInterfaces()) {
793 writeIdxName(file, j.name);
794 writeAnnotations(file, ann, j.annotations);
796 write32(file, ent2->getDirectOptionalBaseInterfaces().size());
797 for (auto & j: ent2->getDirectOptionalBaseInterfaces()) {
798 writeIdxName(file, j.name);
799 writeAnnotations(file, ann, j.annotations);
801 write32(file, ent2->getDirectProperties().size());
802 for (auto & j: ent2->getDirectProperties()) {
803 write16(file, static_cast< sal_uInt16 >(j.attributes));
804 writeIdxName(file, j.name);
805 writeIdxName(file, j.type);
806 writeAnnotations(file, ann, j.annotations);
808 writeAnnotations(file, ann, ent2->getAnnotations());
809 break;
811 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
813 rtl::Reference< unoidl::InterfaceBasedSingletonEntity > ent2(
814 static_cast< unoidl::InterfaceBasedSingletonEntity * >(
815 i.second.entity.get()));
816 bool ann = !ent2->getAnnotations().empty();
817 i.second.dataOffset = getOffset(file);
818 writeKind(file, ent2.get(), ann);
819 writeIdxName(file, ent2->getBase());
820 writeAnnotations(file, ann, ent2->getAnnotations());
821 break;
823 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
825 rtl::Reference< unoidl::ServiceBasedSingletonEntity > ent2(
826 static_cast< unoidl::ServiceBasedSingletonEntity * >(
827 i.second.entity.get()));
828 bool ann = !ent2->getAnnotations().empty();
829 i.second.dataOffset = getOffset(file);
830 writeKind(file, ent2.get(), ann);
831 writeIdxName(file, ent2->getBase());
832 writeAnnotations(file, ann, ent2->getAnnotations());
833 break;
837 for (auto & i: map) {
838 i.second.nameOffset = writeNulName(file, i.first);
840 sal_uInt64 off = getOffset(file);
841 if (rootSize == nullptr) {
842 write8(file, 0); // SORT_MODULE
843 write32(file, map.size());
844 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
845 } else {
846 *rootSize = map.size();
847 // overflow from std::map::size_type -> std::size_t is unrealistic
849 for (const auto & i: map) {
850 write32(file, i.second.nameOffset);
851 write32(file, i.second.dataOffset);
853 return off;
858 SAL_IMPLEMENT_MAIN() {
859 try {
860 sal_uInt32 args = rtl_getAppCommandArgCount();
861 if (args == 0) {
862 badUsage();
864 rtl::Reference< unoidl::Manager > mgr(new unoidl::Manager);
865 bool entities = false;
866 rtl::Reference< unoidl::Provider > prov;
867 std::map< OUString, Item > map;
868 for (sal_uInt32 i = 0; i != args - 1; ++i) {
869 assert(args > 1);
870 OUString uri(getArgumentUri(i, i == args - 2 ? &entities : nullptr));
871 if (entities) {
872 mapEntities(mgr, uri, map);
873 } else {
874 try {
875 prov = mgr->addProvider(uri);
876 } catch (unoidl::NoSuchFileException &) {
877 std::cerr
878 << "Input <" << uri << "> does not exist" << std::endl;
879 std::exit(EXIT_FAILURE);
883 if (!entities) {
884 mapCursor(
885 (prov.is()
886 ? prov->createRootCursor()
887 : rtl::Reference< unoidl::MapCursor >()),
888 map);
890 osl::File f(getArgumentUri(args - 1, nullptr));
891 osl::FileBase::RC e = f.open(osl_File_OpenFlag_Write);
892 if (e == osl::FileBase::E_NOENT) {
893 e = f.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
895 if (e != osl::FileBase::E_None) {
896 std::cerr
897 << "Cannot open <" << f.getURL() << "> for writing, error code "
898 << +e << std::endl;
899 std::exit(EXIT_FAILURE);
901 write(f, "UNOIDL\xFF\0", 8);
902 write32(f, 0); // root map offset
903 write32(f, 0); // root map size
904 write(
906 RTL_CONSTASCII_STRINGPARAM(
907 "\0** Created by LibreOffice " LIBO_VERSION_DOTTED
908 " unoidl-write **\0"));
909 std::size_t size;
910 sal_uInt64 off = writeMap(f, map, &size);
911 e = f.setSize(getOffset(f)); // truncate in case it already existed
912 if (e != osl::FileBase::E_None) {
913 std::cerr
914 << "Cannot set size of <" << f.getURL() << ">, error code "
915 << +e << std::endl;
916 std::exit(EXIT_FAILURE);
918 e = f.setPos(osl_Pos_Absolut, 8);
919 if (e != osl::FileBase::E_None) {
920 std::cerr
921 << "Cannot rewind current position in <" << f.getURL()
922 << ">, error code " << +e << std::endl;
923 std::exit(EXIT_FAILURE);
925 write32(f, off);
926 write32(f, size);
927 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
928 e = f.close();
929 if (e != osl::FileBase::E_None) {
930 std::cerr
931 << "Cannot close <" << f.getURL()
932 << "> after writing, error code " << +e << std::endl;
933 std::exit(EXIT_FAILURE);
935 return EXIT_SUCCESS;
936 } catch (unoidl::FileFormatException & e1) {
937 std::cerr
938 << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
939 << std::endl;
940 std::exit(EXIT_FAILURE);
941 } catch (std::exception & e1) {
942 std::cerr
943 << "Failure: " << e1.what()
944 << std::endl;
945 std::exit(EXIT_FAILURE);
950 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */