diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /codemaker/source | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'codemaker/source')
26 files changed, 10868 insertions, 0 deletions
diff --git a/codemaker/source/codemaker/codemaker.cxx b/codemaker/source/codemaker/codemaker.cxx new file mode 100644 index 000000000..cb797533e --- /dev/null +++ b/codemaker/source/codemaker/codemaker.cxx @@ -0,0 +1,46 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <codemaker/codemaker.hxx> +#include <codemaker/global.hxx> +#include <rtl/string.hxx> +#include <rtl/textcvt.h> +#include <rtl/textenc.h> +#include <rtl/ustring.hxx> + +namespace codemaker { + +OString convertString(OUString const & string) { + OString s; + if (!string.convertToString( + &s, RTL_TEXTENCODING_UTF8, + (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR + | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))) + { + throw CannotDumpException( + "Failure converting string from UTF-16 to UTF-8"); + } + return s; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/codemaker/exceptiontree.cxx b/codemaker/source/codemaker/exceptiontree.cxx new file mode 100644 index 000000000..148f017b6 --- /dev/null +++ b/codemaker/source/codemaker/exceptiontree.cxx @@ -0,0 +1,93 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <codemaker/exceptiontree.hxx> +#include <codemaker/typemanager.hxx> + +#include <rtl/ref.hxx> +#include <rtl/string.hxx> +#include <rtl/textenc.h> +#include <rtl/ustring.hxx> +#include <unoidl/unoidl.hxx> + +#include <memory> +#include <vector> + +using codemaker::ExceptionTree; +using codemaker::ExceptionTreeNode; + +ExceptionTreeNode * ExceptionTreeNode::add(OString const & theName) { + std::unique_ptr< ExceptionTreeNode > node(new ExceptionTreeNode(theName)); + children.push_back(std::move(node)); + return children.back().get(); +} + +void ExceptionTreeNode::clearChildren() { + children.clear(); +} + +void ExceptionTree::add( + OString const & name, rtl::Reference< TypeManager > const & manager) +{ + std::vector< OString > list; + bool bRuntimeException = false; + for (OString n(name); n != "com.sun.star.uno.Exception";) { + if (n == "com.sun.star.uno.RuntimeException") { + bRuntimeException = true; + break; + } + list.push_back(n); + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort s = manager->getSort(b2u(n), &ent); + (void) s; // WaE: unused variable + assert(s == codemaker::UnoType::Sort::Exception); + n = u2b( + static_cast< unoidl::ExceptionTypeEntity * >(ent.get())-> + getDirectBase()); + assert(!n.isEmpty()); + } + if (bRuntimeException) + return; + + ExceptionTreeNode * node = &m_root; + for (std::vector< OString >::reverse_iterator i(list.rbegin()); + !node->present; ++i) + { + if (i == list.rend()) { + node->setPresent(); + break; + } + for (ExceptionTreeNode::Children::iterator j( + node->children.begin());; + ++j) + { + if (j == node->children.end()) { + node = node->add(*i); + break; + } + if ((*j)->name == *i) { + node = j->get(); + break; + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/codemaker/global.cxx b/codemaker/source/codemaker/global.cxx new file mode 100644 index 000000000..1310a0b05 --- /dev/null +++ b/codemaker/source/codemaker/global.cxx @@ -0,0 +1,367 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/process.h> +#include <rtl/strbuf.hxx> +#include <rtl/ustring.hxx> +#include <osl/thread.h> +#include <osl/file.hxx> +#include <o3tl/string_view.hxx> + +#include <string.h> +#include <string_view> +#include <errno.h> + +#if defined(_WIN32) +# include <io.h> +# include <direct.h> +#endif + +#ifdef UNX +# include <sys/stat.h> +# include <unistd.h> +#endif + +#include <codemaker/global.hxx> + +#ifdef SAL_UNX +#define SEPARATOR '/' +#else +#define SEPARATOR '\\' +#endif + +using namespace ::osl; + + +OString getTempDir(const OString& sFileName) +{ + sal_Int32 index = 0; +#ifdef SAL_UNX + if ((index=sFileName.lastIndexOf('/')) > 0) + return sFileName.copy(0, index); +#else + if ((index=sFileName.lastIndexOf('\\')) > 0) + return sFileName.copy(0, index); +#endif + return "."; +} + +OString createFileNameFromType( const OString& destination, + const OString& typeName, + const OString& postfix ) +{ + OString type(typeName.replace('.', '/')); + + sal_Int32 length = destination.getLength(); + + bool bWithPoint = false; + if (length == 0) + { + length++; + bWithPoint = true; + } + + length += type.getLength() + postfix.getLength(); + + bool bWithSeparator = false; + if (!(destination.endsWith("\\") || destination.endsWith("/")) + && !(type.startsWith("\\") || type.startsWith("/"))) + { + length++; + bWithSeparator = true; + } + + OStringBuffer fileNameBuf(length); + + if (bWithPoint) + fileNameBuf.append('.'); + else + fileNameBuf.append(destination); + + if (bWithSeparator) + fileNameBuf.append("/"); + + fileNameBuf.append(type); + fileNameBuf.append(postfix); + + OString fileName(fileNameBuf.makeStringAndClear()); + + char token; +#ifdef SAL_UNX + fileName = fileName.replace('\\', '/'); + token = '/'; +#else + fileName = fileName.replace('/', '\\'); + token = '\\'; +#endif + + OStringBuffer buffer(length); + + sal_Int32 nIndex = 0; + do + { + buffer.append(o3tl::getToken(fileName, 0, token, nIndex)); + if( nIndex == -1 ) + break; + + if (buffer.isEmpty() || std::string_view(".") == buffer) + { + buffer.append(token); + continue; + } + +#if defined(SAL_UNX) + if (mkdir(buffer.getStr(), 0777) == -1) +#else + if (mkdir(buffer.getStr()) == -1) +#endif + { + if ( errno == ENOENT ) + return OString(); + } + + buffer.append(token); + } while(true); + + OUString uSysFileName; + OSL_VERIFY( FileBase::getSystemPathFromFileURL( + convertToFileUrl(fileName), uSysFileName) == FileBase::E_None ); + return OUStringToOString(uSysFileName, osl_getThreadTextEncoding()); +} + +bool fileExists(const OString& fileName) +{ + FILE *f= fopen(fileName.getStr(), "r"); + + if (f != nullptr) + { + fclose(f); + return true; + } + + return false; +} + +static bool checkFileContent(const OString& targetFileName, const OString& tmpFileName) +{ + FILE *target = fopen(targetFileName.getStr(), "r"); + FILE *tmp = fopen(tmpFileName.getStr(), "r"); + bool bFindChanges = false; + + if (target != nullptr && tmp != nullptr) + { + char buffer1[1024+1]; + char buffer2[1024+1]; + sal_Int32 n1 = 0; + sal_Int32 n2 = 0; + + while ( !bFindChanges && !feof(target) && !feof(tmp)) + { + n1 = fread(buffer1, sizeof(char), 1024, target); + n2 = fread(buffer2, sizeof(char), 1024, tmp); + + if ( n1 != n2 ) + bFindChanges = true; + else + if ( memcmp(buffer1, buffer2, n2) != 0 ) + bFindChanges = true; + } + } + + if (target) fclose(target); + if (tmp) fclose(tmp); + + return bFindChanges; +} + +bool makeValidTypeFile(const OString& targetFileName, const OString& tmpFileName, + bool bFileCheck) +{ + if (bFileCheck) { + if (checkFileContent(targetFileName, tmpFileName)) { + if ( !unlink(targetFileName.getStr()) ) + if ( !rename(tmpFileName.getStr(), targetFileName.getStr()) ) + return true; + } else + return removeTypeFile(tmpFileName); + } else { + if (fileExists(targetFileName)) + if (!removeTypeFile(targetFileName)) + return false; + + if ( rename(tmpFileName.getStr(), targetFileName.getStr()) ) { + if (errno == EEXIST) + return true; + } else + return true; + } + return false; +} + +bool removeTypeFile(const OString& fileName) +{ + return unlink(fileName.getStr()) == 0; +} + +OUString convertToFileUrl(const OString& fileName) +{ + if ( fileName.startsWith("file://") ) + { + return OStringToOUString(fileName, osl_getThreadTextEncoding()); + } + + OUString uUrlFileName; + OUString uFileName(fileName.getStr(), fileName.getLength(), osl_getThreadTextEncoding()); + if ( fileName.startsWith(".") || fileName.indexOf(SEPARATOR) < 0 ) + { + OUString uWorkingDir; + if (osl_getProcessWorkingDir(&uWorkingDir.pData) != osl_Process_E_None) + { + OSL_ASSERT(false); + } + if (FileBase::getAbsoluteFileURL(uWorkingDir, uFileName, uUrlFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + } else + { + if (FileBase::getFileURLFromSystemPath(uFileName, uUrlFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + } + + return uUrlFileName; +} + + +// FileStream + +FileStream::FileStream() + : m_file(nullptr) +{ +} + +FileStream::~FileStream() +{ + if ( isValid() ) + osl_closeFile(m_file); +} + +bool FileStream::isValid() const +{ + return m_file != nullptr; +} + +void FileStream::createTempFile(const OString& sPath) +{ + OString sTmp("."); + OUString sTmpPath; + OUString sTmpName; + + if (!sPath.isEmpty()) + sTmp = sPath; + + sTmpPath = convertToFileUrl(sTmp); + + if (osl_createTempFile(sTmpPath.pData, &m_file, &sTmpName.pData) == osl_File_E_None) { +#ifdef SAL_UNX + sal_uInt64 const uAttr = osl_File_Attribute_OwnWrite | + osl_File_Attribute_OwnRead | + osl_File_Attribute_GrpWrite | + osl_File_Attribute_GrpRead | + osl_File_Attribute_OthRead; + if (osl_setFileAttributes(sTmpName.pData, uAttr) != osl_File_E_None) { + m_file = nullptr; + return; + } +#endif + OUString sSysTmpName; + FileBase::getSystemPathFromFileURL(sTmpName, sSysTmpName); + m_name = OUStringToOString(sSysTmpName, osl_getThreadTextEncoding()); + } else + m_file = nullptr; +} + +void FileStream::close() +{ + if ( isValid() ) + { + osl_closeFile(m_file); + m_file = nullptr; + m_name.clear(); + } +} + +bool FileStream::write(void const * buffer, sal_uInt64 size) { + while (size > 0) { + sal_uInt64 written; + if (osl_writeFile(m_file, buffer, size, &written) != osl_File_E_None) { + return false; + } + OSL_ASSERT(written <= size); + size -= written; + buffer = static_cast< char const * >(buffer) + written; + } + return true; +} + +FileStream &operator<<(FileStream& o, sal_uInt32 i) { + sal_uInt64 writtenBytes; + OString s = OString::number(static_cast<sal_Int32>(i)); + osl_writeFile(o.m_file, s.getStr(), s.getLength() * sizeof(char), &writtenBytes); + return o; +} +FileStream &operator<<(FileStream& o, char const * s) { + sal_uInt64 writtenBytes; + osl_writeFile(o.m_file, s, strlen(s), &writtenBytes); + return o; +} +FileStream &operator<<(FileStream& o, OString const * s) { + sal_uInt64 writtenBytes; + osl_writeFile(o.m_file, s->getStr(), s->getLength() * sizeof(char), &writtenBytes); + return o; +} +FileStream &operator<<(FileStream& o, const OString& s) { + sal_uInt64 writtenBytes; + osl_writeFile(o.m_file, s.getStr(), s.getLength() * sizeof(char), &writtenBytes); + return o; + +} +FileStream &operator<<(FileStream& o, OStringBuffer const * s) { + sal_uInt64 writtenBytes; + osl_writeFile(o.m_file, s->getStr(), s->getLength() * sizeof(char), &writtenBytes); + return o; +} +FileStream &operator<<(FileStream& o, const OStringBuffer& s) { + sal_uInt64 writtenBytes; + osl_writeFile( + o.m_file, s.getStr(), s.getLength() * sizeof(char), &writtenBytes); + return o; +} + +FileStream & operator <<(FileStream & out, std::u16string_view s) { + return out << OUStringToOString(s, RTL_TEXTENCODING_UTF8); +} + +CannotDumpException::~CannotDumpException() noexcept {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/codemaker/options.cxx b/codemaker/source/codemaker/options.cxx new file mode 100644 index 000000000..2d85b35a9 --- /dev/null +++ b/codemaker/source/codemaker/options.cxx @@ -0,0 +1,41 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <codemaker/options.hxx> + +Options::Options() {} + +Options::~Options() {} + +bool Options::isValid(const OString& option) const +{ + return m_options.find(option) != m_options.end(); +} + +const OString& Options::getOption(const OString& option) const +{ + OptionMap::const_iterator i(m_options.find(option)); + if (i == m_options.end()) + { + throw IllegalArgument("Option is not valid or currently not set."); + } + return i->second; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/codemaker/typemanager.cxx b/codemaker/source/codemaker/typemanager.cxx new file mode 100644 index 000000000..194840ca9 --- /dev/null +++ b/codemaker/source/codemaker/typemanager.cxx @@ -0,0 +1,258 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cstdlib> +#include <cstring> +#include <vector> + +#include <codemaker/global.hxx> +#include <codemaker/typemanager.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> +#include <unoidl/unoidl.hxx> + +TypeManager::TypeManager(): manager_(new unoidl::Manager) {} + +TypeManager::~TypeManager() {} + +void TypeManager::loadProvider(OUString const & uri, bool primary) { + rtl::Reference< unoidl::Provider > prov(manager_->addProvider(uri)); + if (primary) { + primaryProviders_.push_back(prov); + } +} + +bool TypeManager::foundAtPrimaryProvider(OUString const & name) const { + if (name.isEmpty()) { + return !primaryProviders_.empty(); + } + for (const rtl::Reference< unoidl::Provider >& xProvider : primaryProviders_) + { + if (xProvider->findEntity(name).is()) { + return true; + } + } + if (!manager_->findEntity(name).is()) { + throw CannotDumpException("Unknown entity '" + name + "'"); + } + return false; +} + +codemaker::UnoType::Sort TypeManager::getSort( + OUString const & name, rtl::Reference< unoidl::Entity > * entity, + rtl::Reference< unoidl::MapCursor > * cursor) const +{ + if (name.isEmpty()) { + if (cursor != nullptr) { + *cursor = manager_->createCursor(""); + } + return codemaker::UnoType::Sort::Module; + } + if (name == "void") { + return codemaker::UnoType::Sort::Void; + } + if (name == "boolean") { + return codemaker::UnoType::Sort::Boolean; + } + if (name == "byte") { + return codemaker::UnoType::Sort::Byte; + } + if (name == "short") { + return codemaker::UnoType::Sort::Short; + } + if (name == "unsigned short") { + return codemaker::UnoType::Sort::UnsignedShort; + } + if (name == "long") { + return codemaker::UnoType::Sort::Long; + } + if (name == "unsigned long") { + return codemaker::UnoType::Sort::UnsignedLong; + } + if (name == "hyper") { + return codemaker::UnoType::Sort::Hyper; + } + if (name == "unsigned hyper") { + return codemaker::UnoType::Sort::UnsignedHyper; + } + if (name == "float") { + return codemaker::UnoType::Sort::Float; + } + if (name == "double") { + return codemaker::UnoType::Sort::Double; + } + if (name == "char") { + return codemaker::UnoType::Sort::Char; + } + if (name == "string") { + return codemaker::UnoType::Sort::String; + } + if (name == "type") { + return codemaker::UnoType::Sort::Type; + } + if (name == "any") { + return codemaker::UnoType::Sort::Any; + } + if (name.startsWith("[")) { + return codemaker::UnoType::Sort::Sequence; + } + if (name.indexOf('<') != -1) { + return codemaker::UnoType::Sort::InstantiatedPolymorphicStruct; + } + rtl::Reference< unoidl::Entity > ent(manager_->findEntity(name)); + if (!ent.is()) { + throw CannotDumpException("Unknown entity '" + name + "'"); + } + if (entity != nullptr) { + *entity = ent; + } + switch (ent->getSort()) { + case unoidl::Entity::SORT_MODULE: + if (cursor != nullptr) { + *cursor = manager_->createCursor(name); + } + return codemaker::UnoType::Sort::Module; + case unoidl::Entity::SORT_ENUM_TYPE: + return codemaker::UnoType::Sort::Enum; + case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE: + return codemaker::UnoType::Sort::PlainStruct; + case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE: + return codemaker::UnoType::Sort::PolymorphicStructTemplate; + case unoidl::Entity::SORT_EXCEPTION_TYPE: + return codemaker::UnoType::Sort::Exception; + case unoidl::Entity::SORT_INTERFACE_TYPE: + return codemaker::UnoType::Sort::Interface; + case unoidl::Entity::SORT_TYPEDEF: + return codemaker::UnoType::Sort::Typedef; + case unoidl::Entity::SORT_CONSTANT_GROUP: + return codemaker::UnoType::Sort::ConstantGroup; + case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE: + return codemaker::UnoType::Sort::SingleInterfaceBasedService; + case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE: + return codemaker::UnoType::Sort::AccumulationBasedService; + case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON: + return codemaker::UnoType::Sort::InterfaceBasedSingleton; + case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON: + return codemaker::UnoType::Sort::ServiceBasedSingleton; + default: + for (;;) { std::abort(); } // this cannot happen + } +} + +codemaker::UnoType::Sort TypeManager::decompose( + std::u16string_view name, bool resolveTypedefs, OUString * nucleus, + sal_Int32 * rank, std::vector< OUString > * arguments, + rtl::Reference< unoidl::Entity > * entity) const +{ + sal_Int32 k; + std::vector< OString > args; + OUString n = b2u(codemaker::UnoType::decompose(u2b(name), &k, &args)); + for (;;) { + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort s = getSort(n, &ent); + if (args.empty() + != (s != codemaker::UnoType::Sort::PolymorphicStructTemplate)) + { + throw CannotDumpException( + "template arguments mismatch for \"" + n + + "\" resolved from \"" + name + "\""); + } + switch (s) { + case codemaker::UnoType::Sort::Typedef: + if (resolveTypedefs) { + n = dynamic_cast<unoidl::TypedefEntity&>(*ent).getType(); + while (n.startsWith("[]")) { + ++k; //TODO: overflow + n = n.copy(std::strlen("[]")); + } + break; + } + [[fallthrough]]; + case codemaker::UnoType::Sort::Void: + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::Exception: + case codemaker::UnoType::Sort::Interface: + if (nucleus != nullptr) { + *nucleus = n; + } + if (rank != nullptr) { + *rank = k; + } + if (arguments != nullptr) { + arguments->clear(); + } + if (entity != nullptr) { + *entity = ent; + } + return s; + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + if (args.size() + != (dynamic_cast<unoidl::PolymorphicStructTypeTemplateEntity&>(*ent). + getTypeParameters().size())) + { + throw CannotDumpException( + "bad number of template arguments for \"" + n + + "\" resolved from \"" + name + "\""); + } + if (nucleus != nullptr) { + *nucleus = n; + } + if (rank != nullptr) { + *rank = k; + } + if (arguments != nullptr) { + arguments->clear(); + for (const OString& rArg : args) + { + arguments->push_back(b2u(rArg)); + } + } + if (entity != nullptr) { + *entity = ent; + } + return + codemaker::UnoType::Sort::InstantiatedPolymorphicStruct; + case codemaker::UnoType::Sort::Sequence: + for (;;) std::abort(); // this cannot happen + default: + throw CannotDumpException( + "unexpected \"" + n + "\" resolved from \"" + name + + "\"in call to TypeManager::decompose"); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/codemaker/unotype.cxx b/codemaker/source/codemaker/unotype.cxx new file mode 100644 index 000000000..8c25ac8ae --- /dev/null +++ b/codemaker/source/codemaker/unotype.cxx @@ -0,0 +1,70 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <codemaker/unotype.hxx> + +#include <osl/diagnose.h> +#include <rtl/string.hxx> +#include <sal/types.h> + + +OString codemaker::UnoType::decompose( + OString const & type, sal_Int32 * rank, + std::vector< OString > * arguments) +{ + sal_Int32 len = type.getLength(); + sal_Int32 i = 0; + while (len - i > 1 && type[i + 1] == ']') { + i += 2; + } + if (rank != nullptr) { + *rank = i / 2; + } + sal_Int32 j = arguments == nullptr ? -1 : type.indexOf('<', i); + if (j < 0) { + return type.copy(i); + } + sal_Int32 k = j; + do { + ++k; // skip '<' or ',' + sal_Int32 l = k; + for (sal_Int32 level = 0; l != len; ++l) { + char c = type[l]; + if (c == ',') { + if (level == 0) { + break; + } + } else if (c == '<') { + ++level; + } else if (c == '>') { + if (level == 0) { + break; + } + --level; + } + } + arguments->push_back(type.copy(k, l - k)); + k = l; + } while (k != len && type[k] != '>'); + OSL_ASSERT(k == len - 1 && type[k] == '>'); + return type.copy(i, j - i); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/commoncpp/commoncpp.cxx b/codemaker/source/commoncpp/commoncpp.cxx new file mode 100644 index 000000000..117afaca2 --- /dev/null +++ b/codemaker/source/commoncpp/commoncpp.cxx @@ -0,0 +1,299 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <codemaker/commoncpp.hxx> + +#include <codemaker/options.hxx> +#include <codemaker/typemanager.hxx> +#include <codemaker/unotype.hxx> + +#include <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <o3tl/string_view.hxx> + +#include <vector> + +namespace codemaker::cpp { + +OString scopedCppName(OString const & type, bool ns_alias) +{ + char c('/'); + sal_Int32 nPos = type.lastIndexOf( c ); + if (nPos == -1) { + nPos = type.lastIndexOf( '.' ); + if (nPos == -1) + return type; + + c = '.'; + } + + OStringBuffer tmpBuf(type.getLength()*2); + nPos = 0; + do + { + tmpBuf.append(OString::Concat("::") + o3tl::getToken(type, 0, c, nPos)); + } while( nPos != -1 ); + + OString s(tmpBuf.makeStringAndClear()); + if (ns_alias && s.startsWith("::com::sun::star::", &s)) + { + s = "::css::" + s; // nicer shorthand + } + + return s; +} + +OString translateUnoToCppType( + codemaker::UnoType::Sort sort, std::u16string_view nucleus) +{ + OStringBuffer buf; + if (sort <= codemaker::UnoType::Sort::Any) { + static char const * const cppTypes[static_cast<int>(codemaker::UnoType::Sort::Any) + 1] = { + "void", "::sal_Bool", "::sal_Int8", "::sal_Int16", "::sal_uInt16", + "::sal_Int32", "::sal_uInt32", "::sal_Int64", "::sal_uInt64", + "float", "double", "::sal_Unicode", "rtl::OUString", + "::css::uno::Type", "::css::uno::Any" }; + buf.append(cppTypes[static_cast<int>(sort)]); + } else { + if (sort == codemaker::UnoType::Sort::Interface + && nucleus == u"com.sun.star.uno.XInterface") + { + buf.append("::css::uno::XInterface"); + } else { + //TODO: check that nucleus is a valid (UTF-8) identifier + buf.append(u2b(nucleus)); + } + } + return buf.makeStringAndClear(); +} + +OString translateUnoToCppIdentifier( + OString const & unoIdentifier, std::string_view prefix, + IdentifierTranslationMode transmode, OString const * forbidden) +{ + if (// Keywords: + unoIdentifier == "asm" + || unoIdentifier == "auto" + || unoIdentifier == "bool" + || unoIdentifier == "break" + || unoIdentifier == "case" + || unoIdentifier == "catch" + || unoIdentifier == "char" + || unoIdentifier == "class" + || unoIdentifier == "const" + /* unoIdentifier == "const_cast" */ + || unoIdentifier == "continue" + || unoIdentifier == "default" + || unoIdentifier == "delete" + || unoIdentifier == "do" + || unoIdentifier == "double" + /* unoIdentifier == "dynamic_cast" */ + || unoIdentifier == "else" + || unoIdentifier == "enum" + || unoIdentifier == "explicit" + || unoIdentifier == "export" + || unoIdentifier == "extern" + || unoIdentifier == "false" + || unoIdentifier == "float" + || unoIdentifier == "for" + || unoIdentifier == "friend" + || unoIdentifier == "goto" + || unoIdentifier == "if" + || unoIdentifier == "inline" + || unoIdentifier == "int" + || unoIdentifier == "long" + || unoIdentifier == "mutable" + || unoIdentifier == "namespace" + || unoIdentifier == "new" + || unoIdentifier == "operator" + || unoIdentifier == "private" + || unoIdentifier == "protected" + || unoIdentifier == "public" + || unoIdentifier == "register" + /* unoIdentifier == "reinterpret_cast" */ + || unoIdentifier == "return" + || unoIdentifier == "short" + || unoIdentifier == "signed" + || unoIdentifier == "sizeof" + || unoIdentifier == "static" + /* unoIdentifier == "static_cast" */ + || unoIdentifier == "struct" + || unoIdentifier == "switch" + || unoIdentifier == "template" + || unoIdentifier == "this" + || unoIdentifier == "throw" + || unoIdentifier == "true" + || unoIdentifier == "try" + || unoIdentifier == "typedef" + || unoIdentifier == "typeid" + || unoIdentifier == "typename" + || unoIdentifier == "union" + || unoIdentifier == "unsigned" + || unoIdentifier == "using" + || unoIdentifier == "virtual" + || unoIdentifier == "void" + || unoIdentifier == "volatile" + /* unoIdentifier == "wchar_t" */ + || unoIdentifier == "while" + // Alternative representations: + || unoIdentifier == "and" + /* unoIdentifier == "and_eq" */ + || unoIdentifier == "bitand" + || unoIdentifier == "bitor" + || unoIdentifier == "compl" + || unoIdentifier == "not" + /* unoIdentifier == "not_eq" */ + || unoIdentifier == "or" + /* unoIdentifier == "or_eq" */ + || unoIdentifier == "xor" + /* unoIdentifier == "xor_eq" */ + // Standard macros: + || (unoIdentifier == "BUFSIZ" + || unoIdentifier == "CLOCKS_PER_SEC" + || unoIdentifier == "EDOM" + || unoIdentifier == "EOF" + || unoIdentifier == "ERANGE" + || unoIdentifier == "EXIT_FAILURE" + || unoIdentifier == "EXIT_SUCCESS" + || unoIdentifier == "FILENAME_MAX" + || unoIdentifier == "FOPEN_MAX" + || unoIdentifier == "HUGE_VAL" + || unoIdentifier == "LC_ALL" + || unoIdentifier == "LC_COLLATE" + || unoIdentifier == "LC_CTYPE" + || unoIdentifier == "LC_MONETARY" + || unoIdentifier == "LC_NUMERIC" + || unoIdentifier == "LC_TIME" + || unoIdentifier == "L_tmpnam" + || unoIdentifier == "MB_CUR_MAX" + || unoIdentifier == "NULL" + || unoIdentifier == "RAND_MAX" + || unoIdentifier == "SEEK_CUR" + || unoIdentifier == "SEEK_END" + || unoIdentifier == "SEEK_SET" + || unoIdentifier == "SIGABRT" + || unoIdentifier == "SIGFPE" + || unoIdentifier == "SIGILL" + || unoIdentifier == "SIGINT" + || unoIdentifier == "SIGSEGV" + || unoIdentifier == "SIGTERM" + || unoIdentifier == "SIG_DFL" + || unoIdentifier == "SIG_ERR" + || unoIdentifier == "SIG_IGN" + || unoIdentifier == "TMP_MAX" + || unoIdentifier == "WCHAR_MAX" + || unoIdentifier == "WCHAR_MIN" + || unoIdentifier == "WEOF" + /* unoIdentifier == "_IOFBF" */ + /* unoIdentifier == "_IOLBF" */ + /* unoIdentifier == "_IONBF" */ + || unoIdentifier == "assert" + || unoIdentifier == "errno" + || unoIdentifier == "offsetof" + || unoIdentifier == "setjmp" + || unoIdentifier == "stderr" + || unoIdentifier == "stdin" + || unoIdentifier == "stdout" + /* unoIdentifier == "va_arg" */ + /* unoIdentifier == "va_end" */ + /* unoIdentifier == "va_start" */ + // Standard values: + || unoIdentifier == "CHAR_BIT" + || unoIdentifier == "CHAR_MAX" + || unoIdentifier == "CHAR_MIN" + || unoIdentifier == "DBL_DIG" + || unoIdentifier == "DBL_EPSILON" + || unoIdentifier == "DBL_MANT_DIG" + || unoIdentifier == "DBL_MAX" + || unoIdentifier == "DBL_MAX_10_EXP" + || unoIdentifier == "DBL_MAX_EXP" + || unoIdentifier == "DBL_MIN" + || unoIdentifier == "DBL_MIN_10_EXP" + || unoIdentifier == "DBL_MIN_EXP" + || unoIdentifier == "FLT_DIG" + || unoIdentifier == "FLT_EPSILON" + || unoIdentifier == "FLT_MANT_DIG" + || unoIdentifier == "FLT_MAX" + || unoIdentifier == "FLT_MAX_10_EXP" + || unoIdentifier == "FLT_MAX_EXP" + || unoIdentifier == "FLT_MIN" + || unoIdentifier == "FLT_MIN_10_EXP" + || unoIdentifier == "FLT_MIN_EXP" + || unoIdentifier == "FLT_RADIX" + || unoIdentifier == "FLT_ROUNDS" + || unoIdentifier == "INT_MAX" + || unoIdentifier == "INT_MIN" + || unoIdentifier == "LDBL_DIG" + || unoIdentifier == "LDBL_EPSILON" + || unoIdentifier == "LDBL_MANT_DIG" + || unoIdentifier == "LDBL_MAX" + || unoIdentifier == "LDBL_MAX_10_EXP" + || unoIdentifier == "LDBL_MAX_EXP" + || unoIdentifier == "LDBL_MIN" + || unoIdentifier == "LDBL_MIN_10_EXP" + || unoIdentifier == "LDBL_MIN_EXP" + || unoIdentifier == "LONG_MAX" + || unoIdentifier == "LONG_MIN" + || unoIdentifier == "MB_LEN_MAX" + || unoIdentifier == "SCHAR_MAX" + || unoIdentifier == "SCHAR_MIN" + || unoIdentifier == "SHRT_MAX" + || unoIdentifier == "SHRT_MIN" + || unoIdentifier == "UCHAR_MAX" + || unoIdentifier == "UINT_MAX" + || unoIdentifier == "ULONG_MAX" + || unoIdentifier == "USHRT_MAX") + || (transmode == IdentifierTranslationMode::Global + && (// Standard types: + /* unoIdentifier == "clock_t" */ + /* unoIdentifier == "div_t" */ + unoIdentifier == "FILE" + /* unoIdentifier == "fpos_t" */ + /* unoIdentifier == "jmp_buf" */ + || unoIdentifier == "lconv" + /* unoIdentifier == "ldiv_t" */ + /* unoIdentifier == "mbstate_t" */ + /* unoIdentifier == "ptrdiff_t" */ + /* unoIdentifier == "sig_atomic_t" */ + /* unoIdentifier == "size_t" */ + /* unoIdentifier == "time_t" */ + || unoIdentifier == "tm" + /* unoIdentifier == "va_list" */ + /* unoIdentifier == "wctrans_t" */ + /* unoIdentifier == "wctype_t" */ + /* unoIdentifier == "wint_t" */ + // Standard namespaces: + || unoIdentifier == "std")) + // Others: + || unoIdentifier == "NDEBUG" + || (forbidden != nullptr && unoIdentifier == *forbidden) ) + { + return OString::Concat(prefix) + "_" + unoIdentifier; + } else { + return unoIdentifier; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/commonjava/commonjava.cxx b/codemaker/source/commonjava/commonjava.cxx new file mode 100644 index 000000000..6782789ae --- /dev/null +++ b/codemaker/source/commonjava/commonjava.cxx @@ -0,0 +1,135 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <sal/config.h> + +#include <codemaker/commonjava.hxx> + +#include <codemaker/options.hxx> +#include <codemaker/typemanager.hxx> +#include <codemaker/unotype.hxx> + +#include <rtl/strbuf.h> +#include <rtl/string.h> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include <vector> + +namespace codemaker::java { + +OString translateUnoToJavaType( + codemaker::UnoType::Sort sort, std::string_view nucleus, bool referenceType) +{ + OStringBuffer buf(128); + if (sort <= codemaker::UnoType::Sort::Any) { + OString const javaTypes[static_cast<int>(codemaker::UnoType::Sort::Any) + 1][2] = { + { "void", "java/lang/Void" }, + { "boolean", "java/lang/Boolean" }, + { "byte", "java/lang/Byte" }, + { "short", "java/lang/Short" }, + { "short", "java/lang/Short" }, + { "int", "java/lang/Integer" }, + { "int", "java/lang/Integer" }, + { "long", "java/lang/Long" }, + { "long", "java/lang/Long" }, + { "float", "java/lang/Float" }, + { "double", "java/lang/Double" }, + { "char", "java/lang/Character" }, + { "java/lang/String", "java/lang/String" }, + { "com/sun/star/uno/Type", "com/sun/star/uno/Type" }, + { "java/lang/Object", "java/lang/Object" } }; + buf.append(javaTypes[static_cast<int>(sort)][referenceType]); + } else { + if (nucleus == "com/sun/star/uno/XInterface") { + buf.append("java/lang/Object"); + } else { + //TODO: check that nucleus is a valid (Java-modified UTF-8) + // identifier + buf.append(nucleus); + } + } + return buf.makeStringAndClear(); +} + +OString translateUnoToJavaIdentifier( + OString const & identifier, std::string_view prefix) +{ + if (identifier == "abstract" + || identifier == "assert" // since Java 1.4 + || identifier == "boolean" + || identifier == "break" + || identifier == "byte" + || identifier == "case" + || identifier == "catch" + || identifier == "char" + || identifier == "class" + || identifier == "const" + || identifier == "continue" + || identifier == "default" + || identifier == "do" + || identifier == "double" + || identifier == "else" + || identifier == "enum" // probable addition in Java 1.5 + || identifier == "extends" + || identifier == "final" + || identifier == "finally" + || identifier == "float" + || identifier == "for" + || identifier == "goto" + || identifier == "if" + || identifier == "implements" + || identifier == "import" + || identifier == "instanceof" + || identifier == "int" + || identifier == "interface" + || identifier == "long" + || identifier == "native" + || identifier == "new" + || identifier == "package" + || identifier == "private" + || identifier == "protected" + || identifier == "public" + || identifier == "return" + || identifier == "short" + || identifier == "static" + || identifier == "strictfp" + || identifier == "super" + || identifier == "switch" + || identifier == "synchronized" + || identifier == "this" + || identifier == "throw" + || identifier == "throws" + || identifier == "transient" + || identifier == "try" + || identifier == "void" + || identifier == "volatile" + || identifier == "while") + { + return OString::Concat(prefix) + "_" + identifier; + } else { + return identifier; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/cppumaker.cxx b/codemaker/source/cppumaker/cppumaker.cxx new file mode 100644 index 000000000..b2556655b --- /dev/null +++ b/codemaker/source/cppumaker/cppumaker.cxx @@ -0,0 +1,110 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <vector> + +#include <codemaker/generatedtypeset.hxx> +#include <codemaker/typemanager.hxx> +#include <rtl/ref.hxx> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <sal/main.h> +#include <sal/types.h> +#include <unoidl/unoidl.hxx> +#include <o3tl/string_view.hxx> + +#include "cppuoptions.hxx" +#include "cpputype.hxx" + +// coverity[tainted_data] - this is a build time tool +SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { + CppuOptions options; + try { + if (!options.initOptions(argc, argv)) { + return EXIT_FAILURE; + } + + rtl::Reference typeMgr(new TypeManager); + for (const OString& f :options.getExtraInputFiles()) + { + typeMgr->loadProvider(convertToFileUrl(f), false); + } + for (const OString& f : options.getInputFiles()) + { + typeMgr->loadProvider(convertToFileUrl(f), true); + } + codemaker::GeneratedTypeSet generated; + if (options.isValid("-T")) { + OUString names(b2u(options.getOption("-T"))); + for (sal_Int32 i = 0; i != -1;) { + std::u16string_view name(o3tl::getToken(names, 0, ';', i)); + if (!name.empty()) { + produce( + OUString(name == u"*" + ? u"" + : o3tl::ends_with(name, u".*") + ? name.substr(0, name.size() - std::strlen(".*")) + : name), + typeMgr, generated, options); + } + } + } else { + produce("", typeMgr, generated, options); + } + if (!options.isValid("-nD")) { + // C++ header files generated for the following UNO types are + // included in header files in cppu/inc/com/sun/star/uno (Any.hxx, + // Reference.hxx, Type.h), so it seems best to always generate those + // C++ header files: + produce( + "com.sun.star.uno.RuntimeException", typeMgr, generated, + options); + produce( + "com.sun.star.uno.TypeClass", typeMgr, generated, options); + produce( + "com.sun.star.uno.XInterface", typeMgr, generated, options); + } + } catch (CannotDumpException & e) { + std::cerr << "ERROR: " << e.getMessage() << '\n'; + return EXIT_FAILURE; + } catch (unoidl::NoSuchFileException & e) { + std::cerr << "ERROR: No such file <" << e.getUri() << ">\n"; + return EXIT_FAILURE; + } catch (unoidl::FileFormatException & e) { + std::cerr + << "ERROR: Bad format of <" << e.getUri() << ">, \"" + << e.getDetail() << "\"\n"; + return EXIT_FAILURE; + } catch (IllegalArgument& e) { + std::cerr << "Illegal option " << e.m_message << '\n'; + return EXIT_FAILURE; + } catch (std::exception& e) { + std::cerr << "Failure " << e.what() << '\n'; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/cppuoptions.cxx b/codemaker/source/cppumaker/cppuoptions.cxx new file mode 100644 index 000000000..0a2ad9623 --- /dev/null +++ b/codemaker/source/cppumaker/cppuoptions.cxx @@ -0,0 +1,325 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <string.h> + +#include "cppuoptions.hxx" + +#ifdef SAL_UNX +#define SEPARATOR '/' +#else +#define SEPARATOR '\\' +#endif + +bool CppuOptions::initOptions(int ac, char* av[], bool bCmdFile) +{ + bool ret = true; + int i=0; + + if (!bCmdFile) + { + bCmdFile = true; + + OString name(av[0]); + sal_Int32 index = name.lastIndexOf(SEPARATOR); + m_program = name.copy(index > 0 ? index+1 : 0); + + if (ac < 2) + { + fprintf(stderr, "%s", prepareHelp().getStr()); + ret = false; + } + + i = 1; + } + else + { + i = 0; + } + + char *s=nullptr; + for( ; i < ac; i++) + { + if (av[i][0] == '-') + { + switch (av[i][1]) + { + case 'O': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } + else + { + OString tmp("'-O', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i+1] + "'"; + } + + throw IllegalArgument(tmp); + } + } + else + { + s = av[i] + 2; + } + + m_options["-O"] = OString(s); + break; + case 'n': + if (av[i][2] != 'D' || av[i][3] != '\0') + { + OString tmp = OString::Concat("'-nD', please check your input '") + av[i] + "'"; + throw IllegalArgument(tmp); + } + + m_options["-nD"] = OString(); + break; + case 'T': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } + else + { + OString tmp("'-T', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i+1] + "'"; + } + + throw IllegalArgument(tmp); + } + } + else + { + s = av[i] + 2; + } + + if (m_options.count("-T") > 0) + { + OString tmp = m_options["-T"] + ";" + s; + m_options["-T"] = tmp; + } + else + { + m_options["-T"] = OString(s); + } + break; + case 'L': + if (av[i][2] != '\0') + { + OString tmp("'-L', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + if (isValid("-C") || isValid("-CS")) + { + throw IllegalArgument("'-L' could not be combined with '-C' or '-CS' option"); + } + m_options["-L"] = OString(); + break; + case 'C': + if (av[i][2] == 'S') + { + if (av[i][3] != '\0') + { + OString tmp("'-CS', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + if (isValid("-L") || isValid("-C")) + { + throw IllegalArgument("'-CS' could not be combined with '-L' or '-C' option"); + } + m_options["-CS"] = OString(); + break; + } + else if (av[i][2] != '\0') + { + OString tmp("'-C', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + if (isValid("-L") || isValid("-CS")) + { + throw IllegalArgument("'-C' could not be combined with '-L' or '-CS' option"); + } + m_options["-C"] = OString(); + break; + case 'G': + if (av[i][2] == 'c') + { + if (av[i][3] != '\0') + { + OString tmp("'-Gc', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + m_options["-Gc"] = OString(); + break; + } + else if (av[i][2] != '\0') + { + OString tmp("'-G', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + m_options["-G"] = OString(); + break; + case 'X': // support for eXtra type rdbs + { + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } + else + { + OString tmp("'-X', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i+1] + "'"; + } + + throw IllegalArgument(tmp); + } + } + else + { + s = av[i] + 2; + } + + m_extra_input_files.emplace_back(s ); + break; + } + + default: + throw IllegalArgument(OString::Concat("the option is unknown") + av[i]); + } + } else + { + if (av[i][0] == '@') + { + FILE* cmdFile = fopen(av[i]+1, "r"); + if( cmdFile == nullptr ) + { + fprintf(stderr, "%s", prepareHelp().getStr()); + ret = false; + } + else + { + int rargc=0; + char* rargv[512]; + char buffer[512]; + + while (fscanf(cmdFile, "%511s", buffer) != EOF && rargc < 512) + { + rargv[rargc]= strdup(buffer); + rargc++; + } + fclose(cmdFile); + + ret = initOptions(rargc, rargv, bCmdFile); + + for (int j=0; j < rargc; j++) + { + free(rargv[j]); + } + } + } + else + { + m_inputFiles.emplace_back(av[i]); + } + } + } + + return ret; +} + +OString CppuOptions::prepareHelp() +{ + OString help = "\nusing: " + + m_program + " [-options] file_1 ... file_n\nOptions:\n" + " -O<path> = path describes the root directory for the generated output.\n" + " The output directory tree is generated under this directory.\n" + " -T<name> = name specifies a type or a list of types. The output for this\n" + " [t1;...] type is generated. If no '-T' option is specified,\n" + " then output for all types is generated.\n" + " Example: 'com.sun.star.uno.XInterface' is a valid type.\n" + " -L = UNO type functions are generated lightweight, that means only\n" + " the name and typeclass are given and everything else is retrieved\n" + " from the type library dynamically. The default is that UNO type\n" + " functions provides enough type information for bootstrapping C++.\n" + " '-L' should be the default for external components.\n" + " -C = UNO type functions are generated comprehensive that means all\n" + " necessary information is available for bridging the type in UNO.\n" + " -nD = no dependent types are generated.\n" + " -G = generate only target files which does not exists.\n" + " -Gc = generate only target files which content will be changed.\n" + " -X<file> = extra types which will not be taken into account for generation.\n\n" + + prepareVersion(); + + return help; +} + +OString CppuOptions::prepareVersion() const +{ + OString version = m_program + " Version 2.0\n\n"; + return version; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/cppuoptions.hxx b/codemaker/source/cppumaker/cppuoptions.hxx new file mode 100644 index 000000000..f3d65e4fa --- /dev/null +++ b/codemaker/source/cppumaker/cppuoptions.hxx @@ -0,0 +1,41 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <codemaker/options.hxx> + +class CppuOptions : public Options +{ +public: + CppuOptions() + : Options() + { + } + + bool initOptions(int ac, char* av[], bool bCmdFile = false) override; + + OString prepareHelp() override; + + OString prepareVersion() const; + +protected: +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/cpputype.cxx b/codemaker/source/cppumaker/cpputype.cxx new file mode 100644 index 000000000..03fcd033b --- /dev/null +++ b/codemaker/source/cppumaker/cpputype.cxx @@ -0,0 +1,4105 @@ +/* -*- 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/. +* + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <algorithm> +#include <cassert> +#include <cstdlib> +#include <map> +#include <set> +#include <string_view> +#include <memory> +#include <utility> +#include <vector> +#include <iostream> + +#include <rtl/alloc.h> +#include <rtl/ref.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <rtl/strbuf.hxx> +#include <unoidl/unoidl.hxx> + +#include <codemaker/commoncpp.hxx> +#include <codemaker/exceptiontree.hxx> +#include <codemaker/generatedtypeset.hxx> +#include <codemaker/typemanager.hxx> +#include <codemaker/unotype.hxx> + +#include "cpputype.hxx" +#include "cppuoptions.hxx" +#include "dependencies.hxx" +#include "dumputils.hxx" +#include "includes.hxx" + +namespace +{ + +bool isBootstrapType(OUString const & name) +{ + static char const * const names[] = { + "com.sun.star.beans.Property", + "com.sun.star.beans.PropertyAttribute", + "com.sun.star.beans.PropertyChangeEvent", + "com.sun.star.beans.PropertyState", + "com.sun.star.beans.PropertyValue", + "com.sun.star.beans.XFastPropertySet", + "com.sun.star.beans.XMultiPropertySet", + "com.sun.star.beans.XPropertiesChangeListener", + "com.sun.star.beans.XPropertyAccess", + "com.sun.star.beans.XPropertyChangeListener", + "com.sun.star.beans.XPropertySet", + "com.sun.star.beans.XPropertySetInfo", + "com.sun.star.beans.XPropertySetOption", + "com.sun.star.beans.XVetoableChangeListener", + "com.sun.star.bridge.UnoUrlResolver", + "com.sun.star.bridge.XUnoUrlResolver", + "com.sun.star.connection.SocketPermission", + "com.sun.star.container.XElementAccess", + "com.sun.star.container.XEnumeration", + "com.sun.star.container.XEnumerationAccess", + "com.sun.star.container.XHierarchicalNameAccess", + "com.sun.star.container.XNameAccess", + "com.sun.star.container.XNameContainer", + "com.sun.star.container.XNameReplace", + "com.sun.star.container.XSet", + "com.sun.star.io.FilePermission", + "com.sun.star.io.IOException", + "com.sun.star.lang.DisposedException", + "com.sun.star.lang.EventObject", + "com.sun.star.lang.WrappedTargetRuntimeException", + "com.sun.star.lang.XComponent", + "com.sun.star.lang.XEventListener", + "com.sun.star.lang.XInitialization", + "com.sun.star.lang.XMultiComponentFactory", + "com.sun.star.lang.XMultiServiceFactory", + "com.sun.star.lang.XServiceInfo", + "com.sun.star.lang.XSingleComponentFactory", + "com.sun.star.lang.XSingleServiceFactory", + "com.sun.star.lang.XTypeProvider", + "com.sun.star.loader.XImplementationLoader", + "com.sun.star.reflection.FieldAccessMode", + "com.sun.star.reflection.MethodMode", + "com.sun.star.reflection.ParamInfo", + "com.sun.star.reflection.ParamMode", + "com.sun.star.reflection.TypeDescriptionSearchDepth", + "com.sun.star.reflection.XCompoundTypeDescription", + "com.sun.star.reflection.XEnumTypeDescription", + "com.sun.star.reflection.XIdlArray", + "com.sun.star.reflection.XIdlClass", + "com.sun.star.reflection.XIdlField", + "com.sun.star.reflection.XIdlField2", + "com.sun.star.reflection.XIdlMethod", + "com.sun.star.reflection.XIdlReflection", + "com.sun.star.reflection.XIndirectTypeDescription", + "com.sun.star.reflection.XInterfaceAttributeTypeDescription", + "com.sun.star.reflection.XInterfaceAttributeTypeDescription2", + "com.sun.star.reflection.XInterfaceMemberTypeDescription", + "com.sun.star.reflection.XInterfaceMethodTypeDescription", + "com.sun.star.reflection.XInterfaceTypeDescription", + "com.sun.star.reflection.XInterfaceTypeDescription2", + "com.sun.star.reflection.XMethodParameter", + "com.sun.star.reflection.XStructTypeDescription", + "com.sun.star.reflection.XTypeDescription", + "com.sun.star.reflection.XTypeDescriptionEnumeration", + "com.sun.star.reflection.XTypeDescriptionEnumerationAccess", + "com.sun.star.registry.RegistryKeyType", + "com.sun.star.registry.RegistryValueType", + "com.sun.star.registry.XImplementationRegistration", + "com.sun.star.registry.XRegistryKey", + "com.sun.star.registry.XSimpleRegistry", + "com.sun.star.security.RuntimePermission", + "com.sun.star.security.XAccessControlContext", + "com.sun.star.security.XAccessController", + "com.sun.star.security.XAction", + "com.sun.star.uno.DeploymentException", + "com.sun.star.uno.RuntimeException", + "com.sun.star.uno.TypeClass", + "com.sun.star.uno.Uik", + "com.sun.star.uno.XAdapter", + "com.sun.star.uno.XAggregation", + "com.sun.star.uno.XComponentContext", + "com.sun.star.uno.XCurrentContext", + "com.sun.star.uno.XInterface", + "com.sun.star.uno.XReference", + "com.sun.star.uno.XUnloadingPreference", + "com.sun.star.uno.XWeak", + "com.sun.star.util.XMacroExpander" }; + // cf. cppuhelper/unotypes/Makefile UNOTYPES (plus missing dependencies) + auto const pred = [&name](const char* aName) { + return name.equalsAscii(aName); + }; + return std::any_of(std::begin(names), std::end(names), pred); +} + +class CppuType +{ +public: + CppuType(OUString name, rtl::Reference< TypeManager > const & typeMgr); + + virtual ~CppuType() {} + + CppuType(const CppuType&) = delete; + const CppuType& operator=(const CppuType&) = delete; + + void dump(CppuOptions const & options); + + void dumpFile( + std::u16string_view uri, std::u16string_view name, bool hpp, + CppuOptions const & options); + + void dumpDependedTypes( + codemaker::GeneratedTypeSet & generated, CppuOptions const & options) const; + + virtual void dumpHdlFile( + FileStream & out, codemaker::cppumaker::Includes & includes) { + dumpHFileContent(out, includes); + } + + virtual void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) = 0; + + OUString dumpHeaderDefine(FileStream& o, std::u16string_view extension) const; + + void dumpGetCppuType(FileStream & out); + + virtual void dumpLightGetCppuType(FileStream & out); + + virtual void dumpNormalGetCppuType(FileStream &) { + assert(false); // this cannot happen + } + + virtual void dumpComprehensiveGetCppuType(FileStream &) { + assert(false); // this cannot happen + } + + void dumpType( + FileStream & out, std::u16string_view name, bool isConst = false, + bool isRef = false, bool native = false, bool cppuUnoType = false) + const; + + OUString getTypeClass(OUString const & name, bool cStyle = false); + + void dumpCppuGetType( + FileStream & out, std::u16string_view name, OUString const * ownName = nullptr) const; + + sal_uInt32 getInheritedMemberCount(); + + void inc(sal_Int32 num=4); + void dec(sal_Int32 num=4); + OUString indent() const; +protected: + virtual sal_uInt32 checkInheritedMemberCount() const { + assert(false); // this cannot happen + return 0; + } + + bool passByReference(OUString const & name) const; + + bool canBeWarnUnused(OUString const & name) const; + bool canBeWarnUnused(OUString const & name, int depth) const; + + OUString resolveOuterTypedefs(OUString const & name) const; + + OUString resolveAllTypedefs(std::u16string_view name) const; + + codemaker::cpp::IdentifierTranslationMode isGlobal() const; + + virtual void dumpDeclaration(FileStream &) { + assert(false); // this cannot happen + } + + virtual void dumpFiles(OUString const & uri, CppuOptions const & options); + + virtual void addLightGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const; + + virtual void addNormalGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const; + + virtual void addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const; + + virtual bool isPolymorphic() const; + + virtual void dumpTemplateHead(FileStream &) const {} + + virtual void dumpTemplateParameters(FileStream &) const {} + + void dumpGetCppuTypePreamble(FileStream & out); + + void dumpGetCppuTypePostamble(FileStream & out); + + void addDefaultHIncludes(codemaker::cppumaker::Includes & includes) const; + void addDefaultHxxIncludes(codemaker::cppumaker::Includes & includes) const; + + void dumpInitializer( + FileStream & out, bool parameterized, std::u16string_view name) const; + + void dumpHFileContent( + FileStream & out, codemaker::cppumaker::Includes & includes); + +protected: + sal_uInt32 m_inheritedMemberCount; + + bool m_cppuTypeLeak; + bool m_cppuTypeDynamic; + sal_Int32 m_indentLength; + OUString name_; + OUString id_; + rtl::Reference< TypeManager > m_typeMgr; + codemaker::cppumaker::Dependencies m_dependencies; + +private: + void addGetCppuTypeIncludes(codemaker::cppumaker::Includes & includes) + const; +}; + +CppuType::CppuType( + OUString name, rtl::Reference< TypeManager > const & typeMgr): + m_inheritedMemberCount(0) + , m_cppuTypeLeak(false) + , m_cppuTypeDynamic(true) + , m_indentLength(0) + , name_(std::move(name)) + , id_(name_.copy(name_.lastIndexOf('.') + 1)) + , m_typeMgr(typeMgr) + , m_dependencies(typeMgr, name_) +{} + +void CppuType::addGetCppuTypeIncludes(codemaker::cppumaker::Includes & includes) +const +{ + if (name_ == "com.sun.star.uno.XInterface" + || name_ == "com.sun.star.uno.Exception") { + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); + } else if (m_cppuTypeLeak) { + addLightGetCppuTypeIncludes(includes); + } else if (m_cppuTypeDynamic) { + addNormalGetCppuTypeIncludes(includes); + } else { + addComprehensiveGetCppuTypeIncludes(includes); + } +} + +void CppuType::dumpFiles(OUString const & uri, CppuOptions const & options) +{ + dumpFile(uri, name_, false, options); + dumpFile(uri, name_, true, options); +} + +void CppuType::addLightGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + //TODO: Determine what is really needed, instead of relying on + // addDefaultHxxIncludes + includes.addCppuUnotypeHxx(); +} + +void CppuType::addNormalGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + //TODO: Determine what is really needed, instead of relying on + // addDefaultHxxIncludes + includes.addCppuUnotypeHxx(); +} + +void CppuType::addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + //TODO: Determine what is really needed, instead of relying on + // addDefaultHxxIncludes + includes.addCppuUnotypeHxx(); +} + +bool CppuType::isPolymorphic() const +{ + return false; +} + +void CppuType::dumpGetCppuTypePreamble(FileStream & out) +{ + if (isPolymorphic()) { + out << "namespace cppu {\n\n"; + dumpTemplateHead(out); + out << "class UnoType< "; + dumpType(out, name_); + dumpTemplateParameters(out); + out << " > {\npublic:\n"; + inc(); + out << indent() + << "static inline ::css::uno::Type const & get() {\n"; + } else { + if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) { + out << "\n\n"; + } + out << ("inline ::css::uno::Type const &" + " cppu_detail_getUnoType(SAL_UNUSED_PARAMETER "); + dumpType(out, name_, false, false, true); + out << " const *) {\n"; + } + inc(); +} + +void CppuType::dumpGetCppuTypePostamble(FileStream & out) +{ + dec(); + if (isPolymorphic()) { + out << indent() << "}\n\nprivate:\n" + << indent() << "UnoType(UnoType &); // not defined\n" + << indent() << "~UnoType(); // not defined\n" + << indent() + << "void operator =(UnoType); // not defined\n};\n\n}\n\n"; + } else { + out << "}\n\n"; + if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) { + out << "\n\n"; + } + } + dumpTemplateHead(out); + out << ("SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL" + " getCppuType(SAL_UNUSED_PARAMETER "); + dumpType(out, name_); + dumpTemplateParameters(out); + out << " const *) {\n"; + inc(); + out << indent() << "return ::cppu::UnoType< "; + dumpType(out, name_); + dumpTemplateParameters(out); + out << " >::get();\n"; + dec(); + out << indent() << "}\n"; +} + +void CppuType::dump(CppuOptions const & options) +{ + if (isBootstrapType(name_)) { + m_cppuTypeDynamic = false; + } else { + // -CS was used as an undocumented option to generate static getCppuType + // functions; since the introduction of cppu::UnoType this no longer is + // meaningful (getCppuType is just a forward to cppu::UnoType::get now), + // and -CS is handled the same way as -C now: + if (options.isValid("-L")) + m_cppuTypeLeak = true; + if (options.isValid("-C") || options.isValid("-CS")) + m_cppuTypeDynamic = false; + } + dumpFiles( + options.isValid("-O") ? b2u(options.getOption("-O")) : "", options); +} + +void CppuType::dumpFile( + std::u16string_view uri, std::u16string_view name, bool hpp, + CppuOptions const & options) +{ + OUString fileUri( + b2u(createFileNameFromType( + u2b(uri), u2b(name), hpp ? ".hpp" : ".hdl"))); + if (fileUri.isEmpty()) { + throw CannotDumpException(OUString::Concat("empty target URI for entity ") + name); + } + bool exists = fileExists(u2b(fileUri)); + if (exists && options.isValid("-G")) { + return; + } + FileStream out; + out.createTempFile(getTempDir(u2b(fileUri))); + OUString tmpUri(b2u(out.getName())); + if(!out.isValid()) { + throw CannotDumpException("cannot open " + tmpUri + " for writing"); + } + codemaker::cppumaker::Includes includes(m_typeMgr, m_dependencies, hpp); + try { + if (hpp) { + addGetCppuTypeIncludes(includes); + dumpHppFile(out, includes); + } else { + dumpHdlFile(out, includes); + } + } catch (...) { + out.close(); + // Remove existing type file if something goes wrong to ensure + // consistency: + if (fileExists(u2b(fileUri))) { + removeTypeFile(u2b(fileUri)); + } + removeTypeFile(u2b(tmpUri)); + throw; + } + out.close(); + (void)makeValidTypeFile( + u2b(fileUri), u2b(tmpUri), exists && options.isValid("-Gc")); +} + +void CppuType::dumpDependedTypes( + codemaker::GeneratedTypeSet & generated, CppuOptions const & options) const +{ + if (!options.isValid("-nD")) { + codemaker::cppumaker::Dependencies::Map const & map + = m_dependencies.getMap(); + for (const auto& entry : map) { + produce(entry.first, m_typeMgr, generated, options); + } + } +} + +OUString CppuType::dumpHeaderDefine( + FileStream & out, std::u16string_view extension) const +{ + OUString def( + "INCLUDED_" + name_.replace('.', '_').toAsciiUpperCase() + "_" + + extension); + out << "#ifndef " << def << "\n#define " << def << "\n"; + return def; +} + +void CppuType::addDefaultHIncludes(codemaker::cppumaker::Includes & includes) +const +{ + //TODO: Only include what is really needed + includes.addCppuMacrosHxx(); + if (m_typeMgr->getSort(name_) + == codemaker::UnoType::Sort::Interface) { + includes.addReference(); + } +} + +void CppuType::addDefaultHxxIncludes(codemaker::cppumaker::Includes & includes) +const +{ + //TODO: Only include what is really needed + includes.addType(); + if (m_typeMgr->getSort(name_) + == codemaker::UnoType::Sort::Interface) { + includes.addReference(); + } +} + +void CppuType::dumpInitializer( + FileStream & out, bool parameterized, std::u16string_view name) const +{ + out << "("; + if (!parameterized) { + sal_Int32 k; + std::vector< OString > args; + OUString n( + b2u(codemaker::UnoType::decompose( + u2b(resolveAllTypedefs(name)), &k, &args))); + if (k == 0) { + rtl::Reference< unoidl::Entity > ent; + switch (m_typeMgr->getSort(n, &ent)) { + case codemaker::UnoType::Sort::Boolean: + out << "false"; + break; + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + out << "0"; + break; + case codemaker::UnoType::Sort::Enum: + out << codemaker::cpp::scopedCppName(u2b(n)) << "_" + << (dynamic_cast<unoidl::EnumTypeEntity&>(*ent). + getMembers()[0].name); + break; + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + case codemaker::UnoType::Sort::Interface: + break; + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + name + + "\" in call to CppuType::dumpInitializer"); + } + } + } + out << ")"; +} + +void CppuType::dumpHFileContent( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + addDefaultHIncludes(includes); + dumpHeaderDefine(out, u"HDL"); + out << "\n"; + includes.dump(out, nullptr, false); + // 'exceptions = false' would be wrong for services/singletons, but + // those don't dump .hdl files anyway + out << ("\nnamespace com { namespace sun { namespace star { namespace uno" + " { class Type; } } } }\n\n"); + if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) { + out << "\n"; + } + dumpDeclaration(out); + if (!(name_ == "com.sun.star.uno.XInterface" + || name_ == "com.sun.star.uno.Exception" + || isPolymorphic())) { + out << "\n" << indent() + << ("inline ::css::uno::Type const &" + " cppu_detail_getUnoType(SAL_UNUSED_PARAMETER "); + dumpType(out, name_, false, false, true); + out << " const *);\n"; + } + if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) { + out << "\n"; + } + out << "\n"; + dumpTemplateHead(out); + out << "SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL getCppuType("; + dumpType(out, name_, true); + dumpTemplateParameters(out); + out << " *);\n\n#endif\n"; +} + +void CppuType::dumpGetCppuType(FileStream & out) +{ + if (name_ == "com.sun.star.uno.XInterface") { + out << indent() + << ("SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL" + " getCppuType(SAL_UNUSED_PARAMETER "); + dumpType(out, name_, true); + out << " *) {\n"; + inc(); + out << indent() + << ("return ::cppu::UnoType< ::css::uno::XInterface" + " >::get();\n"); + dec(); + out << indent() << "}\n"; + } else if (name_ == "com.sun.star.uno.Exception") { + out << indent() + << ("SAL_DEPRECATED(\"use cppu::UnoType\") inline ::css::uno::Type const & SAL_CALL" + " getCppuType(SAL_UNUSED_PARAMETER "); + dumpType(out, name_, true); + out << " *) {\n"; + inc(); + out << indent() + << ("return ::cppu::UnoType< ::css::uno::Exception" + " >::get();\n"); + dec(); + out << indent() << "}\n"; + } else if (m_cppuTypeLeak) { + dumpLightGetCppuType(out); + } else if (m_cppuTypeDynamic) { + dumpNormalGetCppuType(out); + } else { + dumpComprehensiveGetCppuType(out); + } +} + +void CppuType::dumpLightGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << "static typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if ( !the_type )\n" << indent() << "{\n"; + inc(); + out << indent() << "typelib_static_type_init( &the_type, " + << getTypeClass(name_, true) << ", \"" << name_ << "\" );\n"; + dec(); + out << indent() << "}\n" << indent() + << ("return * reinterpret_cast< ::css::uno::Type * >(" + " &the_type );\n"); + dumpGetCppuTypePostamble(out); +} + +codemaker::cpp::IdentifierTranslationMode CppuType::isGlobal() const +{ + return name_.indexOf('.') == -1 + ? codemaker::cpp::IdentifierTranslationMode::Global : codemaker::cpp::IdentifierTranslationMode::NonGlobal; +} + +sal_uInt32 CppuType::getInheritedMemberCount() +{ + if (m_inheritedMemberCount == 0) { + m_inheritedMemberCount = checkInheritedMemberCount(); + } + + return m_inheritedMemberCount; +} + +OUString CppuType::getTypeClass(OUString const & name, bool cStyle) +{ + rtl::Reference< unoidl::Entity > ent; + switch (m_typeMgr->getSort(name, &ent)) { + case codemaker::UnoType::Sort::Void: + return cStyle + ? OUString("typelib_TypeClass_VOID") + : OUString("::css::uno::TypeClass_VOID"); + case codemaker::UnoType::Sort::Boolean: + return cStyle + ? OUString("typelib_TypeClass_BOOLEAN") + : OUString("::css::uno::TypeClass_BOOLEAN"); + case codemaker::UnoType::Sort::Byte: + return cStyle + ? OUString("typelib_TypeClass_BYTE") + : OUString("::css::uno::TypeClass_BYTE"); + case codemaker::UnoType::Sort::Short: + return cStyle + ? OUString("typelib_TypeClass_SHORT") + : OUString("::css::uno::TypeClass_SHORT"); + case codemaker::UnoType::Sort::UnsignedShort: + return cStyle + ? OUString("typelib_TypeClass_UNSIGNED_SHORT") + : OUString("::css::uno::TypeClass_UNSIGNED_SHORT"); + case codemaker::UnoType::Sort::Long: + return cStyle + ? OUString("typelib_TypeClass_LONG") + : OUString("::css::uno::TypeClass_LONG"); + case codemaker::UnoType::Sort::UnsignedLong: + return cStyle + ? OUString("typelib_TypeClass_UNSIGNED_LONG") + : OUString("::css::uno::TypeClass_UNSIGNED_LONG"); + case codemaker::UnoType::Sort::Hyper: + return cStyle + ? OUString("typelib_TypeClass_HYPER") + : OUString("::css::uno::TypeClass_HYPER"); + case codemaker::UnoType::Sort::UnsignedHyper: + return cStyle + ? OUString("typelib_TypeClass_UNSIGNED_HYPER") + : OUString("::css::uno::TypeClass_UNSIGNED_HYPER"); + case codemaker::UnoType::Sort::Float: + return cStyle + ? OUString("typelib_TypeClass_FLOAT") + : OUString("::css::uno::TypeClass_FLOAT"); + case codemaker::UnoType::Sort::Double: + return cStyle + ? OUString("typelib_TypeClass_DOUBLE") + : OUString("::css::uno::TypeClass_DOUBLE"); + case codemaker::UnoType::Sort::Char: + return cStyle + ? OUString("typelib_TypeClass_CHAR") + : OUString("::css::uno::TypeClass_CHAR"); + case codemaker::UnoType::Sort::String: + return cStyle + ? OUString("typelib_TypeClass_STRING") + : OUString("::css::uno::TypeClass_STRING"); + case codemaker::UnoType::Sort::Type: + return cStyle + ? OUString("typelib_TypeClass_TYPE") + : OUString("::css::uno::TypeClass_TYPE"); + case codemaker::UnoType::Sort::Any: + return cStyle + ? OUString("typelib_TypeClass_ANY") + : OUString("::css::uno::TypeClass_ANY"); + case codemaker::UnoType::Sort::Sequence: + return cStyle + ? OUString("typelib_TypeClass_SEQUENCE") + : OUString("::css::uno::TypeClass_SEQUENCE"); + case codemaker::UnoType::Sort::Enum: + return cStyle + ? OUString("typelib_TypeClass_ENUM") + : OUString("::css::uno::TypeClass_ENUM"); + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + return cStyle + ? OUString("typelib_TypeClass_STRUCT") + : OUString("::css::uno::TypeClass_STRUCT"); + case codemaker::UnoType::Sort::Exception: + return cStyle + ? OUString("typelib_TypeClass_EXCEPTION") + : OUString("::css::uno::TypeClass_EXCEPTION"); + case codemaker::UnoType::Sort::Interface: + return cStyle + ? OUString("typelib_TypeClass_INTERFACE") + : OUString("::css::uno::TypeClass_INTERFACE"); + case codemaker::UnoType::Sort::Typedef: + return getTypeClass(dynamic_cast<unoidl::TypedefEntity&>(*ent).getType(), cStyle); + default: + for (;;) { + std::abort(); + } + } +} + +void CppuType::dumpType( + FileStream & out, std::u16string_view name, bool isConst, bool isRef, + bool native, bool cppuUnoType) const +{ + sal_Int32 k; + std::vector< OString > args; + OUString n( + b2u(codemaker::UnoType::decompose( + u2b(resolveAllTypedefs(name)), &k, &args))); + if (isConst) { + out << "const "; + } + for (sal_Int32 i = 0; i != k; ++i) { + out << (cppuUnoType + ? "::cppu::UnoSequenceType" : "::css::uno::Sequence") + << "< "; + } + switch (m_typeMgr->getSort(n)) { + case codemaker::UnoType::Sort::Void: + out << "void"; + break; + case codemaker::UnoType::Sort::Boolean: + out << "::sal_Bool"; + break; + case codemaker::UnoType::Sort::Byte: + out << "::sal_Int8"; + break; + case codemaker::UnoType::Sort::Short: + out << "::sal_Int16"; + break; + case codemaker::UnoType::Sort::UnsignedShort: + out << (cppuUnoType ? "::cppu::UnoUnsignedShortType" : "::sal_uInt16"); + break; + case codemaker::UnoType::Sort::Long: + out << "::sal_Int32"; + break; + case codemaker::UnoType::Sort::UnsignedLong: + out << "::sal_uInt32"; + break; + case codemaker::UnoType::Sort::Hyper: + out << "::sal_Int64"; + break; + case codemaker::UnoType::Sort::UnsignedHyper: + out << "::sal_uInt64"; + break; + case codemaker::UnoType::Sort::Float: + out << "float"; + break; + case codemaker::UnoType::Sort::Double: + out << "double"; + break; + case codemaker::UnoType::Sort::Char: + out << (cppuUnoType ? "::cppu::UnoCharType" : "::sal_Unicode"); + break; + case codemaker::UnoType::Sort::String: + out << "::rtl::OUString"; + break; + case codemaker::UnoType::Sort::Type: + out << "::css::uno::Type"; + break; + case codemaker::UnoType::Sort::Any: + out << "::css::uno::Any"; + break; + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::Exception: + out << codemaker::cpp::scopedCppName(u2b(n)); + break; + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + out << codemaker::cpp::scopedCppName(u2b(n)); + if (!args.empty()) { + out << "< "; + for (std::vector< OString >::iterator i(args.begin()); + i != args.end(); ++i) { + if (i != args.begin()) { + out << ", "; + } + dumpType(out, b2u(*i)); + } + out << " >"; + } + break; + case codemaker::UnoType::Sort::Interface: + if (!native) { + out << "::css::uno::Reference< "; + } + out << codemaker::cpp::scopedCppName(u2b(n)); + if (!native) { + out << " >"; + } + break; + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + name + "\" in call to CppuType::dumpType"); + } + for (sal_Int32 i = 0; i != k; ++i) { + out << " >"; + } + if (isRef) { + out << "&"; + } +} + +void CppuType::dumpCppuGetType( + FileStream & out, std::u16string_view name, OUString const * ownName) const +{ + //TODO: What are these calls good for? + OUString nucleus; + sal_Int32 rank; + codemaker::UnoType::Sort sort = m_typeMgr->decompose( + name, true, &nucleus, &rank, nullptr, nullptr); + switch (rank == 0 ? sort : codemaker::UnoType::Sort::Sequence) { + case codemaker::UnoType::Sort::Void: + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + break; + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + case codemaker::UnoType::Sort::Exception: + case codemaker::UnoType::Sort::Interface: + // Take care of recursion like struct S { sequence<S> x; }: + if (ownName == nullptr || nucleus != *ownName) { + out << indent() << "::cppu::UnoType< "; + dumpType(out, name, false, false, false, true); + out << " >::get();\n"; + } + break; + case codemaker::UnoType::Sort::Typedef: + for (;;) std::abort(); // this cannot happen + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + name + + "\" in call to CppuType::dumpCppuGetType"); + } +} + +bool CppuType::passByReference(OUString const & name) const +{ + switch (m_typeMgr->getSort(resolveOuterTypedefs(name))) { + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::Enum: + return false; + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + case codemaker::UnoType::Sort::Interface: + return true; + default: + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to CppuType::passByReference"); + } +} + +bool CppuType::canBeWarnUnused(OUString const & name) const +{ + return canBeWarnUnused(name, 0); +} +bool CppuType::canBeWarnUnused(OUString const & name, int depth) const +{ + // prevent infinite recursion and blowing the stack + if (depth > 10) + return false; + OUString aResolvedName = resolveOuterTypedefs(name); + switch (m_typeMgr->getSort(aResolvedName)) { + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + return true; + case codemaker::UnoType::Sort::PlainStruct: { + rtl::Reference< unoidl::Entity > ent; + m_typeMgr->getSort(aResolvedName, &ent); + rtl::Reference< unoidl::PlainStructTypeEntity > ent2( + dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get())); + if (!ent2->getDirectBase().isEmpty() && !canBeWarnUnused(ent2->getDirectBase(), depth+1)) + return false; + for ( const unoidl::PlainStructTypeEntity::Member& rMember : ent2->getDirectMembers()) { + if (!canBeWarnUnused(rMember.type, depth+1)) + return false; + } + return true; + } + case codemaker::UnoType::Sort::Sequence: { + OUString aInnerType = aResolvedName.copy(2); + return canBeWarnUnused(aInnerType, depth+1); + } + case codemaker::UnoType::Sort::Any: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + case codemaker::UnoType::Sort::Interface: + return false; + default: + throw CannotDumpException( + "unexpected entity \"" + name + + "\" in call to CppuType::canBeWarnUnused"); + } +} + +OUString CppuType::resolveOuterTypedefs(OUString const & name) const +{ + for (OUString n(name);;) { + rtl::Reference< unoidl::Entity > ent; + if (m_typeMgr->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef) { + return n; + } + n = dynamic_cast<unoidl::TypedefEntity&>(*ent).getType(); + } +} + +OUString CppuType::resolveAllTypedefs(std::u16string_view name) const +{ + sal_Int32 k1; + OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k1))); + for (;;) { + rtl::Reference< unoidl::Entity > ent; + if (m_typeMgr->getSort(n, &ent) != codemaker::UnoType::Sort::Typedef) { + break; + } + sal_Int32 k2; + n = b2u(codemaker::UnoType::decompose( + u2b(dynamic_cast<unoidl::TypedefEntity&>(*ent).getType()), &k2)); + k1 += k2; //TODO: overflow + } + OUStringBuffer b(k1*2 + n.getLength()); + for (sal_Int32 i = 0; i != k1; ++i) { + b.append("[]"); + } + b.append(n); + return b.makeStringAndClear(); +} + +void CppuType::inc(sal_Int32 num) +{ + m_indentLength += num; +} + +void CppuType::dec(sal_Int32 num) +{ + m_indentLength = std::max< sal_Int32 >(m_indentLength - num, 0); +} + +OUString CppuType::indent() const +{ + OUStringBuffer buf(m_indentLength); + for (sal_Int32 i = 0; i != m_indentLength; ++i) { + buf.append(' '); + } + return buf.makeStringAndClear(); +} + +bool isDeprecated(std::vector< OUString > const & annotations) +{ + for (const OUString& r : annotations) { + if (r == "deprecated") { + return true; + } + } + return false; +} + +void dumpDeprecation(FileStream & out, bool deprecated) +{ + if (deprecated) { + out << "SAL_DEPRECATED_INTERNAL(\"marked @deprecated in UNOIDL\") "; + } +} + +class BaseOffset +{ +public: + BaseOffset( + rtl::Reference< TypeManager > manager, + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity): + manager_(std::move(manager)), offset_(0) { + calculateBases(entity); + } + BaseOffset(const BaseOffset&) = delete; + const BaseOffset& operator=(const BaseOffset&) = delete; + + sal_Int32 get() const { + return offset_; + } + +private: + void calculateBases( + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity); + + rtl::Reference< TypeManager > manager_; + std::set< OUString > set_; + sal_Int32 offset_; +}; + +void BaseOffset::calculateBases( + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity) +{ + assert(entity.is()); + for (const unoidl::AnnotatedReference& ar : entity->getDirectMandatoryBases()) { + if (set_.insert(ar.name).second) { + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager_->getSort(ar.name, &ent); + if (sort != codemaker::UnoType::Sort::Interface) { + throw CannotDumpException( + "interface type base " + ar.name + + " is not an interface type"); + } + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + assert(ent2.is()); + calculateBases(ent2); + offset_ += ent2->getDirectAttributes().size() + + ent2->getDirectMethods().size(); //TODO: overflow + } + } +} + +class InterfaceType: public CppuType +{ +public: + InterfaceType( + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr); + + virtual void dumpDeclaration(FileStream& o) override; + void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override; + + void dumpAttributes(FileStream& o) const; + void dumpMethods(FileStream& o) const; + void dumpNormalGetCppuType(FileStream& o) override; + void dumpComprehensiveGetCppuType(FileStream& o) override; + void dumpCppuAttributeRefs(FileStream& o, sal_uInt32& index); + void dumpCppuMethodRefs(FileStream& o, sal_uInt32& index); + void dumpCppuAttributes(FileStream& o, sal_uInt32& index); + void dumpCppuMethods(FileStream& o, sal_uInt32& index); + void dumpAttributesCppuDecl(FileStream & out, std::set< OUString > * seen) const; + void dumpMethodsCppuDecl(FileStream & out, std::set< OUString > * seen) const; + +private: + virtual void addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual sal_uInt32 checkInheritedMemberCount() const override { + return BaseOffset(m_typeMgr, entity_).get(); + } + + void dumpExceptionTypeName( + FileStream & out, std::u16string_view prefix, sal_uInt32 index, + std::u16string_view name) const; + + sal_Int32 dumpExceptionTypeNames( + FileStream & out, std::u16string_view prefix, + std::vector< OUString > const & exceptions, bool runtimeException) const; + + rtl::Reference< unoidl::InterfaceTypeEntity > entity_; + bool m_isDeprecated; +}; + +InterfaceType::InterfaceType( + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity), + m_isDeprecated(isDeprecated(entity->getAnnotations())) +{ + assert(entity.is()); +} + +void InterfaceType::dumpDeclaration(FileStream & out) +{ + out << "\nclass SAL_NO_VTABLE SAL_DLLPUBLIC_RTTI " << id_; + for (std::vector< unoidl::AnnotatedReference >::const_iterator i( + entity_->getDirectMandatoryBases().begin()); + i != entity_->getDirectMandatoryBases().end(); ++i) { + out << (i == entity_->getDirectMandatoryBases().begin() ? " :" : ",") + << " public " << codemaker::cpp::scopedCppName(u2b(i->name)); + } + out << "\n{\npublic:\n"; + inc(); + out << "#if defined LIBO_INTERNAL_ONLY\n" + << indent() << id_ << "() = default;\n" + << indent() << id_ << "(" << id_ << " const &) = default;\n" + << indent() << id_ << "(" << id_ << " &&) = default;\n" + << indent() << id_ << " & operator =(" << id_ << " const &) = default;\n" + << indent() << id_ << " & operator =(" << id_ << " &&) = default;\n#endif\n\n"; + dumpAttributes(out); + dumpMethods(out); + out << "\n" << indent() + << ("static inline ::css::uno::Type const & SAL_CALL" + " static_type(void * = 0);\n\n"); + dec(); + out << "protected:\n"; + inc(); + out << indent() << "~" << id_ + << ("() SAL_NOEXCEPT {} // avoid warnings about virtual members and" + " non-virtual dtor\n"); + dec(); + out << "};\n\n"; +} + +void InterfaceType::dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(out, u"HPP")); + out << "\n"; + addDefaultHxxIncludes(includes); + includes.dump(out, &name_, !(m_cppuTypeLeak || m_cppuTypeDynamic)); + out << "\n"; + dumpGetCppuType(out); + out << "\n::css::uno::Type const & " + << codemaker::cpp::scopedCppName(u2b(name_)) + << "::static_type(SAL_UNUSED_PARAMETER void *) {\n"; + inc(); + out << indent() << "return ::cppu::UnoType< "; + dumpType(out, name_, false, false, true); + out << " >::get();\n"; + dec(); + out << "}\n\n#endif // "<< headerDefine << "\n"; +} + +void InterfaceType::dumpAttributes(FileStream & out) const +{ + if (!entity_->getDirectAttributes().empty()) { + out << "\n" << indent() << "// Attributes\n"; + } + for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) { + bool depr = m_isDeprecated || isDeprecated(attr.annotations); + out << indent(); + dumpDeprecation(out, depr); + out << "virtual "; + dumpType(out, attr.type); + out << " SAL_CALL get" << attr.name << "() = 0;\n"; + if (!attr.readOnly) { + bool byRef = passByReference(attr.type); + out << indent(); + dumpDeprecation(out, depr); + out << "virtual void SAL_CALL set" << attr.name << "( "; + dumpType(out, attr.type, byRef, byRef); + out << " _" << attr.name.toAsciiLowerCase() << " ) = 0;\n"; + } + } +} + +void InterfaceType::dumpMethods(FileStream & out) const +{ + if (!entity_->getDirectMethods().empty()) { + out << "\n" << indent() << "// Methods\n"; + } + for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) { + out << indent(); + dumpDeprecation(out, m_isDeprecated || isDeprecated(method.annotations)); + out << "virtual "; + dumpType(out, method.returnType); + out << " SAL_CALL " << method.name << "("; + if (!method.parameters.empty()) { + out << " "; + for (std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >:: + const_iterator j(method.parameters.begin()); + j != method.parameters.end();) { + bool isConst; + bool isRef; + if (j->direction + == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) + { + isConst = passByReference(j->type); + isRef = isConst; + } else { + isConst = false; + isRef = true; + } + dumpType(out, j->type, isConst, isRef); + out << " " << j->name; + ++j; + if (j != method.parameters.end()) { + out << ", "; + } + } + out << " "; + } + out << ") = 0;\n"; + } +} + +void InterfaceType::dumpNormalGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << "static typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if ( !the_type )\n" << indent() << "{\n"; + inc(); + std::vector< unoidl::AnnotatedReference >::size_type bases( + entity_->getDirectMandatoryBases().size()); + if (bases == 1 + && (entity_->getDirectMandatoryBases()[0].name + == "com.sun.star.uno.XInterface")) { + bases = 0; + } + if (bases != 0) { + out << indent() << "typelib_TypeDescriptionReference * aSuperTypes[" + << entity_->getDirectMandatoryBases().size() << "];\n"; + std::vector< unoidl::AnnotatedReference >::size_type n = 0; + for (const unoidl::AnnotatedReference& ar : entity_->getDirectMandatoryBases()) { + out << indent() << "aSuperTypes[" << n++ << "] = ::cppu::UnoType< "; + dumpType(out, ar.name, true, false, false, true); + out << " >::get().getTypeLibType();\n"; + } + } + out << indent() << "typelib_static_mi_interface_type_init( &the_type, \"" + << name_ << "\", " << bases << ", " + << (bases == 0 ? "0" : "aSuperTypes") << " );\n"; + dec(); + out << indent() << "}\n" << indent() + << ("return * reinterpret_cast< ::css::uno::Type * >(" + " &the_type );\n"); + dumpGetCppuTypePostamble(out); +} + +void InterfaceType::dumpComprehensiveGetCppuType(FileStream & out) +{ + codemaker::cppumaker::dumpNamespaceOpen(out, name_, false); + OUString staticTypeClass("the" + id_ + "Type"); + out << " namespace detail {\n\n" << indent() << "struct " << staticTypeClass + << " : public rtl::StaticWithInit< ::css::uno::Type *, " + << staticTypeClass << " >\n" << indent() << "{\n"; + inc(); + out << indent() << "::css::uno::Type * operator()() const\n" + << indent() << "{\n"; + inc(); + out << indent() << "::rtl::OUString sTypeName( \"" << name_ << "\" );\n\n" + << indent() << "// Start inline typedescription generation\n" + << indent() << "typelib_InterfaceTypeDescription * pTD = 0;\n\n"; + out << indent() << "typelib_TypeDescriptionReference * aSuperTypes[" + << entity_->getDirectMandatoryBases().size() << "];\n"; + std::vector< unoidl::AnnotatedReference >::size_type n = 0; + for (const unoidl::AnnotatedReference& ar : entity_->getDirectMandatoryBases()) { + out << indent() << "aSuperTypes[" << n++ << "] = ::cppu::UnoType< "; + dumpType(out, ar.name, false, false, false, true); + out << " >::get().getTypeLibType();\n"; + } + std::size_t count = entity_->getDirectAttributes().size() + + entity_->getDirectMethods().size(); //TODO: overflow + if (count != 0) { + out << indent() << "typelib_TypeDescriptionReference * pMembers[" + << count << "] = { "; + for (std::size_t i = 0; i != count; ++i) { + out << "0"; + if (i + 1 != count) { + out << ","; + } + } + out << " };\n"; + sal_uInt32 index = 0; + dumpCppuAttributeRefs(out, index); + dumpCppuMethodRefs(out, index); + } + out << "\n" << indent() << "typelib_typedescription_newMIInterface(\n"; + inc(); + out << indent() << "&pTD,\n" << indent() + << "sTypeName.pData, 0, 0, 0, 0, 0,\n" << indent() + << entity_->getDirectMandatoryBases().size() << ", aSuperTypes,\n" + << indent() << count << ",\n" << indent() + << (count == 0 ? "0" : "pMembers") << " );\n\n"; + dec(); + out << indent() + << ("typelib_typedescription_register( (typelib_TypeDescription**)&pTD" + " );\n"); + for (std::size_t i = 0; i != count; ++i) { + out << indent() << "typelib_typedescriptionreference_release( pMembers[" + << i << "] );\n"; + } + out << indent() + << ("typelib_typedescription_release( (typelib_TypeDescription*)pTD" + " );\n\n") + << indent() << "return new ::css::uno::Type( " + << getTypeClass(name_) << ", sTypeName ); // leaked\n"; + dec(); + out << indent() << "}\n"; + dec(); + out << indent() << "};\n\n"; + codemaker::cppumaker::dumpNamespaceClose(out, name_, false); + out << " }\n\n"; + dumpGetCppuTypePreamble(out); + out << indent() << "const ::css::uno::Type &rRet = *detail::" + << staticTypeClass << "::get();\n" << indent() + << "// End inline typedescription generation\n" << indent() + << "static bool bInitStarted = false;\n" << indent() + << "if (!bInitStarted)\n" << indent() << "{\n"; + inc(); + out << indent() + << "::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );\n" + << indent() << "if (!bInitStarted)\n" << indent() << "{\n"; + inc(); + out << indent() << "OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();\n" + << indent() << "bInitStarted = true;\n"; + std::set< OUString > seen; + // Type for RuntimeException is always needed: + seen.insert("com.sun.star.uno.RuntimeException"); + dumpCppuGetType(out, u"com.sun.star.uno.RuntimeException"); + dumpAttributesCppuDecl(out, &seen); + dumpMethodsCppuDecl(out, &seen); + if (count != 0) { + sal_uInt32 index = getInheritedMemberCount(); + dumpCppuAttributes(out, index); + dumpCppuMethods(out, index); + } + dec(); + out << indent() << "}\n"; + dec(); + out << indent() << "}\n" << indent() << "else\n" << indent() << "{\n"; + inc(); + out << indent() << "OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();\n"; + dec(); + out << indent() << "}\n" << indent() << "return rRet;\n"; + dumpGetCppuTypePostamble(out); +} + +void InterfaceType::dumpCppuAttributeRefs(FileStream & out, sal_uInt32 & index) +{ + std::vector< unoidl::InterfaceTypeEntity::Attribute >::size_type n = 0; + for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) { + out << indent() << "::rtl::OUString sAttributeName" << n << "( \"" + << name_ << "::" << attr.name << "\" );\n" << indent() + << "typelib_typedescriptionreference_new( &pMembers[" << index++ + << "],\n"; + inc(38); + out << indent() + << "(typelib_TypeClass)::css::uno::TypeClass_INTERFACE_ATTRIBUTE,\n" + << indent() << "sAttributeName" << n << ".pData );\n"; + dec(38); + ++n; + } +} + +void InterfaceType::dumpCppuMethodRefs(FileStream & out, sal_uInt32 & index) +{ + std::vector< unoidl::InterfaceTypeEntity::Method >::size_type n = 0; + for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) { + out << indent() << "::rtl::OUString sMethodName" << n << "( \"" << name_ + << "::" << method.name << "\" );\n" << indent() + << "typelib_typedescriptionreference_new( &pMembers[" << index++ + << "],\n"; + inc(38); + out << indent() + << "(typelib_TypeClass)::css::uno::TypeClass_INTERFACE_METHOD,\n" + << indent() << "sMethodName" << n << ".pData );\n"; + dec(38); + ++n; + } +} + +void InterfaceType::addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + // The comprehensive getCppuType method always includes a line + // "getCppuType( (const ::css::uno::RuntimeException*)0 );": + includes.addCppuUnotypeHxx(); + includes.addRtlInstanceHxx(); // using rtl::StaticWithInit + includes.addOslMutexHxx(); + includes.add("com.sun.star.uno.RuntimeException"); +} + +void InterfaceType::dumpCppuAttributes(FileStream & out, sal_uInt32 & index) +{ + if (entity_->getDirectAttributes().empty()) + return; + + out << "\n" << indent() + << "typelib_InterfaceAttributeTypeDescription * pAttribute = 0;\n"; + std::vector< unoidl::InterfaceTypeEntity::Attribute >::size_type n = 0; + for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) { + OUString type(resolveAllTypedefs(attr.type)); + out << indent() << "{\n"; + inc(); + out << indent() << "::rtl::OUString sAttributeType" << n << "( \"" + << type << "\" );\n" << indent() + << "::rtl::OUString sAttributeName" << n << "( \"" << name_ + << "::" << attr.name << "\" );\n"; + sal_Int32 getExcn = dumpExceptionTypeNames( + out, u"get", attr.getExceptions, false); + sal_Int32 setExcn = dumpExceptionTypeNames( + out, u"set", attr.setExceptions, false); + out << indent() + << ("typelib_typedescription_newExtendedInterfaceAttribute(" + " &pAttribute,\n"); + inc(); + out << indent() << index++ << ", sAttributeName" << n + << ".pData,\n" << indent() << "(typelib_TypeClass)" + << getTypeClass(type) << ", sAttributeType" << n << ".pData,\n" + << indent() << "sal_" << (attr.readOnly ? "True" : "False") + << ", " << getExcn << ", " + << (getExcn == 0 ? "0" : "the_getExceptions") << ", " << setExcn + << ", " << (setExcn == 0 ? "0" : "the_setExceptions") + << " );\n"; + dec(); + out << indent() + << ("typelib_typedescription_register(" + " (typelib_TypeDescription**)&pAttribute );\n"); + dec(); + out << indent() << "}\n"; + ++n; + } + out << indent() + << ("typelib_typedescription_release(" + " (typelib_TypeDescription*)pAttribute );\n"); +} + +void InterfaceType::dumpCppuMethods(FileStream & out, sal_uInt32 & index) +{ + if (entity_->getDirectMethods().empty()) + return; + + out << "\n" << indent() + << "typelib_InterfaceMethodTypeDescription * pMethod = 0;\n"; + std::vector< unoidl::InterfaceTypeEntity::Method >::size_type n = 0; + for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) { + OUString returnType(resolveAllTypedefs(method.returnType)); + out << indent() << "{\n"; + inc(); + if (!method.parameters.empty()) { + out << indent() << "typelib_Parameter_Init aParameters[" + << method.parameters.size() << "];\n"; + } + std::vector< unoidl::InterfaceTypeEntity::Method::Parameter >:: + size_type m = 0; + for (const unoidl::InterfaceTypeEntity::Method::Parameter& param : method.parameters) { + OUString type(resolveAllTypedefs(param.type)); + out << indent() << "::rtl::OUString sParamName" << m << "( \"" + << param.name << "\" );\n" << indent() + << "::rtl::OUString sParamType" << m << "( \"" << type + << "\" );\n" << indent() << "aParameters[" << m + << "].pParamName = sParamName" << m << ".pData;\n" + << indent() << "aParameters[" << m + << "].eTypeClass = (typelib_TypeClass)" + << getTypeClass(type) << ";\n" << indent() << "aParameters[" + << m << "].pTypeName = sParamType" << m << ".pData;\n" + << indent() << "aParameters[" << m << "].bIn = " + << ((param.direction + == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT) + ? "sal_False" : "sal_True") + << ";\n" << indent() << "aParameters[" << m << "].bOut = " + << ((param.direction + == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) + ? "sal_False" : "sal_True") + << ";\n"; + ++m; + } + sal_Int32 excn = dumpExceptionTypeNames( + out, u"", method.exceptions, + method.name != "acquire" && method.name != "release"); + out << indent() << "::rtl::OUString sReturnType" << n << "( \"" + << returnType << "\" );\n" << indent() + << "::rtl::OUString sMethodName" << n << "( \"" << name_ << "::" + << method.name << "\" );\n" << indent() + << "typelib_typedescription_newInterfaceMethod( &pMethod,\n"; + inc(); + out << indent() << index++ << ", sal_False,\n" << indent() + << "sMethodName" << n << ".pData,\n" << indent() + << "(typelib_TypeClass)" << getTypeClass(returnType) + << ", sReturnType" << n << ".pData,\n" << indent() + << method.parameters.size() << ", " + << (method.parameters.empty() ? "0" : "aParameters") << ",\n" + << indent() << excn << ", " + << (excn == 0 ? "0" : "the_Exceptions") << " );\n"; + dec(); + out << indent() + << ("typelib_typedescription_register(" + " (typelib_TypeDescription**)&pMethod );\n"); + dec(); + out << indent() << "}\n"; + ++n; + } + out << indent() + << ("typelib_typedescription_release(" + " (typelib_TypeDescription*)pMethod );\n"); +} + +void InterfaceType::dumpAttributesCppuDecl( + FileStream & out, std::set< OUString > * seen) const +{ + assert(seen != nullptr); + for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes()) { + if (seen->insert(attr.type).second) { + dumpCppuGetType(out, attr.type); + } + for (const OUString& exc : attr.getExceptions) { + if (seen->insert(exc).second) { + dumpCppuGetType(out, exc); + } + } + for (const OUString& exc : attr.setExceptions) { + if (seen->insert(exc).second) { + dumpCppuGetType(out, exc); + } + } + } +} + +void InterfaceType::dumpMethodsCppuDecl( + FileStream & out, std::set< OUString > * seen) const +{ + assert(seen != nullptr); + for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) { + for (const OUString& ex : method.exceptions) { + if (seen->insert(ex).second) { + dumpCppuGetType(out, ex); + } + } + } +} + +void InterfaceType::dumpExceptionTypeName( + FileStream & out, std::u16string_view prefix, sal_uInt32 index, + std::u16string_view name) const +{ + out << indent() << "::rtl::OUString the_" << prefix << "ExceptionName" + << index << "( \"" << name << "\" );\n"; +} + +sal_Int32 InterfaceType::dumpExceptionTypeNames( + FileStream & out, std::u16string_view prefix, + std::vector< OUString > const & exceptions, bool runtimeException) const +{ + sal_Int32 count = 0; + for (const OUString& ex : exceptions) { + if (ex != "com.sun.star.uno.RuntimeException") { + dumpExceptionTypeName(out, prefix, count++, ex); + } + } + if (runtimeException) { + dumpExceptionTypeName( + out, prefix, count++, u"com.sun.star.uno.RuntimeException"); + } + if (count != 0) { + out << indent() << "rtl_uString * the_" << prefix << "Exceptions[] = {"; + for (sal_Int32 i = 0; i != count; ++i) { + out << (i == 0 ? " " : ", ") << "the_" << prefix << "ExceptionName" + << i << ".pData"; + } + out << " };\n"; + } + return count; +} + +class ConstantGroup: public CppuType +{ +public: + ConstantGroup( + rtl::Reference< unoidl::ConstantGroupEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity) { + assert(entity.is()); + } + + bool hasConstants() const { + return !entity_->getMembers().empty(); + } + +private: + virtual void dumpHdlFile( + FileStream & out, codemaker::cppumaker::Includes & includes) override; + + virtual void dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes & includes) override; + + virtual void dumpDeclaration(FileStream & out) override; + + rtl::Reference< unoidl::ConstantGroupEntity > entity_; +}; + +void ConstantGroup::dumpHdlFile( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(out, u"HDL")); + out << "\n"; + addDefaultHIncludes(includes); + includes.dump(out, nullptr, true); + out << "\n"; + if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, true)) { + out << "\n"; + } + out << "\n"; + dumpDeclaration(out); + out << "\n"; + if (codemaker::cppumaker::dumpNamespaceClose(out, name_, true)) { + out << "\n"; + } + out << "\n#endif // "<< headerDefine << "\n"; +} + +void ConstantGroup::dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes &) +{ + OUString headerDefine(dumpHeaderDefine(out, u"HPP")); + out << "\n"; + codemaker::cppumaker::Includes::dumpInclude(out, u2b(name_), false); + out << "\n#endif // "<< headerDefine << "\n"; +} + +void ConstantGroup::dumpDeclaration(FileStream & out) +{ + for (const unoidl::ConstantGroupEntity::Member& member : entity_->getMembers()) { + out << "static const "; + switch (member.value.type) { + case unoidl::ConstantValue::TYPE_BOOLEAN: + out << "::sal_Bool"; + break; + case unoidl::ConstantValue::TYPE_BYTE: + out << "::sal_Int8"; + break; + case unoidl::ConstantValue::TYPE_SHORT: + out << "::sal_Int16"; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT: + out << "::sal_uInt16"; + break; + case unoidl::ConstantValue::TYPE_LONG: + out << "::sal_Int32"; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_LONG: + out << "::sal_uInt32"; + break; + case unoidl::ConstantValue::TYPE_HYPER: + out << "::sal_Int64"; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER: + out << "::sal_uInt64"; + break; + case unoidl::ConstantValue::TYPE_FLOAT: + out << "float"; + break; + case unoidl::ConstantValue::TYPE_DOUBLE: + out << "double"; + break; + } + out << " " << member.name << " = "; + switch (member.value.type) { + case unoidl::ConstantValue::TYPE_BOOLEAN: + out << (member.value.booleanValue ? "sal_True" : "sal_False"); + break; + case unoidl::ConstantValue::TYPE_BYTE: + out << "(sal_Int8)" << OUString::number(member.value.byteValue); + break; + case unoidl::ConstantValue::TYPE_SHORT: + out << "(sal_Int16)" << OUString::number(member.value.shortValue); + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT: + out << "(sal_uInt16)" + << OUString::number(member.value.unsignedShortValue); + break; + case unoidl::ConstantValue::TYPE_LONG: + // Avoid C++ compiler warnings about (un)signedness of literal + // -2^31: + if (member.value.longValue == SAL_MIN_INT32) { + out << "SAL_MIN_INT32"; + } else { + out << "(sal_Int32)" << OUString::number(member.value.longValue); + } + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_LONG: + out << "(sal_uInt32)" + << OUString::number(member.value.unsignedLongValue) << "U"; + break; + case unoidl::ConstantValue::TYPE_HYPER: + // Avoid C++ compiler warnings about (un)signedness of literal + // -2^63: + if (member.value.hyperValue == SAL_MIN_INT64) { + out << "SAL_MIN_INT64"; + } else { + out << "(sal_Int64) SAL_CONST_INT64(" + << OUString::number(member.value.hyperValue) << ")"; + } + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER: + out << "SAL_CONST_UINT64(" + << OUString::number(member.value.unsignedHyperValue) << ")"; + break; + case unoidl::ConstantValue::TYPE_FLOAT: + out << "(float)" << OUString::number(member.value.floatValue); + break; + case unoidl::ConstantValue::TYPE_DOUBLE: + out << "(double)" << OUString::number(member.value.doubleValue); + break; + } + out << ";\n"; + } +} + +void dumpTypeParameterName(FileStream & out, std::u16string_view name) +{ + // Prefix all type parameters with "typeparam_" to avoid problems when a + // struct member has the same name as a type parameter, as in + // struct<T> { T T; }; + out << "typeparam_" << name; +} + +class PlainStructType: public CppuType +{ +public: + PlainStructType( + rtl::Reference< unoidl::PlainStructTypeEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity) { + assert(entity.is()); + } + +private: + virtual sal_uInt32 checkInheritedMemberCount() const override { + return getTotalMemberCount(entity_->getDirectBase()); + } + + virtual void dumpDeclaration(FileStream& o) override; + + void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override; + + virtual void dumpLightGetCppuType(FileStream & out) override; + + virtual void dumpNormalGetCppuType(FileStream & out) override; + + virtual void dumpComprehensiveGetCppuType(FileStream & out) override; + + virtual void addLightGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual void addNormalGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual void addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + bool dumpBaseMembers( + FileStream & out, OUString const & base, bool withType); + + sal_uInt32 getTotalMemberCount(OUString const & base) const; + + rtl::Reference< unoidl::PlainStructTypeEntity > entity_; +}; + +void PlainStructType::dumpDeclaration(FileStream & out) +{ + out << "\n#ifdef _WIN32\n# pragma pack(push, 8)\n#endif\n\n" << indent(); + out << "struct SAL_DLLPUBLIC_RTTI "; + if (canBeWarnUnused(name_)) + out << "SAL_WARN_UNUSED "; + out << id_; + OUString base(entity_->getDirectBase()); + if (!base.isEmpty()) { + out << ": public " << codemaker::cpp::scopedCppName(u2b(base)); + } + out << " {\n"; + inc(); + out << indent() << "inline " << id_ << "();\n"; + if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) { + out << "\n" << indent() << "inline " << id_ << "("; + bool bFirst = !dumpBaseMembers(out, base, true); + for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) { + if (!bFirst) { + out << ", "; + } + dumpType(out, member.type, true, true); + out << " " << member.name << "_"; + bFirst = false; + } + out << ");\n"; + } + if (!entity_->getDirectMembers().empty()) { + out << "\n"; + for (std::vector< unoidl::PlainStructTypeEntity::Member >:: + const_iterator i(entity_->getDirectMembers().begin()); + i != entity_->getDirectMembers().end(); ++i) { + out << indent(); + dumpType(out, i->type); + out << " " << i->name; + if (i == entity_->getDirectMembers().begin() && !base.isEmpty() + && i->type != "hyper" && i->type != "unsigned hyper" + && i->type != "double") { + out << " CPPU_GCC3_ALIGN(" + << codemaker::cpp::scopedCppName(u2b(base)) << ")"; + } + out << ";\n"; + } + } + dec(); + out << "};\n\n#ifdef _WIN32\n# pragma pack(pop)\n#endif\n\n"; +} + +void PlainStructType::dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(out, u"HPP")); + out << "\n"; + includes.dump(out, &name_, true); + out << "\n"; + if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) { + out << "\n"; + } + out << "\ninline " << id_ << "::" << id_ << "()\n"; + inc(); + OUString base(entity_->getDirectBase()); + bool bFirst = true; + if (!base.isEmpty()) { + out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base)) + << "()\n"; + bFirst = false; + } + for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) { + out << indent() << (bFirst ? ":" : ",") << " " << member.name; + dumpInitializer(out, false, member.type); + out << "\n"; + bFirst = false; + } + dec(); + out << "{\n}\n\n"; + if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) { + out << "inline " << id_; + out << "::" << id_ << "("; + bFirst = !dumpBaseMembers(out, base, true); + for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) { + if (!bFirst) { + out << ", "; + } + dumpType(out, member.type, true, true); + out << " " << member.name << "_"; + bFirst = false; + } + out << ")\n"; + inc(); + bFirst = true; + if (!base.isEmpty()) { + out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base)) + << "("; + dumpBaseMembers(out, base, false); + out << ")\n"; + bFirst = false; + } + for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) { + out << indent() << (bFirst ? ":" : ",") << " " << member.name << "(" + << member.name << "_)\n"; + bFirst = false; + } + dec(); + out << "{\n}\n\n"; + } + // print the operator== + out << "\ninline bool operator==(const " << id_ << "& the_lhs, const " << id_ << "& the_rhs)\n"; + out << "{\n"; + inc(); + out << indent() << "return "; + bFirst = true; + if (!base.isEmpty()) { + out << "operator==( static_cast< " << codemaker::cpp::scopedCppName(u2b(base)) + << ">(the_lhs), static_cast< " << codemaker::cpp::scopedCppName(u2b(base)) << ">(the_rhs) )\n"; + bFirst = false; + } + for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) { + if (!bFirst) + out << "\n" << indent() << indent() << "&& "; + out << "the_lhs." << member.name << " == the_rhs." << member.name; + bFirst = false; + } + out << ";\n"; + dec(); + out << "}\n"; + // print the operator!= + out << "\ninline bool operator!=(const " << id_ << "& the_lhs, const " << id_ << "& the_rhs)\n"; + out << "{\n"; + out << indent() << "return !operator==(the_lhs, the_rhs);\n"; + out << "}\n"; + // close namespace + if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) { + out << "\n"; + } + out << "\n"; + dumpGetCppuType(out); + out << "\n#endif // "<< headerDefine << "\n"; +} + +void PlainStructType::dumpLightGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << ("//TODO: On certain platforms with weak memory models, the" + " following code can result in some threads observing that the_type" + " points to garbage\n") + << indent() + << "static ::typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if (the_type == 0) {\n"; + inc(); + out << indent() << "::typelib_static_type_init(&the_type, " + << getTypeClass(name_, true) << ", \"" << name_ << "\");\n"; + dec(); + out << indent() << "}\n" << indent() + << "return *reinterpret_cast< ::css::uno::Type * >(&the_type);\n"; + dumpGetCppuTypePostamble(out); +} + +void PlainStructType::dumpNormalGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << ("//TODO: On certain platforms with weak memory models, the" + " following code can result in some threads observing that the_type" + " points to garbage\n") + << indent() + << "static ::typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if (the_type == 0) {\n"; + inc(); + out << indent() + << "::typelib_TypeDescriptionReference * the_members[] = {\n"; + inc(); + for (std::vector< unoidl::PlainStructTypeEntity::Member >::const_iterator i( + entity_->getDirectMembers().begin()); + i != entity_->getDirectMembers().end();) { + out << indent() << "::cppu::UnoType< "; + dumpType(out, i->type, false, false, false, true); + ++i; + out << " >::get().getTypeLibType()" + << (i == entity_->getDirectMembers().end() ? " };" : ",") << "\n"; + } + dec(); + out << indent() << "::typelib_static_struct_type_init(&the_type, \"" + << name_ << "\", "; + if (entity_->getDirectBase().isEmpty()) { + out << "0"; + } else { + out << "::cppu::UnoType< "; + dumpType(out, entity_->getDirectBase(), false, false, false, true); + out << " >::get().getTypeLibType()"; + } + out << ", " << entity_->getDirectMembers().size() << ", the_members, 0);\n"; + dec(); + out << indent() << "}\n" << indent() + << "return *reinterpret_cast< ::css::uno::Type * >(&the_type);\n"; + dumpGetCppuTypePostamble(out); +} + +void PlainStructType::dumpComprehensiveGetCppuType(FileStream & out) +{ + OUString staticTypeClass("the" + id_ + "Type"); + codemaker::cppumaker::dumpNamespaceOpen(out, name_, false); + out << " namespace detail {\n\n" << indent() << "struct " + << staticTypeClass + << " : public rtl::StaticWithInit< ::css::uno::Type *, " + << staticTypeClass << " >\n" << indent() << "{\n"; + inc(); + out << indent() << "::css::uno::Type * operator()() const\n" + << indent() << "{\n"; + inc(); + out << indent() << "::rtl::OUString the_name( \"" << name_ << "\" );\n"; + std::map< OUString, sal_uInt32 > types; + std::vector< unoidl::PlainStructTypeEntity::Member >::size_type n = 0; + for (const unoidl::PlainStructTypeEntity::Member& member : entity_->getDirectMembers()) { + if (types.emplace( + member.type, static_cast< sal_uInt32 >(types.size())). + second) { + dumpCppuGetType(out, member.type, &name_); + // For typedefs, use the resolved type name, as there will be no + // information available about the typedef itself at runtime (the + // above getCppuType call will make available information about the + // resolved type); no extra #include for the resolved type is + // needed, as the header for the typedef includes it already: + out << indent() << "::rtl::OUString the_tname" + << static_cast< sal_uInt32 >(types.size() - 1) << "( \"" + << resolveAllTypedefs(member.type) << "\" );\n"; + } + out << indent() << "::rtl::OUString the_name" << n++ << "( \"" + << member.name << "\" );\n"; + } + out << indent() << "::typelib_StructMember_Init the_members[] = {\n"; + inc(); + n = 0; + for (std::vector< unoidl::PlainStructTypeEntity::Member >::const_iterator i( + entity_->getDirectMembers().begin()); + i != entity_->getDirectMembers().end();) { + out << indent() << "{ { " << getTypeClass(i->type, true) + << ", the_tname" << types.find(i->type)->second + << ".pData, the_name" << n++ << ".pData }, false }"; + ++i; + out << (i == entity_->getDirectMembers().end() ? " };" : ",") << "\n"; + } + dec(); + out << indent() << "::typelib_TypeDescription * the_newType = 0;\n" + << indent() + << "::typelib_typedescription_newStruct(&the_newType, the_name.pData, "; + if (entity_->getDirectBase().isEmpty()) { + out << "0"; + } else { + out << "::cppu::UnoType< "; + dumpType(out, entity_->getDirectBase(), false, false, false, true); + out << " >::get().getTypeLibType()"; + } + out << ", " << entity_->getDirectMembers().size() << ", the_members);\n" + << indent() << "::typelib_typedescription_register(&the_newType);\n" + << indent() << "::typelib_typedescription_release(the_newType);\n" + << indent() << "return new ::css::uno::Type(" + << getTypeClass(name_) << ", the_name); // leaked\n"; + dec(); + out << indent() << "}\n"; + dec(); + out << indent() << "};\n"; + codemaker::cppumaker::dumpNamespaceClose(out, name_, false); + out << " }\n\n"; + dumpGetCppuTypePreamble(out); + out << indent() << "return *detail::" << staticTypeClass << "::get();\n"; + dumpGetCppuTypePostamble(out); +} + +bool PlainStructType::dumpBaseMembers( + FileStream & out, OUString const & base, bool withType) +{ + if (base.isEmpty()) + return false; + + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent); + if (sort != codemaker::UnoType::Sort::PlainStruct) { + throw CannotDumpException( + "plain struct type base " + base + + " is not a plain struct type"); + } + rtl::Reference< unoidl::PlainStructTypeEntity > ent2( + dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get())); + assert(ent2.is()); + if (!ent2.is()) { + return false; + } + bool hasMember = dumpBaseMembers(out, ent2->getDirectBase(), withType); + for (const unoidl::PlainStructTypeEntity::Member& member : ent2->getDirectMembers()) { + if (hasMember) { + out << ", "; + } + if (withType) { + dumpType(out, member.type, true, true); + out << " "; + } + out << member.name << "_"; + hasMember = true; + } + return hasMember; +} + +void PlainStructType::addLightGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); +} + +void PlainStructType::addNormalGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); +} + +void PlainStructType::addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addRtlInstanceHxx(); + includes.addRtlUstringH(); + includes.addRtlUstringHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); +} + +sal_uInt32 PlainStructType::getTotalMemberCount(OUString const & base) const +{ + if (base.isEmpty()) { + return 0; + } + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent); + if (sort != codemaker::UnoType::Sort::PlainStruct) { + throw CannotDumpException( + "plain struct type base " + base + " is not a plain struct type"); + } + rtl::Reference< unoidl::PlainStructTypeEntity > ent2( + dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get())); + assert(ent2.is()); + if (!ent2.is()) { + return 0; + } + return getTotalMemberCount(ent2->getDirectBase()) + + ent2->getDirectMembers().size(); //TODO: overflow +} + +class PolyStructType: public CppuType +{ +public: + PolyStructType( + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > const & + entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity) { + assert(entity.is()); + } + +private: + virtual void dumpDeclaration(FileStream& o) override; + + void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override; + + virtual void dumpLightGetCppuType(FileStream & out) override; + + virtual void dumpNormalGetCppuType(FileStream & out) override; + + virtual void dumpComprehensiveGetCppuType(FileStream & out) override; + + virtual void addLightGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual void addNormalGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual void addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual bool isPolymorphic() const override { + return true; + } + + virtual void dumpTemplateHead(FileStream & out) const override; + + virtual void dumpTemplateParameters(FileStream & out) const override; + + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > entity_; +}; + +void PolyStructType::dumpDeclaration(FileStream & out) +{ + out << "\n#ifdef _WIN32\n# pragma pack(push, 8)\n#endif\n\n" << indent(); + dumpTemplateHead(out); + out << "struct SAL_DLLPUBLIC_RTTI " << id_ << " {\n"; + inc(); + out << indent() << "inline " << id_ << "();\n"; + if (!entity_->getMembers().empty()) { + out << "\n" << indent() << "inline " << id_ << "("; + for (std::vector< + unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + if (i != entity_->getMembers().begin()) { + out << ", "; + } + if (i->parameterized) { + dumpTypeParameterName(out, i->type); + out << " const &"; + } else { + dumpType(out, i->type, true, true); + } + out << " " << i->name << "_"; + } + out << ");\n\n"; + // print the member fields + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : + entity_->getMembers()) { + out << indent(); + if (member.parameterized) { + dumpTypeParameterName(out, member.type); + } else { + dumpType(out, member.type); + } + out << " " << member.name << ";\n"; + } + } + dec(); + out << "};\n\n#ifdef _WIN32\n# pragma pack(pop)\n#endif\n\n"; +} + +void PolyStructType::dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(out, u"HPP")); + out << "\n"; + includes.dump(out, &name_, true); + out << "\n"; + if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) { + out << "\n"; + } + out << "\n"; + // dump default (no-arg) constructor + dumpTemplateHead(out); + out << "inline " << id_; + dumpTemplateParameters(out); + out << "::" << id_ << "()\n"; + inc(); + for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + out << indent() << (i == entity_->getMembers().begin() ? ":" : ",") + << " " << i->name; + dumpInitializer(out, i->parameterized, i->type); + out << "\n"; + } + dec(); + out << "{\n}\n\n"; + if (!entity_->getMembers().empty()) { + // dump takes-all-fields constructor + dumpTemplateHead(out); + out << "inline " << id_; + dumpTemplateParameters(out); + out << "::" << id_ << "("; + for (std::vector< + unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + if (i != entity_->getMembers().begin()) { + out << ", "; + } + if (i->parameterized) { + dumpTypeParameterName(out, i->type); + out << " const &"; + } else { + dumpType(out, i->type, true, true); + } + out << " " << i->name << "_"; + } + out << ")\n"; + inc(); + for (std::vector< + unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + out << indent() << (i == entity_->getMembers().begin() ? ":" : ",") + << " " << i->name << "(" << i->name << "_)\n"; + } + dec(); + out << "{\n}\n\n" << indent(); + // dump make_T method + dumpTemplateHead(out); + out << "\n" << indent() << "inline " << id_; + dumpTemplateParameters(out); + out << "\n" << indent() << "make_" << id_ << "("; + for (std::vector< + unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + if (i != entity_->getMembers().begin()) { + out << ", "; + } + if (i->parameterized) { + dumpTypeParameterName(out, i->type); + out << " const &"; + } else { + dumpType(out, i->type, true, true); + } + out << " " << i->name << "_"; + } + out << ")\n" << indent() << "{\n"; + inc(); + out << indent() << "return " << id_; + dumpTemplateParameters(out); + out << "("; + for (std::vector< + unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + if (i != entity_->getMembers().begin()) { + out << ", "; + } + out << i->name << "_"; + } + out << ");\n"; + dec(); + out << indent() << "}\n\n"; + } + // print the operator== + dumpTemplateHead(out); + out << " inline bool operator==(const " << id_; + dumpTemplateParameters(out); + out << "& the_lhs, const " << id_; + dumpTemplateParameters(out); + out << "& the_rhs)\n"; + out << "{\n"; + inc(); + out << indent() << "return "; + bool bFirst = true; + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity_->getMembers()) { + if (!bFirst) + out << "\n" << indent() << indent() << "&& "; + out << "the_lhs." << member.name << " == the_rhs." << member.name; + bFirst = false; + } + out << ";\n"; + dec(); + out << "}\n"; + // print the operator!= + dumpTemplateHead(out); + out << " inline bool operator!=(const " << id_; + dumpTemplateParameters(out); + out << "& the_lhs, const " << id_; + dumpTemplateParameters(out); + out << "& the_rhs)\n"; + out << "{\n"; + out << indent() << "return !operator==(the_lhs, the_rhs);\n"; + out << "}\n"; + // close namespace + if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) { + out << "\n"; + } + out << "\n"; + dumpGetCppuType(out); + out << "\n#endif // "<< headerDefine << "\n"; +} + +void PolyStructType::dumpLightGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << ("//TODO: On certain platforms with weak memory models, the" + " following code can result in some threads observing that the_type" + " points to garbage\n") + << indent() + << "static ::typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if (the_type == 0) {\n"; + inc(); + + out << "#ifdef LIBO_INTERNAL_ONLY\n"; + + out << indent() << "::rtl::OString the_buffer = \"" << name_ + << "<\" +\n"; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end();) { + out << indent() + << ("::rtl::OUStringToOString(" + "::cppu::getTypeFavourChar(static_cast< "); + dumpTypeParameterName(out, *i); + out << " * >(0)).getTypeName(), RTL_TEXTENCODING_UTF8) +\n"; + ++i; + if (i != entity_->getTypeParameters().end()) { + out << indent() << "\",\" +\n"; + } + } + out << indent() << "\">\";\n"; + + out << "#else\n"; + + out << indent() << "::rtl::OStringBuffer the_buffer(\"" << name_ + << "<\");\n"; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end();) { + out << indent() + << ("the_buffer.append(::rtl::OUStringToOString(" + "::cppu::getTypeFavourChar(static_cast< "); + dumpTypeParameterName(out, *i); + out << " * >(0)).getTypeName(), RTL_TEXTENCODING_UTF8));\n"; + ++i; + if (i != entity_->getTypeParameters().end()) { + out << indent() << "the_buffer.append(',');\n"; + } + } + out << indent() << "the_buffer.append('>');\n"; + + out << "#endif\n"; + + out << indent() + << "::typelib_static_type_init(&the_type, " << getTypeClass(name_, true) + << ", the_buffer.getStr());\n"; + + dec(); + out << indent() << "}\n" << indent() + << "return *reinterpret_cast< ::css::uno::Type * >(&the_type);\n"; + dumpGetCppuTypePostamble(out); +} + +void PolyStructType::dumpNormalGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << ("//TODO: On certain platforms with weak memory models, the" + " following code can result in some threads observing that the_type" + " points to garbage\n") + << indent() + << "static ::typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if (the_type == 0) {\n"; + inc(); + out << indent() << "::rtl::OStringBuffer the_buffer(\"" << name_ + << "<\");\n"; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end();) { + out << indent() + << ("the_buffer.append(::rtl::OUStringToOString(" + "::cppu::getTypeFavourChar(static_cast< "); + dumpTypeParameterName(out, *i); + out << " * >(0)).getTypeName(), RTL_TEXTENCODING_UTF8));\n"; + ++i; + if (i != entity_->getTypeParameters().end()) { + out << indent() << "the_buffer.append(',');\n"; + } + } + out << indent() << "the_buffer.append('>');\n" << indent() + << "::typelib_TypeDescriptionReference * the_members[] = {\n"; + inc(); + for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end();) { + out << indent(); + if (i->parameterized) { + out << "::cppu::getTypeFavourChar(static_cast< "; + dumpTypeParameterName(out, i->type); + out << " * >(0))"; + } else { + out << "::cppu::UnoType< "; + dumpType(out, i->type, false, false, false, true); + out << " >::get()"; + } + ++i; + out << ".getTypeLibType()" + << (i == entity_->getMembers().end() ? " };" : ",") << "\n"; + } + dec(); + out << indent() << "static ::sal_Bool const the_parameterizedTypes[] = { "; + for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end(); ++i) { + if (i != entity_->getMembers().begin()) { + out << ", "; + } + out << (i->parameterized ? "true" : "false"); + } + out << " };\n" << indent() + << ("::typelib_static_struct_type_init(&the_type, the_buffer.getStr()," + " 0, ") + << entity_->getMembers().size() + << ", the_members, the_parameterizedTypes);\n"; + dec(); + out << indent() << "}\n" << indent() + << ("return *reinterpret_cast< ::css::uno::Type * >(" + "&the_type);\n"); + dumpGetCppuTypePostamble(out); +} + +void PolyStructType::dumpComprehensiveGetCppuType(FileStream & out) +{ + out << "namespace cppu { namespace detail {\n\n" << indent(); + dumpTemplateHead(out); + OUString staticTypeClass("the" + id_ + "Type"); + out << "struct " << staticTypeClass + << " : public rtl::StaticWithInit< ::css::uno::Type *, " + << staticTypeClass; + dumpTemplateParameters(out); + out << " >\n" << indent() << "{\n"; + inc(); + out << indent() << "::css::uno::Type * operator()() const\n" + << indent() << "{\n"; + inc(); + + out << "#ifdef LIBO_INTERNAL_ONLY\n"; + out << indent() + << "::rtl::OUString the_name =\n"; + out << indent() << "\"" << name_ << "<\" +\n"; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end();) { + out << indent() + << "::cppu::getTypeFavourChar(static_cast< "; + dumpTypeParameterName(out, *i); + out << " * >(0)).getTypeName() +\n"; + ++i; + if (i != entity_->getTypeParameters().end()) { + out << indent() + << "\",\" +\n"; + } + } + out << indent() + << "\">\";\n"; + out << "#else\n"; + out << indent() << "::rtl::OUStringBuffer the_buffer;\n" << indent() + << "the_buffer.append(\"" << name_ << "<\");\n"; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end();) { + out << indent() + << "the_buffer.append(::cppu::getTypeFavourChar(static_cast< "; + dumpTypeParameterName(out, *i); + out << " * >(0)).getTypeName());\n"; + ++i; + if (i != entity_->getTypeParameters().end()) { + out << indent() + << ("the_buffer.append(" + "static_cast< ::sal_Unicode >(','));\n"); + } + } + out << indent() << "the_buffer.append(static_cast< ::sal_Unicode >('>'));\n"; + out << indent() + << "::rtl::OUString the_name(the_buffer.makeStringAndClear());\n"; + out << "#endif\n"; + std::map< OUString, sal_uInt32 > parameters; + std::map< OUString, sal_uInt32 > types; + std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + size_type n = 0; + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity_->getMembers()) { + if (member.parameterized) { + if (parameters.emplace( + member.type, static_cast< sal_uInt32 >(parameters.size())). + second) { + sal_uInt32 k = static_cast< sal_uInt32 >(parameters.size() - 1); + out << indent() + << "::css::uno::Type const & the_ptype" << k + << " = ::cppu::getTypeFavourChar(static_cast< "; + dumpTypeParameterName(out, member.type); + out << " * >(0));\n" << indent() + << "::typelib_TypeClass the_pclass" << k + << " = (::typelib_TypeClass) the_ptype" << k + << ".getTypeClass();\n" << indent() + << "::rtl::OUString the_pname" << k << "(the_ptype" << k + << ".getTypeName());\n"; + } + } else if (types.emplace(member.type, static_cast< sal_uInt32 >(types.size())). + second) { + dumpCppuGetType(out, member.type, &name_); + // For typedefs, use the resolved type name, as there will be no + // information available about the typedef itself at runtime (the + // above getCppuType call will make available information about the + // resolved type); no extra #include for the resolved type is + // needed, as the header for the typedef includes it already: + out << indent() << "::rtl::OUString the_tname" + << static_cast< sal_uInt32 >(types.size() - 1) << "( \"" + << resolveAllTypedefs(member.type) << "\" );\n"; + } + out << indent() << "::rtl::OUString the_name" << n++ << "( \"" + << member.name << "\" );\n"; + } + out << indent() << "::typelib_StructMember_Init the_members[] = {\n"; + inc(); + n = 0; + for (std::vector< unoidl::PolymorphicStructTypeTemplateEntity::Member >:: + const_iterator i(entity_->getMembers().begin()); + i != entity_->getMembers().end();) { + out << indent() << "{ { "; + if (i->parameterized) { + sal_uInt32 k = parameters.find(i->type)->second; + out << "the_pclass" << k << ", the_pname" << k << ".pData"; + } else { + out << getTypeClass(i->type, true) << ", the_tname" + << types.find(i->type)->second << ".pData"; + } + out << ", the_name" << n++ << ".pData }, " + << (i->parameterized ? "true" : "false") << " }"; + ++i; + out << (i == entity_->getMembers().end() ? " };" : ",") << "\n"; + } + dec(); + out << indent() << "::typelib_TypeDescription * the_newType = 0;\n"; + out << indent() + << ("::typelib_typedescription_newStruct(&the_newType, the_name.pData," + " 0, ") + << entity_->getMembers().size() << ", the_members);\n" << indent() + << "::typelib_typedescription_register(&the_newType);\n" << indent() + << "::typelib_typedescription_release(the_newType);\n" << indent() + << "return new ::css::uno::Type(" << getTypeClass(name_) + << ", the_name); // leaked\n"; + dec(); + out << indent() << "}\n"; + dec(); + out << indent() << "};\n } }\n\n"; + dumpGetCppuTypePreamble(out); + out << indent() << "return *detail::" << staticTypeClass; + dumpTemplateParameters(out); + out << "::get();\n"; + dumpGetCppuTypePostamble(out); +} + +void PolyStructType::addLightGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); + includes.addRtlStrbufHxx(); + includes.addRtlTextencH(); + includes.addRtlUstringHxx(); +} + +void PolyStructType::addNormalGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); + includes.addRtlStrbufHxx(); + includes.addRtlTextencH(); + includes.addRtlUstringHxx(); +} + +void PolyStructType::addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addType(); + includes.addCppuUnotypeHxx(); + includes.addRtlInstanceHxx(); + includes.addRtlUstringH(); + includes.addRtlUstringHxx(); + includes.addSalTypesH(); + includes.addTypelibTypeclassH(); + includes.addTypelibTypedescriptionH(); + includes.addRtlStringH(); + includes.addRtlUstrbufHxx(); +} + +void PolyStructType::dumpTemplateHead(FileStream & out) const +{ + out << "template< "; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end(); ++i) { + if (i != entity_->getTypeParameters().begin()) { + out << ", "; + } + out << "typename "; + dumpTypeParameterName(out, *i); + } + out << " > "; +} + +void PolyStructType::dumpTemplateParameters(FileStream & out) const +{ + out << "< "; + for (std::vector< OUString >::const_iterator i( + entity_->getTypeParameters().begin()); + i != entity_->getTypeParameters().end(); ++i) { + if (i != entity_->getTypeParameters().begin()) { + out << ", "; + } + dumpTypeParameterName(out, *i); + } + out << " >"; +} + +OUString typeToIdentifier(std::u16string_view name) +{ + sal_Int32 k; + OUString n(b2u(codemaker::UnoType::decompose(u2b(name), &k))); + OUStringBuffer b(4*k + n.getLength()); + for (sal_Int32 i = 0; i != k; ++i) { + b.append("seq_"); + } + b.append(n); + b.replace(' ', '_'); + b.replace(',', '_'); + b.replace('.', '_'); + b.replace('<', '_'); + b.replace('>', '_'); + return b.makeStringAndClear(); +} + +class ExceptionType: public CppuType +{ +public: + ExceptionType( + rtl::Reference< unoidl::ExceptionTypeEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity) { + assert(entity.is()); + } + +private: + virtual void dumpHdlFile( + FileStream & out, codemaker::cppumaker::Includes & includes) override; + + virtual void dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes & includes) override; + + virtual void addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + virtual void dumpLightGetCppuType(FileStream & out) override; + + virtual void dumpNormalGetCppuType(FileStream & out) override; + + virtual void dumpComprehensiveGetCppuType(FileStream & out) override; + + virtual sal_uInt32 checkInheritedMemberCount() const override { + return getTotalMemberCount(entity_->getDirectBase()); + } + + virtual void dumpDeclaration(FileStream & out) override; + + bool dumpBaseMembers( + FileStream & out, OUString const & base, bool withType, + bool eligibleForDefaults); + + sal_uInt32 getTotalMemberCount(OUString const & base) const; + + rtl::Reference< unoidl::ExceptionTypeEntity > entity_; +}; + +void ExceptionType::dumpHdlFile( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + if (name_ == "com.sun.star.uno.Exception") + { + // LIBO_INTERNAL_ONLY implies GCC >= 7, which we need for this + // Merely checking __has_include is not enough because some systems have the header, + // but do not have a new enough Clang 9 supporting __builtin_FILE/LINE/FUNCTION as used by + // that libstdc++ header. + includes.addCustom("#if defined LIBO_INTERNAL_ONLY && ((defined __GNUC__ && !defined __clang__) || (defined __clang__ && __clang_major__ >= 9)) && __has_include(<experimental/source_location>)"); + includes.addCustom("#define LIBO_USE_SOURCE_LOCATION"); + includes.addCustom("#endif"); + includes.addCustom("#if defined LIBO_USE_SOURCE_LOCATION"); + includes.addCustom("#include <experimental/source_location>"); + includes.addCustom("#include <o3tl/runtimetooustring.hxx>"); + includes.addCustom("#endif"); + } + dumpHFileContent(out, includes); +} + +void ExceptionType::addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addCppuUnotypeHxx(); + includes.addRtlInstanceHxx(); // using rtl::StaticWithInit +} + +void ExceptionType::dumpHppFile( + FileStream & out, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(out, u"HPP")); + out << "\n"; + addDefaultHxxIncludes(includes); + includes.dump(out, &name_, true); + + // for the output operator below + if (name_ == "com.sun.star.uno.Exception") + { + out << "#if defined LIBO_INTERNAL_ONLY\n"; + out << "#include <ostream>\n"; + out << "#include <typeinfo>\n"; + out << "#endif\n"; + } + + out << "\n"; + + if (codemaker::cppumaker::dumpNamespaceOpen(out, name_, false)) { + out << "\n"; + } + + // default constructor + out << "\ninline " << id_ << "::" << id_ << "(\n"; + out << "#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " std::experimental::source_location location\n"; + out << "#endif\n"; + out << " )\n"; + inc(); + OUString base(entity_->getDirectBase()); + bool bFirst = true; + if (!base.isEmpty()) { + out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base)) + << "(\n"; + out << "#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " location\n"; + out << "#endif\n"; + out << ")\n"; + bFirst = false; + } + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + out << indent() << (bFirst ? ":" : ",") << " "; + out << member.name; + dumpInitializer(out, false, member.type); + out << "\n"; + bFirst = false; + } + dec(); + out << "{"; + if (!m_cppuTypeDynamic) { + out << "\n"; + inc(); + dumpCppuGetType(out, name_); + dec(); + } else { + out << " "; + } + if (name_ == "com.sun.star.uno.Exception") + { + out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " if (!Message.isEmpty())\n"; + out << " Message += \" \";\n"; + out << " Message += \"at \" + o3tl::runtimeToOUString(location.file_name()) + \":\" + OUString::number(location.line());\n"; + out << "#endif\n"; + } + out << "}\n\n"; + + // fields constructor + if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) { + out << indent() << "inline " << id_ << "::" << id_ << "("; + bFirst = !dumpBaseMembers(out, base, true, false); + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + if (!bFirst) { + out << ", "; + } + dumpType(out, member.type, true, true); + out << " " << member.name << "_"; + bFirst = false; + } + out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " " << (bFirst ? "" : ", ") << "std::experimental::source_location location\n"; + out << "#endif\n"; + out << ")\n"; + inc(); + bFirst = true; + if (!base.isEmpty()) { + out << indent() << ": " << codemaker::cpp::scopedCppName(u2b(base)) + << "("; + dumpBaseMembers(out, base, false, false); + out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " , location\n"; + out << "#endif\n"; + out << ")\n"; + bFirst = false; + } + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + out << indent() << (bFirst ? ":" : ",") << " " << member.name << "(" + << member.name << "_)\n"; + bFirst = false; + } + dec(); + out << "{"; + if (!m_cppuTypeDynamic) { + out << "\n"; + inc(); + dumpCppuGetType(out, name_); + dec(); + } else { + out << " "; + } + if (name_ == "com.sun.star.uno.Exception") + { + out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " if (!Message.isEmpty())\n"; + out << " Message += \" \";\n"; + out << " Message += \"at \" + o3tl::runtimeToOUString(location.file_name()) + \":\" + OUString::number(location.line());\n"; + out << "#endif\n"; + } + out << "}\n\n"; + } + out << "#if !defined LIBO_INTERNAL_ONLY\n" << indent() << id_ << "::" << id_ + << "(" << id_ << " const & the_other)"; + bFirst = true; + if (!base.isEmpty()) { + out << ": " << codemaker::cpp::scopedCppName(u2b(base)) + << "(the_other)"; + bFirst = false; + } + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + out << (bFirst ? ":" : ",") << " " << member.name << "(the_other." << member.name + << ")"; + bFirst = false; + } + out << indent() << " {}\n\n" << indent() << id_ << "::~" << id_ + << "() {}\n\n" << indent() << id_ << " & " << id_ << "::operator =(" + << id_ << " const & the_other) {\n"; + inc(); + out << indent() + << ("//TODO: Just like its implicitly-defined counterpart, this" + " function definition is not exception-safe\n"); + if (!base.isEmpty()) { + out << indent() << codemaker::cpp::scopedCppName(u2b(base)) + << "::operator =(the_other);\n"; + } + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + out << indent() << member.name << " = the_other." << member.name << ";\n"; + } + out << indent() << "return *this;\n"; + dec(); + out << indent() << "}\n#endif\n\n"; + + // Provide an output operator for printing Exception information to SAL_WARN/SAL_INFO. + if (name_ == "com.sun.star.uno.Exception") + { + out << "#if defined LIBO_INTERNAL_ONLY\n"; + out << "template< typename charT, typename traits >\n"; + out << "inline ::std::basic_ostream<charT, traits> & operator<<(\n"; + out << " ::std::basic_ostream<charT, traits> & os, ::com::sun::star::uno::Exception const & exception)\n"; + out << "{\n"; + out << " // the class name is useful because exception throwing code does not always pass in a useful message\n"; + out << " os << typeid(exception).name();\n"; + out << " if (!exception.Message.isEmpty())\n"; + out << " os << \" msg: \" << exception.Message;\n"; + out << " return os;\n"; + out << "}\n"; + out << "#endif\n"; + out << "\n"; + } + + if (codemaker::cppumaker::dumpNamespaceClose(out, name_, false)) { + out << "\n"; + } + out << "\n"; + + dumpGetCppuType(out); + out << "\n#endif // "<< headerDefine << "\n"; +} + +void ExceptionType::dumpLightGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << "static typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if ( !the_type )\n" << indent() << "{\n"; + inc(); + out << indent() << "typelib_static_type_init( &the_type, " + << getTypeClass(name_, true) << ", \"" << name_ << "\" );\n"; + dec(); + out << indent() << "}\n" << indent() + << ("return * reinterpret_cast< ::css::uno::Type * >(" + " &the_type );\n"); + dumpGetCppuTypePostamble(out); +} + +void ExceptionType::dumpNormalGetCppuType(FileStream & out) +{ + dumpGetCppuTypePreamble(out); + out << indent() + << "static typelib_TypeDescriptionReference * the_type = 0;\n" + << indent() << "if ( !the_type )\n" << indent() << "{\n"; + inc(); + OUString base(entity_->getDirectBase()); + bool baseException = false; + if (!base.isEmpty()) { + if (base == "com.sun.star.uno.Exception") { + baseException = true; + } else { + out << indent() + << ("const ::css::uno::Type& rBaseType =" + " ::cppu::UnoType< "); + dumpType(out, base, true, false, false, true); + out << " >::get();\n\n"; + } + } + if (!entity_->getDirectMembers().empty()) { + out << indent() << "typelib_TypeDescriptionReference * aMemberRefs[" + << entity_->getDirectMembers().size() << "];\n"; + std::set< OUString > seen; + std::vector< unoidl::ExceptionTypeEntity::Member >::size_type n = 0; + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + OUString type(resolveAllTypedefs(member.type)); + OUString modType(typeToIdentifier(type)); + if (seen.insert(type).second) { + out << indent() + << "const ::css::uno::Type& rMemberType_" + << modType << " = ::cppu::UnoType< "; + dumpType(out, type, false, false, false, true); + out << " >::get();\n"; + } + out << indent() << "aMemberRefs[" << n++ << "] = rMemberType_" + << modType << ".getTypeLibType();\n"; + } + out << "\n"; + } + out << indent() << "typelib_static_compound_type_init( &the_type, " + << getTypeClass(name_, true) << ", \"" << name_ << "\", "; + if (baseException) { + out << ("* ::typelib_static_type_getByTypeClass(" + " typelib_TypeClass_EXCEPTION )"); + } else if (base.isEmpty()) { + out << "0"; + } else { + out << "rBaseType.getTypeLibType()"; + } + out << ", " << entity_->getDirectMembers().size() << ", " + << (entity_->getDirectMembers().empty() ? "0" : "aMemberRefs") + << " );\n"; + dec(); + out << indent() << "}\n" << indent() + << ("return * reinterpret_cast< const ::css::uno::Type * >(" + " &the_type );\n"); + dumpGetCppuTypePostamble(out); +} + +void ExceptionType::dumpComprehensiveGetCppuType(FileStream & out) +{ + codemaker::cppumaker::dumpNamespaceOpen(out, name_, false); + out << " namespace detail {\n\n"; + OUString staticTypeClass("the" + id_ + "Type"); + out << indent() << "struct " << staticTypeClass + << " : public rtl::StaticWithInit< ::css::uno::Type *, " + << staticTypeClass << " >\n" << indent() << "{\n"; + inc(); + out << indent() << "::css::uno::Type * operator()() const\n" + << indent() << "{\n"; + inc(); + out << indent() << "::rtl::OUString sTypeName( \"" << name_ << "\" );\n\n" + << indent() << "// Start inline typedescription generation\n" + << indent() << "typelib_TypeDescription * pTD = 0;\n"; + OUString base(entity_->getDirectBase()); + if (!base.isEmpty()) { + out << indent() + << ("const ::css::uno::Type& rSuperType =" + " ::cppu::UnoType< "); + dumpType(out, base, false, false, false, true); + out << " >::get();\n"; + } + std::set< OUString > seen; + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + if (seen.insert(member.type).second) { + dumpCppuGetType(out, member.type); + } + } + if (!entity_->getDirectMembers().empty()) { + out << "\n" << indent() << "typelib_CompoundMember_Init aMembers[" + << entity_->getDirectMembers().size() << "];\n"; + std::vector< unoidl::ExceptionTypeEntity::Member >::size_type n = 0; + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + OUString type(resolveAllTypedefs(member.type)); + out << indent() << "::rtl::OUString sMemberType" << n << "( \"" + << type << "\" );\n" << indent() + << "::rtl::OUString sMemberName" << n << "( \"" << member.name + << "\" );\n" << indent() << "aMembers[" << n + << "].eTypeClass = (typelib_TypeClass)" << getTypeClass(type) + << ";\n" << indent() << "aMembers[" << n + << "].pTypeName = sMemberType" << n << ".pData;\n" << indent() + << "aMembers[" << n << "].pMemberName = sMemberName" << n + << ".pData;\n"; + ++n; + } + } + out << "\n" << indent() << "typelib_typedescription_new(\n"; + inc(); + out << indent() << "&pTD,\n" << indent() << "(typelib_TypeClass)" + << getTypeClass(name_) << ", sTypeName.pData,\n" << indent() + << (base.isEmpty() ? "0" : "rSuperType.getTypeLibType()") << ",\n" + << indent() << entity_->getDirectMembers().size() << ",\n" << indent() + << (entity_->getDirectMembers().empty() ? "0" : "aMembers") + << " );\n\n"; + dec(); + out << indent() + << ("typelib_typedescription_register( (typelib_TypeDescription**)&pTD" + " );\n\n") + << indent() << "typelib_typedescription_release( pTD );\n" << indent() + << "// End inline typedescription generation\n\n" << indent() + << "return new ::css::uno::Type( " << getTypeClass(name_) + << ", sTypeName ); // leaked\n"; + dec(); + out << indent() << "}\n"; + dec(); + out << indent() << "};\n\n"; + codemaker::cppumaker::dumpNamespaceClose(out, name_, false); + out << " }\n\n"; + dumpGetCppuTypePreamble(out); + out << indent() << "return *detail::" << staticTypeClass << "::get();\n"; + dumpGetCppuTypePostamble(out); +} + +void ExceptionType::dumpDeclaration(FileStream & out) +{ + out << "\nclass CPPU_GCC_DLLPUBLIC_EXPORT SAL_WARN_UNUSED " << id_; + OUString base(entity_->getDirectBase()); + if (!base.isEmpty()) { + out << " : public " << codemaker::cpp::scopedCppName(u2b(base)); + } + out << "\n{\npublic:\n"; + inc(); + + // default constructor + out << indent() << "inline CPPU_GCC_DLLPRIVATE " << id_ << "(\n"; + out << "#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << " std::experimental::source_location location = std::experimental::source_location::current()\n"; + out << "#endif\n\n"; + out << " );\n"; + + // constructor that initializes data members + if (!entity_->getDirectMembers().empty() || getInheritedMemberCount() > 0) { + out << indent() << "inline CPPU_GCC_DLLPRIVATE " << id_ << "("; + bool eligibleForDefaults = entity_->getDirectMembers().empty(); + bool bFirst = !dumpBaseMembers(out, base, true, eligibleForDefaults); + for (const unoidl::ExceptionTypeEntity::Member& member : entity_->getDirectMembers()) { + if (!bFirst) { + out << ", "; + } + dumpType(out, member.type, true, true); + out << " " << member.name << "_"; + bFirst = false; + } + out << "\n#if defined LIBO_USE_SOURCE_LOCATION\n"; + out << ", std::experimental::source_location location = std::experimental::source_location::current()\n"; + out << "#endif\n"; + out << " );\n\n"; + } + out << "#if !defined LIBO_INTERNAL_ONLY\n" << indent() + << "inline CPPU_GCC_DLLPRIVATE " << id_ << "(" << id_ + << " const &);\n\n" << indent() << "inline CPPU_GCC_DLLPRIVATE ~" + << id_ << "();\n\n" << indent() << "inline CPPU_GCC_DLLPRIVATE " << id_ + << " & operator =(" << id_ << " const &);\n#endif\n\n"; + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity_->getDirectMembers().begin()); + i != entity_->getDirectMembers().end(); ++i) { + out << indent(); + dumpType(out, i->type); + out << " " << i->name; + if (i == entity_->getDirectMembers().begin() && !base.isEmpty() + && i->type != "hyper" && i->type != "unsigned hyper" + && i->type != "double") { + out << " CPPU_GCC3_ALIGN( " + << codemaker::cpp::scopedCppName(u2b(base)) << " )"; + } + out << ";\n"; + } + dec(); + out << "};\n\n"; +} + +bool ExceptionType::dumpBaseMembers( + FileStream & out, OUString const & base, bool withType, bool eligibleForDefaults) +{ + if (base.isEmpty()) + return false; + + bool hasMember = false; + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent); + if (sort != codemaker::UnoType::Sort::Exception) { + throw CannotDumpException( + "exception type base " + base + " is not an exception type"); + } + rtl::Reference< unoidl::ExceptionTypeEntity > ent2( + dynamic_cast< unoidl::ExceptionTypeEntity * >(ent.get())); + assert(ent2.is()); + if (!ent2.is()) { + return false; + } + hasMember = dumpBaseMembers( out, ent2->getDirectBase(), withType, + eligibleForDefaults && ent2->getDirectMembers().empty() ); + int memberCount = 0; + for (const unoidl::ExceptionTypeEntity::Member& member : ent2->getDirectMembers()) { + if (hasMember) { + out << ", "; + } + if (withType) { + dumpType(out, member.type, true, true); + out << " "; + } + out << member.name << "_"; + // We want to provide a default parameter value for uno::Exception subtype + // constructors, since most of the time we don't pass a Context object in to the exception + // throw sites. + if (eligibleForDefaults + && base == "com.sun.star.uno.Exception" + && memberCount == 1 + && member.name == "Context" + && member.type == "com.sun.star.uno.XInterface") { + out << " = ::css::uno::Reference< ::css::uno::XInterface >()"; + } + hasMember = true; + ++memberCount; + } + return hasMember; +} + +sal_uInt32 ExceptionType::getTotalMemberCount(OUString const & base) const +{ + if (base.isEmpty()) { + return 0; + } + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = m_typeMgr->getSort(base, &ent); + if (sort != codemaker::UnoType::Sort::Exception) { + throw CannotDumpException( + "exception type base " + base + " is not an exception type"); + } + unoidl::ExceptionTypeEntity& ent2(dynamic_cast<unoidl::ExceptionTypeEntity&>(*ent)); + return getTotalMemberCount(ent2.getDirectBase()) + + ent2.getDirectMembers().size(); //TODO: overflow +} + +class EnumType: public CppuType +{ +public: + EnumType( + rtl::Reference< unoidl::EnumTypeEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity) { + assert(entity.is()); + } + +private: + virtual void dumpDeclaration(FileStream& o) override; + + virtual void addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const override; + + void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override; + + void dumpNormalGetCppuType(FileStream& o) override; + void dumpComprehensiveGetCppuType(FileStream& o) override; + + rtl::Reference< unoidl::EnumTypeEntity > entity_; +}; + +void EnumType::addComprehensiveGetCppuTypeIncludes( + codemaker::cppumaker::Includes & includes) const +{ + includes.addCppuUnotypeHxx(); + includes.addRtlInstanceHxx(); // using rtl::StaticWithInit +} + +void EnumType::dumpDeclaration(FileStream& o) +{ + o << "\n#if defined LIBO_INTERNAL_ONLY\n"; + o << "\nenum class SAL_DLLPUBLIC_RTTI " << id_ << "\n{\n"; + o << "\n#else\n"; + o << "\nenum SAL_DLLPUBLIC_RTTI " << id_ << "\n{\n"; + o << "\n#endif\n"; + inc(); + + for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) { + o << indent() << id_ << "_" << u2b(member.name) << " = " << member.value + << ",\n"; + } + + o << indent() << id_ << "_MAKE_FIXED_SIZE = SAL_MAX_ENUM\n"; + + dec(); + o << "};\n\n"; + + // use constexpr to create a kind of type-alias so we don't have to modify existing code + o << "#if defined LIBO_INTERNAL_ONLY\n"; + for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) { + o << "constexpr auto " << id_ << "_" << u2b(member.name) + << " = " + << id_ << "::" << id_ << "_" << u2b(member.name) + << ";\n"; + } + o << "#endif\n"; +} + +void EnumType::dumpHppFile( + FileStream& o, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(o, u"HPP")); + o << "\n"; + + addDefaultHxxIncludes(includes); + includes.dump(o, &name_, true); + o << "\n"; + + dumpGetCppuType(o); + + o << "\n#endif // "<< headerDefine << "\n"; +} + +void EnumType::dumpNormalGetCppuType(FileStream& o) +{ + dumpGetCppuTypePreamble(o); + + o << indent() + << "static typelib_TypeDescriptionReference * the_type = 0;\n"; + + o << indent() << "if ( !the_type )\n" << indent() << "{\n"; + inc(); + + o << indent() << "typelib_static_enum_type_init( &the_type,\n"; + inc(31); + o << indent() << "\"" << name_ << "\",\n" + << indent() << codemaker::cpp::scopedCppName(u2b(name_)) << "_" + << u2b(entity_->getMembers()[0].name) << " );\n"; + dec(31); + dec(); + o << indent() << "}\n"; + o << indent() + << ("return * reinterpret_cast< ::css::uno::Type * >(" + " &the_type );\n"); + dumpGetCppuTypePostamble(o); +} + +void EnumType::dumpComprehensiveGetCppuType(FileStream& o) +{ + if (!isPolymorphic()) + codemaker::cppumaker::dumpNamespaceOpen(o, name_, false); + else + o << "namespace cppu { "; + o << " namespace detail {\n\n"; + + OUString sStaticTypeClass("the" + id_ + "Type"); + o << indent() << "struct " << sStaticTypeClass << " : public rtl::StaticWithInit< ::css::uno::Type *, " << sStaticTypeClass << " >\n"; + o << indent() << "{\n"; + inc(); + o << indent() << "::css::uno::Type * operator()() const\n"; + o << indent() << "{\n"; + + inc(); + o << indent() << "::rtl::OUString sTypeName( \"" << name_ + << "\" );\n\n"; + + o << indent() << "// Start inline typedescription generation\n" + << indent() << "typelib_TypeDescription * pTD = 0;\n\n"; + + o << indent() << "rtl_uString* enumValueNames[" + << entity_->getMembers().size() << "];\n"; + std::vector< unoidl::EnumTypeEntity::Member >::size_type n = 0; + for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) { + o << indent() << "::rtl::OUString sEnumValue" << n << "( \"" + << u2b(member.name) << "\" );\n"; + o << indent() << "enumValueNames[" << n << "] = sEnumValue" << n + << ".pData;\n"; + ++n; + } + + o << "\n" << indent() << "sal_Int32 enumValues[" + << entity_->getMembers().size() << "];\n"; + n = 0; + for (const unoidl::EnumTypeEntity::Member& member : entity_->getMembers()) { + o << indent() << "enumValues[" << n++ << "] = " << member.value << ";\n"; + } + + o << "\n" << indent() << "typelib_typedescription_newEnum( &pTD,\n"; + inc(); + o << indent() << "sTypeName.pData,\n" + << indent() << "(sal_Int32)" + << codemaker::cpp::scopedCppName(u2b(name_), false) << "_" + << u2b(entity_->getMembers()[0].name) << ",\n" + << indent() << entity_->getMembers().size() + << ", enumValueNames, enumValues );\n\n"; + dec(); + + o << indent() + << ("typelib_typedescription_register( (typelib_TypeDescription**)&pTD" + " );\n"); + o << indent() << "typelib_typedescription_release( pTD );\n" + << indent() << "// End inline typedescription generation\n\n"; + + o << indent() << "return new ::css::uno::Type( " + << getTypeClass(name_) << ", sTypeName ); // leaked\n"; + + dec(); + o << indent() << "}\n"; + dec(); + o << indent() << "};\n\n"; + + if (!isPolymorphic()) + codemaker::cppumaker::dumpNamespaceClose(o, name_, false); + else + o << " }"; + o << " }\n\n"; + + dumpGetCppuTypePreamble(o); + o << indent() << "return *detail::" << sStaticTypeClass << "::get();\n"; + dumpGetCppuTypePostamble(o); +} + +class Typedef: public CppuType +{ +public: + Typedef( + rtl::Reference< unoidl::TypedefEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & typeMgr): + CppuType(name, typeMgr), entity_(entity) { + assert(entity.is()); + } + +private: + virtual void dumpDeclaration(FileStream& o) override; + + void dumpHdlFile(FileStream& o, codemaker::cppumaker::Includes & includes) override; + + void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override; + + rtl::Reference< unoidl::TypedefEntity > entity_; +}; + +void Typedef::dumpHdlFile( + FileStream& o, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(o, u"HDL")); + o << "\n"; + + addDefaultHIncludes(includes); + includes.dump(o, nullptr, true); + o << "\n"; + + if (codemaker::cppumaker::dumpNamespaceOpen(o, name_, false)) { + o << "\n"; + } + + dumpDeclaration(o); + + if (codemaker::cppumaker::dumpNamespaceClose(o, name_, false)) { + o << "\n"; + } + + o << "#endif // "<< headerDefine << "\n"; +} + +void Typedef::dumpDeclaration(FileStream& o) +{ + o << "\ntypedef "; + dumpType(o, entity_->getType()); + o << " " << id_ << ";\n\n"; +} + +void Typedef::dumpHppFile( + FileStream& o, codemaker::cppumaker::Includes & includes) +{ + OUString headerDefine(dumpHeaderDefine(o, u"HPP")); + o << "\n"; + + addDefaultHxxIncludes(includes); + includes.dump(o, &name_, true); + o << "\n"; + + o << "\n#endif // "<< headerDefine << "\n"; +} + +class ConstructiveType: public CppuType +{ +public: + ConstructiveType( + OUString const & name, rtl::Reference< TypeManager > const & manager): + CppuType(name, manager) {} + +private: + virtual void dumpHdlFile(FileStream &, codemaker::cppumaker::Includes &) override { + assert(false); // this cannot happen + } + + virtual void dumpFiles(OUString const & uri, CppuOptions const & options) override { + dumpFile(uri, name_, true, options); + } +}; + +bool hasRestParameter( + unoidl::SingleInterfaceBasedServiceEntity::Constructor const & constructor) +{ + return !constructor.parameters.empty() + && constructor.parameters.back().rest; +} + +void includeExceptions( + codemaker::cppumaker::Includes & includes, + codemaker::ExceptionTreeNode const * node) +{ + if (node->present) { + includes.add(node->name); + } else { + for (std::unique_ptr<codemaker::ExceptionTreeNode> const & pChild : node->children) { + includeExceptions(includes, pChild.get()); + } + } +} + +class ServiceType: public ConstructiveType +{ +public: + ServiceType( + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > const & + entity, + OUString const & name, rtl::Reference< TypeManager > const & manager): + ConstructiveType(name, manager), entity_(entity) { + assert(entity.is()); + } + +private: + virtual void dumpHppFile( + FileStream & o, codemaker::cppumaker::Includes & includes) override; + + void dumpCatchClauses( + FileStream & out, codemaker::ExceptionTreeNode const * node); + + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > entity_; +}; + +void failsToSupply( + FileStream & o, std::u16string_view service, OString const & type) +{ + o << "::rtl::OUString(\"component context fails to supply service \") + \"" + << service << "\" + \" of type \" + \"" << type << "\""; +} + +void ServiceType::dumpHppFile( + FileStream & o, codemaker::cppumaker::Includes & includes) +{ + if (!entity_->getConstructors().empty()) { + //TODO: Decide whether the types added to includes should rather be + // added to m_dependencies (and thus be generated during + // dumpDependedTypes): + includes.addCassert(); + includes.addReference(); + includes.addRtlUstringH(); + includes.addRtlUstringHxx(); + includes.add("com.sun.star.uno.DeploymentException"); + includes.add("com.sun.star.uno.XComponentContext"); + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons : entity_->getConstructors()) { + if (cons.defaultConstructor) { + includes.add("com.sun.star.uno.Exception"); + includes.add("com.sun.star.uno.RuntimeException"); + } else { + if (!hasRestParameter(cons)) { + includes.addAny(); + includes.addSequence(); + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param : + cons.parameters) { + if (m_typeMgr->getSort( + b2u(codemaker::UnoType::decompose( + u2b(param.type)))) + == codemaker::UnoType::Sort::Char) { + includes.addCppuUnotypeHxx(); + break; + } + } + } + codemaker::ExceptionTree tree; + for (const OUString& ex : cons.exceptions) { + tree.add(u2b(ex), m_typeMgr); + } + if (!tree.getRoot().present) { + includes.add("com.sun.star.uno.Exception"); + includes.add("com.sun.star.uno.RuntimeException"); + includeExceptions(includes, &tree.getRoot()); + } + } + } + } + OString cppName( + codemaker::cpp::translateUnoToCppIdentifier( + u2b(id_), "service", isGlobal())); + OUString headerDefine(dumpHeaderDefine(o, u"HPP")); + o << "\n"; + includes.dump(o, nullptr, true); + if (!entity_->getConstructors().empty()) { + o << ("\n#if defined ANDROID || defined IOS //TODO\n" + "#include <com/sun/star/lang/XInitialization.hpp>\n" + "#include <osl/detail/component-defines.h>\n#endif\n\n" + "#if defined LO_URE_CURRENT_ENV && defined LO_URE_CTOR_ENV_") + << name_.replaceAll(".", "_dot_") + << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_" + << name_.replaceAll(".", "_dot_") << ") && defined LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") + << "\nextern \"C\" ::css::uno::XInterface * SAL_CALL LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") + << "(::css::uno::XComponentContext *, ::css::uno::Sequence< " + "::css::uno::Any > const &);\n#endif\n"; + } + o << "\n"; + if (codemaker::cppumaker::dumpNamespaceOpen(o, name_, false)) { + o << "\n"; + } + o << "\nclass " << cppName << " {\n"; + inc(); + if (!entity_->getConstructors().empty()) { + OString baseName(u2b(entity_->getBase())); + OString scopedBaseName(codemaker::cpp::scopedCppName(baseName)); + o << "public:\n"; + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons : + entity_->getConstructors()) { + if (cons.defaultConstructor) { + o << indent() << "static ::css::uno::Reference< " + << scopedBaseName << " > " + << codemaker::cpp::translateUnoToCppIdentifier( + "create", "method", codemaker::cpp::IdentifierTranslationMode::NonGlobal, + &cppName) + << ("(::css::uno::Reference< ::css::uno::XComponentContext > const &" + " the_context) {\n"); + inc(); + o << indent() << "assert(the_context.is());\n" << indent() + << "::css::uno::Reference< " << scopedBaseName + << " > the_instance;\n" << indent() << "try {\n"; + inc(); + o << ("#if defined LO_URE_CURRENT_ENV && defined " + "LO_URE_CTOR_ENV_") + << name_.replaceAll(".", "_dot_") + << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_" + << name_.replaceAll(".", "_dot_") + << ") && defined LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") << "\n" << indent() + << "the_instance = ::css::uno::Reference< " << scopedBaseName + << (" >(::css::uno::Reference< ::css::uno::XInterface >(" + "static_cast< ::css::uno::XInterface * >((*" + "LO_URE_CTOR_FUN_") + << name_.replaceAll(".", "_dot_") + << (")(the_context.get(), ::css::uno::Sequence<" + " ::css::uno::Any >())), ::SAL_NO_ACQUIRE)," + " ::css::uno::UNO_QUERY);\n#else\n") + << indent() << "the_instance = ::css::uno::Reference< " + << scopedBaseName + << (" >(the_context->getServiceManager()->" + "createInstanceWithContext(" + " \"") + << name_ + << "\", the_context), ::css::uno::UNO_QUERY);\n#endif\n"; + dec(); + o << indent() + << "} catch (const ::css::uno::RuntimeException &) {\n"; + inc(); + o << indent() << "throw;\n"; + dec(); + o << indent() + << "} catch (const ::css::uno::Exception & the_exception) {\n"; + inc(); + o << indent() << "throw ::css::uno::DeploymentException("; + failsToSupply(o, name_, baseName); + o << " + \": \" + the_exception.Message, the_context);\n"; + dec(); + o << indent() << "}\n" << indent() + << "if (!the_instance.is()) {\n"; + inc(); + o << indent() << "throw ::css::uno::DeploymentException("; + failsToSupply(o, name_, baseName); + o << ", the_context);\n"; + dec(); + o << indent() << "}\n" << indent() << "return the_instance;\n"; + dec(); + o << indent() << "}\n\n"; + } else { + o << indent() << "static ::css::uno::Reference< " + << scopedBaseName << " > " + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(cons.name), "method", codemaker::cpp::IdentifierTranslationMode::NonGlobal, + &cppName) + << ("(::css::uno::Reference< ::css::uno::XComponentContext > const &" + " the_context"); + bool rest = hasRestParameter(cons); + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param : + cons.parameters) { + o << ", "; + OUStringBuffer buf(2 + param.type.getLength()); + if (param.rest) { + buf.append("[]"); + } + buf.append(param.type); + OUString type(buf.makeStringAndClear()); + bool byRef = passByReference(type); + dumpType(o, type, byRef, byRef); + o << " " + << codemaker::cpp::translateUnoToCppIdentifier( + u2b(param.name), "param", codemaker::cpp::IdentifierTranslationMode::NonGlobal); + } + o << ") {\n"; + inc(); + o << indent() << "assert(the_context.is());\n"; + if (!rest && !cons.parameters.empty()) { + o << indent() + << "::css::uno::Sequence< ::css::uno::Any > the_arguments(" + << cons.parameters.size() << ");\n"; + o << indent() + << "::css::uno::Any* the_arguments_array = the_arguments.getArray();\n"; + + std::vector< + unoidl::SingleInterfaceBasedServiceEntity::Constructor:: + Parameter >::size_type n = 0; + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& j : + cons.parameters) { + o << indent() << "the_arguments_array[" << n++ << "] "; + OString param( + codemaker::cpp::translateUnoToCppIdentifier( + u2b(j.name), "param", + codemaker::cpp::IdentifierTranslationMode::NonGlobal)); + sal_Int32 rank; + if (resolveOuterTypedefs(j.type) == "any") { + o << "= " << param; + } else if (m_typeMgr->getSort( + b2u(codemaker::UnoType::decompose( + u2b(j.type), &rank))) + == codemaker::UnoType::Sort::Char) { + o << "= ::css::uno::Any(&" << param + << ", ::cppu::UnoType< "; + for (sal_Int32 k = 0; k < rank; ++k) { + o << "::cppu::UnoSequenceType< "; + } + o << "::cppu::UnoCharType"; + for (sal_Int32 k = 0; k < rank; ++k) { + o << " >"; + } + o << " >::get())"; + } else { + o << "<<= " << param; + } + o << ";\n"; + } + } + o << indent() << "::css::uno::Reference< " + << scopedBaseName << " > the_instance;\n"; + codemaker::ExceptionTree tree; + for (const OUString& ex : cons.exceptions) { + tree.add(u2b(ex), m_typeMgr); + } + if (!tree.getRoot().present) { + o << indent() << "try {\n"; + inc(); + } + o << ("#if defined LO_URE_CURRENT_ENV && defined " + "LO_URE_CTOR_ENV_") + << name_.replaceAll(".", "_dot_") + << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_" + << name_.replaceAll(".", "_dot_") + << ") && defined LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") << "\n" << indent() + << "the_instance = ::css::uno::Reference< " << scopedBaseName + << (" >(::css::uno::Reference< ::css::uno::XInterface >(" + "static_cast< ::css::uno::XInterface * >((*" + "LO_URE_CTOR_FUN_") + << name_.replaceAll(".", "_dot_") + << ")(the_context.get(), "; + if (rest) { + o << codemaker::cpp::translateUnoToCppIdentifier( + u2b(cons.parameters.back().name), "param", + codemaker::cpp::IdentifierTranslationMode::NonGlobal); + } else if (cons.parameters.empty()) { + o << "::css::uno::Sequence< ::css::uno::Any >()"; + } else { + o << "the_arguments"; + } + o << ")), ::SAL_NO_ACQUIRE), ::css::uno::UNO_QUERY);\n" << indent() + << ("::css::uno::Reference< ::css::lang::XInitialization > " + "init(the_instance, ::css::uno::UNO_QUERY);\n") + << indent() << "if (init.is()) {\n" + << indent() << " init->initialize("; + if (cons.parameters.empty()) { + o << "::css::uno::Sequence< ::css::uno::Any >()"; + } else { + o << "the_arguments"; + } + o << ");\n" << indent() << "}\n"; + o << "#else\n" + << indent() << "the_instance = ::css::uno::Reference< " + << scopedBaseName + << (" >(the_context->getServiceManager()->" + "createInstanceWithArgumentsAndContext(" + " \"") + << name_ << "\", "; + if (rest) { + o << codemaker::cpp::translateUnoToCppIdentifier( + u2b(cons.parameters.back().name), "param", + codemaker::cpp::IdentifierTranslationMode::NonGlobal); + } else if (cons.parameters.empty()) { + o << "::css::uno::Sequence< ::css::uno::Any >()"; + } else { + o << "the_arguments"; + } + o << ", the_context), ::css::uno::UNO_QUERY);\n#endif\n"; + if (!tree.getRoot().present) { + dec(); + o << indent() + << "} catch (const ::css::uno::RuntimeException &) {\n"; + inc(); + o << indent() << "throw;\n"; + dec(); + dumpCatchClauses(o, &tree.getRoot()); + o << indent() + << ("} catch (const ::css::uno::Exception &" + " the_exception) {\n"); + inc(); + o << indent() << "throw ::css::uno::DeploymentException("; + failsToSupply(o, name_, baseName); + o << " + \": \" + the_exception.Message, the_context);\n"; + dec(); + o << indent() << "}\n"; + } + o << indent() << "if (!the_instance.is()) {\n"; + inc(); + o << indent() << "throw ::css::uno::DeploymentException("; + failsToSupply(o, name_, baseName); + o << ", the_context);\n"; + dec(); + o << indent() << "}\n" << indent() << "return the_instance;\n"; + dec(); + o << indent() << "}\n\n"; + } + } + } + o << "private:\n"; + o << indent() << cppName << "(); // not implemented\n" + << indent() << cppName << "(" << cppName << " &); // not implemented\n" + << indent() << "~" << cppName << "(); // not implemented\n" + << indent() << "void operator =(" << cppName << "); // not implemented\n"; + dec(); + o << "};\n\n"; + if (codemaker::cppumaker::dumpNamespaceClose(o, name_, false)) { + o << "\n"; + } + o << "\n#endif // "<< headerDefine << "\n"; +} + +void ServiceType::dumpCatchClauses( + FileStream & out, codemaker::ExceptionTreeNode const * node) +{ + if (node->present) { + out << indent() << "} catch (const "; + dumpType(out, b2u(node->name)); + out << " &) {\n"; + inc(); + out << indent() << "throw;\n"; + dec(); + } else { + for (std::unique_ptr<codemaker::ExceptionTreeNode> const & pChild : node->children) { + dumpCatchClauses(out, pChild.get()); + } + } +} + +class SingletonType: public ConstructiveType +{ +public: + SingletonType( + rtl::Reference< unoidl::InterfaceBasedSingletonEntity > const & entity, + OUString const & name, rtl::Reference< TypeManager > const & manager): + ConstructiveType(name, manager), entity_(entity) { + assert(entity.is()); + } + +private: + virtual void dumpHppFile( + FileStream & o, codemaker::cppumaker::Includes & includes) override; + + rtl::Reference< unoidl::InterfaceBasedSingletonEntity > entity_; +}; + +void SingletonType::dumpHppFile( + FileStream & o, codemaker::cppumaker::Includes & includes) +{ + OString cppName( + codemaker::cpp::translateUnoToCppIdentifier( + u2b(id_), "singleton", isGlobal())); + OString baseName(u2b(entity_->getBase())); + OString scopedBaseName(codemaker::cpp::scopedCppName(baseName)); + OUString headerDefine(dumpHeaderDefine(o, u"HPP")); + o << "\n"; + //TODO: Decide whether the types added to includes should rather be added to + // m_dependencies (and thus be generated during dumpDependedTypes): + includes.add("com.sun.star.uno.DeploymentException"); + includes.add("com.sun.star.uno.XComponentContext"); + includes.addCassert(); + includes.addAny(); + includes.addReference(); + includes.addRtlUstringH(); + includes.addRtlUstringHxx(); + includes.dump(o, nullptr, true); + o << ("\n#if defined ANDROID || defined IOS //TODO\n" + "#include <com/sun/star/lang/XInitialization.hpp>\n" + "#include <osl/detail/component-defines.h>\n#endif\n\n" + "#if defined LO_URE_CURRENT_ENV && defined LO_URE_CTOR_ENV_") + << name_.replaceAll(".", "_dot_") + << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_" + << name_.replaceAll(".", "_dot_") << ") && defined LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") + << "\nextern \"C\" ::css::uno::XInterface * SAL_CALL LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") + << "(::css::uno::XComponentContext *, ::css::uno::Sequence< " + "::css::uno::Any > const &);\n#endif\n"; + o << "\n"; + if (codemaker::cppumaker::dumpNamespaceOpen(o, name_, false)) { + o << "\n"; + } + o << "\nclass " << cppName << " {\npublic:\n"; + inc(); + o << indent() << "static ::css::uno::Reference< " + << scopedBaseName << " > " + << codemaker::cpp::translateUnoToCppIdentifier( + "get", "method", codemaker::cpp::IdentifierTranslationMode::NonGlobal, &cppName) + << ("(::css::uno::Reference<" + " ::css::uno::XComponentContext > const & the_context)" + " {\n"); + inc(); + o << indent() << "assert(the_context.is());\n" << indent() + << "::css::uno::Reference< " << scopedBaseName + << (" > instance;\n#if defined LO_URE_CURRENT_ENV && defined " + "LO_URE_CTOR_ENV_") + << name_.replaceAll(".", "_dot_") + << " && (LO_URE_CURRENT_ENV) == (LO_URE_CTOR_ENV_" + << name_.replaceAll(".", "_dot_") + << ") && defined LO_URE_CTOR_FUN_" + << name_.replaceAll(".", "_dot_") << "\n" << indent() + << "instance = ::css::uno::Reference< " << scopedBaseName + << (" >(::css::uno::Reference< ::css::uno::XInterface >(" + "static_cast< ::css::uno::XInterface * >((*" + "LO_URE_CTOR_FUN_") + << name_.replaceAll(".", "_dot_") + << (")(the_context.get(), ::css::uno::Sequence<" + " ::css::uno::Any >())), ::SAL_NO_ACQUIRE)," + " ::css::uno::UNO_QUERY);\n#else\n") + << indent() << ("the_context->getValueByName(" + "::rtl::OUString( \"/singletons/") + << name_ << "\" )) >>= instance;\n#endif\n" + << indent() << "if (!instance.is()) {\n"; + inc(); + o << indent() + << ("throw ::css::uno::DeploymentException(" + "::rtl::OUString( \"component context" + " fails to supply singleton ") + << name_ << " of type " << baseName << "\" ), the_context);\n"; + dec(); + o << indent() << "}\n" << indent() << "return instance;\n"; + dec(); + o << indent() << "}\n\n"; + o << "private:\n"; + o << indent() << cppName << "(); // not implemented\n" + << indent() << cppName << "(" << cppName << " &); // not implemented\n" + << indent() << "~" << cppName << "(); // not implemented\n" + << indent() << "void operator =(" << cppName << "); // not implemented\n"; + dec(); + o << "};\n\n"; + if (codemaker::cppumaker::dumpNamespaceClose(o, name_, false)) { + o << "\n"; + } + o << "\n#endif // "<< headerDefine << "\n"; +} + +} + +void produce( + OUString const & name, rtl::Reference< TypeManager > const & manager, + codemaker::GeneratedTypeSet & generated, CppuOptions const & options) +{ + if (generated.contains(u2b(name))) { + return; + } + generated.add(u2b(name)); + if (!manager->foundAtPrimaryProvider(name)) { + return; + } + rtl::Reference< unoidl::Entity > ent; + rtl::Reference< unoidl::MapCursor > cur; + switch (manager->getSort(name, &ent, &cur)) { + case codemaker::UnoType::Sort::Module: { + OUString prefix; + if (!name.isEmpty()) { + prefix = name + "."; + } + for (;;) { + OUString mem; + if (!cur->getNext(&mem).is()) { + break; + } + produce(prefix + mem, manager, generated, options); + } + break; + } + case codemaker::UnoType::Sort::Enum: { + EnumType t( + dynamic_cast< unoidl::EnumTypeEntity * >(ent.get()), name, + manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::PlainStruct: { + PlainStructType t( + dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()), + name, manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::PolymorphicStructTemplate: { + PolyStructType t( + dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + ent.get()), + name, manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::Exception: { + ExceptionType t( + dynamic_cast< unoidl::ExceptionTypeEntity * >(ent.get()), name, + manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::Interface: { + InterfaceType t( + dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()), name, + manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::Typedef: { + Typedef t( + dynamic_cast< unoidl::TypedefEntity * >(ent.get()), name, + manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::ConstantGroup: { + ConstantGroup t( + dynamic_cast< unoidl::ConstantGroupEntity * >(ent.get()), name, + manager); + if (t.hasConstants()) { + t.dump(options); + } + break; + } + case codemaker::UnoType::Sort::SingleInterfaceBasedService: { + ServiceType t( + dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get()), + name, manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::InterfaceBasedSingleton: { + SingletonType t( + dynamic_cast< unoidl::InterfaceBasedSingletonEntity * >( + ent.get()), + name, manager); + t.dump(options); + t.dumpDependedTypes(generated, options); + break; + } + case codemaker::UnoType::Sort::AccumulationBasedService: + case codemaker::UnoType::Sort::ServiceBasedSingleton: + break; + default: + throw CannotDumpException( + "unexpected entity \"" + name + "\" in call to produce"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/cpputype.hxx b/codemaker/source/cppumaker/cpputype.hxx new file mode 100644 index 000000000..40fc94f26 --- /dev/null +++ b/codemaker/source/cppumaker/cpputype.hxx @@ -0,0 +1,35 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +namespace codemaker { class GeneratedTypeSet; } +namespace rtl { class OUString; } +class CppuOptions; +class TypeManager; + +void produce( + OUString const & name, rtl::Reference< TypeManager > const & manager, + codemaker::GeneratedTypeSet & generated, CppuOptions const & options); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/dependencies.cxx b/codemaker/source/cppumaker/dependencies.cxx new file mode 100644 index 000000000..1af6b9d46 --- /dev/null +++ b/codemaker/source/cppumaker/dependencies.cxx @@ -0,0 +1,296 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cassert> +#include <utility> +#include <vector> + +#include <codemaker/global.hxx> +#include <codemaker/typemanager.hxx> +#include <codemaker/unotype.hxx> + +#include <rtl/ref.hxx> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <unoidl/unoidl.hxx> + +#include "dependencies.hxx" + +namespace codemaker::cppumaker { + +Dependencies::Dependencies( + rtl::Reference< TypeManager > const & manager, OUString const & name): + m_manager(manager), m_voidDependency(false), m_booleanDependency(false), + m_byteDependency(false), m_shortDependency(false), + m_unsignedShortDependency(false), m_longDependency(false), + m_unsignedLongDependency(false), m_hyperDependency(false), + m_unsignedHyperDependency(false), m_charDependency(false), + m_stringDependency(false), m_typeDependency(false), m_anyDependency(false), + m_sequenceDependency(false) +{ + assert(manager.is()); + rtl::Reference< unoidl::Entity > ent; + switch (m_manager->getSort(name, &ent)) { + case UnoType::Sort::Enum: + break; + case UnoType::Sort::PlainStruct: + { + rtl::Reference< unoidl::PlainStructTypeEntity > ent2( + static_cast< unoidl::PlainStructTypeEntity * >(ent.get())); + if (!ent2->getDirectBase().isEmpty()) { + insert(ent2->getDirectBase(), KIND_NORMAL); + } + for (const unoidl::PlainStructTypeEntity::Member& member : ent2->getDirectMembers()) + { + insert(member.type, KIND_NORMAL); + } + break; + } + case UnoType::Sort::PolymorphicStructTemplate: + { + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > ent2( + static_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + ent.get())); + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : ent2->getMembers()) + { + if (!member.parameterized) { + insert(member.type, KIND_NORMAL); + } + } + break; + } + case UnoType::Sort::Exception: + { + rtl::Reference< unoidl::ExceptionTypeEntity > ent2( + static_cast< unoidl::ExceptionTypeEntity * >(ent.get())); + if (!ent2->getDirectBase().isEmpty()) { + insert(ent2->getDirectBase(), KIND_NORMAL); + } + for (const unoidl::ExceptionTypeEntity::Member& member : ent2->getDirectMembers()) + { + insert(member.type, KIND_NORMAL); + } + break; + } + case UnoType::Sort::Interface: + { + rtl::Reference< unoidl::InterfaceTypeEntity > ent2( + static_cast< unoidl::InterfaceTypeEntity * >(ent.get())); + for (const unoidl::AnnotatedReference& ar : ent2->getDirectMandatoryBases()) + { + insert(ar.name, KIND_BASE); + } + if (!(ent2->getDirectAttributes().empty() + && ent2->getDirectMethods().empty())) + { + insert(u"com.sun.star.uno.RuntimeException", KIND_EXCEPTION); + } + for (const unoidl::InterfaceTypeEntity::Attribute& attr : ent2->getDirectAttributes()) + { + insert(attr.type, KIND_NORMAL); + for (const OUString& ex : attr.getExceptions) + { + insert(ex, KIND_EXCEPTION); + } + for (const OUString& ex : attr.setExceptions) + { + insert(ex, KIND_EXCEPTION); + } + } + for (const unoidl::InterfaceTypeEntity::Method& method : ent2->getDirectMethods()) + { + insert(method.returnType, KIND_NORMAL); + for (const unoidl::InterfaceTypeEntity::Method::Parameter& param : method.parameters) + { + insert(param.type, KIND_NORMAL); + } + for (const OUString& ex : method.exceptions) + { + insert(ex, KIND_EXCEPTION); + } + } + break; + } + case UnoType::Sort::Typedef: + insert( + static_cast< unoidl::TypedefEntity * >(ent.get())->getType(), + KIND_NORMAL); + break; + case UnoType::Sort::ConstantGroup: + { + rtl::Reference< unoidl::ConstantGroupEntity > ent2( + static_cast< unoidl::ConstantGroupEntity * >(ent.get())); + for (const unoidl::ConstantGroupEntity::Member& member : ent2->getMembers()) + { + switch (member.value.type) { + case unoidl::ConstantValue::TYPE_BOOLEAN: + m_booleanDependency = true; + break; + case unoidl::ConstantValue::TYPE_BYTE: + m_byteDependency = true; + break; + case unoidl::ConstantValue::TYPE_SHORT: + m_shortDependency = true; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT: + m_unsignedShortDependency = true; + break; + case unoidl::ConstantValue::TYPE_LONG: + m_longDependency = true; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_LONG: + m_unsignedLongDependency = true; + break; + case unoidl::ConstantValue::TYPE_HYPER: + m_hyperDependency = true; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER: + m_unsignedHyperDependency = true; + break; + case unoidl::ConstantValue::TYPE_FLOAT: + break; + case unoidl::ConstantValue::TYPE_DOUBLE: + break; + } + } + break; + } + case UnoType::Sort::SingleInterfaceBasedService: + { + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > ent2( + static_cast< unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get())); + if (!ent2->getConstructors().empty()) { + insert(ent2->getBase(), KIND_NORMAL); + } + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons : ent2->getConstructors()) + { + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param + : cons.parameters) + { + insert(param.type, KIND_NORMAL); + if (param.rest) { + m_sequenceDependency = true; + } + } + for (const OUString& ex : cons.exceptions) + { + insert(ex, KIND_EXCEPTION); + } + } + break; + } + case UnoType::Sort::InterfaceBasedSingleton: + insert( + static_cast< unoidl::InterfaceBasedSingletonEntity * >(ent.get())-> + getBase(), + KIND_NORMAL); + break; + default: + assert(false); // this cannot happen + } +} + +Dependencies::~Dependencies() {} + +void Dependencies::insert(std::u16string_view name, Kind kind) { + sal_Int32 k; + std::vector< OString > args; + OUString n(b2u(UnoType::decompose(u2b(name), &k, &args))); + if (k != 0) { + m_sequenceDependency = true; + } + switch (m_manager->getSort(n)) { + case UnoType::Sort::Void: + m_voidDependency = true; + break; + case UnoType::Sort::Boolean: + m_booleanDependency = true; + break; + case UnoType::Sort::Byte: + m_byteDependency = true; + break; + case UnoType::Sort::Short: + m_shortDependency = true; + break; + case UnoType::Sort::UnsignedShort: + m_unsignedShortDependency = true; + break; + case UnoType::Sort::Long: + m_longDependency = true; + break; + case UnoType::Sort::UnsignedLong: + m_unsignedLongDependency = true; + break; + case UnoType::Sort::Hyper: + m_hyperDependency = true; + break; + case UnoType::Sort::UnsignedHyper: + m_unsignedHyperDependency = true; + break; + case UnoType::Sort::Float: + break; + case UnoType::Sort::Double: + break; + case UnoType::Sort::Char: + m_charDependency = true; + break; + case UnoType::Sort::String: + m_stringDependency = true; + break; + case UnoType::Sort::Type: + m_typeDependency = true; + break; + case UnoType::Sort::Any: + m_anyDependency = true; + break; + case UnoType::Sort::PolymorphicStructTemplate: + for (const OString& arg : args) + { + insert(b2u(arg), KIND_NORMAL); + } + [[fallthrough]]; + case UnoType::Sort::Sequence: + case UnoType::Sort::Enum: + case UnoType::Sort::PlainStruct: + case UnoType::Sort::Exception: + case UnoType::Sort::Interface: + case UnoType::Sort::Typedef: + { + std::pair< Map::iterator, bool > i( + m_map.emplace(n, kind)); + if (!i.second && kind == KIND_BASE) { + assert(i.first->second != KIND_EXCEPTION); + i.first->second = KIND_BASE; + } + break; + } + default: + throw CannotDumpException( + OUString::Concat("unexpected type \"") + name + + "\" in call to codemaker::cppumaker::Dependencies::Dependencies"); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/dependencies.hxx b/codemaker/source/cppumaker/dependencies.hxx new file mode 100644 index 000000000..0071397aa --- /dev/null +++ b/codemaker/source/cppumaker/dependencies.hxx @@ -0,0 +1,126 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <map> +#include <string_view> + +#include <rtl/ref.hxx> + +namespace rtl { class OUString; } +class TypeManager; + +/// @HTML + +namespace codemaker::cppumaker { + +/** + A simple class to track which other entities a given entity depends on. + + <p>This class is not multi-thread–safe.</p> + */ +class Dependencies { +public: + /** + Flags to distinguish whether one entity depends on another entity because + the second is a direct base of the first or an exception thrown by the + first. + */ + enum Kind { KIND_NORMAL, KIND_BASE, KIND_EXCEPTION }; + + typedef std::map< OUString, Kind > Map; + + /** + Constructs the dependencies for a given entity. + + @param manager a type manager, to obtain information about the given + entity; must not be null + + @param name the UNOIDL name of an enum type, plain struct type, + polymorphic struct type template, exception type, interface type, + typedef, constant group, single-interface--based service, or + interface-based singleton entity + */ + Dependencies( + rtl::Reference< TypeManager > const & manager, + OUString const & name); + + ~Dependencies(); + + Dependencies(const Dependencies&) = delete; + const Dependencies& operator=(const Dependencies&) = delete; + + Map const & getMap() const { return m_map; } + + bool hasBooleanDependency() const { return m_booleanDependency; } + + bool hasByteDependency() const { return m_byteDependency; } + + bool hasShortDependency() const { return m_shortDependency; } + + bool hasUnsignedShortDependency() const + { return m_unsignedShortDependency; } + + bool hasLongDependency() const { return m_longDependency; } + + bool hasUnsignedLongDependency() const + { return m_unsignedLongDependency; } + + bool hasHyperDependency() const { return m_hyperDependency; } + + bool hasUnsignedHyperDependency() const + { return m_unsignedHyperDependency; } + + bool hasCharDependency() const { return m_charDependency; } + + bool hasStringDependency() const { return m_stringDependency; } + + bool hasTypeDependency() const { return m_typeDependency; } + + bool hasAnyDependency() const { return m_anyDependency; } + + bool hasSequenceDependency() const { return m_sequenceDependency; } + +private: + void insert(std::u16string_view name, Kind kind); + + rtl::Reference< TypeManager > m_manager; + Map m_map; + bool m_voidDependency; + bool m_booleanDependency; + bool m_byteDependency; + bool m_shortDependency; + bool m_unsignedShortDependency; + bool m_longDependency; + bool m_unsignedLongDependency; + bool m_hyperDependency; + bool m_unsignedHyperDependency; + bool m_charDependency; + bool m_stringDependency; + bool m_typeDependency; + bool m_anyDependency; + bool m_sequenceDependency; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/dumputils.cxx b/codemaker/source/cppumaker/dumputils.cxx new file mode 100644 index 000000000..2a3e809e7 --- /dev/null +++ b/codemaker/source/cppumaker/dumputils.cxx @@ -0,0 +1,79 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "dumputils.hxx" + +#include <codemaker/global.hxx> + +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <o3tl/string_view.hxx> + + +namespace codemaker::cppumaker { + +bool dumpNamespaceOpen( + FileStream & out, std::u16string_view entityName, bool fullModuleType) +{ + bool bOutput = false; + bool bFirst = true; + for (sal_Int32 i = 0; i >= 0;) { + std::u16string_view id(o3tl::getToken(entityName, 0, '.', i)); + if (fullModuleType || i >= 0) { + if (!bFirst) { + out << " "; + } + out << "namespace " << id << " {"; + bFirst = false; + bOutput = true; + } + } + return bOutput; +} + +bool dumpNamespaceClose( + FileStream & out, std::u16string_view entityName, bool fullModuleType) +{ + bool bOutput = false; + bool bFirst = true; + for (size_t i = 0; i != std::u16string_view::npos;) { + i = entityName.find('.', i); + if (i != std::u16string_view::npos) { + ++i; + } + if (fullModuleType || i != std::u16string_view::npos) { + if (!bFirst) { + out << " "; + } + out << "}"; + bFirst = false; + bOutput = true; + } + } + return bOutput; +} + +void dumpTypeIdentifier(FileStream & out, std::u16string_view entityName) { + out << entityName.substr(entityName.rfind('.') + 1); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/dumputils.hxx b/codemaker/source/cppumaker/dumputils.hxx new file mode 100644 index 000000000..24e5bae3b --- /dev/null +++ b/codemaker/source/cppumaker/dumputils.hxx @@ -0,0 +1,40 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> +#include <string_view> + +namespace rtl +{ +class OUString; +} +class FileStream; + +namespace codemaker::cppumaker +{ +bool dumpNamespaceOpen(FileStream& out, std::u16string_view entityName, bool fullModuleType); + +bool dumpNamespaceClose(FileStream& out, std::u16string_view entityName, bool fullModuleType); + +void dumpTypeIdentifier(FileStream& out, std::u16string_view entityName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/includes.cxx b/codemaker/source/cppumaker/includes.cxx new file mode 100644 index 000000000..9dacdf268 --- /dev/null +++ b/codemaker/source/cppumaker/includes.cxx @@ -0,0 +1,273 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "includes.hxx" + +#include "dependencies.hxx" +#include "dumputils.hxx" + +#include <codemaker/global.hxx> +#include <codemaker/typemanager.hxx> +#include <codemaker/unotype.hxx> + +#include <osl/diagnose.h> +#include <rtl/ref.hxx> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include <utility> +#include <vector> + +using codemaker::cppumaker::Includes; + +Includes::Includes( + rtl::Reference< TypeManager > manager, + codemaker::cppumaker::Dependencies const & dependencies, bool hpp): + m_manager(std::move(manager)), m_map(dependencies.getMap()), m_hpp(hpp), + m_includeCassert(false), + m_includeAny(dependencies.hasAnyDependency()), m_includeReference(false), + m_includeSequence(dependencies.hasSequenceDependency()), + m_includeType(dependencies.hasTypeDependency()), + m_includeCppuMacrosHxx(false), m_includeCppuUnotypeHxx(false), + m_includeOslMutexHxx(false), + m_includeRtlStrbufHxx(false), m_includeRtlStringH(false), + m_includeRtlTextencH(false), m_includeRtlUstrbufHxx(false), + m_includeRtlUstringH(false), + m_includeRtlUstringHxx(dependencies.hasStringDependency()), + m_includeRtlInstanceHxx(false), + m_includeSalTypesH( + dependencies.hasBooleanDependency() || dependencies.hasByteDependency() + || dependencies.hasShortDependency() + || dependencies.hasUnsignedShortDependency() + || dependencies.hasLongDependency() + || dependencies.hasUnsignedLongDependency() + || dependencies.hasHyperDependency() + || dependencies.hasUnsignedHyperDependency() + || dependencies.hasCharDependency()), + m_includeTypelibTypeclassH(false), + m_includeTypelibTypedescriptionH(false) +{} + +Includes::~Includes() +{} + +void Includes::add(OString const & entityName) { + sal_Int32 k; + std::vector< OString > args; + OUString n(b2u(codemaker::UnoType::decompose(entityName, &k, &args))); + if (k != 0) { + m_includeSequence = true; + } + switch (m_manager->getSort(n)) { + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Char: + m_includeSalTypesH = true; + break; + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + break; + case codemaker::UnoType::Sort::String: + m_includeRtlUstringHxx = true; + break; + case codemaker::UnoType::Sort::Type: + m_includeType = true; + break; + case codemaker::UnoType::Sort::Any: + m_includeAny = true; + break; + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + for (const OString& arg : args) + { + add(arg); + } + [[fallthrough]]; + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::Exception: + case codemaker::UnoType::Sort::Interface: + case codemaker::UnoType::Sort::Typedef: + m_map.emplace(n, Dependencies::KIND_NORMAL); + break; + default: + throw CannotDumpException( + "unexpected type \"" + b2u(entityName) + + "\" in call to codemaker::cppumaker::Includes::add"); + } +} + +namespace { + +void dumpEmptyLineBeforeFirst(FileStream & out, bool * first) { + OSL_ASSERT(first != nullptr); + if (*first) { + out << "\n"; + *first = false; + } +} + +} + +void Includes::dump( + FileStream & out, OUString const * companionHdl, bool exceptions) +{ + OSL_ASSERT(companionHdl == nullptr || m_hpp); + if (!m_includeReference) { + for (const auto& pair : m_map) + { + if (isInterfaceType(u2b(pair.first))) { + m_includeReference = true; + break; + } + } + } + out << "#include \"sal/config.h\"\n"; + if (m_includeCassert) { + out << "\n#include <cassert>\n"; + } + if (companionHdl) { + out << "\n"; + dumpInclude(out, u2b(*companionHdl), false); + } + bool first = true; + for (const auto& pair : m_map) + { + if (exceptions || pair.second != Dependencies::KIND_EXCEPTION) { + dumpEmptyLineBeforeFirst(out, &first); + if (m_hpp || pair.second == Dependencies::KIND_BASE + || !isInterfaceType(u2b(pair.first))) + { + // If we know our name, then avoid including ourselves. + if (!companionHdl || *companionHdl != pair.first) { + dumpInclude(out, u2b(pair.first), m_hpp); + } + } else { + bool ns = dumpNamespaceOpen(out, pair.first, false); + if (ns) { + out << " "; + } + out << "class "; + dumpTypeIdentifier(out, pair.first); + out << ";"; + if (ns) { + out << " "; + } + dumpNamespaceClose(out, pair.first, false); + out << "\n"; + } + } + } + static char const * hxxExtension[2] = { "h", "hxx" }; + if (m_includeAny) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"com/sun/star/uno/Any." << hxxExtension[m_hpp] + << "\"\n"; + } + if (m_includeReference) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"com/sun/star/uno/Reference." << hxxExtension[m_hpp] + << "\"\n"; + } + if (m_includeSequence) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[m_hpp] + << "\"\n"; + } + if (m_includeType) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"com/sun/star/uno/Type." << hxxExtension[m_hpp] + << "\"\n"; + } + if (m_includeCppuMacrosHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"cppu/macros.hxx\"\n"; + } + if (m_includeCppuUnotypeHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"cppu/unotype.hxx\"\n"; + } + if (m_includeOslMutexHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"osl/mutex.hxx\"\n"; + } + if (m_includeRtlStrbufHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/strbuf.hxx\"\n"; + } + if (m_includeRtlStringH) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/string.h\"\n"; + } + if (m_includeRtlTextencH) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/textenc.h\"\n"; + } + if (m_includeRtlUstrbufHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/ustrbuf.hxx\"\n"; + } + if (m_includeRtlUstringH) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/ustring.h\"\n"; + } + if (m_includeRtlUstringHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/ustring.hxx\"\n"; + } + if (m_includeRtlInstanceHxx) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"rtl/instance.hxx\"\n"; + } + if (m_includeSalTypesH) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"sal/types.h\"\n"; + } + if (m_includeTypelibTypeclassH) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"typelib/typeclass.h\"\n"; + } + if (m_includeTypelibTypedescriptionH) { + dumpEmptyLineBeforeFirst(out, &first); + out << "#include \"typelib/typedescription.h\"\n"; + } + for (OUString const & s : m_custom) + out << s << "\n"; +} + +void Includes::dumpInclude( + FileStream & out, OString const & entityName, bool hpp) +{ + out << "#include \"" << entityName.replace('.', '/') << "." + << (hpp ? "hpp" : "hdl") << "\"\n"; +} + +bool Includes::isInterfaceType(std::string_view entityName) const { + return m_manager->getSort(b2u(entityName)) == UnoType::Sort::Interface; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/cppumaker/includes.hxx b/codemaker/source/cppumaker/includes.hxx new file mode 100644 index 000000000..8cd830b4a --- /dev/null +++ b/codemaker/source/cppumaker/includes.hxx @@ -0,0 +1,100 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> +#include <string_view> +#include <vector> +#include "dependencies.hxx" + +class FileStream; +class TypeManager; + +namespace codemaker::cppumaker { + +class Includes { +public: + Includes( + rtl::Reference< TypeManager > manager, + Dependencies const & dependencies, bool hpp); + + ~Includes(); + + void add(OString const & entityName); + void addCassert() { m_includeCassert = true; } + void addAny() { m_includeAny = true; } + void addReference() { m_includeReference = true; } + void addSequence() { m_includeSequence = true; } + void addType() { m_includeType = true; } + void addCppuMacrosHxx() { m_includeCppuMacrosHxx = true; } + void addCppuUnotypeHxx() { m_includeCppuUnotypeHxx = true; } + void addOslMutexHxx() { m_includeOslMutexHxx = true; } + void addRtlStrbufHxx() { m_includeRtlStrbufHxx = true; } + void addRtlStringH() { m_includeRtlStringH = true; } + void addRtlTextencH() { m_includeRtlTextencH = true; } + void addRtlUstrbufHxx() { m_includeRtlUstrbufHxx = true; } + void addRtlUstringH() { m_includeRtlUstringH = true; } + void addRtlUstringHxx() { m_includeRtlUstringHxx = true; } + void addRtlInstanceHxx() { m_includeRtlInstanceHxx = true; } + void addSalTypesH() { m_includeSalTypesH = true; } + void addTypelibTypeclassH() { m_includeTypelibTypeclassH = true; } + void addTypelibTypedescriptionH() + { m_includeTypelibTypedescriptionH = true; } + void addCustom(const OUString& s) { m_custom.push_back(s); } + void dump( + FileStream & out, OUString const * companionHdl, bool exceptions); + + static void dumpInclude( + FileStream & out, OString const & entityName, bool hpp); + +private: + Includes(Includes const &) = delete; + Includes& operator =(const Includes&) = delete; + + bool isInterfaceType(std::string_view entityName) const; + + rtl::Reference< TypeManager > m_manager; + Dependencies::Map m_map; + bool m_hpp; + bool m_includeCassert; + bool m_includeAny; + bool m_includeReference; + bool m_includeSequence; + bool m_includeType; + bool m_includeCppuMacrosHxx; + bool m_includeCppuUnotypeHxx; + bool m_includeOslMutexHxx; + bool m_includeRtlStrbufHxx; + bool m_includeRtlStringH; + bool m_includeRtlTextencH; + bool m_includeRtlUstrbufHxx; + bool m_includeRtlUstringH; + bool m_includeRtlUstringHxx; + bool m_includeRtlInstanceHxx; + bool m_includeSalTypesH; + bool m_includeTypelibTypeclassH; + bool m_includeTypelibTypedescriptionH; + std::vector<OUString> m_custom; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/classfile.cxx b/codemaker/source/javamaker/classfile.cxx new file mode 100644 index 000000000..67177a718 --- /dev/null +++ b/codemaker/source/javamaker/classfile.cxx @@ -0,0 +1,828 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "classfile.hxx" + +#include <codemaker/global.hxx> +#include <codemaker/options.hxx> +#include <codemaker/unotype.hxx> + +#include <osl/diagnose.h> +#include <rtl/string.h> +#include <rtl/string.hxx> +#include <sal/types.h> + +#include <map> +#include <utility> +#include <vector> + +using codemaker::javamaker::ClassFile; + +namespace { + +void appendU1(std::vector< unsigned char > & stream, sal_uInt8 data) { + stream.push_back(static_cast< unsigned char >(data)); +} + +void appendU2(std::vector< unsigned char > & stream, sal_uInt16 data) { + stream.push_back(static_cast< unsigned char >(data >> 8)); + stream.push_back(static_cast< unsigned char >(data & 0xFF)); +} + +void appendU4(std::vector< unsigned char > & stream, sal_uInt32 data) { + stream.push_back(static_cast< unsigned char >(data >> 24)); + stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF)); + stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF)); + stream.push_back(static_cast< unsigned char >(data & 0xFF)); +} + +void appendU8(std::vector< unsigned char > & stream, sal_uInt64 data) { + stream.push_back(static_cast< unsigned char >(data >> 56)); + stream.push_back(static_cast< unsigned char >((data >> 48) & 0xFF)); + stream.push_back(static_cast< unsigned char >((data >> 40) & 0xFF)); + stream.push_back(static_cast< unsigned char >((data >> 32) & 0xFF)); + stream.push_back(static_cast< unsigned char >((data >> 24) & 0xFF)); + stream.push_back(static_cast< unsigned char >((data >> 16) & 0xFF)); + stream.push_back(static_cast< unsigned char >((data >> 8) & 0xFF)); + stream.push_back(static_cast< unsigned char >(data & 0xFF)); +} + +void appendStream( + std::vector< unsigned char > & stream, + std::vector< unsigned char > const & data) +{ + stream.insert(stream.end(), data.begin(), data.end()); +} + +void write(FileStream & file, void const * buffer, sal_uInt64 size) { + if (!file.write(buffer, size)) + throw CannotDumpException("Error writing file"); +} + +void writeU2(FileStream & file, sal_uInt16 data) { + unsigned char buf[] = { + static_cast< unsigned char >(data >> 8), + static_cast< unsigned char >(data & 0xFF) }; + write(file, buf, sizeof buf); +} + +void writeU4(FileStream & file, sal_uInt32 data) { + unsigned char buf[] = { + static_cast< unsigned char >(data >> 24), + static_cast< unsigned char >((data >> 16) & 0xFF), + static_cast< unsigned char >((data >> 8) & 0xFF), + static_cast< unsigned char >(data & 0xFF) }; + write(file, buf, sizeof buf); +} + +void writeStream(FileStream & file, std::vector< unsigned char > const & stream) +{ + std::vector< unsigned char >::size_type n = stream.size(); + static_assert( + sizeof (std::vector< unsigned char >::size_type) + <= sizeof (sal_uInt64), "must be at most equal in size"); + // both unsigned integral, so sizeof is a practically sufficient + // approximation of std::numeric_limits<T1>::max() <= + // std::numeric_limits<T2>::max() + if (n != 0) { + write(file, stream.data(), static_cast< sal_uInt64 >(n)); + } +} + +} + +ClassFile::Code::~Code() {} + +void ClassFile::Code::instrAastore() { + // aastore: + appendU1(m_code, 0x53); +} + +void ClassFile::Code::instrAconstNull() { + // aconst_null: + appendU1(m_code, 0x01); +} + +void ClassFile::Code::instrAnewarray(OString const & type) { + // anewarray <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xBD); + appendU2(m_code, m_classFile.addClassInfo(type)); +} + +void ClassFile::Code::instrAreturn() { + // areturn: + appendU1(m_code, 0xB0); +} + +void ClassFile::Code::instrAthrow() { + // athrow: + appendU1(m_code, 0xBF); +} + +void ClassFile::Code::instrCheckcast(OString const & type) { + // checkcast <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xC0); + appendU2(m_code, m_classFile.addClassInfo(type)); +} + +void ClassFile::Code::instrDup() { + // dup: + appendU1(m_code, 0x59); +} + +void ClassFile::Code::instrGetstatic( + OString const & type, OString const & name, + OString const & descriptor) +{ + // getstatic <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB2); + appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); +} + +ClassFile::Code::Branch ClassFile::Code::instrIfAcmpne() { + // if_acmpne <branchbyte1> <branchbyte2>: + Branch branch = m_code.size(); + appendU1(m_code, 0xA6); + appendU2(m_code, 0); + return branch; +} + +ClassFile::Code::Branch ClassFile::Code::instrIfeq() { + // ifeq <branchbyte1> <branchbyte2>: + Branch branch = m_code.size(); + appendU1(m_code, 0x99); + appendU2(m_code, 0); + return branch; +} + +ClassFile::Code::Branch ClassFile::Code::instrIfnull() { + // ifnull <branchbyte1> <branchbyte2>: + Branch branch = m_code.size(); + appendU1(m_code, 0xC6); + appendU2(m_code, 0); + return branch; +} + +void ClassFile::Code::instrInstanceof(OString const & type) { + // instanceof <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xC1); + appendU2(m_code, m_classFile.addClassInfo(type)); +} + +void ClassFile::Code::instrInvokeinterface( + OString const & type, OString const & name, + OString const & descriptor, sal_uInt8 args) +{ + // invokeinterface <indexbyte1> <indexbyte2> <nargs> 0: + appendU1(m_code, 0xB9); + appendU2( + m_code, m_classFile.addInterfaceMethodrefInfo(type, name, descriptor)); + appendU1(m_code, args); + appendU1(m_code, 0); +} + +void ClassFile::Code::instrInvokespecial( + OString const & type, OString const & name, + OString const & descriptor) +{ + // invokespecial <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB7); + appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrInvokestatic( + OString const & type, OString const & name, + OString const & descriptor) +{ + // invokestatic <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB8); + appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrInvokevirtual( + OString const & type, OString const & name, + OString const & descriptor) +{ + // invokevirtual <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB6); + appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrLookupswitch( + Code const * defaultBlock, + std::vector< std::pair< sal_Int32, Code * > > const & blocks) +{ + // lookupswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3> + // <defaultbyte4> <npairs1> <npairs2> <npairs3> <npairs4> + // <match--offset pairs...>: + std::vector< std::pair< sal_Int32, Code * > >::size_type size = blocks.size(); + if (size > SAL_MAX_INT32) { + throw CannotDumpException("Lookup-switch too large for Java class file format"); + } + Position pos1 = m_code.size(); + appendU1(m_code, 0xAB); + int pad = (pos1 + 1) % 4; + for (int i = 0; i < pad; ++i) { + appendU1(m_code, 0); + } + Position pos2 = pos1 + 1 + pad + 8 + blocks.size() * 8; //FIXME: overflow + appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); //FIXME: overflow + pos2 += defaultBlock->m_code.size(); //FIXME: overflow + appendU4(m_code, static_cast< sal_uInt32 >(size)); + for (const std::pair< sal_Int32, Code * >& pair : blocks) + { + appendU4(m_code, static_cast< sal_uInt32 >(pair.first)); + appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); + //FIXME: overflow + pos2 += pair.second->m_code.size(); //FIXME: overflow + } + appendStream(m_code, defaultBlock->m_code); + for (const std::pair< sal_Int32, Code * >& pair : blocks) + { + appendStream(m_code, pair.second->m_code); + } +} + +void ClassFile::Code::instrNew(OString const & type) { + // new <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xBB); + appendU2(m_code, m_classFile.addClassInfo(type)); +} + +void ClassFile::Code::instrNewarray(codemaker::UnoType::Sort sort) { + OSL_ASSERT( + sort >= codemaker::UnoType::Sort::Boolean + && sort <= codemaker::UnoType::Sort::Char); + // newarray <atype>: + appendU1(m_code, 0xBC); + static sal_uInt8 const atypes[static_cast<int>(codemaker::UnoType::Sort::Char)] = { + 0x04, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x06, 0x07, 0x05 }; + appendU1(m_code, atypes[static_cast<int>(sort) - 1]); +} + +void ClassFile::Code::instrPop() { + // pop: + appendU1(m_code, 0x57); +} + +void ClassFile::Code::instrPutfield( + OString const & type, OString const & name, + OString const & descriptor) +{ + // putfield <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB5); + appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrPutstatic( + OString const & type, OString const & name, + OString const & descriptor) +{ + // putstatic <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB3); + appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrReturn() { + // return: + appendU1(m_code, 0xB1); +} + +void ClassFile::Code::instrSwap() { + // swap: + appendU1(m_code, 0x5F); +} + +void ClassFile::Code::instrTableswitch( + Code const * defaultBlock, sal_Int32 low, + std::vector< std::unique_ptr<Code> > const & blocks) +{ + // tableswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3> + // <defaultbyte4> <lowbyte1> <lowbyte2> <lowbyte3> <lowbyte4> <highbyte1> + // <highbyte2> <highbyte3> <highbyte4> <jump offsets...>: + Position pos1 = m_code.size(); + appendU1(m_code, 0xAA); + int pad = (pos1 + 1) % 4; + for (int i = 0; i < pad; ++i) { + appendU1(m_code, 0); + } + std::vector< Code * >::size_type size = blocks.size(); + Position pos2 = pos1 + 1 + pad + 12 + size * 4; //FIXME: overflow + sal_uInt32 defaultOffset = static_cast< sal_uInt32 >(pos2 - pos1); + //FIXME: overflow + appendU4(m_code, defaultOffset); + pos2 += defaultBlock->m_code.size(); //FIXME: overflow + appendU4(m_code, static_cast< sal_uInt32 >(low)); + appendU4(m_code, static_cast< sal_uInt32 >(low + (size - 1))); + for (std::unique_ptr<Code> const & pCode : blocks) + { + if (pCode == nullptr) { + appendU4(m_code, defaultOffset); + } else { + appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); + //FIXME: overflow + pos2 += pCode->m_code.size(); //FIXME: overflow + } + } + appendStream(m_code, defaultBlock->m_code); + for (std::unique_ptr<Code> const & pCode : blocks) + { + if (pCode != nullptr) { + appendStream(m_code, pCode->m_code); + } + } +} + +void ClassFile::Code::loadIntegerConstant(sal_Int32 value) { + if (value >= -1 && value <= 5) { + // iconst_<i>: + appendU1(m_code, static_cast< sal_uInt8 >(0x02 + value + 1)); + } else if (value >= -128 && value <= 127) { + // bipush <byte>: + appendU1(m_code, 0x10); + appendU1(m_code, static_cast< sal_uInt8 >(value)); + } else if (value >= -32768 && value <= 32767) { + // sipush <byte1> <byte2>: + appendU1(m_code, 0x11); + appendU2(m_code, static_cast< sal_uInt16 >(value)); + } else { + ldc(m_classFile.addIntegerInfo(value)); + } +} + +void ClassFile::Code::loadStringConstant(OString const & value) { + ldc(m_classFile.addStringInfo(value)); +} + +void ClassFile::Code::loadLocalInteger(sal_uInt16 index) { + accessLocal(index, 0x1A, 0x15); // iload_<n>, iload +} + +void ClassFile::Code::loadLocalLong(sal_uInt16 index) { + accessLocal(index, 0x1E, 0x16); // load_<n>, load +} + +void ClassFile::Code::loadLocalFloat(sal_uInt16 index) { + accessLocal(index, 0x22, 0x17); // load_<n>, load +} + +void ClassFile::Code::loadLocalDouble(sal_uInt16 index) { + accessLocal(index, 0x26, 0x18); // load_<n>, load +} + +void ClassFile::Code::loadLocalReference(sal_uInt16 index) { + accessLocal(index, 0x2A, 0x19); // aload_<n>, aload +} + +void ClassFile::Code::storeLocalReference(sal_uInt16 index) { + accessLocal(index, 0x4B, 0x3A); // astore_<n>, astore +} + +void ClassFile::Code::branchHere(Branch branch) { + std::vector< unsigned char >::size_type n = m_code.size(); + OSL_ASSERT(n > branch && n - branch <= SAL_MAX_INT16); + n -= branch; + m_code[branch + 1] = static_cast< sal_uInt8 >(n >> 8); + m_code[branch + 2] = static_cast< sal_uInt8 >(n & 0xFF); +} + +void ClassFile::Code::addException( + Position start, Position end, Position handler, OString const & type) +{ + OSL_ASSERT(start < end && end <= m_code.size() && handler <= m_code.size()); + if (m_exceptionTableLength == SAL_MAX_UINT16) { + throw CannotDumpException("Too many exception handlers for Java class file format"); + } + ++m_exceptionTableLength; + appendU2(m_exceptionTable, static_cast< sal_uInt16 >(start)); + //FIXME: overflow + appendU2(m_exceptionTable, static_cast< sal_uInt16 >(end)); + //FIXME: overflow + appendU2(m_exceptionTable, static_cast< sal_uInt16 >(handler)); + //FIXME: overflow + appendU2(m_exceptionTable, m_classFile.addClassInfo(type)); +} + +ClassFile::Code::Position ClassFile::Code::getPosition() const { + return m_code.size(); +} + +ClassFile::Code::Code(ClassFile & classFile) + : m_classFile(classFile) + , m_maxStack(0) + , m_maxLocals(0) + , m_exceptionTableLength(0) +{} + +void ClassFile::Code::ldc(sal_uInt16 index) { + if (index <= 0xFF) { + // ldc <index>: + appendU1(m_code, 0x12); + appendU1(m_code, static_cast< sal_uInt8 >(index)); + } else { + // ldc_w <indexbyte1> <indexbyte2>: + appendU1(m_code, 0x13); + appendU2(m_code, index); + } +} + +void ClassFile::Code::accessLocal( + sal_uInt16 index, sal_uInt8 fastOp, sal_uInt8 normalOp) +{ + if (index <= 3) { + // ...load/store_<n>: + appendU1(m_code, static_cast< sal_uInt8 >(fastOp + index)); + } else if (index <= 0xFF) { + // ...load/store <index>: + appendU1(m_code, normalOp); + appendU1(m_code, static_cast< sal_uInt8 >(index)); + } else { + // wide ...load/store <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xC4); + appendU1(m_code, normalOp); + appendU2(m_code, index); + } +} + +ClassFile::ClassFile( + AccessFlags accessFlags, OString const & thisClass, + OString const & superClass, OString const & signature): + m_constantPoolCount(1), m_accessFlags(accessFlags), m_interfacesCount(0), + m_fieldsCount(0), m_methodsCount(0), m_attributesCount(0) +{ + m_thisClass = addClassInfo(thisClass); + m_superClass = addClassInfo(superClass); + if (!signature.isEmpty()) { + ++m_attributesCount; + appendU2(m_attributes, addUtf8Info("Signature")); + appendU4(m_attributes, 2); + appendU2(m_attributes, addUtf8Info(signature)); + } +} + +ClassFile::~ClassFile() {} + +std::unique_ptr<ClassFile::Code> ClassFile::newCode() { + return std::unique_ptr<Code>(new Code(*this)); +} + +sal_uInt16 ClassFile::addIntegerInfo(sal_Int32 value) { + std::map< sal_Int32, sal_uInt16 >::iterator i(m_integerInfos.find(value)); + if (i != m_integerInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 3); + appendU4(m_constantPool, static_cast< sal_uInt32 >(value)); + if (!m_integerInfos.emplace(value, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addFloatInfo(float value) { + std::map< float, sal_uInt16 >::iterator i(m_floatInfos.find(value)); + if (i != m_floatInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 4); + union { float floatBytes; sal_uInt32 uint32Bytes; } bytes; + bytes.floatBytes = value; + appendU4(m_constantPool, bytes.uint32Bytes); + if (!m_floatInfos.emplace(value, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addLongInfo(sal_Int64 value) { + std::map< sal_Int64, sal_uInt16 >::iterator i(m_longInfos.find(value)); + if (i != m_longInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(2); + appendU1(m_constantPool, 5); + appendU8(m_constantPool, static_cast< sal_uInt64 >(value)); + if (!m_longInfos.emplace(value, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addDoubleInfo(double value) { + std::map< double, sal_uInt16 >::iterator i(m_doubleInfos.find(value)); + if (i != m_doubleInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(2); + appendU1(m_constantPool, 6); + union { double doubleBytes; sal_uInt64 uint64Bytes; } bytes; + bytes.doubleBytes = value; + appendU8(m_constantPool, bytes.uint64Bytes); + if (!m_doubleInfos.emplace(value, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +void ClassFile::addInterface(OString const & interface) { + if (m_interfacesCount == SAL_MAX_UINT16) { + throw CannotDumpException("Too many interfaces for Java class file format"); + } + ++m_interfacesCount; + appendU2(m_interfaces, addClassInfo(interface)); +} + +void ClassFile::addField( + AccessFlags accessFlags, OString const & name, + OString const & descriptor, sal_uInt16 constantValueIndex, + OString const & signature) +{ + if (m_fieldsCount == SAL_MAX_UINT16) { + throw CannotDumpException("Too many fields for Java class file format"); + } + ++m_fieldsCount; + appendU2(m_fields, static_cast< sal_uInt16 >(accessFlags)); + appendU2(m_fields, addUtf8Info(name)); + appendU2(m_fields, addUtf8Info(descriptor)); + appendU2( + m_fields, + ((constantValueIndex == 0 ? 0 : 1) + + (signature.isEmpty() ? 0 : 1))); + if (constantValueIndex != 0) { + appendU2(m_fields, addUtf8Info("ConstantValue")); + appendU4(m_fields, 2); + appendU2(m_fields, constantValueIndex); + } + appendSignatureAttribute(m_fields, signature); +} + +void ClassFile::addMethod( + AccessFlags accessFlags, OString const & name, + OString const & descriptor, Code const * code, + std::vector< OString > const & exceptions, + OString const & signature) +{ + if (m_methodsCount == SAL_MAX_UINT16) { + throw CannotDumpException("Too many methods for Java class file format"); + } + ++m_methodsCount; + appendU2(m_methods, static_cast< sal_uInt16 >(accessFlags)); + appendU2(m_methods, addUtf8Info(name)); + appendU2(m_methods, addUtf8Info(descriptor)); + std::vector< OString >::size_type excs = exceptions.size(); + if (excs > SAL_MAX_UINT16) { + throw CannotDumpException("Too many exception specifications for Java class file format"); + } + appendU2( + m_methods, + ((code == nullptr ? 0 : 1) + (exceptions.empty() ? 0 : 1) + + (signature.isEmpty() ? 0 : 1))); + if (code != nullptr) { + std::vector< unsigned char >::size_type codeSize = code->m_code.size(); + std::vector< unsigned char >::size_type exceptionTableSize + = code->m_exceptionTable.size(); + if (codeSize > SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2) + || (exceptionTableSize + > (SAL_MAX_UINT32 - (2 + 2 + 4 + 2 + 2) + - static_cast< sal_uInt32 >(codeSize)))) + { + throw CannotDumpException("Code block is too big for Java class file format"); + } + appendU2(m_methods, addUtf8Info("Code")); + appendU4( + m_methods, + (2 + 2 + 4 + static_cast< sal_uInt32 >(codeSize) + 2 + + static_cast< sal_uInt32 >(exceptionTableSize) + 2)); + appendU2(m_methods, code->m_maxStack); + appendU2(m_methods, code->m_maxLocals); + appendU4(m_methods, static_cast< sal_uInt32 >(codeSize)); + appendStream(m_methods, code->m_code); + appendU2(m_methods, code->m_exceptionTableLength); + appendStream(m_methods, code->m_exceptionTable); + appendU2(m_methods, 0); + } + if (!exceptions.empty()) { + appendU2(m_methods, addUtf8Info("Exceptions")); + appendU4( + m_methods, + static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs))); + appendU2(m_methods, static_cast< sal_uInt16 >(excs)); + for (const OString& ex : exceptions) + { + appendU2(m_methods, addClassInfo(ex)); + } + } + appendSignatureAttribute(m_methods, signature); +} + +void ClassFile::write(FileStream & file) const { + writeU4(file, 0xCAFEBABE); + writeU2(file, 0); + writeU2(file, 49); // class file version of JRE 1.5 + writeU2(file, m_constantPoolCount); + writeStream(file, m_constantPool); + writeU2(file, static_cast< sal_uInt16 >(m_accessFlags)); + writeU2(file, m_thisClass); + writeU2(file, m_superClass); + writeU2(file, m_interfacesCount); + writeStream(file, m_interfaces); + writeU2(file, m_fieldsCount); + writeStream(file, m_fields); + writeU2(file, m_methodsCount); + writeStream(file, m_methods); + writeU2(file, m_attributesCount); + writeStream(file, m_attributes); +} + +sal_uInt16 ClassFile::nextConstantPoolIndex(sal_uInt16 width) { + OSL_ASSERT(width == 1 || width == 2); + if (m_constantPoolCount > SAL_MAX_UINT16 - width) { + throw CannotDumpException("Too many constant pool items for Java class file format"); + } + sal_uInt16 index = m_constantPoolCount; + m_constantPoolCount = m_constantPoolCount + width; + return index; +} + +sal_uInt16 ClassFile::addUtf8Info(OString const & value) { + std::map< OString, sal_uInt16 >::iterator i(m_utf8Infos.find(value)); + if (i != m_utf8Infos.end()) { + return i->second; + } + if (value.getLength() > SAL_MAX_UINT16) { + throw CannotDumpException("UTF-8 string too long for Java class file format"); + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 1); + appendU2(m_constantPool, static_cast< sal_uInt16 >(value.getLength())); + for (sal_Int32 j = 0; j < value.getLength(); ++j) { + appendU1(m_constantPool, static_cast< sal_uInt8 >(value[j])); + } + if (!m_utf8Infos.emplace(value, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addClassInfo(OString const & type) { + sal_uInt16 nameIndex = addUtf8Info(type); + std::map< sal_uInt16, sal_uInt16 >::iterator i( + m_classInfos.find(nameIndex)); + if (i != m_classInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 7); + appendU2(m_constantPool, nameIndex); + if (!m_classInfos.emplace(nameIndex, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addStringInfo(OString const & value) { + sal_uInt16 stringIndex = addUtf8Info(value); + std::map< sal_uInt16, sal_uInt16 >::iterator i( + m_stringInfos.find(stringIndex)); + if (i != m_stringInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 8); + appendU2(m_constantPool, stringIndex); + if (!m_stringInfos.emplace(stringIndex, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addFieldrefInfo( + OString const & type, OString const & name, + OString const & descriptor) +{ + sal_uInt16 classIndex = addClassInfo(type); + sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor); + sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16) + | nameAndTypeIndex; + std::map< sal_uInt32, sal_uInt16 >::iterator i(m_fieldrefInfos.find(key)); + if (i != m_fieldrefInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 9); + appendU2(m_constantPool, classIndex); + appendU2(m_constantPool, nameAndTypeIndex); + if (!m_fieldrefInfos.emplace(key, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addMethodrefInfo( + OString const & type, OString const & name, + OString const & descriptor) +{ + sal_uInt16 classIndex = addClassInfo(type); + sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor); + sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16) + | nameAndTypeIndex; + std::map< sal_uInt32, sal_uInt16 >::iterator i(m_methodrefInfos.find(key)); + if (i != m_methodrefInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 10); + appendU2(m_constantPool, classIndex); + appendU2(m_constantPool, nameAndTypeIndex); + if (!m_methodrefInfos.emplace(key, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addInterfaceMethodrefInfo( + OString const & type, OString const & name, + OString const & descriptor) +{ + sal_uInt16 classIndex = addClassInfo(type); + sal_uInt16 nameAndTypeIndex = addNameAndTypeInfo(name, descriptor); + sal_uInt32 key = (static_cast< sal_uInt32 >(classIndex) << 16) + | nameAndTypeIndex; + std::map< sal_uInt32, sal_uInt16 >::iterator i( + m_interfaceMethodrefInfos.find(key)); + if (i != m_interfaceMethodrefInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 11); + appendU2(m_constantPool, classIndex); + appendU2(m_constantPool, nameAndTypeIndex); + if (!m_interfaceMethodrefInfos.emplace(key, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addNameAndTypeInfo( + OString const & name, OString const & descriptor) +{ + sal_uInt16 nameIndex = addUtf8Info(name); + sal_uInt16 descriptorIndex = addUtf8Info(descriptor); + sal_uInt32 key = (static_cast< sal_uInt32 >(nameIndex) << 16) + | descriptorIndex; + std::map< sal_uInt32, sal_uInt16 >::iterator i( + m_nameAndTypeInfos.find(key)); + if (i != m_nameAndTypeInfos.end()) { + return i->second; + } + sal_uInt16 index = nextConstantPoolIndex(1); + appendU1(m_constantPool, 12); + appendU2(m_constantPool, nameIndex); + appendU2(m_constantPool, descriptorIndex); + if (!m_nameAndTypeInfos.emplace(key, index).second) + { + OSL_ASSERT(false); + } + return index; +} + +void ClassFile::appendSignatureAttribute( + std::vector< unsigned char > & stream, OString const & signature) +{ + if (!signature.isEmpty()) { + appendU2(stream, addUtf8Info("Signature")); + appendU4(stream, 2); + appendU2(stream, addUtf8Info(signature)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/classfile.hxx b/codemaker/source/javamaker/classfile.hxx new file mode 100644 index 000000000..ebfef0782 --- /dev/null +++ b/codemaker/source/javamaker/classfile.hxx @@ -0,0 +1,239 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <codemaker/unotype.hxx> +#include <sal/types.h> + +#include <map> +#include <memory> +#include <utility> +#include <vector> + +class FileStream; + +namespace codemaker::javamaker { + +class ClassFile { +public: + enum AccessFlags { + ACC_PUBLIC = 0x0001, + ACC_PRIVATE = 0x0002, + ACC_STATIC = 0x0008, + ACC_FINAL = 0x0010, + ACC_SUPER = 0x0020, + ACC_VARARGS = 0x0080, + ACC_INTERFACE = 0x0200, + ACC_ABSTRACT = 0x0400, + ACC_SYNTHETIC = 0x1000 + }; + + class Code { + public: + typedef std::vector< unsigned char >::size_type Branch; + typedef std::vector< unsigned char >::size_type Position; + + ~Code(); + + void instrAastore(); + void instrAconstNull(); + void instrAnewarray(rtl::OString const & type); + void instrAreturn(); + void instrAthrow(); + void instrCheckcast(rtl::OString const & type); + void instrDup(); + + void instrGetstatic( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + Branch instrIfAcmpne(); + Branch instrIfeq(); + Branch instrIfnull(); + + void instrInstanceof(rtl::OString const & type); + + void instrInvokeinterface( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor, sal_uInt8 args); + + void instrInvokespecial( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + void instrInvokestatic( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + void instrInvokevirtual( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + void instrLookupswitch( + Code const * defaultBlock, + std::vector< std::pair< sal_Int32, Code * > > const & blocks); + + void instrNew(rtl::OString const & type); + void instrNewarray(codemaker::UnoType::Sort sort); + void instrPop(); + + void instrPutfield( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + void instrPutstatic( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + void instrReturn(); + void instrSwap(); + + void instrTableswitch( + Code const * defaultBlock, sal_Int32 low, + std::vector< std::unique_ptr<Code> > const & blocks); + + void loadIntegerConstant(sal_Int32 value); + void loadStringConstant(rtl::OString const & value); + void loadLocalInteger(sal_uInt16 index); + void loadLocalLong(sal_uInt16 index); + void loadLocalFloat(sal_uInt16 index); + void loadLocalDouble(sal_uInt16 index); + void loadLocalReference(sal_uInt16 index); + void storeLocalReference(sal_uInt16 index); + void branchHere(Branch branch); + + void addException( + Position start, Position end, Position handler, + rtl::OString const & type); + + void setMaxStackAndLocals(sal_uInt16 maxStack, sal_uInt16 maxLocals) + { m_maxStack = maxStack; m_maxLocals = maxLocals; } + + Position getPosition() const; + + private: + Code(Code const &) = delete; + Code& operator =(const Code&) = delete; + + explicit Code(ClassFile & classFile); + + void ldc(sal_uInt16 index); + + void accessLocal( + sal_uInt16 index, sal_uInt8 fastOp, sal_uInt8 normalOp); + + ClassFile & m_classFile; + sal_uInt16 m_maxStack; + sal_uInt16 m_maxLocals; + std::vector< unsigned char > m_code; + sal_uInt16 m_exceptionTableLength; + std::vector< unsigned char > m_exceptionTable; + + friend class ClassFile; + }; + + ClassFile( + AccessFlags accessFlags, rtl::OString const & thisClass, + rtl::OString const & superClass, rtl::OString const & signature); + + ~ClassFile(); + + std::unique_ptr<Code> newCode(); + + sal_uInt16 addIntegerInfo(sal_Int32 value); + sal_uInt16 addFloatInfo(float value); + sal_uInt16 addLongInfo(sal_Int64 value); + sal_uInt16 addDoubleInfo(double value); + + void addInterface(rtl::OString const & interface); + + void addField( + AccessFlags accessFlags, rtl::OString const & name, + rtl::OString const & descriptor, sal_uInt16 constantValueIndex, + rtl::OString const & signature); + + void addMethod( + AccessFlags accessFlags, rtl::OString const & name, + rtl::OString const & descriptor, Code const * code, + std::vector< rtl::OString > const & exceptions, + rtl::OString const & signature); + + void write(FileStream & file) const; //TODO + +private: + typedef std::map< rtl::OString, sal_uInt16 > Map; + + ClassFile(ClassFile const &) = delete; + ClassFile& operator =(const ClassFile&) = delete; + + sal_uInt16 nextConstantPoolIndex(sal_uInt16 width); + sal_uInt16 addUtf8Info(rtl::OString const & value); + sal_uInt16 addClassInfo(rtl::OString const & type); + sal_uInt16 addStringInfo(rtl::OString const & value); + + sal_uInt16 addFieldrefInfo( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + sal_uInt16 addMethodrefInfo( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + sal_uInt16 addInterfaceMethodrefInfo( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor); + + sal_uInt16 addNameAndTypeInfo( + rtl::OString const & name, rtl::OString const & descriptor); + + void appendSignatureAttribute( + std::vector< unsigned char > & stream, rtl::OString const & signature); + + sal_uInt16 m_constantPoolCount; + std::vector< unsigned char > m_constantPool; + std::map< rtl::OString, sal_uInt16 > m_utf8Infos; + std::map< sal_Int32, sal_uInt16 > m_integerInfos; + std::map< sal_Int64, sal_uInt16 > m_longInfos; + std::map< float, sal_uInt16 > m_floatInfos; + std::map< double, sal_uInt16 > m_doubleInfos; + std::map< sal_uInt16, sal_uInt16 > m_classInfos; + std::map< sal_uInt16, sal_uInt16 > m_stringInfos; + std::map< sal_uInt32, sal_uInt16 > m_fieldrefInfos; + std::map< sal_uInt32, sal_uInt16 > m_methodrefInfos; + std::map< sal_uInt32, sal_uInt16 > m_interfaceMethodrefInfos; + std::map< sal_uInt32, sal_uInt16 > m_nameAndTypeInfos; + AccessFlags m_accessFlags; + sal_uInt16 m_thisClass; + sal_uInt16 m_superClass; + sal_uInt16 m_interfacesCount; + std::vector< unsigned char > m_interfaces; + sal_uInt16 m_fieldsCount; + std::vector< unsigned char > m_fields; + sal_uInt16 m_methodsCount; + std::vector< unsigned char > m_methods; + sal_uInt16 m_attributesCount; + std::vector< unsigned char > m_attributes; + + friend class Code; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/javamaker.cxx b/codemaker/source/javamaker/javamaker.cxx new file mode 100644 index 000000000..ee376c8cc --- /dev/null +++ b/codemaker/source/javamaker/javamaker.cxx @@ -0,0 +1,98 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <vector> + +#include <codemaker/generatedtypeset.hxx> +#include <codemaker/typemanager.hxx> +#include <rtl/ref.hxx> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <sal/main.h> +#include <sal/types.h> +#include <unoidl/unoidl.hxx> +#include <o3tl/string_view.hxx> + +#include "javaoptions.hxx" +#include "javatype.hxx" + +// coverity[tainted_data] - this is a build time tool +SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) { + JavaOptions options; + try { + if (!options.initOptions(argc, argv)) { + return EXIT_FAILURE; + } + + rtl::Reference typeMgr(new TypeManager); + for (const OString& i : options.getExtraInputFiles()) + { + typeMgr->loadProvider(convertToFileUrl(i), false); + } + for (const OString& i : options.getInputFiles()) + { + typeMgr->loadProvider(convertToFileUrl(i), true); + } + codemaker::GeneratedTypeSet generated; + if (options.isValid("-T")) { + OUString names(b2u(options.getOption("-T"))); + for (sal_Int32 i = 0; i != -1;) { + std::u16string_view name(o3tl::getToken(names, 0, ';', i)); + if (!name.empty()) { + produce( + OUString(name == u"*" + ? u"" + : o3tl::ends_with(name, u".*") + ? name.substr(0, name.size() - std::strlen(".*")) + : name), + typeMgr, generated, options); + } + } + } else { + produce("", typeMgr, generated, options); + } + } + catch (CannotDumpException & e) { + std::cerr << "ERROR: " << e.getMessage() << '\n'; + return EXIT_FAILURE; + } catch (unoidl::NoSuchFileException & e) { + std::cerr << "ERROR: No such file <" << e.getUri() << ">\n"; + return EXIT_FAILURE; + } catch (unoidl::FileFormatException & e) { + std::cerr + << "ERROR: Bad format of <" << e.getUri() << ">, \"" + << e.getDetail() << "\"\n"; + return EXIT_FAILURE; + } catch (IllegalArgument & e) { + std::cerr << "Illegal option " << e.m_message << '\n'; + return EXIT_FAILURE; + } catch (std::exception & e) { + std::cerr << "Failure " << e.what() << '\n'; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/javaoptions.cxx b/codemaker/source/javamaker/javaoptions.cxx new file mode 100644 index 000000000..e0e51c973 --- /dev/null +++ b/codemaker/source/javamaker/javaoptions.cxx @@ -0,0 +1,249 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <stdio.h> +#include <string.h> +#include "javaoptions.hxx" +#include <osl/process.h> +#include <osl/thread.h> + + +#ifdef SAL_UNX +#define SEPARATOR '/' +#else +#define SEPARATOR '\\' +#endif + +bool JavaOptions::initOptions(int ac, char* av[], bool bCmdFile) +{ + bool ret = true; + int i=0; + + if (!bCmdFile) + { + bCmdFile = true; + + OString name(av[0]); + sal_Int32 index = name.lastIndexOf(SEPARATOR); + m_program = name.copy(index > 0 ? index+1 : 0); + + if (ac < 2) + { + fprintf(stderr, "%s", prepareHelp().getStr()); + ret = false; + } + + i = 1; + } + + char *s=nullptr; + for( ; i < ac; i++) + { + if (av[i][0] == '-') + { + switch (av[i][1]) + { + case 'O': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + OString tmp("'-O', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i+1] + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + m_options["-O"] = OString(s); + break; + case 'n': + if (av[i][2] != 'D' || av[i][3] != '\0') + { + OString tmp(OString::Concat("'-nD', please check your input '") + av[i] + "'"); + throw IllegalArgument(tmp); + } + + m_options["-nD"] = OString(); + break; + case 'T': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + OString tmp("'-T', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i+1] + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + if (m_options.count("-T") > 0) + { + OString tmp = m_options["-T"] + ";" + s; + m_options["-T"] = tmp; + } else + { + m_options["-T"] = OString(s); + } + break; + case 'G': + if (av[i][2] == 'c') + { + if (av[i][3] != '\0') + { + OString tmp("'-Gc', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + m_options["-Gc"] = OString(); + break; + } else if (av[i][2] != '\0') + { + OString tmp("'-G', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i] + "'"; + } + + throw IllegalArgument(tmp); + } + + m_options["-G"] = OString(); + break; + case 'X': // support for eXtra type rdbs + { + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + OString tmp("'-X', please check"); + if (i <= ac - 1) + { + tmp += OString::Concat(" your input '") + av[i+1] + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + m_extra_input_files.emplace_back(s ); + break; + } + + default: + throw IllegalArgument(OString::Concat("the option is unknown") + av[i]); + } + } else + { + if (av[i][0] == '@') + { + FILE* cmdFile = fopen(av[i]+1, "r"); + if( cmdFile == nullptr ) + { + fprintf(stderr, "%s", prepareHelp().getStr()); + ret = false; + } else + { + int rargc=0; + char* rargv[512]; + char buffer[512]; + + while (fscanf(cmdFile, "%511s", buffer) != EOF && rargc < 512) + { + rargv[rargc]= strdup(buffer); + rargc++; + } + fclose(cmdFile); + + ret = initOptions(rargc, rargv, bCmdFile); + + for (int j=0; j < rargc; j++) + { + free(rargv[j]); + } + } + } else + { + m_inputFiles.emplace_back(av[i]); + } + } + } + + return ret; +} + +OString JavaOptions::prepareHelp() +{ + OString help = "\nusing: " + + m_program + " [-options] file_1 ... file_n -Xfile_n+1 -Xfile_n+2\nOptions:\n" + " -O<path> = path describes the root directory for the generated output.\n" + " The output directory tree is generated under this directory.\n" + " -T<name> = name specifies a type or a list of types. The output for this\n" + " [t1;...] type and all dependent types are generated. If no '-T' option is\n" + " specified, then output for all types is generated.\n" + " Example: 'com.sun.star.uno.XInterface' is a valid type.\n" + " -nD = no dependent types are generated.\n" + " -G = generate only target files which does not exists.\n" + " -Gc = generate only target files which content will be changed.\n" + " -X<file> = extra types which will not be taken into account for generation.\n\n" + + prepareVersion(); + + return help; +} + +OString JavaOptions::prepareVersion() const +{ + return m_program + " Version 2.0\n\n"; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/javaoptions.hxx b/codemaker/source/javamaker/javaoptions.hxx new file mode 100644 index 000000000..5e6161c04 --- /dev/null +++ b/codemaker/source/javamaker/javaoptions.hxx @@ -0,0 +1,41 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <codemaker/options.hxx> + +class JavaOptions : public Options +{ +public: + JavaOptions() + : Options() + { + } + + bool initOptions(int ac, char* av[], bool bCmdFile = false) override; + + OString prepareHelp() override; + + OString prepareVersion() const; + +protected: +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/javatype.cxx b/codemaker/source/javamaker/javatype.cxx new file mode 100644 index 000000000..3db9572e5 --- /dev/null +++ b/codemaker/source/javamaker/javatype.cxx @@ -0,0 +1,2539 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <algorithm> +#include <cassert> +#include <cstdlib> +#include <map> +#include <memory> +#include <set> +#include <string_view> +#include <utility> +#include <vector> + +#include <codemaker/codemaker.hxx> +#include <codemaker/exceptiontree.hxx> +#include <codemaker/generatedtypeset.hxx> +#include <codemaker/global.hxx> +#include <codemaker/options.hxx> +#include <codemaker/typemanager.hxx> +#include <codemaker/unotype.hxx> +#include <codemaker/commonjava.hxx> +#include <rtl/ref.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <unoidl/unoidl.hxx> +#include <o3tl/string_view.hxx> + +#include "classfile.hxx" +#include "javaoptions.hxx" +#include "javatype.hxx" + +using codemaker::javamaker::ClassFile; + +namespace { + +void appendUnoName( + rtl::Reference< TypeManager > const & manager, std::u16string_view nucleus, + sal_Int32 rank, std::vector< OUString > const & arguments, + OUStringBuffer * buffer) +{ + assert(manager.is()); + assert(rank >= 0); + assert(buffer != nullptr); + for (sal_Int32 i = 0; i != rank; ++i) { + buffer->append("[]"); + } + buffer->append(nucleus); + if (arguments.empty()) + return; + + buffer->append('<'); + for (std::vector< OUString >::const_iterator i(arguments.begin()); + i != arguments.end(); ++i) + { + if (i != arguments.begin()) { + buffer->append(','); + } + OUString n; + sal_Int32 k; + std::vector< OUString > args; + manager->decompose(*i, false, &n, &k, &args, nullptr); + appendUnoName(manager, n, k, args, buffer); + } + buffer->append('>'); +} + +// Translate the name of a UNOIDL entity (enum type, plain struct type, +// polymorphic struct type template, or interface type, decomposed into nucleus, +// sequence rank, and template arguments) into a core UNO type name: +OUString createUnoName( + rtl::Reference< TypeManager > const & manager, std::u16string_view nucleus, + sal_Int32 rank, std::vector< OUString > const & arguments) +{ + OUStringBuffer buf(256); + appendUnoName(manager, nucleus, rank, arguments, &buf); + return buf.makeStringAndClear(); +} + +enum SpecialType { + SPECIAL_TYPE_NONE, + SPECIAL_TYPE_ANY, + SPECIAL_TYPE_UNSIGNED, + SPECIAL_TYPE_INTERFACE +}; + +bool isSpecialType(SpecialType special) { + return special >= SPECIAL_TYPE_UNSIGNED; +} + +OString translateUnoidlEntityNameToJavaFullyQualifiedName( + std::u16string_view name, std::string_view prefix) +{ + assert(!o3tl::starts_with(name, u"[]")); + assert(name.find('<') == std::string_view::npos); + size_t i = name.rfind('.'); + if (i == std::string_view::npos) + i = 0; + else + ++i; + return codemaker::convertString(OUString(name.substr(0, i))).replace('.', '/') + + codemaker::java::translateUnoToJavaIdentifier( + codemaker::convertString(OUString(name.substr(i))), prefix); +} + +struct PolymorphicUnoType { + PolymorphicUnoType(): kind(KIND_NONE) {} + + enum Kind { KIND_NONE, KIND_STRUCT, KIND_SEQUENCE }; + Kind kind; + OUString name; +}; + +SpecialType translateUnoTypeToDescriptor( + rtl::Reference< TypeManager > const & manager, std::u16string_view type, + bool array, bool classType, std::set<OUString> * dependencies, + OStringBuffer * descriptor, OStringBuffer * signature, + bool * needsSignature, PolymorphicUnoType * polymorphicUnoType); + +SpecialType translateUnoTypeToDescriptor( + rtl::Reference< TypeManager > const & manager, + codemaker::UnoType::Sort sort, OUString const & nucleus, sal_Int32 rank, + std::vector< OUString > const & arguments, bool array, bool classType, + std::set<OUString> * dependencies, OStringBuffer * descriptor, + OStringBuffer * signature, bool * needsSignature, + PolymorphicUnoType * polymorphicUnoType) +{ + assert(rank >= 0); + assert((signature == nullptr) == (needsSignature == nullptr)); + assert( + arguments.empty() + == (sort + != codemaker::UnoType::Sort::InstantiatedPolymorphicStruct)); + if (rank > 0xFF - (array ? 1 : 0)) { + throw CannotDumpException( + "Too many array dimensions for Java class file format"); + } + if (array) { + ++rank; + } + for (sal_Int32 i = 0; i != rank; ++i) { + if (descriptor != nullptr) { + descriptor->append('['); + } + if (signature != nullptr) { + signature->append('['); + } + } + if (polymorphicUnoType != nullptr) { + if (sort + == codemaker::UnoType::Sort::InstantiatedPolymorphicStruct) + { + polymorphicUnoType->kind = rank == 0 + ? PolymorphicUnoType::KIND_STRUCT + : PolymorphicUnoType::KIND_SEQUENCE; + polymorphicUnoType->name = createUnoName( + manager, nucleus, rank, arguments); + } else { + polymorphicUnoType->kind = PolymorphicUnoType::KIND_NONE; + } + } + switch (sort) { + case codemaker::UnoType::Sort::Void: + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + { + static char const * const + simpleTypeDescriptors[static_cast<int>(codemaker::UnoType::Sort::Any) + 1][2] = { + { "V", "Ljava/lang/Void;" }, + { "Z", "Ljava/lang/Boolean;" }, + { "B", "Ljava/lang/Byte;" }, + { "S", "Ljava/lang/Short;" }, + { "S", "Ljava/lang/Short;" }, + { "I", "Ljava/lang/Integer;" }, + { "I", "Ljava/lang/Integer;" }, + { "J", "Ljava/lang/Long;" }, + { "J", "Ljava/lang/Long;" }, + { "F", "Ljava/lang/Float;" }, + { "D", "Ljava/lang/Double;" }, + { "C", "Ljava/lang/Character;" }, + { "Ljava/lang/String;", "Ljava/lang/String;" }, + { "Lcom/sun/star/uno/Type;", "Lcom/sun/star/uno/Type;" }, + { "Ljava/lang/Object;", "Ljava/lang/Object;" } }; + char const * s + = simpleTypeDescriptors[static_cast<int>(sort)][rank == 0 && classType]; + if (descriptor != nullptr) { + descriptor->append(s); + } + if (signature != nullptr) { + signature->append(s); + } + static SpecialType const + simpleTypeSpecials[static_cast<int>(codemaker::UnoType::Sort::Any) + 1] = { + SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, + SPECIAL_TYPE_NONE, SPECIAL_TYPE_UNSIGNED, SPECIAL_TYPE_NONE, + SPECIAL_TYPE_UNSIGNED, SPECIAL_TYPE_NONE, SPECIAL_TYPE_UNSIGNED, + SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, + SPECIAL_TYPE_NONE, SPECIAL_TYPE_NONE, SPECIAL_TYPE_ANY }; + return simpleTypeSpecials[static_cast<int>(sort)]; + } + case codemaker::UnoType::Sort::Interface: + if (nucleus == "com.sun.star.uno.XInterface") { + if (descriptor != nullptr) { + descriptor->append("Ljava/lang/Object;"); + } + if (signature != nullptr) { + signature->append("Ljava/lang/Object;"); + } + return SPECIAL_TYPE_INTERFACE; + } + [[fallthrough]]; + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + if (dependencies != nullptr) { + dependencies->insert(nucleus); + } + if (descriptor != nullptr) { + descriptor->append( + "L" + codemaker::convertString(nucleus).replace('.', '/') + + ";"); + } + if (signature != nullptr) { + signature->append( + "L" + codemaker::convertString(nucleus).replace('.', '/')); + if (!arguments.empty()) { + signature->append('<'); + for (const OUString& arg : arguments) + { + translateUnoTypeToDescriptor( + manager, arg, false, true, dependencies, nullptr, signature, + needsSignature, nullptr); + } + signature->append('>'); + *needsSignature = true; + } + signature->append(';'); + } + return SPECIAL_TYPE_NONE; + default: + throw CannotDumpException( + "unexpected nucleus \"" + nucleus + + "\" in call to translateUnoTypeToDescriptor"); + } +} + +SpecialType translateUnoTypeToDescriptor( + rtl::Reference< TypeManager > const & manager, std::u16string_view type, + bool array, bool classType, std::set<OUString> * dependencies, + OStringBuffer * descriptor, OStringBuffer * signature, + bool * needsSignature, PolymorphicUnoType * polymorphicUnoType) +{ + assert(manager.is()); + OUString nucleus; + sal_Int32 rank; + std::vector< OUString > args; + codemaker::UnoType::Sort sort = manager->decompose( + type, true, &nucleus, &rank, &args, nullptr); + return translateUnoTypeToDescriptor( + manager, sort, nucleus, rank, args, array, classType, dependencies, + descriptor, signature, needsSignature, polymorphicUnoType); +} + +SpecialType getFieldDescriptor( + rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies, + std::u16string_view type, OString * descriptor, OString * signature, + PolymorphicUnoType * polymorphicUnoType) +{ + assert(descriptor != nullptr); + OStringBuffer desc(64); + OStringBuffer sig(64); + bool needsSig = false; + SpecialType specialType = translateUnoTypeToDescriptor( + manager, type, false, false, dependencies, &desc, &sig, &needsSig, + polymorphicUnoType); + *descriptor = desc.makeStringAndClear(); + if (signature != nullptr) { + if (needsSig) { + *signature = sig.makeStringAndClear(); + } else { + signature->clear(); + } + } + return specialType; +} + +class MethodDescriptor { +public: + MethodDescriptor( + rtl::Reference< TypeManager > manager, + std::set<OUString> * dependencies, std::u16string_view returnType, + SpecialType * specialReturnType, + PolymorphicUnoType * polymorphicUnoType); + + SpecialType addParameter( + std::u16string_view type, bool array, bool dependency, + PolymorphicUnoType * polymorphicUnoType); + + void addTypeParameter(OUString const & name); + + OString getDescriptor() const; + + OString getSignature() const { return m_needsSignature ? m_signatureStart + m_signatureEnd : OString();} + +private: + rtl::Reference< TypeManager > m_manager; + std::set<OUString> * m_dependencies; + OStringBuffer m_descriptorStart{16*1024}; + OString m_descriptorEnd; + OStringBuffer m_signatureStart{16*1024}; + OString m_signatureEnd; + bool m_needsSignature; +}; + +MethodDescriptor::MethodDescriptor( + rtl::Reference< TypeManager > manager, std::set<OUString> * dependencies, + std::u16string_view returnType, SpecialType * specialReturnType, + PolymorphicUnoType * polymorphicUnoType): + m_manager(std::move(manager)), m_dependencies(dependencies), m_needsSignature(false) +{ + assert(dependencies != nullptr); + m_descriptorStart.append('('); + m_signatureStart.append('('); + OStringBuffer descEnd(128); + descEnd.append(')'); + OStringBuffer sigEnd(128); + sigEnd.append(')'); + SpecialType special = translateUnoTypeToDescriptor( + m_manager, returnType, false, false, m_dependencies, &descEnd, &sigEnd, + &m_needsSignature, polymorphicUnoType); + m_descriptorEnd = descEnd.makeStringAndClear(); + m_signatureEnd = sigEnd.makeStringAndClear(); + if (specialReturnType != nullptr) { + *specialReturnType = special; + } +} + +SpecialType MethodDescriptor::addParameter( + std::u16string_view type, bool array, bool dependency, + PolymorphicUnoType * polymorphicUnoType) +{ + return translateUnoTypeToDescriptor( + m_manager, type, array, false, dependency ? m_dependencies : nullptr, + &m_descriptorStart, &m_signatureStart, &m_needsSignature, + polymorphicUnoType); +} + +void MethodDescriptor::addTypeParameter(OUString const & name) { + m_descriptorStart.append("Ljava/lang/Object;"); + m_signatureStart.append("T" + codemaker::convertString(name) + ";"); + m_needsSignature = true; +} + +OString MethodDescriptor::getDescriptor() const { + return m_descriptorStart + m_descriptorEnd; +} + + +class TypeInfo { +public: + enum Kind { KIND_MEMBER, KIND_ATTRIBUTE, KIND_METHOD, KIND_PARAMETER }; + + // Same values as in com/sun/star/lib/uno/typeinfo/TypeInfo.java: + enum Flags { + FLAG_READONLY = 0x008, FLAG_BOUND = 0x100 + }; + + // KIND_MEMBER: + TypeInfo( + OString name, SpecialType specialType, sal_Int32 index, + PolymorphicUnoType const & polymorphicUnoType, + sal_Int32 typeParameterIndex); + + // KIND_ATTRIBUTE/METHOD: + TypeInfo( + Kind kind, OString name, SpecialType specialType, Flags flags, + sal_Int32 index, PolymorphicUnoType polymorphicUnoType); + + // KIND_PARAMETER: + TypeInfo( + OString parameterName, SpecialType specialType, + bool inParameter, bool outParameter, OString methodName, + sal_Int32 index, PolymorphicUnoType polymorphicUnoType); + + sal_uInt16 generateCode(ClassFile::Code & code, std::set<OUString> * dependencies) + const; + + void generatePolymorphicUnoTypeCode( + ClassFile::Code & code, std::set<OUString> * dependencies) const; + +private: + Kind m_kind; + OString m_name; + sal_Int32 m_flags; + sal_Int32 m_index; + OString m_methodName; + PolymorphicUnoType m_polymorphicUnoType; + sal_Int32 m_typeParameterIndex; +}; + +sal_Int32 translateSpecialTypeFlags( + SpecialType specialType, bool inParameter, bool outParameter) +{ + static sal_Int32 const specialTypeFlags[SPECIAL_TYPE_INTERFACE + 1] = { + 0, 0x0040 /* ANY */, 0x0004 /* UNSIGNED */, 0x0080 /* INTERFACE */ }; + sal_Int32 flags = specialTypeFlags[specialType]; + if (inParameter) { + flags |= 0x0001; /* IN */ + } + if (outParameter) { + flags |= 0x0002; /* OUT */ + } + return flags; +} + +TypeInfo::TypeInfo( + OString name, SpecialType specialType, sal_Int32 index, + PolymorphicUnoType const & polymorphicUnoType, + sal_Int32 typeParameterIndex): + m_kind(KIND_MEMBER), m_name(std::move(name)), + m_flags(translateSpecialTypeFlags(specialType, false, false)), + m_index(index), m_polymorphicUnoType(polymorphicUnoType), + m_typeParameterIndex(typeParameterIndex) +{ + assert( + polymorphicUnoType.kind == PolymorphicUnoType::KIND_NONE + ? typeParameterIndex >= -1 : typeParameterIndex == -1); +} + +TypeInfo::TypeInfo( + Kind kind, OString name, SpecialType specialType, Flags flags, + sal_Int32 index, PolymorphicUnoType polymorphicUnoType): + m_kind(kind), m_name(std::move(name)), + m_flags(flags | translateSpecialTypeFlags(specialType, false, false)), + m_index(index), m_polymorphicUnoType(std::move(polymorphicUnoType)), + m_typeParameterIndex(0) +{ + assert(kind == KIND_ATTRIBUTE || kind == KIND_METHOD); +} + +TypeInfo::TypeInfo( + OString parameterName, SpecialType specialType, bool inParameter, + bool outParameter, OString methodName, sal_Int32 index, + PolymorphicUnoType polymorphicUnoType): + m_kind(KIND_PARAMETER), m_name(std::move(parameterName)), + m_flags(translateSpecialTypeFlags(specialType, inParameter, outParameter)), + m_index(index), m_methodName(std::move(methodName)), + m_polymorphicUnoType(std::move(polymorphicUnoType)), + m_typeParameterIndex(0) +{} + +sal_uInt16 TypeInfo::generateCode( + ClassFile::Code & code, std::set<OUString> * dependencies) const +{ + switch (m_kind) { + case KIND_MEMBER: + code.instrNew("com/sun/star/lib/uno/typeinfo/MemberTypeInfo"); + code.instrDup(); + code.loadStringConstant(m_name); + code.loadIntegerConstant(m_index); + code.loadIntegerConstant(m_flags); + if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) { + generatePolymorphicUnoTypeCode(code, dependencies); + code.loadIntegerConstant(m_typeParameterIndex); + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/MemberTypeInfo", "<init>", + "(Ljava/lang/String;IILcom/sun/star/uno/Type;I)V"); + return 8; + } else if (m_typeParameterIndex >= 0) { + code.instrAconstNull(); + code.loadIntegerConstant(m_typeParameterIndex); + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/MemberTypeInfo", "<init>", + "(Ljava/lang/String;IILcom/sun/star/uno/Type;I)V"); + return 6; + } else { + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/MemberTypeInfo", "<init>", + "(Ljava/lang/String;II)V"); + return 4; + } + case KIND_ATTRIBUTE: + code.instrNew("com/sun/star/lib/uno/typeinfo/AttributeTypeInfo"); + code.instrDup(); + code.loadStringConstant(m_name); + code.loadIntegerConstant(m_index); + code.loadIntegerConstant(m_flags); + if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) { + generatePolymorphicUnoTypeCode(code, dependencies); + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/AttributeTypeInfo", "<init>", + "(Ljava/lang/String;IILcom/sun/star/uno/Type;)V"); + return 8; + } else { + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/AttributeTypeInfo", "<init>", + "(Ljava/lang/String;II)V"); + return 4; + } + case KIND_METHOD: + code.instrNew("com/sun/star/lib/uno/typeinfo/MethodTypeInfo"); + code.instrDup(); + code.loadStringConstant(m_name); + code.loadIntegerConstant(m_index); + code.loadIntegerConstant(m_flags); + if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) { + generatePolymorphicUnoTypeCode(code, dependencies); + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/MethodTypeInfo", "<init>", + "(Ljava/lang/String;IILcom/sun/star/uno/Type;)V"); + return 8; + } else { + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/MethodTypeInfo", "<init>", + "(Ljava/lang/String;II)V"); + return 4; + } + case KIND_PARAMETER: + code.instrNew("com/sun/star/lib/uno/typeinfo/ParameterTypeInfo"); + code.instrDup(); + code.loadStringConstant(m_name); + code.loadStringConstant(m_methodName); + code.loadIntegerConstant(m_index); + code.loadIntegerConstant(m_flags); + if (m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) { + generatePolymorphicUnoTypeCode(code, dependencies); + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/ParameterTypeInfo", "<init>", + ("(Ljava/lang/String;Ljava/lang/String;II" + "Lcom/sun/star/uno/Type;)V")); + return 9; + } else { + code.instrInvokespecial( + "com/sun/star/lib/uno/typeinfo/ParameterTypeInfo", "<init>", + "(Ljava/lang/String;Ljava/lang/String;II)V"); + return 5; + } + default: + assert(false); + return 0; + } +} + +void TypeInfo::generatePolymorphicUnoTypeCode( + ClassFile::Code & code, std::set<OUString> * dependencies) const +{ + assert(dependencies != nullptr); + assert(m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE); + code.instrNew("com/sun/star/uno/Type"); + code.instrDup(); + code.loadStringConstant( + codemaker::convertString(m_polymorphicUnoType.name)); + if (m_polymorphicUnoType.kind == PolymorphicUnoType::KIND_STRUCT) { + code.instrGetstatic( + "com/sun/star/uno/TypeClass", "STRUCT", + "Lcom/sun/star/uno/TypeClass;"); + } else { + code.instrGetstatic( + "com/sun/star/uno/TypeClass", "SEQUENCE", + "Lcom/sun/star/uno/TypeClass;"); + } + dependencies->insert("com.sun.star.uno.TypeClass"); + code.instrInvokespecial( + "com/sun/star/uno/Type", "<init>", + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"); +} + +void writeClassFile( + JavaOptions const & options, OString const & type, + ClassFile const & classFile) +{ + OString path; + if (options.isValid("-O")) { + path = options.getOption("-O"); + } + OString filename(createFileNameFromType(path, type, ".class")); + bool bCheck = false; + if (fileExists(filename)) { + if (options.isValid("-G")) { + return; + } + bCheck = options.isValid("-Gc"); + } + FileStream tempfile; + tempfile.createTempFile(getTempDir(filename)); + if (!tempfile.isValid()) { + throw CannotDumpException( + "Cannot create temporary file for " + b2u(filename)); + } + OString tempname(tempfile.getName()); + try { + classFile.write(tempfile); + } catch (...) { + // Remove existing file for consistency: + if (fileExists(filename)) { + removeTypeFile(filename); + } + tempfile.close(); + removeTypeFile(tempname); + throw; + } + tempfile.close(); + if (!makeValidTypeFile(filename, tempname, bCheck)) { + throw CannotDumpException( + "Cannot create " + b2u(filename) + " from temporary file " + + b2u(tempname)); + } +} + +void addTypeInfo( + OString const & className, std::vector< TypeInfo > const & typeInfo, + std::set<OUString> * dependencies, ClassFile * classFile) +{ + assert(classFile != nullptr); + std::vector< TypeInfo >::size_type typeInfos = typeInfo.size(); + if (typeInfos > SAL_MAX_INT32) { + throw CannotDumpException( + "UNOTYPEINFO array too big for Java class file format"); + } + if (typeInfos == 0) + return; + + classFile->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + "UNOTYPEINFO", "[Lcom/sun/star/lib/uno/typeinfo/TypeInfo;", + 0, ""); + std::unique_ptr< ClassFile::Code > code(classFile->newCode()); + code->loadIntegerConstant(static_cast< sal_Int32 >(typeInfos)); + code->instrAnewarray("com/sun/star/lib/uno/typeinfo/TypeInfo"); + sal_Int32 index = 0; + sal_uInt16 stack = 0; + for (const TypeInfo& ti : typeInfo) + { + code->instrDup(); + code->loadIntegerConstant(index++); + stack = std::max(stack, ti.generateCode(*code, dependencies)); + code->instrAastore(); + } + code->instrPutstatic( + className, "UNOTYPEINFO", + "[Lcom/sun/star/lib/uno/typeinfo/TypeInfo;"); + code->instrReturn(); + if (stack > SAL_MAX_UINT16 - 4) { + throw CannotDumpException( + "Stack too big for Java class file format"); + } + code->setMaxStackAndLocals(static_cast< sal_uInt16 >(stack + 4), 0); + classFile->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC), + "<clinit>", "()V", code.get(), std::vector< OString >(), ""); +} + +void handleEnumType( + const OUString& name, rtl::Reference< unoidl::EnumTypeEntity > const & entity, + JavaOptions const & options) +{ + assert(entity.is()); + OString className(codemaker::convertString(name).replace('.', '/')); + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL + | ClassFile::ACC_SUPER), + className, "com/sun/star/uno/Enum", "")); + OString classDescriptor("L" + className + ";"); + for (const unoidl::EnumTypeEntity::Member& member : entity->getMembers()) + { + OString fieldName(codemaker::convertString(member.name)); + cf->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + fieldName, classDescriptor, 0, OString()); + cf->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + fieldName + "_value", "I", + cf->addIntegerInfo(member.value), ""); + } + std::unique_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + code->loadLocalInteger(1); + code->instrInvokespecial("com/sun/star/uno/Enum", "<init>", "(I)V"); + code->instrReturn(); + code->setMaxStackAndLocals(2, 2); + cf->addMethod( + ClassFile::ACC_PRIVATE, + "<init>", "(I)V", code.get(), + std::vector< OString >(), ""); + code = cf->newCode(); + code->instrGetstatic( + className, + codemaker::convertString(entity->getMembers()[0].name), + classDescriptor); + code->instrAreturn(); + code->setMaxStackAndLocals(1, 0); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC), + "getDefault", "()" + classDescriptor, + code.get(), std::vector< OString >(), ""); + code = cf->newCode(); + code->loadLocalInteger(0); + std::map< sal_Int32, OString > map; + sal_Int32 min = SAL_MAX_INT32; + sal_Int32 max = SAL_MIN_INT32; + for (const unoidl::EnumTypeEntity::Member& member : entity->getMembers()) + { + min = std::min(min, member.value); + max = std::max(max, member.value); + map.emplace(member.value, codemaker::convertString(member.name)); + } + sal_uInt64 size = static_cast< sal_uInt64 >(map.size()); + if ((static_cast< sal_uInt64 >(max) - static_cast< sal_uInt64 >(min) + <= 2 * size) + || size > SAL_MAX_INT32) + { + std::unique_ptr< ClassFile::Code > defCode(cf->newCode()); + defCode->instrAconstNull(); + defCode->instrAreturn(); + std::vector< std::unique_ptr<ClassFile::Code> > blocks; + //FIXME: pointers contained in blocks may leak + sal_Int32 last = SAL_MAX_INT32; + for (const auto& pair : map) + { + sal_Int32 value = pair.first; + if (last != SAL_MAX_INT32) { + for (sal_Int32 j = last + 1; j < value; ++j) { + blocks.push_back(nullptr); + } + } + last = value; + std::unique_ptr< ClassFile::Code > blockCode(cf->newCode()); + blockCode->instrGetstatic(className, pair.second, classDescriptor); + blockCode->instrAreturn(); + blocks.push_back(std::move(blockCode)); + } + code->instrTableswitch(defCode.get(), min, blocks); + } else{ + std::unique_ptr< ClassFile::Code > defCode(cf->newCode()); + defCode->instrAconstNull(); + defCode->instrAreturn(); + std::vector< std::pair< sal_Int32, ClassFile::Code * > > blocks; + //FIXME: pointers contained in blocks may leak + for (const auto& pair : map ) + { + std::unique_ptr< ClassFile::Code > blockCode(cf->newCode()); + blockCode->instrGetstatic(className, pair.second, classDescriptor); + blockCode->instrAreturn(); + blocks.emplace_back(pair.first, blockCode.release()); + } + code->instrLookupswitch(defCode.get(), blocks); + for (const std::pair< sal_Int32, ClassFile::Code * >& pair : blocks) + { + delete pair.second; + } + } + code->setMaxStackAndLocals(1, 1); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC), + "fromInt", "(I)" + classDescriptor, code.get(), + std::vector< OString >(), ""); + code = cf->newCode(); + for (const unoidl::EnumTypeEntity::Member& member : entity->getMembers()) + { + code->instrNew(className); + code->instrDup(); + code->loadIntegerConstant(member.value); + code->instrInvokespecial(className, "<init>", "(I)V"); + code->instrPutstatic( + className, codemaker::convertString(member.name), classDescriptor); + } + code->instrReturn(); + code->setMaxStackAndLocals(3, 0); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC), + "<clinit>", "()V", code.get(), std::vector< OString >(), ""); + writeClassFile(options, className, *cf); +} + +void addField( + rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies, + ClassFile * classFile, std::vector< TypeInfo > * typeInfo, + sal_Int32 typeParameterIndex, OUString const & type, OUString const & name, + sal_Int32 index) +{ + assert(classFile != nullptr); + assert(typeInfo != nullptr); + OString descriptor; + OString signature; + SpecialType specialType; + PolymorphicUnoType polymorphicUnoType; + if (typeParameterIndex >= 0) { + descriptor = "Ljava/lang/Object;"; + signature = "T" + codemaker::convertString(type).replace('.', '/') + + ";"; + specialType = SPECIAL_TYPE_NONE; //TODO: SPECIAL_TYPE_TYPE_PARAMETER? + } else { + specialType = getFieldDescriptor( + manager, dependencies, type, &descriptor, &signature, + &polymorphicUnoType); + } + classFile->addField( + ClassFile::ACC_PUBLIC, codemaker::convertString(name), descriptor, 0, + signature); + typeInfo->push_back( + TypeInfo( + codemaker::convertString(name), specialType, index, + polymorphicUnoType, typeParameterIndex)); +} + +sal_uInt16 addFieldInit( + rtl::Reference< TypeManager > const & manager, OString const & className, + OUString const & fieldName, bool typeParameter, std::u16string_view fieldType, + std::set<OUString> * dependencies, ClassFile::Code * code) +{ + assert(manager.is()); + assert(code != nullptr); + if (typeParameter) { + return 0; + } + OString name(codemaker::convertString(fieldName)); + OUString nucleus; + sal_Int32 rank; + std::vector< OUString > args; + rtl::Reference< unoidl::Entity > ent; + codemaker::UnoType::Sort sort = manager->decompose( + fieldType, true, &nucleus, &rank, &args, &ent); + if (rank == 0) { + switch (sort) { + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::Interface: + return 0; + case codemaker::UnoType::Sort::String: + code->loadLocalReference(0); + code->loadStringConstant(OString()); + code->instrPutfield(className, name, "Ljava/lang/String;"); + return 2; + case codemaker::UnoType::Sort::Type: + code->loadLocalReference(0); + code->instrGetstatic( + "com/sun/star/uno/Type", "VOID", "Lcom/sun/star/uno/Type;"); + code->instrPutfield(className, name, "Lcom/sun/star/uno/Type;"); + return 2; + case codemaker::UnoType::Sort::Any: + code->loadLocalReference(0); + code->instrGetstatic( + "com/sun/star/uno/Any", "VOID", "Lcom/sun/star/uno/Any;"); + code->instrPutfield(className, name, "Ljava/lang/Object;"); + return 2; + case codemaker::UnoType::Sort::Enum: + { + rtl::Reference< unoidl::EnumTypeEntity > ent2( + dynamic_cast< unoidl::EnumTypeEntity * >(ent.get())); + assert(ent2.is()); + code->loadLocalReference(0); + OStringBuffer descBuf(128); + translateUnoTypeToDescriptor( + manager, sort, nucleus, 0, std::vector< OUString >(), false, + false, dependencies, &descBuf, nullptr, nullptr, nullptr); + OString desc(descBuf.makeStringAndClear()); + code->instrGetstatic( + codemaker::convertString(nucleus).replace('.', '/'), + codemaker::convertString(ent2->getMembers()[0].name), desc); + code->instrPutfield(className, name, desc); + return 2; + } + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + { + code->loadLocalReference(0); + code->instrNew( + codemaker::convertString(nucleus).replace('.', '/')); + code->instrDup(); + code->instrInvokespecial( + codemaker::convertString(nucleus).replace('.', '/'), + "<init>", "()V"); + OStringBuffer desc(128); + translateUnoTypeToDescriptor( + manager, sort, nucleus, 0, args, false, false, dependencies, + &desc, nullptr, nullptr, nullptr); + code->instrPutfield(className, name, desc.makeStringAndClear()); + return 3; + } + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::Typedef: + for (;;) std::abort(); // this cannot happen + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + fieldType + + "\" in call to addFieldInit"); + } + } + code->loadLocalReference(0); + code->loadIntegerConstant(0); + if (rank == 1) { + if (sort >= codemaker::UnoType::Sort::Boolean + && sort <= codemaker::UnoType::Sort::Char) + { + code->instrNewarray(sort); + } else { + code->instrAnewarray( + codemaker::java::translateUnoToJavaType( + sort, codemaker::convertString(nucleus).replace('.', '/'), + false)); + } + } else { + OStringBuffer desc(128); + translateUnoTypeToDescriptor( + manager, sort, nucleus, rank - 1, std::vector< OUString >(), false, + false, dependencies, &desc, nullptr, nullptr, nullptr); + code->instrAnewarray(desc.makeStringAndClear()); + } + OStringBuffer desc(128); + translateUnoTypeToDescriptor( + manager, sort, nucleus, rank, std::vector< OUString >(), false, false, + dependencies, &desc, nullptr, nullptr, nullptr); + code->instrPutfield(className, name, desc.makeStringAndClear()); + return 2; +} + +sal_uInt16 addLoadLocal( + rtl::Reference< TypeManager > const & manager, ClassFile::Code * code, + sal_uInt16 * index, bool typeParameter, std::u16string_view type, bool any, + std::set<OUString> * dependencies) +{ + assert(manager.is()); + assert(code != nullptr); + assert(index != nullptr); + assert(!(typeParameter && any)); + assert(dependencies != nullptr); + sal_uInt16 stack = 1; + sal_uInt16 size = 1; + if (typeParameter) { + code->loadLocalReference(*index); + stack = size = 1; + } else { + OUString nucleus; + sal_Int32 rank; + std::vector< OUString > args; + codemaker::UnoType::Sort sort = manager->decompose( + type, true, &nucleus, &rank, &args, nullptr); + if (rank == 0) { + switch (sort) { + case codemaker::UnoType::Sort::Boolean: + if (any) { + code->instrNew("java/lang/Boolean"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Boolean", "<init>", "(Z)V"); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Byte: + if (any) { + code->instrNew("java/lang/Byte"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Byte", "<init>", "(B)V"); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Short: + if (any) { + code->instrNew("java/lang/Short"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Short", "<init>", "(S)V"); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::UnsignedShort: + if (any) { + code->instrNew("com/sun/star/uno/Any"); + code->instrDup(); + code->instrGetstatic( + "com/sun/star/uno/Type", "UNSIGNED_SHORT", + "Lcom/sun/star/uno/Type;"); + code->instrNew("java/lang/Short"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Short", "<init>", "(S)V"); + code->instrInvokespecial( + "com/sun/star/uno/Any", "<init>", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"); + stack = 6; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Long: + if (any) { + code->instrNew("java/lang/Integer"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Integer", "<init>", "(I)V"); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::UnsignedLong: + if (any) { + code->instrNew("com/sun/star/uno/Any"); + code->instrDup(); + code->instrGetstatic( + "com/sun/star/uno/Type", "UNSIGNED_LONG", + "Lcom/sun/star/uno/Type;"); + code->instrNew("java/lang/Integer"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Integer", "<init>", "(I)V"); + code->instrInvokespecial( + "com/sun/star/uno/Any", "<init>", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"); + stack = 6; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Hyper: + if (any) { + code->instrNew("java/lang/Long"); + code->instrDup(); + code->loadLocalLong(*index); + code->instrInvokespecial( + "java/lang/Long", "<init>", "(J)V"); + stack = 4; + } else { + code->loadLocalLong(*index); + stack = 2; + } + size = 2; + break; + case codemaker::UnoType::Sort::UnsignedHyper: + if (any) { + code->instrNew("com/sun/star/uno/Any"); + code->instrDup(); + code->instrGetstatic( + "com/sun/star/uno/Type", "UNSIGNED_HYPER", + "Lcom/sun/star/uno/Type;"); + code->instrNew("java/lang/Long"); + code->instrDup(); + code->loadLocalLong(*index); + code->instrInvokespecial( + "java/lang/Long", "<init>", "(J)V"); + code->instrInvokespecial( + "com/sun/star/uno/Any", "<init>", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"); + stack = 7; + } else { + code->loadLocalLong(*index); + stack = 2; + } + size = 2; + break; + case codemaker::UnoType::Sort::Float: + if (any) { + code->instrNew("java/lang/Float"); + code->instrDup(); + code->loadLocalFloat(*index); + code->instrInvokespecial( + "java/lang/Float", "<init>", "(F)V"); + stack = 3; + } else { + code->loadLocalFloat(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Double: + if (any) { + code->instrNew("java/lang/Double"); + code->instrDup(); + code->loadLocalDouble(*index); + code->instrInvokespecial( + "java/lang/Double", "<init>", "(D)V"); + stack = 4; + } else { + code->loadLocalDouble(*index); + stack = 2; + } + size = 2; + break; + case codemaker::UnoType::Sort::Char: + if (any) { + code->instrNew("java/lang/Character"); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + "java/lang/Character", "<init>", "(C)V"); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + code->loadLocalReference(*index); + stack = size = 1; + break; + case codemaker::UnoType::Sort::Enum: + // Assuming that no Java types are derived from Java types that + // are directly derived from com.sun.star.uno.Enum: + code->loadLocalReference(*index); + stack = size = 1; + break; + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + if (any) { + code->instrNew("com/sun/star/uno/Any"); + code->instrDup(); + code->instrNew("com/sun/star/uno/Type"); + code->instrDup(); + code->loadStringConstant( + codemaker::convertString( + createUnoName(manager, nucleus, rank, args))); + code->instrGetstatic( + "com/sun/star/uno/TypeClass", "STRUCT", + "Lcom/sun/star/uno/TypeClass;"); + dependencies->insert("com.sun.star.uno.TypeClass"); + code->instrInvokespecial( + "com/sun/star/uno/Type", "<init>", + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"); + code->loadLocalReference(*index); + code->instrInvokespecial( + "com/sun/star/uno/Any", "<init>", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"); + stack = 6; + } else { + code->loadLocalReference(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Interface: + if (any && nucleus != "com.sun.star.uno.XInterface") { + code->instrNew("com/sun/star/uno/Any"); + code->instrDup(); + code->instrNew("com/sun/star/uno/Type"); + code->instrDup(); + code->loadStringConstant(codemaker::convertString(nucleus)); + code->instrGetstatic( + "com/sun/star/uno/TypeClass", "INTERFACE", + "Lcom/sun/star/uno/TypeClass;"); + dependencies->insert("com.sun.star.uno.TypeClass"); + code->instrInvokespecial( + "com/sun/star/uno/Type", "<init>", + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"); + code->loadLocalReference(*index); + code->instrInvokespecial( + "com/sun/star/uno/Any", "<init>", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"); + stack = 6; + } else { + code->loadLocalReference(*index); + stack = 1; + } + size = 1; + break; + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::Typedef: + for (;;) std::abort(); // this cannot happen + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + type + + "\" in call to addLoadLocal"); + } + } else { + bool bWrap = false; + if (any) { + switch (sort) { + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + // assuming that no Java types are derived from + // com.sun.star.uno.Type + case codemaker::UnoType::Sort::Enum: + // assuming that no Java types are derived from Java + // types that are directly derived from + // com.sun.star.uno.Enum + break; + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Any: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::InstantiatedPolymorphicStruct: + case codemaker::UnoType::Sort::Interface: + bWrap = true; + break; + case codemaker::UnoType::Sort::Sequence: + case codemaker::UnoType::Sort::Typedef: + for (;;) std::abort(); // this cannot happen + default: + throw CannotDumpException( + OUString::Concat("unexpected entity \"") + type + + "\" in call to addLoadLocal"); + } + } + if (bWrap) { + code->instrNew("com/sun/star/uno/Any"); + code->instrDup(); + code->instrNew("com/sun/star/uno/Type"); + code->instrDup(); + code->loadStringConstant( + codemaker::convertString( + createUnoName(manager, nucleus, rank, args))); + code->instrInvokespecial( + "com/sun/star/uno/Type", "<init>", "(Ljava/lang/String;)V"); + code->loadLocalReference(*index); + code->instrInvokespecial( + "com/sun/star/uno/Any", "<init>", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)V"); + stack = 5; + } else { + code->loadLocalReference(*index); + stack = 1; + } + size = 1; + } + } + if (*index > SAL_MAX_UINT16 - size) { + throw CannotDumpException( + "Too many local variables for Java class file format"); + } + *index = *index + size; + return stack; +} + +sal_uInt16 addDirectArgument( + rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies, + MethodDescriptor * methodDescriptor, ClassFile::Code * code, + sal_uInt16 * index, OString const & className, OString const & fieldName, + bool typeParameter, OUString const & fieldType) +{ + assert(methodDescriptor != nullptr); + assert(code != nullptr); + OString desc; + if (typeParameter) { + methodDescriptor->addTypeParameter(fieldType); + desc = "Ljava/lang/Object;"; + } else { + methodDescriptor->addParameter(fieldType, false, true, nullptr); + getFieldDescriptor(manager, dependencies, fieldType, &desc, nullptr, nullptr); + } + code->loadLocalReference(0); + sal_uInt16 stack = addLoadLocal( + manager, code, index, typeParameter, fieldType, false, dependencies); + code->instrPutfield(className, fieldName, desc); + return stack + 1; +} + +void addPlainStructBaseArguments( + rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies, + MethodDescriptor * methodDescriptor, ClassFile::Code * code, + OUString const & base, sal_uInt16 * index) +{ + assert(manager.is()); + assert(methodDescriptor != nullptr); + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(base, &ent) + != codemaker::UnoType::Sort::PlainStruct) + { + throw CannotDumpException( + "unexpected entity \"" + base + + "\" in call to addPlainStructBaseArguments"); + } + unoidl::PlainStructTypeEntity& ent2(dynamic_cast<unoidl::PlainStructTypeEntity&>(*ent)); + if (!ent2.getDirectBase().isEmpty()) { + addPlainStructBaseArguments( + manager, dependencies, methodDescriptor, code, + ent2.getDirectBase(), index); + } + for (const unoidl::PlainStructTypeEntity::Member& member : ent2.getDirectMembers()) + { + methodDescriptor->addParameter(member.type, false, true, nullptr); + addLoadLocal(manager, code, index, false, member.type, false, dependencies); + } +} + +void handlePlainStructType( + const OUString& name, + rtl::Reference< unoidl::PlainStructTypeEntity > const & entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + assert(dependencies != nullptr); + OString className(codemaker::convertString(name).replace('.', '/')); + OString superClass; + if (entity->getDirectBase().isEmpty()) { + superClass = "java/lang/Object"; + } else { + superClass = codemaker::convertString(entity->getDirectBase()). + replace('.', '/'); + dependencies->insert(entity->getDirectBase()); + } + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER), + className, superClass, "")); + std::vector< TypeInfo > typeInfo; + sal_Int32 index = 0; + for (const unoidl::PlainStructTypeEntity::Member& member : entity->getDirectMembers()) + { + addField( + manager, dependencies, cf.get(), &typeInfo, -1, member.type, member.name, + index++); + } + std::unique_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + code->instrInvokespecial(superClass, "<init>", "()V"); + sal_uInt16 stack = 0; + for (const unoidl::PlainStructTypeEntity::Member& member : entity->getDirectMembers()) + { + stack = std::max( + stack, + addFieldInit( + manager, className, member.name, false, member.type, dependencies, + code.get())); + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 1, 1); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", "()V", code.get(), + std::vector< OString >(), ""); + MethodDescriptor desc(manager, dependencies, u"void", nullptr, nullptr); + code = cf->newCode(); + code->loadLocalReference(0); + sal_uInt16 index2 = 1; + if (!entity->getDirectBase().isEmpty()) { + addPlainStructBaseArguments( + manager, dependencies, &desc, code.get(), entity->getDirectBase(), + &index2); + } + code->instrInvokespecial(superClass, "<init>", desc.getDescriptor()); + sal_uInt16 maxSize = index2; + for (const unoidl::PlainStructTypeEntity::Member& member : entity->getDirectMembers()) + { + maxSize = std::max( + maxSize, + addDirectArgument( + manager, dependencies, &desc, code.get(), &index2, className, + codemaker::convertString(member.name), false, member.type)); + } + code->instrReturn(); + code->setMaxStackAndLocals(maxSize, index2); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", desc.getDescriptor(), code.get(), + std::vector< OString >(), desc.getSignature()); + addTypeInfo(className, typeInfo, dependencies, cf.get()); + writeClassFile(options, className, *cf); +} + +void handlePolyStructType( + const OUString& name, + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > const & + entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + OString className(codemaker::convertString(name).replace('.', '/')); + std::map< OUString, sal_Int32 > typeParameters; + OStringBuffer sig(128); + sig.append("<"); + sal_Int32 index = 0; + for (const OUString& param : entity->getTypeParameters()) + { + sig.append(codemaker::convertString(param) + ":Ljava/lang/Object;"); + if (!typeParameters.emplace(param, index++).second) + { + throw CannotDumpException("Bad type information"); //TODO + } + } + sig.append(">Ljava/lang/Object;"); + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER), + className, "java/lang/Object", sig.makeStringAndClear())); + std::vector< TypeInfo > typeInfo; + index = 0; + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity->getMembers()) + { + sal_Int32 typeParameterIndex; + if (member.parameterized) { + std::map< OUString, sal_Int32 >::iterator it( + typeParameters.find(member.type)); + if (it == typeParameters.end()) { + throw CannotDumpException("Bad type information"); //TODO + } + typeParameterIndex = it->second; + } else { + typeParameterIndex = -1; + } + addField( + manager, dependencies, cf.get(), &typeInfo, typeParameterIndex, + member.type, member.name, index++); + } + std::unique_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + code->instrInvokespecial("java/lang/Object", "<init>", "()V"); + sal_uInt16 stack = 0; + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity->getMembers()) + { + stack = std::max( + stack, + addFieldInit( + manager, className, member.name, member.parameterized, member.type, + dependencies, code.get())); + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 1, 1); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", "()V", code.get(), + std::vector< OString >(), ""); + MethodDescriptor desc(manager, dependencies, u"void", nullptr, nullptr); + code = cf->newCode(); + code->loadLocalReference(0); + sal_uInt16 index2 = 1; + code->instrInvokespecial( + "java/lang/Object", "<init>", desc.getDescriptor()); + sal_uInt16 maxSize = index2; + for (const unoidl::PolymorphicStructTypeTemplateEntity::Member& member : entity->getMembers()) + { + maxSize = std::max( + maxSize, + addDirectArgument( + manager, dependencies, &desc, code.get(), &index2, className, + codemaker::convertString(member.name), member.parameterized, member.type)); + } + code->instrReturn(); + code->setMaxStackAndLocals(maxSize, index2); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", desc.getDescriptor(), code.get(), + std::vector< OString >(), desc.getSignature()); + addTypeInfo(className, typeInfo, dependencies, cf.get()); + writeClassFile(options, className, *cf); +} + +void addExceptionBaseArguments( + rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies, + MethodDescriptor * methodDescriptor, ClassFile::Code * code, + OUString const & base, sal_uInt16 * index) +{ + assert(manager.is()); + assert(methodDescriptor != nullptr); + rtl::Reference< unoidl::Entity > ent; + if (manager->getSort(base, &ent) != codemaker::UnoType::Sort::Exception) + { + throw CannotDumpException( + "unexpected entity \"" + base + + "\" in call to addExceptionBaseArguments"); + } + unoidl::ExceptionTypeEntity& ent2(dynamic_cast<unoidl::ExceptionTypeEntity&>(*ent)); + bool baseException = base == "com.sun.star.uno.Exception"; + if (!baseException) { + addExceptionBaseArguments( + manager, dependencies, methodDescriptor, code, + ent2.getDirectBase(), index); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + ent2.getDirectMembers().begin()); + i != ent2.getDirectMembers().end(); ++i) + { + if (!baseException || i != ent2.getDirectMembers().begin()) { + methodDescriptor->addParameter(i->type, false, true, nullptr); + addLoadLocal( + manager, code, index, false, i->type, false, dependencies); + } + } +} + +void handleExceptionType( + const OUString& name, rtl::Reference< unoidl::ExceptionTypeEntity > const & entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + assert(dependencies != nullptr); + OString className(codemaker::convertString(name).replace('.', '/')); + bool baseException = false; + bool baseRuntimeException = false; + OString superClass; + if (className == "com/sun/star/uno/Exception") { + baseException = true; + superClass = "java/lang/Exception"; + } else if (className == "com/sun/star/uno/RuntimeException") { + baseRuntimeException = true; + superClass = "java/lang/RuntimeException"; + } else { + if (entity->getDirectBase().isEmpty()) { + throw CannotDumpException( + "Exception type \"" + name + "\" lacks base"); + } + superClass = codemaker::convertString(entity->getDirectBase()). + replace('.', '/'); + dependencies->insert(entity->getDirectBase()); + } + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER), + className, superClass, "")); + std::vector< TypeInfo > typeInfo; + sal_Int32 index = 0; + if (baseRuntimeException) { + addField( + manager, dependencies, cf.get(), &typeInfo, -1, + "com.sun.star.uno.XInterface", "Context", index++); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + addField( + manager, dependencies, cf.get(), &typeInfo, -1, i->type, + i->name, index++); + } + } + + // create default constructor + std::unique_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + code->instrInvokespecial(superClass, "<init>", "()V"); + sal_uInt16 stack = 0; + if (baseRuntimeException) { + stack = std::max( + stack, + addFieldInit( + manager, className, "Context", false, + u"com.sun.star.uno.XInterface", dependencies, code.get())); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + stack = std::max( + stack, + addFieldInit( + manager, className, i->name, false, i->type, dependencies, + code.get())); + } + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 1, 1); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", "()V", code.get(), + std::vector< OString >(), ""); + + + // create (Throwable Cause) constructor + code = cf->newCode(); + code->loadLocalReference(0); + code->loadLocalReference(1); + code->instrInvokespecial(superClass, "<init>", "(Ljava/lang/Throwable;)V"); + stack = 0; + if (baseRuntimeException) { + stack = std::max( + stack, + addFieldInit( + manager, className, "Context", false, + u"com.sun.star.uno.XInterface", dependencies, code.get())); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + stack = std::max( + stack, + addFieldInit( + manager, className, i->name, false, i->type, dependencies, + code.get())); + } + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 2, 2); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", "(Ljava/lang/Throwable;)V", code.get(), + std::vector< OString >(), ""); + + // create (Throwable Cause, String Message) constructor + code = cf->newCode(); + code->loadLocalReference(0); + if (baseException || baseRuntimeException) { + code->loadLocalReference(2); + code->loadLocalReference(1); + code->instrInvokespecial(superClass, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V"); + } else { + code->loadLocalReference(1); + code->loadLocalReference(2); + code->instrInvokespecial(superClass, "<init>", "(Ljava/lang/Throwable;Ljava/lang/String;)V"); + } + stack = 0; + if (baseRuntimeException) { + stack = std::max( + stack, + addFieldInit( + manager, className, "Context", false, + u"com.sun.star.uno.XInterface", dependencies, code.get())); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + stack = std::max( + stack, + addFieldInit( + manager, className, i->name, false, i->type, dependencies, + code.get())); + } + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 3, 3); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", "(Ljava/lang/Throwable;Ljava/lang/String;)V", code.get(), + std::vector< OString >(), ""); + + // create (String Message) constructor + code = cf->newCode(); + code->loadLocalReference(0); + code->loadLocalReference(1); + code->instrInvokespecial(superClass, "<init>", "(Ljava/lang/String;)V"); + stack = 0; + if (baseRuntimeException) { + stack = std::max( + stack, + addFieldInit( + manager, className, "Context", false, + u"com.sun.star.uno.XInterface", dependencies, code.get())); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + stack = std::max( + stack, + addFieldInit( + manager, className, i->name, false, i->type, dependencies, + code.get())); + } + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 2, 2); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", code.get(), + std::vector< OString >(), ""); + + + // create (String Message, Object Context, T1 m1, ..., Tn mn) constructor + MethodDescriptor desc1(manager, dependencies, u"void", nullptr, nullptr); + code = cf->newCode(); + code->loadLocalReference(0); + sal_uInt16 index2 = 1; + code->loadLocalReference(index2++); + desc1.addParameter(u"string", false, true, nullptr); + if (!(baseException || baseRuntimeException)) { + addExceptionBaseArguments( + manager, dependencies, &desc1, code.get(), entity->getDirectBase(), + &index2); + } + code->instrInvokespecial(superClass, "<init>", desc1.getDescriptor()); + sal_uInt16 maxSize = index2; + if (baseRuntimeException) { + maxSize = std::max( + maxSize, + addDirectArgument( + manager, dependencies, &desc1, code.get(), &index2, className, + "Context", false, "com.sun.star.uno.XInterface")); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + maxSize = std::max( + maxSize, + addDirectArgument( + manager, dependencies, &desc1, code.get(), &index2, + className, codemaker::convertString(i->name), false, + i->type)); + } + } + code->instrReturn(); + code->setMaxStackAndLocals(maxSize, index2); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", desc1.getDescriptor(), code.get(), + std::vector< OString >(), desc1.getSignature()); + + // create (Throwable Cause, String Message, Object Context, T1 m1, ..., Tn mn) constructor + MethodDescriptor desc2(manager, dependencies, u"void", nullptr, nullptr); + code = cf->newCode(); + code->loadLocalReference(0); + sal_uInt16 index3 = 3; + // Note that we hack in the java.lang.Throwable parameter further down, + // because MethodDescriptor does not know how to handle it. + desc2.addParameter(u"string", false, true, nullptr); + if (baseException || baseRuntimeException) { + code->loadLocalReference(2); + code->loadLocalReference(1); + code->instrInvokespecial(superClass, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V"); + } else { + code->loadLocalReference(1); + code->loadLocalReference(2); + addExceptionBaseArguments( + manager, dependencies, &desc2, code.get(), entity->getDirectBase(), + &index3); + code->instrInvokespecial(superClass, "<init>", OString::Concat("(Ljava/lang/Throwable;") + desc2.getDescriptor().subView(1)); + } + sal_uInt16 maxSize2 = index3; + if (baseRuntimeException) { + maxSize2 = std::max( + maxSize2, + addDirectArgument( + manager, dependencies, &desc2, code.get(), &index3, className, + "Context", false, "com.sun.star.uno.XInterface")); + } + for (std::vector< unoidl::ExceptionTypeEntity::Member >::const_iterator i( + entity->getDirectMembers().begin()); + i != entity->getDirectMembers().end(); ++i) + { + if (!baseException || i != entity->getDirectMembers().begin()) { + maxSize2 = std::max( + maxSize2, + addDirectArgument( + manager, dependencies, &desc2, code.get(), &index3, + className, codemaker::convertString(i->name), false, + i->type)); + } + } + code->instrReturn(); + code->setMaxStackAndLocals(maxSize2, index3); + cf->addMethod( + ClassFile::ACC_PUBLIC, "<init>", OString::Concat("(Ljava/lang/Throwable;") + desc2.getDescriptor().subView(1), code.get(), + std::vector< OString >(), desc2.getSignature()); + + addTypeInfo(className, typeInfo, dependencies, cf.get()); + writeClassFile(options, className, *cf); +} + +void createExceptionsAttribute( + rtl::Reference< TypeManager > const & manager, + std::vector< OUString > const & exceptionTypes, + std::set<OUString> * dependencies, std::vector< OString > * exceptions, + codemaker::ExceptionTree * tree) +{ + assert(dependencies != nullptr); + assert(exceptions != nullptr); + for (const OUString& ex : exceptionTypes) + { + dependencies->insert(ex); + OString type(codemaker::convertString(ex).replace('.', '/')); + exceptions->push_back(type); + if (tree != nullptr) { + tree->add(type.replace('/', '.'), manager); + } + } +} + +void handleInterfaceType( + const OUString& name, rtl::Reference< unoidl::InterfaceTypeEntity > const & entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + assert(dependencies != nullptr); + OString className(codemaker::convertString(name).replace('.', '/')); + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE + | ClassFile::ACC_ABSTRACT), + className, "java/lang/Object", "")); + for (const unoidl::AnnotatedReference& ar : entity->getDirectMandatoryBases()) + { + dependencies->insert(ar.name); + cf->addInterface(codemaker::convertString(ar.name).replace('.', '/')); + } + // As a special case, let com.sun.star.lang.XEventListener extend + // java.util.EventListener ("A tagging interface that all event listener + // interfaces must extend"): + if (className == "com/sun/star/lang/XEventListener") { + cf->addInterface("java/util/EventListener"); + } + std::vector< TypeInfo > typeInfo; + if (className != "com/sun/star/uno/XInterface") { + sal_Int32 index = 0; + for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity->getDirectAttributes()) + { + SpecialType specialType; + PolymorphicUnoType polymorphicUnoType; + MethodDescriptor gdesc( + manager, dependencies, attr.type, &specialType, + &polymorphicUnoType); + std::vector< OString > exc; + createExceptionsAttribute( + manager, attr.getExceptions, dependencies, &exc, nullptr); + OString attrName(codemaker::convertString(attr.name)); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT), + "get" + attrName, gdesc.getDescriptor(), nullptr, exc, + gdesc.getSignature()); + if (!attr.readOnly) { + MethodDescriptor sdesc(manager, dependencies, u"void", nullptr, nullptr); + sdesc.addParameter(attr.type, false, true, nullptr); + std::vector< OString > exc2; + createExceptionsAttribute( + manager, attr.setExceptions, dependencies, &exc2, nullptr); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT), + "set" + attrName, sdesc.getDescriptor(), nullptr, exc2, + sdesc.getSignature()); + } + typeInfo.emplace_back( + TypeInfo::KIND_ATTRIBUTE, attrName, specialType, + static_cast< TypeInfo::Flags >( + (attr.readOnly ? TypeInfo::FLAG_READONLY : 0) + | (attr.bound ? TypeInfo::FLAG_BOUND : 0)), + index, polymorphicUnoType); + index += (attr.readOnly ? 1 : 2); + } + for (const unoidl::InterfaceTypeEntity::Method& method : entity->getDirectMethods()) + { + OString methodName(codemaker::convertString(method.name)); + SpecialType specialReturnType; + PolymorphicUnoType polymorphicUnoReturnType; + MethodDescriptor desc( + manager, dependencies, method.returnType, &specialReturnType, + &polymorphicUnoReturnType); + typeInfo.emplace_back( + TypeInfo::KIND_METHOD, methodName, specialReturnType, + static_cast< TypeInfo::Flags >(0), index++, + polymorphicUnoReturnType); + sal_Int32 paramIndex = 0; + for (const unoidl::InterfaceTypeEntity::Method::Parameter& param : method.parameters) + { + bool in = param.direction + != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT; + bool out = param.direction + != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN; + PolymorphicUnoType polymorphicUnoType; + SpecialType specialType = desc.addParameter( + param.type, out, true, &polymorphicUnoType); + if (out || isSpecialType(specialType) + || polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE) + { + typeInfo.emplace_back( + codemaker::convertString(param.name), specialType, in, + out, methodName, paramIndex, polymorphicUnoType); + } + ++paramIndex; + } + std::vector< OString > exc2; + createExceptionsAttribute( + manager, method.exceptions, dependencies, &exc2, nullptr); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT), + methodName, desc.getDescriptor(), nullptr, exc2, desc.getSignature()); + } + } + addTypeInfo(className, typeInfo, dependencies, cf.get()); + writeClassFile(options, className, *cf); +} + +void handleTypedef( + rtl::Reference< unoidl::TypedefEntity > const & entity, + rtl::Reference< TypeManager > const & manager, std::set<OUString> * dependencies) +{ + assert(entity.is()); + assert(manager.is()); + assert(dependencies != nullptr); + OUString nucleus; + switch (manager->decompose(entity->getType(), false, &nucleus, nullptr, nullptr, nullptr)) + { + case codemaker::UnoType::Sort::Boolean: + case codemaker::UnoType::Sort::Byte: + case codemaker::UnoType::Sort::Short: + case codemaker::UnoType::Sort::UnsignedShort: + case codemaker::UnoType::Sort::Long: + case codemaker::UnoType::Sort::UnsignedLong: + case codemaker::UnoType::Sort::Hyper: + case codemaker::UnoType::Sort::UnsignedHyper: + case codemaker::UnoType::Sort::Float: + case codemaker::UnoType::Sort::Double: + case codemaker::UnoType::Sort::Char: + case codemaker::UnoType::Sort::String: + case codemaker::UnoType::Sort::Type: + case codemaker::UnoType::Sort::Any: + break; + case codemaker::UnoType::Sort::Enum: + case codemaker::UnoType::Sort::PlainStruct: + case codemaker::UnoType::Sort::Interface: + case codemaker::UnoType::Sort::Typedef: + dependencies->insert(nucleus); + break; + default: + assert(false); // this cannot happen + } +} + +void handleConstantGroup( + const OUString& name, rtl::Reference< unoidl::ConstantGroupEntity > const & entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + OString className(codemaker::convertString(name).replace('.', '/')); + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE + | ClassFile::ACC_ABSTRACT), + className, "java/lang/Object", "")); + for (const unoidl::ConstantGroupEntity::Member& member : entity->getMembers()) + { + OUString type; + sal_uInt16 valueIndex = sal_uInt16(); // avoid false warnings + switch (member.value.type) { + case unoidl::ConstantValue::TYPE_BOOLEAN: + type = "boolean"; + valueIndex = cf->addIntegerInfo(sal_Int32(member.value.booleanValue)); + break; + case unoidl::ConstantValue::TYPE_BYTE: + type = "byte"; + valueIndex = cf->addIntegerInfo(member.value.byteValue); + break; + case unoidl::ConstantValue::TYPE_SHORT: + type = "short"; + valueIndex = cf->addIntegerInfo(member.value.shortValue); + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT: + type = "unsigned short"; + valueIndex = cf->addIntegerInfo(member.value.unsignedShortValue); + break; + case unoidl::ConstantValue::TYPE_LONG: + type = "long"; + valueIndex = cf->addIntegerInfo(member.value.longValue); + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_LONG: + type = "unsigned long"; + valueIndex = cf->addIntegerInfo( + static_cast< sal_Int32 >(member.value.unsignedLongValue)); + break; + case unoidl::ConstantValue::TYPE_HYPER: + type = "hyper"; + valueIndex = cf->addLongInfo(member.value.hyperValue); + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER: + type = "unsigned hyper"; + valueIndex = cf->addLongInfo( + static_cast< sal_Int64 >(member.value.unsignedHyperValue)); + break; + case unoidl::ConstantValue::TYPE_FLOAT: + type = "float"; + valueIndex = cf->addFloatInfo(member.value.floatValue); + break; + case unoidl::ConstantValue::TYPE_DOUBLE: + type = "double"; + valueIndex = cf->addDoubleInfo(member.value.doubleValue); + break; + } + OString desc; + OString sig; + getFieldDescriptor(manager, dependencies, type, &desc, &sig, nullptr); + cf->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + codemaker::convertString(member.name), desc, valueIndex, sig); + } + writeClassFile(options, className, *cf); +} + +void addExceptionHandlers( + codemaker::ExceptionTreeNode const * node, + ClassFile::Code::Position start, ClassFile::Code::Position end, + ClassFile::Code::Position handler, ClassFile::Code * code) +{ + assert(node != nullptr); + assert(code != nullptr); + if (node->present) { + code->addException(start, end, handler, node->name.replace('.', '/')); + } else { + for (std::unique_ptr<codemaker::ExceptionTreeNode> const & p : node->children) + { + addExceptionHandlers(p.get(), start, end, handler, code); + } + } +} + +void addConstructor( + rtl::Reference< TypeManager > const & manager, + std::string_view realJavaBaseName, OString const & unoName, + OString const & className, + unoidl::SingleInterfaceBasedServiceEntity::Constructor const & constructor, + OUString const & returnType, std::set<OUString> * dependencies, + ClassFile * classFile) +{ + assert(dependencies != nullptr); + assert(classFile != nullptr); + MethodDescriptor desc(manager, dependencies, returnType, nullptr, nullptr); + desc.addParameter(u"com.sun.star.uno.XComponentContext", false, false, nullptr); + std::unique_ptr< ClassFile::Code > code(classFile->newCode()); + code->loadLocalReference(0); + // stack: context + code->instrInvokeinterface( + "com/sun/star/uno/XComponentContext", "getServiceManager", + "()Lcom/sun/star/lang/XMultiComponentFactory;", 1); + // stack: factory + code->loadStringConstant(unoName); + // stack: factory serviceName + codemaker::ExceptionTree tree; + ClassFile::Code::Position tryStart; + ClassFile::Code::Position tryEnd; + std::vector< OString > exc; + sal_uInt16 stack; + sal_uInt16 localIndex = 1; + ClassFile::AccessFlags access = static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC); + if (constructor.defaultConstructor) { + code->loadLocalReference(0); + // stack: factory serviceName context + tryStart = code->getPosition(); + code->instrInvokeinterface( + "com/sun/star/lang/XMultiComponentFactory", + "createInstanceWithContext", + ("(Ljava/lang/String;Lcom/sun/star/uno/XComponentContext;)" + "Ljava/lang/Object;"), + 3); + tryEnd = code->getPosition(); + // stack: instance + stack = 3; + } else { + if (constructor.parameters.size() == 1 + && constructor.parameters[0].rest) + { + desc.addParameter(u"any", true, true, nullptr); + code->loadLocalReference(localIndex++); + // stack: factory serviceName args + stack = 4; + access = static_cast< ClassFile::AccessFlags >( + access | ClassFile::ACC_VARARGS); + } else { + code->loadIntegerConstant(constructor.parameters.size()); + // stack: factory serviceName N + code->instrAnewarray("java/lang/Object"); + // stack: factory serviceName args + stack = 0; + sal_Int32 n = 0; + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter& param : + constructor.parameters) + { + desc.addParameter(param.type, false, true, nullptr); + code->instrDup(); + // stack: factory serviceName args args + code->loadIntegerConstant(n++); + // stack: factory serviceName args args i + stack = std::max( + stack, + addLoadLocal( + manager, code.get(), &localIndex, false, param.type, true, + dependencies)); + // stack: factory serviceName args args i any + code->instrAastore(); + // stack: factory serviceName args + } + stack += 5; + } + code->loadLocalReference(0); + // stack: factory serviceName args context + tryStart = code->getPosition(); + code->instrInvokeinterface( + "com/sun/star/lang/XMultiComponentFactory", + "createInstanceWithArgumentsAndContext", + ("(Ljava/lang/String;[Ljava/lang/Object;" + "Lcom/sun/star/uno/XComponentContext;)Ljava/lang/Object;"), + 4); + tryEnd = code->getPosition(); + // stack: instance + createExceptionsAttribute( + manager, constructor.exceptions, dependencies, &exc, &tree); + } + code->loadLocalReference(0); + // stack: instance context + code->instrInvokestatic( + className, "$castInstance", + ("(Ljava/lang/Object;Lcom/sun/star/uno/XComponentContext;)" + "Ljava/lang/Object;")); + // stack: instance + code->instrCheckcast( + codemaker::convertString(returnType).replace('.', '/')); + // stack: instance + code->instrAreturn(); + if (!tree.getRoot().present) { + ClassFile::Code::Position pos1 = code->getPosition(); + // stack: e + code->instrInvokevirtual( + "java/lang/Throwable", "toString", "()Ljava/lang/String;"); + // stack: str + localIndex = std::max< sal_uInt16 >(localIndex, 2); + code->storeLocalReference(1); + // stack: - + code->instrNew("com/sun/star/uno/DeploymentException"); + // stack: ex + code->instrDup(); + // stack: ex ex + code->loadStringConstant( + "component context fails to supply service " + unoName + " of type " + + realJavaBaseName + ": "); + // stack: ex ex "..." + code->loadLocalReference(1); + // stack: ex ex "..." str + code->instrInvokevirtual( + "java/lang/String", "concat", + "(Ljava/lang/String;)Ljava/lang/String;"); + // stack: ex ex "..." + code->loadLocalReference(0); + // stack: ex ex "..." context + code->instrInvokespecial( + "com/sun/star/uno/DeploymentException", "<init>", + "(Ljava/lang/String;Ljava/lang/Object;)V"); + // stack: ex + ClassFile::Code::Position pos2 = code->getPosition(); + code->instrAthrow(); + addExceptionHandlers( + &tree.getRoot(), tryStart, tryEnd, pos2, code.get()); + code->addException( + tryStart, tryEnd, pos1, "com/sun/star/uno/Exception"); + dependencies->insert("com.sun.star.uno.Exception"); + stack = std::max< sal_uInt16 >(stack, 4); + } + code->setMaxStackAndLocals(stack, localIndex); + classFile->addMethod( + access, + codemaker::java::translateUnoToJavaIdentifier( + (constructor.defaultConstructor + ? OString("create") : codemaker::convertString(constructor.name)), + "method"), + desc.getDescriptor(), code.get(), exc, desc.getSignature()); +} + +void handleService( + const OUString& name, + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > const & entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + assert(dependencies != nullptr); + OString unoName(codemaker::convertString(name)); + OString className( + translateUnoidlEntityNameToJavaFullyQualifiedName(name, "service")); + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL + | ClassFile::ACC_SUPER), + className, "java/lang/Object", "")); + if (!entity->getConstructors().empty()) { + OString realJavaBaseName( + codemaker::convertString(entity->getBase())); + dependencies->insert(entity->getBase()); + dependencies->insert("com.sun.star.lang.XMultiComponentFactory"); + dependencies->insert("com.sun.star.uno.DeploymentException"); + dependencies->insert("com.sun.star.uno.TypeClass"); + dependencies->insert("com.sun.star.uno.XComponentContext"); + for (const unoidl::SingleInterfaceBasedServiceEntity::Constructor& cons : + entity->getConstructors()) + { + addConstructor( + manager, realJavaBaseName, unoName, className, cons, + entity->getBase(), dependencies, cf.get()); + } + // Synthetic castInstance method: + { + std::unique_ptr< ClassFile::Code > code(cf->newCode()); + code->instrNew("com/sun/star/uno/Type"); + // stack: type + code->instrDup(); + // stack: type type + code->loadStringConstant(realJavaBaseName); + // stack: type type "..." + code->instrGetstatic( + "com/sun/star/uno/TypeClass", "INTERFACE", + "Lcom/sun/star/uno/TypeClass;"); + // stack: type type "..." INTERFACE + code->instrInvokespecial( + "com/sun/star/uno/Type", "<init>", + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"); + // stack: type + code->loadLocalReference(0); + // stack: type instance + code->instrInvokestatic( + "com/sun/star/uno/UnoRuntime", "queryInterface", + ("(Lcom/sun/star/uno/Type;Ljava/lang/Object;)" + "Ljava/lang/Object;")); + // stack: instance + code->instrDup(); + // stack: instance instance + ClassFile::Code::Branch branch = code->instrIfnull(); + // stack: instance + code->instrAreturn(); + code->branchHere(branch); + code->instrPop(); + // stack: - + code->instrNew("com/sun/star/uno/DeploymentException"); + // stack: ex + code->instrDup(); + // stack: ex ex + code->loadStringConstant( + "component context fails to supply service " + unoName + + " of type " + realJavaBaseName); + // stack: ex ex "..." + code->loadLocalReference(1); + // stack: ex ex "..." context + code->instrInvokespecial( + "com/sun/star/uno/DeploymentException", "<init>", + "(Ljava/lang/String;Ljava/lang/Object;)V"); + // stack: ex + code->instrAthrow(); + code->setMaxStackAndLocals(4, 2); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC + | ClassFile::ACC_SYNTHETIC), + "$castInstance", + ("(Ljava/lang/Object;Lcom/sun/star/uno/XComponentContext;)" + "Ljava/lang/Object;"), + code.get(), std::vector< OString >(), ""); + } + } + writeClassFile(options, className, *cf); +} + +void handleSingleton( + const OUString& name, + rtl::Reference< unoidl::InterfaceBasedSingletonEntity > const & entity, + rtl::Reference< TypeManager > const & manager, JavaOptions const & options, + std::set<OUString> * dependencies) +{ + assert(entity.is()); + assert(dependencies != nullptr); + OString realJavaBaseName(codemaker::convertString(entity->getBase())); + OString base(realJavaBaseName.replace('.', '/')); + dependencies->insert(entity->getBase()); + OString unoName(codemaker::convertString(name)); + OString className( + translateUnoidlEntityNameToJavaFullyQualifiedName(name, "singleton")); + dependencies->insert("com.sun.star.uno.DeploymentException"); + dependencies->insert("com.sun.star.uno.TypeClass"); + dependencies->insert("com.sun.star.uno.XComponentContext"); + std::unique_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL + | ClassFile::ACC_SUPER), + className, "java/lang/Object", "")); + MethodDescriptor desc(manager, dependencies, entity->getBase(), nullptr, nullptr); + desc.addParameter(u"com.sun.star.uno.XComponentContext", false, false, nullptr); + std::unique_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + // stack: context + code->loadStringConstant("/singletons/" + unoName); + // stack: context "..." + code->instrInvokeinterface( + "com/sun/star/uno/XComponentContext", "getValueByName", + "(Ljava/lang/String;)Ljava/lang/Object;", 2); + // stack: value + code->instrDup(); + // stack: value value + code->instrInstanceof("com/sun/star/uno/Any"); + // stack: value 0/1 + ClassFile::Code::Branch branch1 = code->instrIfeq(); + // stack: value + code->instrCheckcast("com/sun/star/uno/Any"); + // stack: value + code->instrDup(); + // stack: value value + code->instrInvokevirtual( + "com/sun/star/uno/Any", "getType", "()Lcom/sun/star/uno/Type;"); + // stack: value type + code->instrInvokevirtual( + "com/sun/star/uno/Type", "getTypeClass", + "()Lcom/sun/star/uno/TypeClass;"); + // stack: value typeClass + code->instrGetstatic( + "com/sun/star/uno/TypeClass", "INTERFACE", + "Lcom/sun/star/uno/TypeClass;"); + // stack: value typeClass INTERFACE + ClassFile::Code::Branch branch2 = code->instrIfAcmpne(); + // stack: value + code->instrInvokevirtual( + "com/sun/star/uno/Any", "getObject", "()Ljava/lang/Object;"); + // stack: value + code->branchHere(branch1); + code->instrNew("com/sun/star/uno/Type"); + // stack: value type + code->instrDup(); + // stack: value type type + code->loadStringConstant(realJavaBaseName); + // stack: value type type "..." + code->instrGetstatic( + "com/sun/star/uno/TypeClass", "INTERFACE", + "Lcom/sun/star/uno/TypeClass;"); + // stack: value type type "..." INTERFACE + code->instrInvokespecial( + "com/sun/star/uno/Type", "<init>", + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"); + // stack: value type + code->instrSwap(); + // stack: type value + code->instrInvokestatic( + "com/sun/star/uno/UnoRuntime", "queryInterface", + "(Lcom/sun/star/uno/Type;Ljava/lang/Object;)Ljava/lang/Object;"); + // stack: instance + code->instrDup(); + // stack: instance instance + ClassFile::Code::Branch branch3 = code->instrIfnull(); + // stack: instance + code->instrCheckcast(base); + // stack: instance + code->instrAreturn(); + code->branchHere(branch2); + code->branchHere(branch3); + code->instrPop(); + // stack: - + code->instrNew("com/sun/star/uno/DeploymentException"); + // stack: ex + code->instrDup(); + // stack: ex ex + code->loadStringConstant( + "component context fails to supply singleton " + unoName + " of type " + + realJavaBaseName); + // stack: ex ex "..." + code->loadLocalReference(0); + // stack: ex ex "..." context + code->instrInvokespecial( + "com/sun/star/uno/DeploymentException", "<init>", + "(Ljava/lang/String;Ljava/lang/Object;)V"); + // stack: ex + code->instrAthrow(); + code->setMaxStackAndLocals(5, 1); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC), + "get", desc.getDescriptor(), code.get(), std::vector< OString >(), + desc.getSignature()); + writeClassFile(options, className, *cf); +} + +} + +void produce( + OUString const & name, rtl::Reference< TypeManager > const & manager, + codemaker::GeneratedTypeSet & generated, JavaOptions const & options) +{ + if (generated.contains(u2b(name))) { + return; + } + generated.add(u2b(name)); + if (!manager->foundAtPrimaryProvider(name)) { + return; + } + std::set<OUString> deps; + rtl::Reference< unoidl::Entity > ent; + rtl::Reference< unoidl::MapCursor > cur; + switch (manager->getSort(name, &ent, &cur)) { + case codemaker::UnoType::Sort::Module: + { + OUString prefix; + if (!name.isEmpty()) { + prefix = name + "."; + } + for (;;) { + OUString mem; + if (!cur->getNext(&mem).is()) { + break; + } + produce(prefix + mem, manager, generated, options); + } + return; + } + case codemaker::UnoType::Sort::Enum: + handleEnumType( + name, dynamic_cast< unoidl::EnumTypeEntity * >(ent.get()), options); + break; + case codemaker::UnoType::Sort::PlainStruct: + handlePlainStructType( + name, dynamic_cast< unoidl::PlainStructTypeEntity * >(ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::PolymorphicStructTemplate: + handlePolyStructType( + name, + dynamic_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::Exception: + handleExceptionType( + name, dynamic_cast< unoidl::ExceptionTypeEntity * >(ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::Interface: + handleInterfaceType( + name, dynamic_cast< unoidl::InterfaceTypeEntity * >(ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::Typedef: + handleTypedef( + dynamic_cast< unoidl::TypedefEntity * >(ent.get()), manager, &deps); + break; + case codemaker::UnoType::Sort::ConstantGroup: + handleConstantGroup( + name, dynamic_cast< unoidl::ConstantGroupEntity * >(ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::SingleInterfaceBasedService: + handleService( + name, + dynamic_cast< unoidl::SingleInterfaceBasedServiceEntity * >( + ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::InterfaceBasedSingleton: + handleSingleton( + name, + dynamic_cast< unoidl::InterfaceBasedSingletonEntity * >(ent.get()), + manager, options, &deps); + break; + case codemaker::UnoType::Sort::AccumulationBasedService: + case codemaker::UnoType::Sort::ServiceBasedSingleton: + break; + default: + throw CannotDumpException( + "unexpected entity \"" + name + "\" in call to produce"); + } + if (!options.isValid("-nD")) { + for (const OUString& d : deps) { + produce(d, manager, generated, options); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/codemaker/source/javamaker/javatype.hxx b/codemaker/source/javamaker/javatype.hxx new file mode 100644 index 000000000..9df1d94b5 --- /dev/null +++ b/codemaker/source/javamaker/javatype.hxx @@ -0,0 +1,35 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <rtl/ref.hxx> + +namespace codemaker { class GeneratedTypeSet; } +namespace rtl { class OUString; } +class JavaOptions; +class TypeManager; + +void produce( + OUString const & name, rtl::Reference< TypeManager > const & manager, + codemaker::GeneratedTypeSet & generated, JavaOptions const & options); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |