summaryrefslogtreecommitdiffstats
path: root/unoidl/source/unoidl-write.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'unoidl/source/unoidl-write.cxx')
-rw-r--r--unoidl/source/unoidl-write.cxx950
1 files changed, 950 insertions, 0 deletions
diff --git a/unoidl/source/unoidl-write.cxx b/unoidl/source/unoidl-write.cxx
new file mode 100644
index 000000000..1afca0e21
--- /dev/null
+++ b/unoidl/source/unoidl-write.cxx
@@ -0,0 +1,950 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <config_version.h>
+#include <osl/endian.h>
+#include <osl/file.h>
+#include <osl/file.hxx>
+#include <osl/process.h>
+#include <rtl/byteseq.hxx>
+#include <rtl/process.h>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/textenc.h>
+#include <rtl/textcvt.h>
+#include <rtl/ustring.hxx>
+#include <sal/macros.h>
+#include <sal/main.h>
+#include <unoidl/unoidl.hxx>
+
+namespace {
+
+void badUsage() {
+ std::cerr
+ << "Usage:" << std::endl << std::endl
+ << " unoidl-write [<registries>] [@<entities file>] <unoidl file>"
+ << std::endl << std::endl
+ << ("where each <registry> is either a new- or legacy-format .rdb file,"
+ " a single .idl")
+ << std::endl
+ << ("file, or a root directory of an .idl file tree; and the UTF-8"
+ " encoded <entities")
+ << std::endl
+ << ("file> contains zero or more space-separated names of (non-module)"
+ " entities to")
+ << std::endl
+ << ("include in the output, and, if omitted, defaults to the complete"
+ " content of the")
+ << std::endl << "last <registry>, if any." << std::endl;
+ std::exit(EXIT_FAILURE);
+}
+
+OUString getArgumentUri(sal_uInt32 argument, bool * entities) {
+ OUString arg;
+ rtl_getAppCommandArg(argument, &arg.pData);
+ if (arg.startsWith("@", &arg)) {
+ if (entities == nullptr) {
+ badUsage();
+ }
+ *entities = true;
+ } else if (entities != nullptr) {
+ *entities = false;
+ }
+ OUString url;
+ osl::FileBase::RC e1 = osl::FileBase::getFileURLFromSystemPath(arg, url);
+ if (e1 != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot convert \"" << arg << "\" to file URL, error code "
+ << +e1 << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ OUString cwd;
+ oslProcessError e2 = osl_getProcessWorkingDir(&cwd.pData);
+ if (e2 != osl_Process_E_None) {
+ std::cerr
+ << "Cannot obtain working directory, error code " << +e2
+ << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ OUString abs;
+ e1 = osl::FileBase::getAbsoluteFileURL(cwd, url, abs);
+ if (e1 != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot make \"" << url
+ << "\" into an absolute file URL, error code " << +e1 << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return abs;
+}
+
+sal_uInt64 getOffset(osl::File & file) {
+ sal_uInt64 off;
+ osl::FileBase::RC e = file.getPos(off);
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot determine current position in <" << file.getURL()
+ << ">, error code " << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return off;
+}
+
+void write(osl::File & file, void const * buffer, sal_uInt64 size) {
+ sal_uInt64 n;
+ osl::FileBase::RC e = file.write(buffer, size, n);
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot write to <" << file.getURL() << ">, error code " << +e
+ << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ if (n != size) {
+ std::cerr
+ << "Bad write of " << n << " instead of " << size << " bytes to <"
+ << file.getURL() << '>' << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+}
+
+void write8(osl::File & file, sal_uInt64 value) {
+ if (value > 0xFF) {
+ std::cerr
+ << "Cannot write value >= 2^8; input is too large" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ unsigned char buf[1];
+ buf[0] = value & 0xFF;
+ write(file, buf, SAL_N_ELEMENTS(buf));
+}
+
+void write16(osl::File & file, sal_uInt64 value) {
+ if (value > 0xFFFF) {
+ std::cerr
+ << "Cannot write value >= 2^16; input is too large" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ unsigned char buf[2];
+ buf[0] = value & 0xFF;
+ buf[1] = (value >> 8) & 0xFF;
+ write(file, buf, SAL_N_ELEMENTS(buf));
+}
+
+void write32(osl::File & file, sal_uInt64 value) {
+ if (value > 0xFFFFFFFF) {
+ std::cerr
+ << "Cannot write value >= 2^32; input is too large" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ unsigned char buf[4];
+ buf[0] = value & 0xFF;
+ buf[1] = (value >> 8) & 0xFF;
+ buf[2] = (value >> 16) & 0xFF;
+ buf[3] = (value >> 24) & 0xFF;
+ write(file, buf, SAL_N_ELEMENTS(buf));
+}
+
+void write64(osl::File & file, sal_uInt64 value) {
+ unsigned char buf[8];
+ buf[0] = value & 0xFF;
+ buf[1] = (value >> 8) & 0xFF;
+ buf[2] = (value >> 16) & 0xFF;
+ buf[3] = (value >> 24) & 0xFF;
+ buf[4] = (value >> 32) & 0xFF;
+ buf[5] = (value >> 40) & 0xFF;
+ buf[6] = (value >> 48) & 0xFF;
+ buf[7] = (value >> 56) & 0xFF;
+ write(file, buf, SAL_N_ELEMENTS(buf));
+}
+
+void writeIso60599Binary32(osl::File & file, float value) {
+ union {
+ unsigned char buf[4];
+ float f; // assuming float is ISO 60599 binary32
+ } sa;
+ sa.f = value;
+#if defined OSL_BIGENDIAN
+ std::swap(sa.buf[0], sa.buf[3]);
+ std::swap(sa.buf[1], sa.buf[2]);
+#endif
+ write(file, sa.buf, SAL_N_ELEMENTS(sa.buf));
+}
+
+void writeIso60599Binary64(osl::File & file, double value) {
+ union {
+ unsigned char buf[8];
+ float d; // assuming double is ISO 60599 binary64
+ } sa;
+ sa.d = value;
+#if defined OSL_BIGENDIAN
+ std::swap(sa.buf[0], sa.buf[7]);
+ std::swap(sa.buf[1], sa.buf[6]);
+ std::swap(sa.buf[2], sa.buf[5]);
+ std::swap(sa.buf[3], sa.buf[4]);
+#endif
+ write(file, sa.buf, SAL_N_ELEMENTS(sa.buf));
+}
+
+OString toAscii(OUString const & name) {
+ OString ascii;
+ if (!name.convertToString(
+ &ascii, RTL_TEXTENCODING_ASCII_US,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ std::cerr
+ << "Cannot convert \"" << name << "\" to US ASCII" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return ascii;
+}
+
+OString toUtf8(OUString const & string) {
+ OString ascii;
+ if (!string.convertToString(
+ &ascii, RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ std::cerr
+ << "Cannot convert \"" << string << "\" to UTF-8" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return ascii;
+}
+
+sal_uInt64 writeNulName(osl::File & file, OUString const & name) {
+ OString ascii(toAscii(name));
+ if (ascii.indexOf('\0') != -1) {
+ std::cerr
+ << "Name \"" << ascii << "\" contains NUL characters" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ sal_uInt64 off = getOffset(file);
+ write(file, ascii.getStr(), ascii.getLength() + 1);
+ return off;
+}
+
+void writeIdxString(osl::File & file, OString const & string) {
+ static std::map< OString, sal_uInt64 > reuse;
+ std::map< OString, sal_uInt64 >::iterator i(reuse.find(string));
+ if (i == reuse.end()) {
+ reuse.insert(std::make_pair(string, getOffset(file)));
+ assert(
+ (static_cast< sal_uInt64 >(string.getLength()) & 0x80000000) == 0);
+ write32(file, static_cast< sal_uInt64 >(string.getLength()));
+ write(file, string.getStr(), string.getLength());
+ } else {
+ if ((i->second & 0x80000000) != 0) {
+ std::cerr
+ << "Cannot write index 0x" << std::hex << i->second << std::dec
+ << " of \"" << string << "\"; input is too large" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ write32(file, i->second | 0x80000000);
+ }
+}
+
+void writeIdxName(osl::File & file, OUString const & name) {
+ writeIdxString(file, toAscii(name));
+}
+
+void writeAnnotations(
+ osl::File & file, bool annotate,
+ std::vector< OUString > const & annotations)
+{
+ assert(annotate || annotations.empty());
+ if (annotate) {
+ write32(file, annotations.size());
+ // overflow from std::vector::size_type -> sal_uInt64 is unrealistic
+ for (auto & i: annotations) {
+ writeIdxString(file, toUtf8(i));
+ }
+ }
+}
+
+void writeKind(
+ osl::File & file,
+ rtl::Reference< unoidl::PublishableEntity > const & entity,
+ bool annotated, bool flag = false)
+{
+ assert(entity.is());
+ sal_uInt64 v = entity->getSort();
+ if (entity->isPublished()) {
+ v |= 0x80;
+ }
+ if (annotated) {
+ v |= 0x40;
+ }
+ if (flag) {
+ v |= 0x20;
+ }
+ write8(file, v);
+}
+
+struct Item {
+ explicit Item(rtl::Reference< unoidl::Entity > const & theEntity):
+ entity(theEntity), nameOffset(0), dataOffset(0)
+ {}
+
+ rtl::Reference< unoidl::Entity > entity;
+ std::map< OUString, Item > module;
+ sal_uInt64 nameOffset;
+ sal_uInt64 dataOffset;
+};
+
+struct ConstItem {
+ ConstItem(
+ unoidl::ConstantValue const & theConstant,
+ std::vector< OUString > const & theAnnotations):
+ constant(theConstant), annotations(theAnnotations), nameOffset(0),
+ dataOffset(0)
+ {}
+
+ unoidl::ConstantValue constant;
+ std::vector< OUString > annotations;
+ sal_uInt64 nameOffset;
+ sal_uInt64 dataOffset;
+};
+
+void mapEntities(
+ rtl::Reference< unoidl::Manager > const & manager, OUString const & uri,
+ std::map< OUString, Item > & map)
+{
+ assert(manager.is());
+ osl::File f(uri);
+ osl::FileBase::RC e = f.open(osl_File_OpenFlag_Read);
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot open <" << f.getURL() << "> for reading, error code "
+ << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ for (;;) {
+ sal_Bool eof;
+ e = f.isEndOfFile(&eof);
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot check <" << f.getURL() << "> for EOF, error code "
+ << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ if (eof) {
+ break;
+ }
+ rtl::ByteSequence s1;
+ e = f.readLine(s1);
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot read from <" << f.getURL() << ">, error code "
+ << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ OUString s2;
+ if (!rtl_convertStringToUString(
+ &s2.pData, reinterpret_cast< char const * >(s1.getConstArray()),
+ s1.getLength(), RTL_TEXTENCODING_UTF8,
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
+ | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ std::cerr
+ << "Cannot interpret line read from <" << f.getURL()
+ << "> as UTF-8" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ for (sal_Int32 i = 0; i != -1;) {
+ OUString t(s2.getToken(0, ' ', i));
+ if (!t.isEmpty()) {
+ rtl::Reference< unoidl::Entity > ent(manager->findEntity(t));
+ if (!ent.is()) {
+ std::cerr
+ << "Unknown entity \"" << t << "\" read from <"
+ << f.getURL() << ">" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ if (ent->getSort() == unoidl::Entity::SORT_MODULE) {
+ std::cerr
+ << "Module entity \"" << t << "\" read from <"
+ << f.getURL() << ">" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ std::map< OUString, Item > * map2 = &map;
+ for (sal_Int32 j = 0;;) {
+ OUString id(t.getToken(0, '.', j));
+ if (j == -1) {
+ map2->insert(std::make_pair(id, Item(ent)));
+ break;
+ }
+ std::map< OUString, Item >::iterator k(map2->find(id));
+ if (k == map2->end()) {
+ rtl::Reference< unoidl::Entity > ent2(
+ manager->findEntity(t.copy(0, j - 1)));
+ assert(ent2.is());
+ k = map2->insert(std::make_pair(id, Item(ent2))).first;
+ }
+ assert(
+ k->second.entity->getSort()
+ == unoidl::Entity::SORT_MODULE);
+ map2 = &k->second.module;
+ }
+ }
+ }
+ }
+ e = f.close();
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot close <" << f.getURL() << "> after reading, error code "
+ << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+}
+
+void mapCursor(
+ rtl::Reference< unoidl::MapCursor > const & cursor,
+ std::map< OUString, Item > & map)
+{
+ if (cursor.is()) {
+ for (;;) {
+ OUString name;
+ rtl::Reference< unoidl::Entity > ent(cursor->getNext(&name));
+ if (!ent.is()) {
+ break;
+ }
+ std::pair< std::map< OUString, Item >::iterator, bool > i(
+ map.insert(std::make_pair(name, Item(ent))));
+ if (!i.second) {
+ std::cout << "Duplicate name \"" << name << '"' << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ if (i.first->second.entity->getSort()
+ == unoidl::Entity::SORT_MODULE)
+ {
+ mapCursor(
+ rtl::Reference< unoidl::ModuleEntity >(
+ static_cast< unoidl::ModuleEntity * >(
+ i.first->second.entity.get()))->createCursor(),
+ i.first->second.module);
+ }
+ }
+ }
+}
+
+template<typename T>
+bool hasNotEmptyAnnotations(const std::vector<T>& v)
+{
+ return std::any_of(v.begin(), v.end(), [](const T& rItem) { return !rItem.annotations.empty(); });
+}
+
+sal_uInt64 writeMap(
+ osl::File & file, std::map< OUString, Item > & map, std::size_t * rootSize)
+{
+ for (auto & i: map) {
+ switch (i.second.entity->getSort()) {
+ case unoidl::Entity::SORT_MODULE:
+ i.second.dataOffset = writeMap(file, i.second.module, nullptr);
+ break;
+ case unoidl::Entity::SORT_ENUM_TYPE:
+ {
+ rtl::Reference< unoidl::EnumTypeEntity > ent2(
+ static_cast< unoidl::EnumTypeEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty() ||
+ hasNotEmptyAnnotations(ent2->getMembers());
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ write32(file, ent2->getMembers().size());
+ for (auto & j: ent2->getMembers()) {
+ writeIdxName(file, j.name);
+ write32(file, static_cast< sal_uInt32 >(j.value));
+ writeAnnotations(file, ann, j.annotations);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
+ {
+ rtl::Reference< unoidl::PlainStructTypeEntity > ent2(
+ static_cast< unoidl::PlainStructTypeEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty() ||
+ hasNotEmptyAnnotations(ent2->getDirectMembers());
+ i.second.dataOffset = getOffset(file);
+ writeKind(
+ file, ent2.get(), ann, !ent2->getDirectBase().isEmpty());
+ if (!ent2->getDirectBase().isEmpty()) {
+ writeIdxName(file, ent2->getDirectBase());
+ }
+ write32(file, ent2->getDirectMembers().size());
+ for (auto & j: ent2->getDirectMembers()) {
+ writeIdxName(file, j.name);
+ writeIdxName(file, j.type);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
+ {
+ rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity >
+ ent2(
+ static_cast<
+ unoidl::PolymorphicStructTypeTemplateEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty() ||
+ hasNotEmptyAnnotations(ent2->getMembers());
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ write32(file, ent2->getTypeParameters().size());
+ for (auto & j: ent2->getTypeParameters()) {
+ writeIdxName(file, j);
+ }
+ write32(file, ent2->getMembers().size());
+ for (auto & j: ent2->getMembers()) {
+ sal_uInt64 f = 0;
+ if (j.parameterized) {
+ f |= 0x01;
+ }
+ write8(file, f);
+ writeIdxName(file, j.name);
+ writeIdxName(file, j.type);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_EXCEPTION_TYPE:
+ {
+ rtl::Reference< unoidl::ExceptionTypeEntity > ent2(
+ static_cast< unoidl::ExceptionTypeEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty() ||
+ hasNotEmptyAnnotations(ent2->getDirectMembers());
+ i.second.dataOffset = getOffset(file);
+ writeKind(
+ file, ent2.get(), ann, !ent2->getDirectBase().isEmpty());
+ if (!ent2->getDirectBase().isEmpty()) {
+ writeIdxName(file, ent2->getDirectBase());
+ }
+ write32(file, ent2->getDirectMembers().size());
+ for (auto & j: ent2->getDirectMembers()) {
+ writeIdxName(file, j.name);
+ writeIdxName(file, j.type);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_INTERFACE_TYPE:
+ {
+ rtl::Reference< unoidl::InterfaceTypeEntity > ent2(
+ static_cast< unoidl::InterfaceTypeEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty() ||
+ hasNotEmptyAnnotations(ent2->getDirectMandatoryBases()) ||
+ hasNotEmptyAnnotations(ent2->getDirectOptionalBases()) ||
+ hasNotEmptyAnnotations(ent2->getDirectAttributes()) ||
+ hasNotEmptyAnnotations(ent2->getDirectMethods());
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ write32(file, ent2->getDirectMandatoryBases().size());
+ for (auto & j: ent2->getDirectMandatoryBases()) {
+ writeIdxName(file, j.name);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectOptionalBases().size());
+ for (auto & j: ent2->getDirectOptionalBases()) {
+ writeIdxName(file, j.name);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectAttributes().size());
+ for (auto & j: ent2->getDirectAttributes()) {
+ sal_uInt64 f = 0;
+ if (j.bound) {
+ f |= 0x01;
+ }
+ if (j.readOnly) {
+ f |= 0x02;
+ }
+ write8(file, f);
+ writeIdxName(file, j.name);
+ writeIdxName(file, j.type);
+ write32(file, j.getExceptions.size());
+ for (auto & k: j.getExceptions) {
+ writeIdxName(file, k);
+ }
+ if (!j.readOnly) {
+ write32(file, j.setExceptions.size());
+ for (auto & k: j.setExceptions) {
+ writeIdxName(file, k);
+ }
+ }
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectMethods().size());
+ for (auto & j: ent2->getDirectMethods()) {
+ writeIdxName(file, j.name);
+ writeIdxName(file, j.returnType);
+ write32(file, j.parameters.size());
+ for (auto & k: j.parameters) {
+ write8(file, k.direction);
+ writeIdxName(file, k.name);
+ writeIdxName(file, k.type);
+ }
+ write32(file, j.exceptions.size());
+ for (auto & k: j.exceptions) {
+ writeIdxName(file, k);
+ }
+ writeAnnotations(file, ann, j.annotations);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_TYPEDEF:
+ {
+ rtl::Reference< unoidl::TypedefEntity > ent2(
+ static_cast< unoidl::TypedefEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty();
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ writeIdxName(file, ent2->getType());
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_CONSTANT_GROUP:
+ {
+ rtl::Reference< unoidl::ConstantGroupEntity > ent2(
+ static_cast< unoidl::ConstantGroupEntity * >(
+ i.second.entity.get()));
+ std::map< OUString, ConstItem > cmap;
+ for (auto & j: ent2->getMembers()) {
+ if (!cmap.insert(
+ std::make_pair(
+ j.name, ConstItem(j.value, j.annotations))).
+ second)
+ {
+ std::cout
+ << "Duplicate constant group member name \""
+ << j.name << '"' << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ }
+ for (auto & j: cmap) {
+ j.second.dataOffset = getOffset(file);
+ sal_uInt64 v = j.second.constant.type;
+ if (!j.second.annotations.empty()) {
+ v |= 0x80;
+ }
+ write8(file, v);
+ switch (j.second.constant.type) {
+ case unoidl::ConstantValue::TYPE_BOOLEAN:
+ write8(file, j.second.constant.booleanValue ? 1 : 0);
+ break;
+ case unoidl::ConstantValue::TYPE_BYTE:
+ write8(
+ file,
+ static_cast< sal_uInt8 >(
+ j.second.constant.byteValue));
+ break;
+ case unoidl::ConstantValue::TYPE_SHORT:
+ write16(
+ file,
+ static_cast< sal_uInt16 >(
+ j.second.constant.shortValue));
+ break;
+ case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
+ write16(file, j.second.constant.unsignedShortValue);
+ break;
+ case unoidl::ConstantValue::TYPE_LONG:
+ write32(
+ file,
+ static_cast< sal_uInt32 >(
+ j.second.constant.longValue));
+ break;
+ case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
+ write32(file, j.second.constant.unsignedLongValue);
+ break;
+ case unoidl::ConstantValue::TYPE_HYPER:
+ write64(
+ file,
+ static_cast< sal_uInt64 >(
+ j.second.constant.hyperValue));
+ break;
+ case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
+ write64(file, j.second.constant.unsignedHyperValue);
+ break;
+ case unoidl::ConstantValue::TYPE_FLOAT:
+ writeIso60599Binary32(
+ file, j.second.constant.floatValue);
+ break;
+ case unoidl::ConstantValue::TYPE_DOUBLE:
+ writeIso60599Binary64(
+ file, j.second.constant.doubleValue);
+ break;
+ default:
+ for (;;) { std::abort(); } // this cannot happen
+ }
+ writeAnnotations(
+ file, !j.second.annotations.empty(),
+ j.second.annotations);
+ }
+ for (auto & j: cmap) {
+ j.second.nameOffset = writeNulName(file, j.first);
+ }
+ bool ann = !ent2->getAnnotations().empty();
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ write32(file, cmap.size());
+ // overflow from std::map::size_type -> sal_uInt64 is
+ // unrealistic
+ for (const auto & j: cmap) {
+ write32(file, j.second.nameOffset);
+ write32(file, j.second.dataOffset);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE:
+ {
+ rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity >
+ ent2(
+ static_cast<
+ unoidl::SingleInterfaceBasedServiceEntity * >(
+ i.second.entity.get()));
+ bool dfltCtor = ent2->getConstructors().size() == 1
+ && ent2->getConstructors()[0].defaultConstructor;
+ bool ann = !ent2->getAnnotations().empty();
+ if (!dfltCtor && !ann)
+ ann = hasNotEmptyAnnotations(ent2->getConstructors());
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann, dfltCtor);
+ writeIdxName(file, ent2->getBase());
+ if (!dfltCtor) {
+ write32(file, ent2->getConstructors().size());
+ for (auto & j: ent2->getConstructors()) {
+ if (j.defaultConstructor) {
+ std::cout
+ << "Unexpected default constructor \""
+ << j.name << '"' << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ writeIdxName(file, j.name);
+ write32(file, j.parameters.size());
+ for (auto & k: j.parameters) {
+ sal_uInt64 f = 0;
+ if (k.rest) {
+ f |= 0x04;
+ }
+ write8(file, f);
+ writeIdxName(file, k.name);
+ writeIdxName(file, k.type);
+ }
+ write32(file, j.exceptions.size());
+ for (auto & k: j.exceptions) {
+ writeIdxName(file, k);
+ }
+ writeAnnotations(file, ann, j.annotations);
+ }
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE:
+ {
+ rtl::Reference< unoidl::AccumulationBasedServiceEntity > ent2(
+ static_cast< unoidl::AccumulationBasedServiceEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty() ||
+ hasNotEmptyAnnotations(ent2->getDirectMandatoryBaseServices()) ||
+ hasNotEmptyAnnotations(ent2->getDirectOptionalBaseServices()) ||
+ hasNotEmptyAnnotations(ent2->getDirectMandatoryBaseInterfaces()) ||
+ hasNotEmptyAnnotations(ent2->getDirectOptionalBaseInterfaces()) ||
+ hasNotEmptyAnnotations(ent2->getDirectProperties());
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ write32(file, ent2->getDirectMandatoryBaseServices().size());
+ for (auto & j: ent2->getDirectMandatoryBaseServices()) {
+ writeIdxName(file, j.name);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectOptionalBaseServices().size());
+ for (auto & j: ent2->getDirectOptionalBaseServices()) {
+ writeIdxName(file, j.name);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectMandatoryBaseInterfaces().size());
+ for (auto & j: ent2->getDirectMandatoryBaseInterfaces()) {
+ writeIdxName(file, j.name);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectOptionalBaseInterfaces().size());
+ for (auto & j: ent2->getDirectOptionalBaseInterfaces()) {
+ writeIdxName(file, j.name);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ write32(file, ent2->getDirectProperties().size());
+ for (auto & j: ent2->getDirectProperties()) {
+ write16(file, static_cast< sal_uInt16 >(j.attributes));
+ writeIdxName(file, j.name);
+ writeIdxName(file, j.type);
+ writeAnnotations(file, ann, j.annotations);
+ }
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON:
+ {
+ rtl::Reference< unoidl::InterfaceBasedSingletonEntity > ent2(
+ static_cast< unoidl::InterfaceBasedSingletonEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty();
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ writeIdxName(file, ent2->getBase());
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON:
+ {
+ rtl::Reference< unoidl::ServiceBasedSingletonEntity > ent2(
+ static_cast< unoidl::ServiceBasedSingletonEntity * >(
+ i.second.entity.get()));
+ bool ann = !ent2->getAnnotations().empty();
+ i.second.dataOffset = getOffset(file);
+ writeKind(file, ent2.get(), ann);
+ writeIdxName(file, ent2->getBase());
+ writeAnnotations(file, ann, ent2->getAnnotations());
+ break;
+ }
+ }
+ }
+ for (auto & i: map) {
+ i.second.nameOffset = writeNulName(file, i.first);
+ }
+ sal_uInt64 off = getOffset(file);
+ if (rootSize == nullptr) {
+ write8(file, 0); // SORT_MODULE
+ write32(file, map.size());
+ // overflow from std::map::size_type -> sal_uInt64 is unrealistic
+ } else {
+ *rootSize = map.size();
+ // overflow from std::map::size_type -> std::size_t is unrealistic
+ }
+ for (const auto & i: map) {
+ write32(file, i.second.nameOffset);
+ write32(file, i.second.dataOffset);
+ }
+ return off;
+}
+
+}
+
+SAL_IMPLEMENT_MAIN() {
+ try {
+ sal_uInt32 args = rtl_getAppCommandArgCount();
+ if (args == 0) {
+ badUsage();
+ }
+ rtl::Reference< unoidl::Manager > mgr(new unoidl::Manager);
+ bool entities = false;
+ rtl::Reference< unoidl::Provider > prov;
+ std::map< OUString, Item > map;
+ for (sal_uInt32 i = 0; i != args - 1; ++i) {
+ assert(args > 1);
+ OUString uri(getArgumentUri(i, i == args - 2 ? &entities : nullptr));
+ if (entities) {
+ mapEntities(mgr, uri, map);
+ } else {
+ try {
+ prov = mgr->addProvider(uri);
+ } catch (unoidl::NoSuchFileException &) {
+ std::cerr
+ << "Input <" << uri << "> does not exist" << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ }
+ }
+ if (!entities) {
+ mapCursor(
+ (prov.is()
+ ? prov->createRootCursor()
+ : rtl::Reference< unoidl::MapCursor >()),
+ map);
+ }
+ osl::File f(getArgumentUri(args - 1, nullptr));
+ osl::FileBase::RC e = f.open(osl_File_OpenFlag_Write);
+ if (e == osl::FileBase::E_NOENT) {
+ e = f.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
+ }
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot open <" << f.getURL() << "> for writing, error code "
+ << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ write(f, "UNOIDL\xFF\0", 8);
+ write32(f, 0); // root map offset
+ write32(f, 0); // root map size
+ write(
+ f,
+ RTL_CONSTASCII_STRINGPARAM(
+ "\0** Created by LibreOffice " LIBO_VERSION_DOTTED
+ " unoidl-write **\0"));
+ std::size_t size;
+ sal_uInt64 off = writeMap(f, map, &size);
+ e = f.setSize(getOffset(f)); // truncate in case it already existed
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot set size of <" << f.getURL() << ">, error code "
+ << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ e = f.setPos(osl_Pos_Absolut, 8);
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot rewind current position in <" << f.getURL()
+ << ">, error code " << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ write32(f, off);
+ write32(f, size);
+ // overflow from std::map::size_type -> sal_uInt64 is unrealistic
+ e = f.close();
+ if (e != osl::FileBase::E_None) {
+ std::cerr
+ << "Cannot close <" << f.getURL()
+ << "> after writing, error code " << +e << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+ return EXIT_SUCCESS;
+ } catch (unoidl::FileFormatException & e1) {
+ std::cerr
+ << "Bad input <" << e1.getUri() << ">: " << e1.getDetail()
+ << std::endl;
+ std::exit(EXIT_FAILURE);
+ } catch (std::exception & e1) {
+ std::cerr
+ << "Failure: " << e1.what()
+ << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */