office-gobmx/unoidl/source/unoidl-write.cxx
Caolán McNamara b26ff81a6f use [[noreturn]] instead of asserts that badUsage exits
Change-Id: I927434290b02b6cc0386b1e0038cd8385a762249
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166996
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Tested-by: Jenkins
2024-05-02 13:21:40 +02:00

951 lines
36 KiB
C++

/* -*- 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 {
[[noreturn]] 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, std::size(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, std::size(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, std::size(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, std::size(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, std::size(sa.buf));
}
void writeIso60599Binary64(osl::File & file, double value) {
union {
unsigned char buf[8];
double 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, std::size(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 > theEntity):
entity(std::move(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 >&& theAnnotations):
constant(theConstant), annotations(std::move(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())
return;
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, 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, 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, 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, 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, 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, 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, std::vector(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, 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, 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, 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, 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, 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: */