tdf#116301: write correct content type for diagramDrawing
[LibreOffice.git] / unoidl / source / unoidl-write.cxx
blobfcb004a24df3a197ba0f5a47ebfdb550ae98eb92
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 <cassert>
13 #include <cstddef>
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/process.h>
26 #include <rtl/string.h>
27 #include <rtl/string.hxx>
28 #include <rtl/textenc.h>
29 #include <rtl/textcvt.h>
30 #include <rtl/ustring.hxx>
31 #include <sal/macros.h>
32 #include <sal/main.h>
33 #include <unoidl/unoidl.hxx>
35 namespace {
37 void badUsage() {
38 std::cerr
39 << "Usage:" << std::endl << std::endl
40 << " unoidl-write [<registries>] [@<entities file>] <unoidl file>"
41 << std::endl << std::endl
42 << ("where each <registry> is either a new- or legacy-format .rdb file,"
43 " a single .idl")
44 << std::endl
45 << ("file, or a root directory of an .idl file tree; and the UTF-8"
46 " encoded <entities")
47 << std::endl
48 << ("file> contains zero or more space-separated names of (non-module)"
49 " entities to")
50 << std::endl
51 << ("include in the output, and, if omitted, defaults to the complete"
52 " content of the")
53 << std::endl << "last <registry>, if any." << std::endl;
54 std::exit(EXIT_FAILURE);
57 OUString getArgumentUri(sal_uInt32 argument, bool * entities) {
58 OUString arg;
59 rtl_getAppCommandArg(argument, &arg.pData);
60 if (arg.startsWith("@", &arg)) {
61 if (entities == nullptr) {
62 badUsage();
64 *entities = true;
65 } else if (entities != nullptr) {
66 *entities = false;
68 OUString url;
69 osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
70 if (e1 != osl::FileBase::E_None) {
71 std::cerr
72 << "Cannot convert \"" << arg << "\" to file URL, error code "
73 << +e1 << std::endl;
74 std::exit(EXIT_FAILURE);
76 OUString cwd;
77 oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData);
78 if (e2 != osl_Process_E_None) {
79 std::cerr
80 << "Cannot obtain working directory, error code " << +e2
81 << std::endl;
82 std::exit(EXIT_FAILURE);
84 OUString abs;
85 e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs);
86 if (e1 != osl::FileBase::E_None) {
87 std::cerr
88 << "Cannot make \"" << url
89 << "\" into an absolute file URL, error code " << +e1 << std::endl;
90 std::exit(EXIT_FAILURE);
92 return abs;
95 sal_uInt64 getOffset(osl::File & file) {
96 sal_uInt64 off;
97 osl::FileBase::RC e = file.getPos(off);
98 if (e != osl::FileBase::E_None) {
99 std::cerr
100 << "Cannot determine current position in <" << file.getURL()
101 << ">, error code " << +e << std::endl;
102 std::exit(EXIT_FAILURE);
104 return off;
107 void write(osl::File & file, void const * buffer, sal_uInt64 size) {
108 sal_uInt64 n;
109 osl::FileBase::RC e = file.write(buffer, size, n);
110 if (e != osl::FileBase::E_None) {
111 std::cerr
112 << "Cannot write to <" << file.getURL() << ">, error code " << +e
113 << std::endl;
114 std::exit(EXIT_FAILURE);
116 if (n != size) {
117 std::cerr
118 << "Bad write of " << n << " instead of " << size << " bytes to <"
119 << file.getURL() << '>' << std::endl;
120 std::exit(EXIT_FAILURE);
124 void write8(osl::File & file, sal_uInt64 value) {
125 if (value > 0xFF) {
126 std::cerr
127 << "Cannot write value >= 2^8; input is too large" << std::endl;
128 std::exit(EXIT_FAILURE);
130 unsigned char buf[1];
131 buf[0] = value & 0xFF;
132 write(file, buf, SAL_N_ELEMENTS(buf));
135 void write16(osl::File & file, sal_uInt64 value) {
136 if (value > 0xFFFF) {
137 std::cerr
138 << "Cannot write value >= 2^16; input is too large" << std::endl;
139 std::exit(EXIT_FAILURE);
141 unsigned char buf[2];
142 buf[0] = value & 0xFF;
143 buf[1] = (value >> 8) & 0xFF;
144 write(file, buf, SAL_N_ELEMENTS(buf));
147 void write32(osl::File & file, sal_uInt64 value) {
148 if (value > 0xFFFFFFFF) {
149 std::cerr
150 << "Cannot write value >= 2^32; input is too large" << std::endl;
151 std::exit(EXIT_FAILURE);
153 unsigned char buf[4];
154 buf[0] = value & 0xFF;
155 buf[1] = (value >> 8) & 0xFF;
156 buf[2] = (value >> 16) & 0xFF;
157 buf[3] = (value >> 24) & 0xFF;
158 write(file, buf, SAL_N_ELEMENTS(buf));
161 void write64(osl::File & file, sal_uInt64 value) {
162 unsigned char buf[8];
163 buf[0] = value & 0xFF;
164 buf[1] = (value >> 8) & 0xFF;
165 buf[2] = (value >> 16) & 0xFF;
166 buf[3] = (value >> 24) & 0xFF;
167 buf[4] = (value >> 32) & 0xFF;
168 buf[5] = (value >> 40) & 0xFF;
169 buf[6] = (value >> 48) & 0xFF;
170 buf[7] = (value >> 56) & 0xFF;
171 write(file, buf, SAL_N_ELEMENTS(buf));
174 void writeIso60599Binary32(osl::File & file, float value) {
175 union {
176 unsigned char buf[4];
177 float f; // assuming float is ISO 60599 binary32
178 } sa;
179 sa.f = value;
180 #if defined OSL_BIGENDIAN
181 std::swap(sa.buf[0], sa.buf[3]);
182 std::swap(sa.buf[1], sa.buf[2]);
183 #endif
184 write(file, sa.buf, SAL_N_ELEMENTS(sa.buf));
187 void writeIso60599Binary64(osl::File & file, double value) {
188 union {
189 unsigned char buf[8];
190 float d; // assuming double is ISO 60599 binary64
191 } sa;
192 sa.d = value;
193 #if defined OSL_BIGENDIAN
194 std::swap(sa.buf[0], sa.buf[7]);
195 std::swap(sa.buf[1], sa.buf[6]);
196 std::swap(sa.buf[2], sa.buf[5]);
197 std::swap(sa.buf[3], sa.buf[4]);
198 #endif
199 write(file, sa.buf, SAL_N_ELEMENTS(sa.buf));
202 OString toAscii(OUString const & name) {
203 OString ascii;
204 if (!name.convertToString(
205 &ascii, RTL_TEXTENCODING_ASCII_US,
206 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
207 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
209 std::cerr
210 << "Cannot convert \"" << name << "\" to US ASCII" << std::endl;
211 std::exit(EXIT_FAILURE);
213 return ascii;
216 OString toUtf8(OUString const & string) {
217 OString ascii;
218 if (!string.convertToString(
219 &ascii, RTL_TEXTENCODING_UTF8,
220 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
221 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
223 std::cerr
224 << "Cannot convert \"" << string << "\" to UTF-8" << std::endl;
225 std::exit(EXIT_FAILURE);
227 return ascii;
230 sal_uInt64 writeNulName(osl::File & file, OUString const & name) {
231 OString ascii(toAscii(name));
232 if (ascii.indexOf('\0') != -1) {
233 std::cerr
234 << "Name \"" << ascii << "\" contains NUL characters" << std::endl;
235 std::exit(EXIT_FAILURE);
237 sal_uInt64 off = getOffset(file);
238 write(file, ascii.getStr(), ascii.getLength() + 1);
239 return off;
242 void writeIdxString(osl::File & file, OString const & string) {
243 static std::map< OString, sal_uInt64 > reuse;
244 std::map< OString, sal_uInt64 >::iterator i(reuse.find(string));
245 if (i == reuse.end()) {
246 reuse.insert(std::make_pair(string, getOffset(file)));
247 assert(
248 (static_cast< sal_uInt64 >(string.getLength()) & 0x80000000) == 0);
249 write32(file, static_cast< sal_uInt64 >(string.getLength()));
250 write(file, string.getStr(), string.getLength());
251 } else {
252 if ((i->second & 0x80000000) != 0) {
253 std::cerr
254 << "Cannot write index 0x" << std::hex << i->second << std::dec
255 << " of \"" << string << "\"; input is too large" << std::endl;
256 std::exit(EXIT_FAILURE);
258 write32(file, i->second | 0x80000000);
262 void writeIdxName(osl::File & file, OUString const & name) {
263 writeIdxString(file, toAscii(name));
266 void writeAnnotations(
267 osl::File & file, bool annotate,
268 std::vector< OUString > const & annotations)
270 assert(annotate || annotations.empty());
271 if (annotate) {
272 write32(file, annotations.size());
273 // overflow from std::vector::size_type -> sal_uInt64 is unrealistic
274 for (auto & i: annotations) {
275 writeIdxString(file, toUtf8(i));
280 void writeKind(
281 osl::File & file,
282 rtl::Reference< unoidl::PublishableEntity > const & entity,
283 bool annotated, bool flag = false)
285 assert(entity.is());
286 sal_uInt64 v = entity->getSort();
287 if (entity->isPublished()) {
288 v |= 0x80;
290 if (annotated) {
291 v |= 0x40;
293 if (flag) {
294 v |= 0x20;
296 write8(file, v);
299 struct Item {
300 explicit Item(rtl::Reference< unoidl::Entity > const & theEntity):
301 entity(theEntity), nameOffset(0), dataOffset(0)
304 rtl::Reference< unoidl::Entity > entity;
305 std::map< OUString, Item > module;
306 sal_uInt64 nameOffset;
307 sal_uInt64 dataOffset;
310 struct ConstItem {
311 ConstItem(
312 unoidl::ConstantValue const & theConstant,
313 std::vector< OUString > const & theAnnotations):
314 constant(theConstant), annotations(theAnnotations), nameOffset(0),
315 dataOffset(0)
318 unoidl::ConstantValue constant;
319 std::vector< OUString > annotations;
320 sal_uInt64 nameOffset;
321 sal_uInt64 dataOffset;
324 void mapEntities(
325 rtl::Reference< unoidl::Manager > const & manager, OUString const & uri,
326 std::map< OUString, Item > & map)
328 assert(manager.is());
329 osl::File f(uri);
330 osl::FileBase::RC e = f.open(osl_File_OpenFlag_Read);
331 if (e != osl::FileBase::E_None) {
332 std::cerr
333 << "Cannot open <" << f.getURL() << "> for reading, error code "
334 << +e << std::endl;
335 std::exit(EXIT_FAILURE);
337 for (;;) {
338 sal_Bool eof;
339 e = f.isEndOfFile(&eof);
340 if (e != osl::FileBase::E_None) {
341 std::cerr
342 << "Cannot check <" << f.getURL() << "> for EOF, error code "
343 << +e << std::endl;
344 std::exit(EXIT_FAILURE);
346 if (eof) {
347 break;
349 rtl::ByteSequence s1;
350 e = f.readLine(s1);
351 if (e != osl::FileBase::E_None) {
352 std::cerr
353 << "Cannot read from <" << f.getURL() << ">, error code "
354 << +e << std::endl;
355 std::exit(EXIT_FAILURE);
357 OUString s2;
358 if (!rtl_convertStringToUString(
359 &s2.pData, reinterpret_cast< char const * >(s1.getConstArray()),
360 s1.getLength(), RTL_TEXTENCODING_UTF8,
361 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
362 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
363 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
365 std::cerr
366 << "Cannot interpret line read from <" << f.getURL()
367 << "> as UTF-8" << std::endl;
368 std::exit(EXIT_FAILURE);
370 for (sal_Int32 i = 0; i != -1;) {
371 OUString t(s2.getToken(0, ' ', i));
372 if (!t.isEmpty()) {
373 rtl::Reference< unoidl::Entity > ent(manager->findEntity(t));
374 if (!ent.is()) {
375 std::cerr
376 << "Unknown entity \"" << t << "\" read from <"
377 << f.getURL() << ">" << std::endl;
378 std::exit(EXIT_FAILURE);
380 if (ent->getSort() == unoidl::Entity::SORT_MODULE) {
381 std::cerr
382 << "Module entity \"" << t << "\" read from <"
383 << f.getURL() << ">" << std::endl;
384 std::exit(EXIT_FAILURE);
386 std::map< OUString, Item > * map2 = &map;
387 for (sal_Int32 j = 0;;) {
388 OUString id(t.getToken(0, '.', j));
389 if (j == -1) {
390 map2->insert(std::make_pair(id, Item(ent)));
391 break;
393 std::map< OUString, Item >::iterator k(map2->find(id));
394 if (k == map2->end()) {
395 rtl::Reference< unoidl::Entity > ent2(
396 manager->findEntity(t.copy(0, j - 1)));
397 assert(ent2.is());
398 k = map2->insert(std::make_pair(id, Item(ent2))).first;
400 assert(
401 k->second.entity->getSort()
402 == unoidl::Entity::SORT_MODULE);
403 map2 = &k->second.module;
408 e = f.close();
409 if (e != osl::FileBase::E_None) {
410 std::cerr
411 << "Cannot close <" << f.getURL() << "> after reading, error code "
412 << +e << std::endl;
413 std::exit(EXIT_FAILURE);
417 void mapCursor(
418 rtl::Reference< unoidl::MapCursor > const & cursor,
419 std::map< OUString, Item > & map)
421 if (cursor.is()) {
422 for (;;) {
423 OUString name;
424 rtl::Reference< unoidl::Entity > ent(cursor->getNext(&name));
425 if (!ent.is()) {
426 break;
428 std::pair< std::map< OUString, Item >::iterator, bool > i(
429 map.insert(std::make_pair(name, Item(ent))));
430 if (!i.second) {
431 std::cout << "Duplicate name \"" << name << '"' << std::endl;
432 std::exit(EXIT_FAILURE);
434 if (i.first->second.entity->getSort()
435 == unoidl::Entity::SORT_MODULE)
437 mapCursor(
438 rtl::Reference< unoidl::ModuleEntity >(
439 static_cast< unoidl::ModuleEntity * >(
440 i.first->second.entity.get()))->createCursor(),
441 i.first->second.module);
447 sal_uInt64 writeMap(
448 osl::File & file, std::map< OUString, Item > & map, std::size_t * rootSize)
450 for (auto & i: map) {
451 switch (i.second.entity->getSort()) {
452 case unoidl::Entity::SORT_MODULE:
453 i.second.dataOffset = writeMap(file, i.second.module, nullptr);
454 break;
455 case unoidl::Entity::SORT_ENUM_TYPE:
457 rtl::Reference< unoidl::EnumTypeEntity > ent2(
458 static_cast< unoidl::EnumTypeEntity * >(
459 i.second.entity.get()));
460 bool ann = !ent2->getAnnotations().empty();
461 for (auto j(ent2->getMembers().begin());
462 !ann && j != ent2->getMembers().end(); ++j)
464 ann = !j->annotations.empty();
466 i.second.dataOffset = getOffset(file);
467 writeKind(file, ent2.get(), ann);
468 write32(file, ent2->getMembers().size());
469 for (auto & j: ent2->getMembers()) {
470 writeIdxName(file, j.name);
471 write32(file, static_cast< sal_uInt32 >(j.value));
472 writeAnnotations(file, ann, j.annotations);
474 writeAnnotations(file, ann, ent2->getAnnotations());
475 break;
477 case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
479 rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
480 static_cast< unoidl::PlainStructTypeEntity * >(
481 i.second.entity.get()));
482 bool ann = !ent2->getAnnotations().empty();
483 for (auto j(ent2->getDirectMembers().begin());
484 !ann && j != ent2->getDirectMembers().end(); ++j)
486 ann = !j->annotations.empty();
488 i.second.dataOffset = getOffset(file);
489 writeKind(
490 file, ent2.get(), 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 for (auto j(ent2->getMembers().begin());
512 !ann && j != ent2->getMembers().end(); ++j)
514 ann = !j->annotations.empty();
516 i.second.dataOffset = getOffset(file);
517 writeKind(file, ent2.get(), ann);
518 write32(file, ent2->getTypeParameters().size());
519 for (auto & j: ent2->getTypeParameters()) {
520 writeIdxName(file, j);
522 write32(file, ent2->getMembers().size());
523 for (auto & j: ent2->getMembers()) {
524 sal_uInt64 f = 0;
525 if (j.parameterized) {
526 f |= 0x01;
528 write8(file, f);
529 writeIdxName(file, j.name);
530 writeIdxName(file, j.type);
531 writeAnnotations(file, ann, j.annotations);
533 writeAnnotations(file, ann, ent2->getAnnotations());
534 break;
536 case unoidl::Entity::SORT_EXCEPTION_TYPE:
538 rtl::Reference< unoidl::ExceptionTypeEntity > ent2(
539 static_cast< unoidl::ExceptionTypeEntity * >(
540 i.second.entity.get()));
541 bool ann = !ent2->getAnnotations().empty();
542 for (auto j(ent2->getDirectMembers().begin());
543 !ann && j != ent2->getDirectMembers().end(); ++j)
545 ann = !j->annotations.empty();
547 i.second.dataOffset = getOffset(file);
548 writeKind(
549 file, ent2.get(), ann, !ent2->getDirectBase().isEmpty());
550 if (!ent2->getDirectBase().isEmpty()) {
551 writeIdxName(file, ent2->getDirectBase());
553 write32(file, ent2->getDirectMembers().size());
554 for (auto & j: ent2->getDirectMembers()) {
555 writeIdxName(file, j.name);
556 writeIdxName(file, j.type);
557 writeAnnotations(file, ann, j.annotations);
559 writeAnnotations(file, ann, ent2->getAnnotations());
560 break;
562 case unoidl::Entity::SORT_INTERFACE_TYPE:
564 rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
565 static_cast< unoidl::InterfaceTypeEntity * >(
566 i.second.entity.get()));
567 bool ann = !ent2->getAnnotations().empty();
568 for (auto j(ent2->getDirectMandatoryBases().begin());
569 !ann && j != ent2->getDirectMandatoryBases().end(); ++j)
571 ann = !j->annotations.empty();
573 for (auto j(ent2->getDirectOptionalBases().begin());
574 !ann && j != ent2->getDirectOptionalBases().end(); ++j)
576 ann = !j->annotations.empty();
578 for (auto j(ent2->getDirectAttributes().begin());
579 !ann && j != ent2->getDirectAttributes().end(); ++j)
581 ann = !j->annotations.empty();
583 for (auto j(ent2->getDirectMethods().begin());
584 !ann && j != ent2->getDirectMethods().end(); ++j)
586 ann = !j->annotations.empty();
588 i.second.dataOffset = getOffset(file);
589 writeKind(file, ent2.get(), ann);
590 write32(file, ent2->getDirectMandatoryBases().size());
591 for (auto & j: ent2->getDirectMandatoryBases()) {
592 writeIdxName(file, j.name);
593 writeAnnotations(file, ann, j.annotations);
595 write32(file, ent2->getDirectOptionalBases().size());
596 for (auto & j: ent2->getDirectOptionalBases()) {
597 writeIdxName(file, j.name);
598 writeAnnotations(file, ann, j.annotations);
600 write32(file, ent2->getDirectAttributes().size());
601 for (auto & j: ent2->getDirectAttributes()) {
602 sal_uInt64 f = 0;
603 if (j.bound) {
604 f |= 0x01;
606 if (j.readOnly) {
607 f |= 0x02;
609 write8(file, f);
610 writeIdxName(file, j.name);
611 writeIdxName(file, j.type);
612 write32(file, j.getExceptions.size());
613 for (auto & k: j.getExceptions) {
614 writeIdxName(file, k);
616 if (!j.readOnly) {
617 write32(file, j.setExceptions.size());
618 for (auto & k: j.setExceptions) {
619 writeIdxName(file, k);
622 writeAnnotations(file, ann, j.annotations);
624 write32(file, ent2->getDirectMethods().size());
625 for (auto & j: ent2->getDirectMethods()) {
626 writeIdxName(file, j.name);
627 writeIdxName(file, j.returnType);
628 write32(file, j.parameters.size());
629 for (auto & k: j.parameters) {
630 write8(file, k.direction);
631 writeIdxName(file, k.name);
632 writeIdxName(file, k.type);
634 write32(file, j.exceptions.size());
635 for (auto & k: j.exceptions) {
636 writeIdxName(file, k);
638 writeAnnotations(file, ann, j.annotations);
640 writeAnnotations(file, ann, ent2->getAnnotations());
641 break;
643 case unoidl::Entity::SORT_TYPEDEF:
645 rtl::Reference< unoidl::TypedefEntity > ent2(
646 static_cast< unoidl::TypedefEntity * >(
647 i.second.entity.get()));
648 bool ann = !ent2->getAnnotations().empty();
649 i.second.dataOffset = getOffset(file);
650 writeKind(file, ent2.get(), ann);
651 writeIdxName(file, ent2->getType());
652 writeAnnotations(file, ann, ent2->getAnnotations());
653 break;
655 case unoidl::Entity::SORT_CONSTANT_GROUP:
657 rtl::Reference< unoidl::ConstantGroupEntity > ent2(
658 static_cast< unoidl::ConstantGroupEntity * >(
659 i.second.entity.get()));
660 std::map< OUString, ConstItem > cmap;
661 for (auto & j: ent2->getMembers()) {
662 if (!cmap.insert(
663 std::make_pair(
664 j.name, ConstItem(j.value, j.annotations))).
665 second)
667 std::cout
668 << "Duplicate constant group member name \""
669 << j.name << '"' << std::endl;
670 std::exit(EXIT_FAILURE);
673 for (auto & j: cmap) {
674 j.second.dataOffset = getOffset(file);
675 sal_uInt64 v = j.second.constant.type;
676 if (!j.second.annotations.empty()) {
677 v |= 0x80;
679 write8(file, v);
680 switch (j.second.constant.type) {
681 case unoidl::ConstantValue::TYPE_BOOLEAN:
682 write8(file, j.second.constant.booleanValue ? 1 : 0);
683 break;
684 case unoidl::ConstantValue::TYPE_BYTE:
685 write8(
686 file,
687 static_cast< sal_uInt8 >(
688 j.second.constant.byteValue));
689 break;
690 case unoidl::ConstantValue::TYPE_SHORT:
691 write16(
692 file,
693 static_cast< sal_uInt16 >(
694 j.second.constant.shortValue));
695 break;
696 case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
697 write16(file, j.second.constant.unsignedShortValue);
698 break;
699 case unoidl::ConstantValue::TYPE_LONG:
700 write32(
701 file,
702 static_cast< sal_uInt32 >(
703 j.second.constant.longValue));
704 break;
705 case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
706 write32(file, j.second.constant.unsignedLongValue);
707 break;
708 case unoidl::ConstantValue::TYPE_HYPER:
709 write64(
710 file,
711 static_cast< sal_uInt64 >(
712 j.second.constant.hyperValue));
713 break;
714 case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
715 write64(file, j.second.constant.unsignedHyperValue);
716 break;
717 case unoidl::ConstantValue::TYPE_FLOAT:
718 writeIso60599Binary32(
719 file, j.second.constant.floatValue);
720 break;
721 case unoidl::ConstantValue::TYPE_DOUBLE:
722 writeIso60599Binary64(
723 file, j.second.constant.doubleValue);
724 break;
725 default:
726 for (;;) { std::abort(); } // this cannot happen
728 writeAnnotations(
729 file, !j.second.annotations.empty(),
730 j.second.annotations);
732 for (auto & j: cmap) {
733 j.second.nameOffset = writeNulName(file, j.first);
735 bool ann = !ent2->getAnnotations().empty();
736 i.second.dataOffset = getOffset(file);
737 writeKind(file, ent2.get(), ann);
738 write32(file, cmap.size());
739 // overflow from std::map::size_type -> sal_uInt64 is
740 // unrealistic
741 for (auto & j: cmap) {
742 write32(file, j.second.nameOffset);
743 write32(file, j.second.dataOffset);
745 writeAnnotations(file, ann, ent2->getAnnotations());
746 break;
748 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
750 rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity >
751 ent2(
752 static_cast<
753 unoidl::SingleInterfaceBasedServiceEntity * >(
754 i.second.entity.get()));
755 bool dfltCtor = ent2->getConstructors().size() == 1
756 && ent2->getConstructors()[0].defaultConstructor;
757 bool ann = !ent2->getAnnotations().empty();
758 if (!dfltCtor) {
759 for (auto j(ent2->getConstructors().begin());
760 !ann && j != ent2->getConstructors().end(); ++j)
762 ann = !j->annotations.empty();
765 i.second.dataOffset = getOffset(file);
766 writeKind(file, ent2.get(), ann, dfltCtor);
767 writeIdxName(file, ent2->getBase());
768 if (!dfltCtor) {
769 write32(file, ent2->getConstructors().size());
770 for (auto & j: ent2->getConstructors()) {
771 if (j.defaultConstructor) {
772 std::cout
773 << "Unexpected default constructor \""
774 << j.name << '"' << std::endl;
775 std::exit(EXIT_FAILURE);
777 writeIdxName(file, j.name);
778 write32(file, j.parameters.size());
779 for (auto & k: j.parameters) {
780 sal_uInt64 f = 0;
781 if (k.rest) {
782 f |= 0x04;
784 write8(file, f);
785 writeIdxName(file, k.name);
786 writeIdxName(file, k.type);
788 write32(file, j.exceptions.size());
789 for (auto & k: j.exceptions) {
790 writeIdxName(file, k);
792 writeAnnotations(file, ann, j.annotations);
795 writeAnnotations(file, ann, ent2->getAnnotations());
796 break;
798 case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
800 rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
801 static_cast< unoidl::AccumulationBasedServiceEntity * >(
802 i.second.entity.get()));
803 bool ann = !ent2->getAnnotations().empty();
804 for (auto j(ent2->getDirectMandatoryBaseServices().begin());
805 !ann && j != ent2->getDirectMandatoryBaseServices().end();
806 ++j)
808 ann = !j->annotations.empty();
810 for (auto j(ent2->getDirectOptionalBaseServices().begin());
811 !ann && j != ent2->getDirectOptionalBaseServices().end();
812 ++j)
814 ann = !j->annotations.empty();
816 for (auto j(ent2->getDirectMandatoryBaseInterfaces().begin());
817 (!ann
818 && j != ent2->getDirectMandatoryBaseInterfaces().end());
819 ++j)
821 ann = !j->annotations.empty();
823 for (auto j(ent2->getDirectOptionalBaseInterfaces().begin());
824 !ann && j != ent2->getDirectOptionalBaseInterfaces().end();
825 ++j)
827 ann = !j->annotations.empty();
829 for (auto j(ent2->getDirectProperties().begin());
830 !ann && j != ent2->getDirectProperties().end(); ++j)
832 ann = !j->annotations.empty();
834 i.second.dataOffset = getOffset(file);
835 writeKind(file, ent2.get(), ann);
836 write32(file, ent2->getDirectMandatoryBaseServices().size());
837 for (auto & j: ent2->getDirectMandatoryBaseServices()) {
838 writeIdxName(file, j.name);
839 writeAnnotations(file, ann, j.annotations);
841 write32(file, ent2->getDirectOptionalBaseServices().size());
842 for (auto & j: ent2->getDirectOptionalBaseServices()) {
843 writeIdxName(file, j.name);
844 writeAnnotations(file, ann, j.annotations);
846 write32(file, ent2->getDirectMandatoryBaseInterfaces().size());
847 for (auto & j: ent2->getDirectMandatoryBaseInterfaces()) {
848 writeIdxName(file, j.name);
849 writeAnnotations(file, ann, j.annotations);
851 write32(file, ent2->getDirectOptionalBaseInterfaces().size());
852 for (auto & j: ent2->getDirectOptionalBaseInterfaces()) {
853 writeIdxName(file, j.name);
854 writeAnnotations(file, ann, j.annotations);
856 write32(file, ent2->getDirectProperties().size());
857 for (auto & j: ent2->getDirectProperties()) {
858 write16(file, static_cast< sal_uInt16 >(j.attributes));
859 writeIdxName(file, j.name);
860 writeIdxName(file, j.type);
861 writeAnnotations(file, ann, j.annotations);
863 writeAnnotations(file, ann, ent2->getAnnotations());
864 break;
866 case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
868 rtl::Reference< unoidl::InterfaceBasedSingletonEntity > ent2(
869 static_cast< unoidl::InterfaceBasedSingletonEntity * >(
870 i.second.entity.get()));
871 bool ann = !ent2->getAnnotations().empty();
872 i.second.dataOffset = getOffset(file);
873 writeKind(file, ent2.get(), ann);
874 writeIdxName(file, ent2->getBase());
875 writeAnnotations(file, ann, ent2->getAnnotations());
876 break;
878 case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
880 rtl::Reference< unoidl::ServiceBasedSingletonEntity > ent2(
881 static_cast< unoidl::ServiceBasedSingletonEntity * >(
882 i.second.entity.get()));
883 bool ann = !ent2->getAnnotations().empty();
884 i.second.dataOffset = getOffset(file);
885 writeKind(file, ent2.get(), ann);
886 writeIdxName(file, ent2->getBase());
887 writeAnnotations(file, ann, ent2->getAnnotations());
888 break;
892 for (auto & i: map) {
893 i.second.nameOffset = writeNulName(file, i.first);
895 sal_uInt64 off = getOffset(file);
896 if (rootSize == nullptr) {
897 write8(file, 0); // SORT_MODULE
898 write32(file, map.size());
899 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
900 } else {
901 *rootSize = map.size();
902 // overflow from std::map::size_type -> std::size_t is unrealistic
904 for (auto & i: map) {
905 write32(file, i.second.nameOffset);
906 write32(file, i.second.dataOffset);
908 return off;
913 SAL_IMPLEMENT_MAIN() {
914 try {
915 sal_uInt32 args = rtl_getAppCommandArgCount();
916 if (args == 0) {
917 badUsage();
919 rtl::Reference< unoidl::Manager > mgr(new unoidl::Manager);
920 bool entities = false;
921 rtl::Reference< unoidl::Provider > prov;
922 std::map< OUString, Item > map;
923 for (sal_uInt32 i = 0; i != args - 1; ++i) {
924 assert(args > 1);
925 OUString uri(getArgumentUri(i, i == args - 2 ? &entities : nullptr));
926 if (entities) {
927 mapEntities(mgr, uri, map);
928 } else {
929 try {
930 prov = mgr->addProvider(uri);
931 } catch (unoidl::NoSuchFileException &) {
932 std::cerr
933 << "Input <" << uri << "> does not exist" << std::endl;
934 std::exit(EXIT_FAILURE);
938 if (!entities) {
939 mapCursor(
940 (prov.is()
941 ? prov->createRootCursor()
942 : rtl::Reference< unoidl::MapCursor >()),
943 map);
945 osl::File f(getArgumentUri(args - 1, nullptr));
946 osl::FileBase::RC e = f.open(osl_File_OpenFlag_Write);
947 if (e == osl::FileBase::E_NOENT) {
948 e = f.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
950 if (e != osl::FileBase::E_None) {
951 std::cerr
952 << "Cannot open <" << f.getURL() << "> for writing, error code "
953 << +e << std::endl;
954 std::exit(EXIT_FAILURE);
956 write(f, "UNOIDL\xFF\0", 8);
957 write32(f, 0); // root map offset
958 write32(f, 0); // root map size
959 write(
961 RTL_CONSTASCII_STRINGPARAM(
962 "\0** Created by LibreOffice " LIBO_VERSION_DOTTED
963 " unoidl-write **\0"));
964 std::size_t size;
965 sal_uInt64 off = writeMap(f, map, &size);
966 e = f.setSize(getOffset(f)); // truncate in case it already existed
967 if (e != osl::FileBase::E_None) {
968 std::cerr
969 << "Cannot set size of <" << f.getURL() << ">, error code "
970 << +e << std::endl;
971 std::exit(EXIT_FAILURE);
973 e = f.setPos(osl_Pos_Absolut, 8);
974 if (e != osl::FileBase::E_None) {
975 std::cerr
976 << "Cannot rewind current position in <" << f.getURL()
977 << ">, error code " << +e << std::endl;
978 std::exit(EXIT_FAILURE);
980 write32(f, off);
981 write32(f, size);
982 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
983 e = f.close();
984 if (e != osl::FileBase::E_None) {
985 std::cerr
986 << "Cannot close <" << f.getURL()
987 << "> after writing, error code " << +e << std::endl;
988 std::exit(EXIT_FAILURE);
990 return EXIT_SUCCESS;
991 } catch (unoidl::FileFormatException & e1) {
992 std::cerr
993 << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
994 << std::endl;
995 std::exit(EXIT_FAILURE);
996 } catch (std::exception & e1) {
997 std::cerr
998 << "Failure: " << e1.what()
999 << std::endl;
1000 std::exit(EXIT_FAILURE);
1005 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */