1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #include <sal/config.h>
20 #include <config_version.h>
21 #include <osl/endian.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>
34 #include <unoidl/unoidl.hxx>
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,"
46 << ("file, or a root directory of an .idl file tree; and the UTF-8"
49 << ("file> contains zero or more space-separated names of (non-module)"
52 << ("include in the output, and, if omitted, defaults to the complete"
54 << std::endl
<< "last <registry>, if any." << std::endl
;
55 std::exit(EXIT_FAILURE
);
58 OUString
getArgumentUri(sal_uInt32 argument
, bool * entities
) {
60 rtl_getAppCommandArg(argument
, &arg
.pData
);
61 if (arg
.startsWith("@", &arg
)) {
62 if (entities
== nullptr) {
66 } else if (entities
!= nullptr) {
70 osl::FileBase::RC e1
= osl::FileBase::getFileURLFromSystemPath(arg
, url
);
71 if (e1
!= osl::FileBase::E_None
) {
73 << "Cannot convert \"" << arg
<< "\" to file URL, error code "
75 std::exit(EXIT_FAILURE
);
78 oslProcessError e2
= osl_getProcessWorkingDir(&cwd
.pData
);
79 if (e2
!= osl_Process_E_None
) {
81 << "Cannot obtain working directory, error code " << +e2
83 std::exit(EXIT_FAILURE
);
86 e1
= osl::FileBase::getAbsoluteFileURL(cwd
, url
, abs
);
87 if (e1
!= osl::FileBase::E_None
) {
89 << "Cannot make \"" << url
90 << "\" into an absolute file URL, error code " << +e1
<< std::endl
;
91 std::exit(EXIT_FAILURE
);
96 sal_uInt64
getOffset(osl::File
& file
) {
98 osl::FileBase::RC e
= file
.getPos(off
);
99 if (e
!= osl::FileBase::E_None
) {
101 << "Cannot determine current position in <" << file
.getURL()
102 << ">, error code " << +e
<< std::endl
;
103 std::exit(EXIT_FAILURE
);
108 void write(osl::File
& file
, void const * buffer
, sal_uInt64 size
) {
110 osl::FileBase::RC e
= file
.write(buffer
, size
, n
);
111 if (e
!= osl::FileBase::E_None
) {
113 << "Cannot write to <" << file
.getURL() << ">, error code " << +e
115 std::exit(EXIT_FAILURE
);
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
) {
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) {
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) {
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
) {
177 unsigned char buf
[4];
178 float f
; // assuming float is ISO 60599 binary32
181 #if defined OSL_BIGENDIAN
182 std::swap(sa
.buf
[0], sa
.buf
[3]);
183 std::swap(sa
.buf
[1], sa
.buf
[2]);
185 write(file
, sa
.buf
, SAL_N_ELEMENTS(sa
.buf
));
188 void writeIso60599Binary64(osl::File
& file
, double value
) {
190 unsigned char buf
[8];
191 float d
; // assuming double is ISO 60599 binary64
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]);
200 write(file
, sa
.buf
, SAL_N_ELEMENTS(sa
.buf
));
203 OString
toAscii(OUString
const & name
) {
205 if (!name
.convertToString(
206 &ascii
, RTL_TEXTENCODING_ASCII_US
,
207 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
208 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
211 << "Cannot convert \"" << name
<< "\" to US ASCII" << std::endl
;
212 std::exit(EXIT_FAILURE
);
217 OString
toUtf8(OUString
const & string
) {
219 if (!string
.convertToString(
220 &ascii
, RTL_TEXTENCODING_UTF8
,
221 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
222 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
225 << "Cannot convert \"" << string
<< "\" to UTF-8" << std::endl
;
226 std::exit(EXIT_FAILURE
);
231 sal_uInt64
writeNulName(osl::File
& file
, OUString
const & name
) {
232 OString
ascii(toAscii(name
));
233 if (ascii
.indexOf('\0') != -1) {
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);
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
)));
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());
253 if ((i
->second
& 0x80000000) != 0) {
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());
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
));
283 rtl::Reference
< unoidl::PublishableEntity
> const & entity
,
284 bool annotated
, bool flag
= false)
287 sal_uInt64 v
= entity
->getSort();
288 if (entity
->isPublished()) {
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
;
313 unoidl::ConstantValue
const & theConstant
,
314 std::vector
< OUString
> const & theAnnotations
):
315 constant(theConstant
), annotations(theAnnotations
), nameOffset(0),
319 unoidl::ConstantValue
const constant
;
320 std::vector
< OUString
> const annotations
;
321 sal_uInt64 nameOffset
;
322 sal_uInt64 dataOffset
;
326 rtl::Reference
< unoidl::Manager
> const & manager
, OUString
const & uri
,
327 std::map
< OUString
, Item
> & map
)
329 assert(manager
.is());
331 osl::FileBase::RC e
= f
.open(osl_File_OpenFlag_Read
);
332 if (e
!= osl::FileBase::E_None
) {
334 << "Cannot open <" << f
.getURL() << "> for reading, error code "
336 std::exit(EXIT_FAILURE
);
340 e
= f
.isEndOfFile(&eof
);
341 if (e
!= osl::FileBase::E_None
) {
343 << "Cannot check <" << f
.getURL() << "> for EOF, error code "
345 std::exit(EXIT_FAILURE
);
350 rtl::ByteSequence s1
;
352 if (e
!= osl::FileBase::E_None
) {
354 << "Cannot read from <" << f
.getURL() << ">, error code "
356 std::exit(EXIT_FAILURE
);
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
)))
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
));
374 rtl::Reference
< unoidl::Entity
> ent(manager
->findEntity(t
));
377 << "Unknown entity \"" << t
<< "\" read from <"
378 << f
.getURL() << ">" << std::endl
;
379 std::exit(EXIT_FAILURE
);
381 if (ent
->getSort() == unoidl::Entity::SORT_MODULE
) {
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
));
391 map2
->insert(std::make_pair(id
, Item(ent
)));
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)));
399 k
= map2
->insert(std::make_pair(id
, Item(ent2
))).first
;
402 k
->second
.entity
->getSort()
403 == unoidl::Entity::SORT_MODULE
);
404 map2
= &k
->second
.module
;
410 if (e
!= osl::FileBase::E_None
) {
412 << "Cannot close <" << f
.getURL() << "> after reading, error code "
414 std::exit(EXIT_FAILURE
);
419 rtl::Reference
< unoidl::MapCursor
> const & cursor
,
420 std::map
< OUString
, Item
> & map
)
425 rtl::Reference
< unoidl::Entity
> ent(cursor
->getNext(&name
));
429 std::pair
< std::map
< OUString
, Item
>::iterator
, bool > i(
430 map
.insert(std::make_pair(name
, Item(ent
))));
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
)
439 rtl::Reference
< unoidl::ModuleEntity
>(
440 static_cast< unoidl::ModuleEntity
* >(
441 i
.first
->second
.entity
.get()))->createCursor(),
442 i
.first
->second
.module
);
449 bool hasNotEmptyAnnotations(const std::vector
<T
>& v
)
451 return std::any_of(v
.begin(), v
.end(), [](const T
& rItem
) { return !rItem
.annotations
.empty(); });
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);
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());
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
);
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());
502 case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE
:
504 rtl::Reference
< unoidl::PolymorphicStructTypeTemplateEntity
>
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()) {
520 if (j
.parameterized
) {
524 writeIdxName(file
, j
.name
);
525 writeIdxName(file
, j
.type
);
526 writeAnnotations(file
, ann
, j
.annotations
);
528 writeAnnotations(file
, ann
, ent2
->getAnnotations());
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
);
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());
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()) {
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
);
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());
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());
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()) {
639 j
.name
, ConstItem(j
.value
, j
.annotations
))).
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()) {
655 switch (j
.second
.constant
.type
) {
656 case unoidl::ConstantValue::TYPE_BOOLEAN
:
657 write8(file
, j
.second
.constant
.booleanValue
? 1 : 0);
659 case unoidl::ConstantValue::TYPE_BYTE
:
662 static_cast< sal_uInt8
>(
663 j
.second
.constant
.byteValue
));
665 case unoidl::ConstantValue::TYPE_SHORT
:
668 static_cast< sal_uInt16
>(
669 j
.second
.constant
.shortValue
));
671 case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT
:
672 write16(file
, j
.second
.constant
.unsignedShortValue
);
674 case unoidl::ConstantValue::TYPE_LONG
:
677 static_cast< sal_uInt32
>(
678 j
.second
.constant
.longValue
));
680 case unoidl::ConstantValue::TYPE_UNSIGNED_LONG
:
681 write32(file
, j
.second
.constant
.unsignedLongValue
);
683 case unoidl::ConstantValue::TYPE_HYPER
:
686 static_cast< sal_uInt64
>(
687 j
.second
.constant
.hyperValue
));
689 case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER
:
690 write64(file
, j
.second
.constant
.unsignedHyperValue
);
692 case unoidl::ConstantValue::TYPE_FLOAT
:
693 writeIso60599Binary32(
694 file
, j
.second
.constant
.floatValue
);
696 case unoidl::ConstantValue::TYPE_DOUBLE
:
697 writeIso60599Binary64(
698 file
, j
.second
.constant
.doubleValue
);
701 for (;;) { std::abort(); } // this cannot happen
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
716 for (auto & j
: cmap
) {
717 write32(file
, j
.second
.nameOffset
);
718 write32(file
, j
.second
.dataOffset
);
720 writeAnnotations(file
, ann
, ent2
->getAnnotations());
723 case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE
:
725 rtl::Reference
< unoidl::SingleInterfaceBasedServiceEntity
>
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());
739 write32(file
, ent2
->getConstructors().size());
740 for (auto & j
: ent2
->getConstructors()) {
741 if (j
.defaultConstructor
) {
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
) {
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());
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());
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());
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());
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
846 *rootSize
= map
.size();
847 // overflow from std::map::size_type -> std::size_t is unrealistic
849 for (auto & i
: map
) {
850 write32(file
, i
.second
.nameOffset
);
851 write32(file
, i
.second
.dataOffset
);
858 SAL_IMPLEMENT_MAIN() {
860 sal_uInt32 args
= rtl_getAppCommandArgCount();
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
) {
870 OUString
uri(getArgumentUri(i
, i
== args
- 2 ? &entities
: nullptr));
872 mapEntities(mgr
, uri
, map
);
875 prov
= mgr
->addProvider(uri
);
876 } catch (unoidl::NoSuchFileException
&) {
878 << "Input <" << uri
<< "> does not exist" << std::endl
;
879 std::exit(EXIT_FAILURE
);
886 ? prov
->createRootCursor()
887 : rtl::Reference
< unoidl::MapCursor
>()),
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
) {
897 << "Cannot open <" << f
.getURL() << "> for writing, error code "
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
906 RTL_CONSTASCII_STRINGPARAM(
907 "\0** Created by LibreOffice " LIBO_VERSION_DOTTED
908 " unoidl-write **\0"));
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
) {
914 << "Cannot set size of <" << f
.getURL() << ">, error code "
916 std::exit(EXIT_FAILURE
);
918 e
= f
.setPos(osl_Pos_Absolut
, 8);
919 if (e
!= osl::FileBase::E_None
) {
921 << "Cannot rewind current position in <" << f
.getURL()
922 << ">, error code " << +e
<< std::endl
;
923 std::exit(EXIT_FAILURE
);
927 // overflow from std::map::size_type -> sal_uInt64 is unrealistic
929 if (e
!= osl::FileBase::E_None
) {
931 << "Cannot close <" << f
.getURL()
932 << "> after writing, error code " << +e
<< std::endl
;
933 std::exit(EXIT_FAILURE
);
936 } catch (unoidl::FileFormatException
& e1
) {
938 << "Bad input <" << e1
.getUri() << ">: " << e1
.getDetail()
940 std::exit(EXIT_FAILURE
);
941 } catch (std::exception
& e1
) {
943 << "Failure: " << e1
.what()
945 std::exit(EXIT_FAILURE
);
950 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */