/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { [[noreturn]] void badUsage() { std::cerr << "Usage:" << std::endl << std::endl << " unoidl-write [] [@] " << std::endl << std::endl << ("where each 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 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 , 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 = ↦ 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 bool hasNotEmptyAnnotations(const std::vector& 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: */