diff options
Diffstat (limited to 'codemaker/source/javamaker')
-rw-r--r-- | codemaker/source/javamaker/classfile.cxx | 903 | ||||
-rw-r--r-- | codemaker/source/javamaker/classfile.hxx | 274 | ||||
-rw-r--r-- | codemaker/source/javamaker/javamaker.cxx | 247 | ||||
-rw-r--r-- | codemaker/source/javamaker/javaoptions.cxx | 306 | ||||
-rw-r--r-- | codemaker/source/javamaker/javaoptions.hxx | 51 | ||||
-rw-r--r-- | codemaker/source/javamaker/javatype.cxx | 3374 | ||||
-rw-r--r-- | codemaker/source/javamaker/javatype.hxx | 45 | ||||
-rw-r--r-- | codemaker/source/javamaker/makefile.mk | 58 |
8 files changed, 5258 insertions, 0 deletions
diff --git a/codemaker/source/javamaker/classfile.cxx b/codemaker/source/javamaker/classfile.cxx new file mode 100644 index 000000000000..05c473256738 --- /dev/null +++ b/codemaker/source/javamaker/classfile.cxx @@ -0,0 +1,903 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_codemaker.hxx" + +#include "classfile.hxx" + +#include "codemaker/global.hxx" +#include "codemaker/options.hxx" +#include "codemaker/unotype.hxx" + +#include "boost/static_assert.hpp" +#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( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Error writing file"))); + } +} + +void writeU1(FileStream & file, sal_uInt8 data) { + unsigned char buf[] = { static_cast< unsigned char >(data) }; + write(file, &buf, sizeof buf); +} + +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(); + BOOST_STATIC_ASSERT( + sizeof (std::vector< unsigned char >::size_type) + <= sizeof (sal_uInt64)); + // 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[0], 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(rtl::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(rtl::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( + rtl::OString const & type, rtl::OString const & name, + rtl::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(rtl::OString const & type) { + // instanceof <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xC1); + appendU2(m_code, m_classFile.addClassInfo(type)); +} + +void ClassFile::Code::instrInvokeinterface( + rtl::OString const & type, rtl::OString const & name, + rtl::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( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor) +{ + // invokespecial <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB7); + appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrInvokestatic( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor) +{ + // invokestatic <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB8); + appendU2(m_code, m_classFile.addMethodrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrInvokevirtual( + rtl::OString const & type, rtl::OString const & name, + rtl::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::list< std::pair< sal_Int32, Code * > > const & blocks) +{ + // lookupswitch <0--3 byte pad> <defaultbyte1> <defaultbyte2> <defaultbyte3> + // <defaultbyte4> <npairs1> <npairs2> <npairs3> <npairs4> + // <match--offset pairs...>: + std::list< std::pair< sal_Int32, Code * > >::size_type size = blocks.size(); + if (size > SAL_MAX_INT32) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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 (std::list< std::pair< sal_Int32, Code * > >::const_iterator i( + blocks.begin()); + i != blocks.end(); ++i) + { + appendU4(m_code, static_cast< sal_uInt32 >(i->first)); + appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); + //FIXME: overflow + pos2 += i->second->m_code.size(); //FIXME: overflow + }} + appendStream(m_code, defaultBlock->m_code); + {for (std::list< std::pair< sal_Int32, Code * > >::const_iterator i( + blocks.begin()); + i != blocks.end(); ++i) + { + appendStream(m_code, i->second->m_code); + }} +} + +void ClassFile::Code::instrNew(rtl::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[codemaker::UnoType::SORT_CHAR] = { + 0x04, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x06, 0x07, 0x05 }; + appendU1(m_code, atypes[sort - 1]); +} + +void ClassFile::Code::instrPop() { + // pop: + appendU1(m_code, 0x57); +} + +void ClassFile::Code::instrPutfield( + rtl::OString const & type, rtl::OString const & name, + rtl::OString const & descriptor) +{ + // putfield <indexbyte1> <indexbyte2>: + appendU1(m_code, 0xB5); + appendU2(m_code, m_classFile.addFieldrefInfo(type, name, descriptor)); +} + +void ClassFile::Code::instrPutstatic( + rtl::OString const & type, rtl::OString const & name, + rtl::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::list< 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::list< 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::list< Code * >::const_iterator i(blocks.begin()); + i != blocks.end(); ++i) + { + if (*i == 0) { + appendU4(m_code, defaultOffset); + } else { + appendU4(m_code, static_cast< sal_uInt32 >(pos2 - pos1)); + //FIXME: overflow + pos2 += (*i)->m_code.size(); //FIXME: overflow + } + }} + appendStream(m_code, defaultBlock->m_code); + {for (std::list< Code * >::const_iterator i(blocks.begin()); + i != blocks.end(); ++i) + { + if (*i != 0) { + appendStream(m_code, (*i)->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(rtl::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, rtl::OString const & type) +{ + OSL_ASSERT(start < end && end <= m_code.size() && handler <= m_code.size()); + if (m_exceptionTableLength == SAL_MAX_UINT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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_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, rtl::OString const & thisClass, + rtl::OString const & superClass, rtl::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.getLength() != 0) { + ++m_attributesCount; + appendU2( + m_attributes, + addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature")))); + appendU4(m_attributes, 2); + appendU2(m_attributes, addUtf8Info(signature)); + } +} + +ClassFile::~ClassFile() {} + +ClassFile::Code * ClassFile::newCode() { + return 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.insert( + std::map< sal_Int32, sal_uInt16 >::value_type(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.insert( + std::map< float, sal_uInt16 >::value_type(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.insert( + std::map< sal_Int64, sal_uInt16 >::value_type(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.insert( + std::map< double, sal_uInt16 >::value_type(value, index)).second) + { + OSL_ASSERT(false); + } + return index; +} + +void ClassFile::addInterface(rtl::OString const & interface) { + if (m_interfacesCount == SAL_MAX_UINT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Too many interfaces for Java class file format"))); + } + ++m_interfacesCount; + appendU2(m_interfaces, addClassInfo(interface)); +} + +void ClassFile::addField( + AccessFlags accessFlags, rtl::OString const & name, + rtl::OString const & descriptor, sal_uInt16 constantValueIndex, + rtl::OString const & signature) +{ + if (m_fieldsCount == SAL_MAX_UINT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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.getLength() == 0 ? 0 : 1))); + if (constantValueIndex != 0) { + appendU2( + m_fields, + addUtf8Info( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("ConstantValue")))); + appendU4(m_fields, 2); + appendU2(m_fields, constantValueIndex); + } + appendSignatureAttribute(m_fields, signature); +} + +void ClassFile::addMethod( + AccessFlags accessFlags, rtl::OString const & name, + rtl::OString const & descriptor, Code const * code, + std::vector< rtl::OString > const & exceptions, + rtl::OString const & signature) +{ + if (m_methodsCount == SAL_MAX_UINT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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< rtl::OString >::size_type excs = exceptions.size(); + if (excs > SAL_MAX_UINT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Too many exception specifications for Java class file" + " format"))); + } + appendU2( + m_methods, + ((code == 0 ? 0 : 1) + (exceptions.empty() ? 0 : 1) + + (signature.getLength() == 0 ? 0 : 1))); + if (code != 0) { + 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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Code block is too big for Java class file format"))); + } + appendU2( + m_methods, + addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("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( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Exceptions")))); + appendU4( + m_methods, + static_cast< sal_uInt32 >(2 + 2 * static_cast< sal_uInt32 >(excs))); + appendU2(m_methods, static_cast< sal_uInt16 >(excs)); + for (std::vector< rtl::OString >::const_iterator i(exceptions.begin()); + i != exceptions.end(); ++i) + { + appendU2(m_methods, addClassInfo(*i)); + } + } + appendSignatureAttribute(m_methods, signature); +} + +void ClassFile::write(FileStream & file) const { + writeU4(file, 0xCAFEBABE); + writeU2(file, 0); + writeU2(file, 46); + 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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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(rtl::OString const & value) { + std::map< rtl::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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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.insert( + std::map< rtl::OString, sal_uInt16 >::value_type(value, index)). + second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addClassInfo(rtl::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.insert( + std::map< sal_uInt16, sal_uInt16 >::value_type(nameIndex, index)). + second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addStringInfo(rtl::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.insert( + std::map< sal_uInt16, sal_uInt16 >::value_type(stringIndex, index)). + second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addFieldrefInfo( + rtl::OString const & type, rtl::OString const & name, + rtl::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.insert( + std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addMethodrefInfo( + rtl::OString const & type, rtl::OString const & name, + rtl::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.insert( + std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addInterfaceMethodrefInfo( + rtl::OString const & type, rtl::OString const & name, + rtl::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.insert( + std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) + { + OSL_ASSERT(false); + } + return index; +} + +sal_uInt16 ClassFile::addNameAndTypeInfo( + rtl::OString const & name, rtl::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.insert( + std::map< sal_uInt32, sal_uInt16 >::value_type(key, index)).second) + { + OSL_ASSERT(false); + } + return index; +} + +void ClassFile::appendSignatureAttribute( + std::vector< unsigned char > & stream, rtl::OString const & signature) +{ + if (signature.getLength() != 0) { + appendU2( + stream, + addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature")))); + appendU4(stream, 2); + appendU2(stream, addUtf8Info(signature)); + } +} diff --git a/codemaker/source/javamaker/classfile.hxx b/codemaker/source/javamaker/classfile.hxx new file mode 100644 index 000000000000..6a0018ac38d0 --- /dev/null +++ b/codemaker/source/javamaker/classfile.hxx @@ -0,0 +1,274 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_CLASSFILE_HXX +#define INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_CLASSFILE_HXX + +#include "codemaker/unotype.hxx" +#include "sal/types.h" + +#include <list> +#include <map> +#include <utility> +#include <vector> + +class FileStream; +namespace rtl { class OString; } + +namespace codemaker { namespace 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::list< 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::list< 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 &); // not implemented + void operator =(Code); // not implemented + + 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(); + + 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 &); // not implemented + void operator =(ClassFile); // not implemented + + 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; +}; + +} } + +#endif // INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_CLASSFILE_HXX diff --git a/codemaker/source/javamaker/javamaker.cxx b/codemaker/source/javamaker/javamaker.cxx new file mode 100644 index 000000000000..b4e612d55823 --- /dev/null +++ b/codemaker/source/javamaker/javamaker.cxx @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_codemaker.hxx" + +#include <stdio.h> + +#include "sal/main.h" + +#include "codemaker/typemanager.hxx" +#include "codemaker/generatedtypeset.hxx" +#include "javaoptions.hxx" +#include "javatype.hxx" + +using namespace rtl; + +sal_Bool produceAllTypes(RegistryKey& rTypeKey, sal_Bool bIsExtraType, + TypeManager const & typeMgr, + codemaker::GeneratedTypeSet & generated, + JavaOptions* pOptions, + sal_Bool bFullScope) + throw( CannotDumpException ) +{ + OString typeName = typeMgr.getTypeName(rTypeKey); + + if (!produceType(rTypeKey, bIsExtraType, typeMgr, generated, pOptions)) + { + fprintf(stderr, "%s ERROR: %s\n", + pOptions->getProgramName().getStr(), + OString("cannot dump Type '" + typeName + "'").getStr()); + exit(99); + } + + RegistryKeyList typeKeys = typeMgr.getTypeKeys(typeName); + RegistryKeyList::const_iterator iter = typeKeys.begin(); + RegistryKey key, subKey; + RegistryKeyArray subKeys; + + while (iter != typeKeys.end()) + { + key = (*iter).first; + + if (!(*iter).second && !key.openSubKeys(OUString(), subKeys)) + { + for (sal_uInt32 i = 0; i < subKeys.getLength(); i++) + { + subKey = subKeys.getElement(i); + if (bFullScope) + { + if (!produceAllTypes( + subKey, (*iter).second, + typeMgr, generated, pOptions, sal_True)) + return sal_False; + } else + { + if (!produceType(subKey, (*iter).second, + typeMgr, generated, pOptions)) + return sal_False; + } + } + } + + ++iter; + } + + return sal_True; +} + +sal_Bool produceAllTypes(const OString& typeName, + TypeManager const & typeMgr, + codemaker::GeneratedTypeSet & generated, + JavaOptions* pOptions, + sal_Bool bFullScope) + throw( CannotDumpException ) +{ + if (!produceType(typeName, typeMgr, generated, pOptions)) + { + fprintf(stderr, "%s ERROR: %s\n", + pOptions->getProgramName().getStr(), + OString("cannot dump Type '" + typeName + "'").getStr()); + exit(99); + } + + RegistryKeyList typeKeys = typeMgr.getTypeKeys(typeName); + RegistryKeyList::const_iterator iter = typeKeys.begin(); + RegistryKey key, subKey; + RegistryKeyArray subKeys; + + while (iter != typeKeys.end()) + { + key = (*iter).first; + if (!(*iter).second && !key.openSubKeys(OUString(), subKeys)) + { + for (sal_uInt32 i = 0; i < subKeys.getLength(); i++) + { + subKey = subKeys.getElement(i); + if (bFullScope) + { + if (!produceAllTypes( + subKey, (*iter).second, + typeMgr, generated, pOptions, sal_True)) + return sal_False; + } else + { + if (!produceType(subKey, (*iter).second, + typeMgr, generated, pOptions)) + return sal_False; + } + } + } + + ++iter; + } + + return sal_True; +} + +SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) +{ + JavaOptions options; + + try + { + if (!options.initOptions(argc, argv)) + { + exit(1); + } + } + catch( IllegalArgument& e) + { + fprintf(stderr, "Illegal option: %s\n", e.m_message.getStr()); + exit(99); + } + + RegistryTypeManager typeMgr; + + if (!typeMgr.init(options.getInputFiles(), options.getExtraInputFiles())) + { + fprintf(stderr, "%s : init registries failed, check your registry files.\n", options.getProgramName().getStr()); + exit(99); + } + + if (options.isValid("-B")) + { + typeMgr.setBase(options.getOption("-B")); + } + + try + { + if (options.isValid("-T")) + { + OString tOption(options.getOption("-T")); + sal_Int32 nIndex = 0; + + codemaker::GeneratedTypeSet generated; + OString typeName, tmpName; + sal_Bool ret = sal_False; + do + { + typeName = tOption.getToken(0, ';', nIndex); + + sal_Int32 nPos = typeName.lastIndexOf( '.' ); + tmpName = typeName.copy( nPos != -1 ? nPos+1 : 0 ); + if (tmpName == "*") + { + // produce this type and his scope. + if (typeName.equals("*")) + { + tmpName = "/"; + } else + { + tmpName = typeName.copy(0, typeName.lastIndexOf('.')).replace('.', '/'); + if (tmpName.getLength() == 0) + tmpName = "/"; + else + tmpName.replace('.', '/'); + } + // related to task #116780# the scope is recursively + // generated. bFullScope = true + ret = produceAllTypes( + tmpName, typeMgr, generated, &options, sal_True); + } else + { + // produce only this type + ret = produceType( + typeName.replace('.', '/'), typeMgr, generated, + &options); + } + + if (!ret) + { + fprintf(stderr, "%s ERROR: %s\n", + options.getProgramName().getStr(), + OString("cannot dump Type '" + typeName + "'").getStr()); + exit(99); + } + } while( nIndex != -1 ); + } else + { + // produce all types + codemaker::GeneratedTypeSet generated; + if (!produceAllTypes("/", typeMgr, generated, &options, sal_True)) + { + fprintf(stderr, "%s ERROR: %s\n", + options.getProgramName().getStr(), + "an error occurs while dumping all types."); + exit(99); + } + } + } + catch( CannotDumpException& e) + { + fprintf(stderr, "%s ERROR: %s\n", + options.getProgramName().getStr(), + e.m_message.getStr()); + exit(99); + } + + return 0; +} + + diff --git a/codemaker/source/javamaker/javaoptions.cxx b/codemaker/source/javamaker/javaoptions.cxx new file mode 100644 index 000000000000..58235bd32616 --- /dev/null +++ b/codemaker/source/javamaker/javaoptions.cxx @@ -0,0 +1,306 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_codemaker.hxx" +#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 + +using namespace rtl; + +sal_Bool JavaOptions::initOptions(int ac, char* av[], sal_Bool bCmdFile) + throw( IllegalArgument ) +{ + sal_Bool ret = sal_True; + sal_uInt16 i=0; + + if (!bCmdFile) + { + bCmdFile = sal_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 = sal_False; + } + + i = 1; + } else + { + i = 0; + } + + char *s=NULL; + 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 += " your input '" + OString(av[i+1]) + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + m_options["-O"] = OString(s); + break; + case 'B': + if (av[i][2] == '\0') + { + if (i < ac - 1 && av[i+1][0] != '-') + { + i++; + s = av[i]; + } else + { + OString tmp("'-B', please check"); + if (i <= ac - 1) + { + tmp += " your input '" + OString(av[i+1]) + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + m_options["-B"] = OString(s); + break; + case 'n': + if (av[i][2] != 'D' || av[i][3] != '\0') + { + OString tmp("'-nD', please check"); + tmp += " your input '" + OString(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 += " your input '" + OString(av[i+1]) + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + if (m_options.count("-T") > 0) + { + OString tmp(m_options["-T"]); + tmp = tmp + ";" + 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 += " your input '" + OString(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 += " your input '" + OString(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 += " your input '" + OString(av[i+1]) + "'"; + } + + throw IllegalArgument(tmp); + } + } else + { + s = av[i] + 2; + } + + m_extra_input_files.push_back( s ); + break; + } + + default: + throw IllegalArgument("the option is unknown" + OString(av[i])); + } + } else + { + if (av[i][0] == '@') + { + FILE* cmdFile = fopen(av[i]+1, "r"); + if( cmdFile == NULL ) + { + fprintf(stderr, "%s", prepareHelp().getStr()); + ret = sal_False; + } else + { + int rargc=0; + char* rargv[512]; + char buffer[512]; + + while ( fscanf(cmdFile, "%s", buffer) != EOF ) + { + rargv[rargc]= strdup(buffer); + rargc++; + } + fclose(cmdFile); + + ret = initOptions(rargc, rargv, bCmdFile); + + for (long j=0; j < rargc; j++) + { + free(rargv[j]); + } + } + } else + { + if (bCmdFile) + { + m_inputFiles.push_back(av[i]); + } else + { + OUString system_filepath; + if (osl_getCommandArg( i-1, &system_filepath.pData ) + != osl_Process_E_None) + { + OSL_ASSERT(false); + } + m_inputFiles.push_back(OUStringToOString(system_filepath, osl_getThreadTextEncoding())); + } + } + } + } + + return ret; +} + +OString JavaOptions::prepareHelp() +{ + OString help("\nusing: "); + help += m_program + " [-options] file_1 ... file_n -Xfile_n+1 -Xfile_n+2\nOptions:\n"; + help += " -O<path> = path describes the root directory for the generated output.\n"; + help += " The output directory tree is generated under this directory.\n"; + help += " -T<name> = name specifies a type or a list of types. The output for this\n"; + help += " [t1;...] type and all dependent types are generated. If no '-T' option is \n"; + help += " specified, then output for all types is generated.\n"; + help += " Example: 'com.sun.star.uno.XInterface' is a valid type.\n"; + help += " -B<name> = name specifies the base node. All types are searched under this\n"; + help += " node. Default is the root '/' of the registry files.\n"; + help += " -nD = no dependent types are generated.\n"; + help += " -G = generate only target files which does not exists.\n"; + help += " -Gc = generate only target files which content will be changed.\n"; + help += " -X<file> = extra types which will not be taken into account for generation.\n\n"; + help += prepareVersion(); + + return help; +} + +OString JavaOptions::prepareVersion() +{ + OString version(m_program); + version += " Version 2.0\n\n"; + return version; +} + + diff --git a/codemaker/source/javamaker/javaoptions.hxx b/codemaker/source/javamaker/javaoptions.hxx new file mode 100644 index 000000000000..8bcc04150370 --- /dev/null +++ b/codemaker/source/javamaker/javaoptions.hxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_JAVAOPTIONS_HXX +#define INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_JAVAOPTIONS_HXX + +#include "codemaker/options.hxx" + +class JavaOptions : public Options +{ +public: + JavaOptions() + : Options() {} + + ~JavaOptions() {} + + sal_Bool initOptions(int ac, char* av[], sal_Bool bCmdFile=sal_False) + throw( IllegalArgument ); + + ::rtl::OString prepareHelp(); + + ::rtl::OString prepareVersion(); + +protected: +}; + +#endif // INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_JAVAOPTIONS_HXX diff --git a/codemaker/source/javamaker/javatype.cxx b/codemaker/source/javamaker/javatype.cxx new file mode 100644 index 000000000000..7820a419a205 --- /dev/null +++ b/codemaker/source/javamaker/javatype.cxx @@ -0,0 +1,3374 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_codemaker.hxx" + +#include "javatype.hxx" + +#include "classfile.hxx" +#include "javaoptions.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 "osl/diagnose.h" +#include "registry/reader.hxx" +#include "registry/refltype.hxx" +#include "registry/types.h" +#include "rtl/strbuf.hxx" +#include "rtl/string.h" +#include "rtl/string.hxx" +#include "rtl/textcvt.h" +#include "rtl/textenc.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" + +#include <algorithm> +#include <list> +#include <map> +#include <memory> +#include <set> +#include <utility> +#include <vector> + +using codemaker::javamaker::ClassFile; + +namespace { + +void checkNoTypeArguments(std::vector< rtl::OString > const & arguments) { + if (!arguments.empty()) { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } +} + +// helper function for createUnoName +void appendUnoName( + TypeManager const & manager, rtl::OString const & nucleus, sal_Int32 rank, + std::vector< rtl::OString > const & arguments, rtl::OStringBuffer * buffer) +{ + OSL_ASSERT(rank >= 0 && buffer != 0); + for (sal_Int32 i = 0; i < rank; ++i) { + buffer->append(RTL_CONSTASCII_STRINGPARAM("[]")); + } + buffer->append(nucleus.replace('/', '.')); + if (!arguments.empty()) { + buffer->append('<'); + for (std::vector< rtl::OString >::const_iterator i(arguments.begin()); + i != arguments.end(); ++i) + { + if (i != arguments.begin()) { + buffer->append(','); + } + RTTypeClass argTypeClass; + rtl::OString argNucleus; + sal_Int32 argRank; + std::vector< rtl::OString > argArgs; + codemaker::decomposeAndResolve( + manager, *i, true, false, false, &argTypeClass, &argNucleus, + &argRank, &argArgs); + appendUnoName(manager, argNucleus, argRank, argArgs, buffer); + } + buffer->append('>'); + } +} + +// Translate the name of a UNO type registry entity (enum type, plain struct +// type, polymorphic struct type template, or interface type, decomposed into +// nucleus, rank, and arguments) into a core UNO type name: +rtl::OString createUnoName( + TypeManager const & manager, rtl::OString const & nucleus, sal_Int32 rank, + std::vector< rtl::OString > const & arguments) +{ + rtl::OStringBuffer buf; + appendUnoName(manager, nucleus, rank, arguments, &buf); + return buf.makeStringAndClear(); +} + +/** + Set of UTF-8--encoded names of UNO type registry entities a given UNO type + registry entity depends on. + + UNO type registry entities are enum types, plain struct types, polymorphic + struct type templates, exception types, interface types, typedefs, modules, + constant groupds, single-interface--based services, accumulation-based + services, interface-based singletons, and service-based singletons. + */ +typedef std::set< rtl::OString > Dependencies; + +enum SpecialType { + SPECIAL_TYPE_NONE, + SPECIAL_TYPE_ANY, + SPECIAL_TYPE_UNSIGNED, + SPECIAL_TYPE_INTERFACE +}; + +bool isSpecialType(SpecialType special) { + return special >= SPECIAL_TYPE_UNSIGNED; +} + +rtl::OString translateUnoTypeToJavaFullyQualifiedName( + rtl::OString const & type, rtl::OString const & prefix) +{ + sal_Int32 i = type.lastIndexOf('/') + 1; + return type.copy(0, i) + + codemaker::java::translateUnoToJavaIdentifier(type.copy(i), prefix); +} + +struct PolymorphicUnoType { + PolymorphicUnoType(): kind(KIND_NONE) {} + + enum Kind { KIND_NONE, KIND_STRUCT, KIND_SEQUENCE }; + Kind kind; + rtl::OString name; +}; + +SpecialType translateUnoTypeToDescriptor( + TypeManager const & manager, rtl::OString const & type, bool array, + bool classType, Dependencies * dependencies, + rtl::OStringBuffer * descriptor, rtl::OStringBuffer * signature, + bool * needsSignature, PolymorphicUnoType * polymorphicUnoType); + +SpecialType translateUnoTypeToDescriptor( + TypeManager const & manager, codemaker::UnoType::Sort sort, + RTTypeClass typeClass, rtl::OString const & nucleus, sal_Int32 rank, + std::vector< rtl::OString > const & arguments, bool array, bool classType, + Dependencies * dependencies, rtl::OStringBuffer * descriptor, + rtl::OStringBuffer * signature, bool * needsSignature, + PolymorphicUnoType * polymorphicUnoType) +{ + OSL_ASSERT(rank >= 0 && (signature == 0) == (needsSignature == 0)); + if (rank > 0xFF - (array ? 1 : 0)) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Too many array dimensions for Java class file format"))); + } + if (array) { + ++rank; + } + for (sal_Int32 i = 0; i < rank; ++i) { + if (descriptor != 0) { + descriptor->append('['); + } + if (signature != 0) { + signature->append('['); + } + } + if (sort == codemaker::UnoType::SORT_COMPLEX) { + //TODO: check that nucleus is a valid (Java-modified UTF-8) identifier + rtl::OString superClass; + if (typeClass == RT_TYPE_INTERFACE + && (nucleus + == rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XInterface")))) + { + if (descriptor != 0) { + descriptor->append( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;"))); + } + if (signature != 0) { + signature->append( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;"))); + } + if (polymorphicUnoType != 0) { + polymorphicUnoType->kind = PolymorphicUnoType::KIND_NONE; + } + return SPECIAL_TYPE_INTERFACE; + } else { + if (dependencies != 0) { + dependencies->insert(nucleus); + } + if (descriptor != 0) { + descriptor->append('L'); + descriptor->append(nucleus); + descriptor->append(';'); + } + if (signature != 0) { + signature->append('L'); + signature->append(nucleus); + if (!arguments.empty()) { + signature->append('<'); + for (std::vector< rtl::OString >::const_iterator i( + arguments.begin()); + i != arguments.end(); ++i) + { + translateUnoTypeToDescriptor( + manager, *i, false, true, dependencies, 0, + signature, needsSignature, 0); + } + signature->append('>'); + *needsSignature = true; + } + signature->append(';'); + } + if (polymorphicUnoType != 0) { + if (arguments.empty()) { + polymorphicUnoType->kind = PolymorphicUnoType::KIND_NONE; + } else { + polymorphicUnoType->kind = rank == 0 + ? PolymorphicUnoType::KIND_STRUCT + : PolymorphicUnoType::KIND_SEQUENCE; + polymorphicUnoType->name = createUnoName( + manager, nucleus, rank, arguments); + } + } + return SPECIAL_TYPE_NONE; + } + } else { + static rtl::OString const + simpleTypeDescriptors[codemaker::UnoType::SORT_ANY + 1][2] = { + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("V")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Void;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("Z")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Boolean;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("B")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Byte;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("S")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Short;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("S")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Short;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("I")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Integer;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("I")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Integer;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("J")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Long;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("J")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Long;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("F")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Float;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("D")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Double;")) + }, + { rtl::OString(RTL_CONSTASCII_STRINGPARAM("C")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Character;")) + }, + { rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/String;")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/String;")) + }, + { rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/Type;")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/Type;")) + }, + { rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;")) + } }; + rtl::OString const & s + = simpleTypeDescriptors[sort][rank == 0 && classType]; + if (descriptor != 0) { + descriptor->append(s); + } + if (signature != 0) { + signature->append(s); + } + if (polymorphicUnoType != 0) { + polymorphicUnoType->kind = PolymorphicUnoType::KIND_NONE; + } + static SpecialType const + simpleTypeSpecials[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[sort]; + } +} + +SpecialType translateUnoTypeToDescriptor( + TypeManager const & manager, rtl::OString const & type, bool array, + bool classType, Dependencies * dependencies, + rtl::OStringBuffer * descriptor, rtl::OStringBuffer * signature, + bool * needsSignature, PolymorphicUnoType * polymorphicUnoType) +{ + RTTypeClass typeClass; + rtl::OString nucleus; + sal_Int32 rank; + std::vector< rtl::OString > args; + codemaker::UnoType::Sort sort = codemaker::decomposeAndResolve( + manager, type, true, true, false, &typeClass, &nucleus, &rank, &args); + OSL_ASSERT(rank < SAL_MAX_INT32); + return translateUnoTypeToDescriptor( + manager, sort, typeClass, nucleus, rank, args, array, classType, + dependencies, descriptor, signature, needsSignature, + polymorphicUnoType); +} + +SpecialType getFieldDescriptor( + TypeManager const & manager, Dependencies * dependencies, + rtl::OString const & type, rtl::OString * descriptor, + rtl::OString * signature, PolymorphicUnoType * polymorphicUnoType) +{ + OSL_ASSERT(dependencies != 0 && descriptor != 0); + rtl::OStringBuffer desc; + rtl::OStringBuffer sig; + bool needsSig = false; + SpecialType specialType = translateUnoTypeToDescriptor( + manager, type, false, false, dependencies, &desc, &sig, &needsSig, + polymorphicUnoType); + *descriptor = desc.makeStringAndClear(); + if (signature != 0) { + if (needsSig) { + *signature = sig.makeStringAndClear(); + } else { + *signature = rtl::OString(); + } + } + return specialType; +} + +class MethodDescriptor { +public: + MethodDescriptor( + TypeManager const & manager, Dependencies * dependencies, + rtl::OString const & returnType, SpecialType * specialReturnType, + PolymorphicUnoType * polymorphicUnoType); + + SpecialType addParameter( + rtl::OString const & type, bool array, bool dependency, + PolymorphicUnoType * polymorphicUnoType); + + void addTypeParameter(rtl::OString const & name); + + rtl::OString getDescriptor() const; + + rtl::OString getSignature() const; + +private: + TypeManager const & m_manager; + Dependencies * m_dependencies; + rtl::OStringBuffer m_descriptorStart; + rtl::OString m_descriptorEnd; + rtl::OStringBuffer m_signatureStart; + rtl::OString m_signatureEnd; + bool m_needsSignature; +}; + +MethodDescriptor::MethodDescriptor( + TypeManager const & manager, Dependencies * dependencies, + rtl::OString const & returnType, SpecialType * specialReturnType, + PolymorphicUnoType * polymorphicUnoType): + m_manager(manager), m_dependencies(dependencies), m_needsSignature(false) +{ + OSL_ASSERT(dependencies != 0); + m_descriptorStart.append('('); + m_signatureStart.append('('); + rtl::OStringBuffer descEnd; + descEnd.append(')'); + rtl::OStringBuffer sigEnd; + 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 != 0) { + *specialReturnType = special; + } +} + +SpecialType MethodDescriptor::addParameter( + rtl::OString const & type, bool array, bool dependency, + PolymorphicUnoType * polymorphicUnoType) +{ + return translateUnoTypeToDescriptor( + m_manager, type, array, false, dependency ? m_dependencies : 0, + &m_descriptorStart, &m_signatureStart, &m_needsSignature, + polymorphicUnoType); +} + +void MethodDescriptor::addTypeParameter(rtl::OString const & name) { + m_descriptorStart.append(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;")); + m_signatureStart.append('T'); + m_signatureStart.append(name); + m_signatureStart.append(';'); + m_needsSignature = true; +} + +rtl::OString MethodDescriptor::getDescriptor() const { + rtl::OStringBuffer buf(m_descriptorStart); + buf.append(m_descriptorEnd); + return buf.makeStringAndClear(); +} + +rtl::OString MethodDescriptor::getSignature() const { + if (m_needsSignature) { + rtl::OStringBuffer buf(m_signatureStart); + buf.append(m_signatureEnd); + return buf.makeStringAndClear(); + } else { + return rtl::OString(); + } +} + +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, FLAG_ONEWAY = 0x010 + }; + + // KIND_MEMBER: + TypeInfo( + rtl::OString const & name, SpecialType specialType, sal_Int32 index, + PolymorphicUnoType const & polymorphicUnoType, + sal_Int32 typeParameterIndex); + + // KIND_ATTRIBUTE/METHOD: + TypeInfo( + Kind kind, rtl::OString const & name, SpecialType specialType, + Flags flags, sal_Int32 index, + PolymorphicUnoType const & polymorphicUnoType); + + // KIND_PARAMETER: + TypeInfo( + rtl::OString const & parameterName, SpecialType specialType, + bool inParameter, bool outParameter, rtl::OString const & methodName, + sal_Int32 index, PolymorphicUnoType const & polymorphicUnoType); + + sal_uInt16 generateCode(ClassFile::Code & code, Dependencies * dependencies) + const; + + void generatePolymorphicUnoTypeCode( + ClassFile::Code & code, Dependencies * dependencies) const; + +private: + Kind m_kind; + rtl::OString m_name; + sal_Int32 m_flags; + sal_Int32 m_index; + rtl::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( + rtl::OString const & name, SpecialType specialType, sal_Int32 index, + PolymorphicUnoType const & polymorphicUnoType, + sal_Int32 typeParameterIndex): + m_kind(KIND_MEMBER), m_name(name), + m_flags(translateSpecialTypeFlags(specialType, false, false)), + m_index(index), m_polymorphicUnoType(polymorphicUnoType), + m_typeParameterIndex(typeParameterIndex) +{ + OSL_ASSERT( + polymorphicUnoType.kind == PolymorphicUnoType::KIND_NONE + ? typeParameterIndex >= -1 : typeParameterIndex == -1); +} + +TypeInfo::TypeInfo( + Kind kind, rtl::OString const & name, SpecialType specialType, + Flags flags, sal_Int32 index, + PolymorphicUnoType const & polymorphicUnoType): + m_kind(kind), m_name(name), + m_flags(flags | translateSpecialTypeFlags(specialType, false, false)), + m_index(index), m_polymorphicUnoType(polymorphicUnoType) +{ + OSL_ASSERT(kind == KIND_ATTRIBUTE || kind == KIND_METHOD); +} + +TypeInfo::TypeInfo( + rtl::OString const & parameterName, SpecialType specialType, + bool inParameter, bool outParameter, rtl::OString const & methodName, + sal_Int32 index, PolymorphicUnoType const & polymorphicUnoType): + m_kind(KIND_PARAMETER), m_name(parameterName), + m_flags(translateSpecialTypeFlags(specialType, inParameter, outParameter)), + m_index(index), m_methodName(methodName), + m_polymorphicUnoType(polymorphicUnoType) +{} + +sal_uInt16 TypeInfo::generateCode( + ClassFile::Code & code, Dependencies * dependencies) const +{ + OSL_ASSERT(dependencies != 0); + switch (m_kind) { + case KIND_MEMBER: + code.instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/MemberTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/MemberTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;IILcom/sun/star/uno/Type;I)V"))); + return 6; + } else { + code.instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/MemberTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("(Ljava/lang/String;II)V"))); + return 4; + } + + case KIND_ATTRIBUTE: + code.instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/AttributeTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;IILcom/sun/star/uno/Type;)V"))); + return 8; + } else { + code.instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/AttributeTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("(Ljava/lang/String;II)V"))); + return 4; + } + + case KIND_METHOD: + code.instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/MethodTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;IILcom/sun/star/uno/Type;)V"))); + return 8; + } else { + code.instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/MethodTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("(Ljava/lang/String;II)V"))); + return 4; + } + + case KIND_PARAMETER: + code.instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/ParameterTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Ljava/lang/String;II" + "Lcom/sun/star/uno/Type;)V"))); + return 9; + } else { + code.instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/ParameterTypeInfo")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Ljava/lang/String;II)V"))); + return 5; + } + + default: + OSL_ASSERT(false); + return 0; + } +} + +void TypeInfo::generatePolymorphicUnoTypeCode( + ClassFile::Code & code, Dependencies * dependencies) const +{ + OSL_ASSERT( + dependencies != 0 + && m_polymorphicUnoType.kind != PolymorphicUnoType::KIND_NONE); + code.instrNew( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type"))); + code.instrDup(); + code.loadStringConstant(m_polymorphicUnoType.name); + if (m_polymorphicUnoType.kind == PolymorphicUnoType::KIND_STRUCT) { + code.instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("STRUCT")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/TypeClass;"))); + } else { + code.instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("SEQUENCE")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/TypeClass;"))); + } + dependencies->insert( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass"))); + code.instrInvokespecial( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"))); +} + +void writeClassFile( + JavaOptions /*TODO const*/ & options, rtl::OString const & type, + ClassFile const & classFile) +{ + rtl::OString path; + if (options.isValid(rtl::OString(RTL_CONSTASCII_STRINGPARAM("-O")))) { + path = options.getOption( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("-O"))); + } + rtl::OString filename( + createFileNameFromType( + path, type, rtl::OString(RTL_CONSTASCII_STRINGPARAM(".class")))); + bool check = false; + if (fileExists(filename)) { + if (options.isValid(rtl::OString(RTL_CONSTASCII_STRINGPARAM("-G")))) { + return; + } + check = options.isValid( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("-Gc"))); + } + FileStream tempfile; + tempfile.createTempFile(getTempDir(filename)); + if (!tempfile.isValid()) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Cannot create temporary file for ")) + + filename); + } + rtl::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, check)) { + rtl::OStringBuffer msg; + msg.append(RTL_CONSTASCII_STRINGPARAM("Cannot create ")); + msg.append(filename); + msg.append(RTL_CONSTASCII_STRINGPARAM(" from temporary file ")); + msg.append(tempname); + throw CannotDumpException(msg.makeStringAndClear()); + } +} + +void addTypeInfo( + rtl::OString const & className, std::vector< TypeInfo > const & typeInfo, + Dependencies * dependencies, ClassFile * classFile) +{ + OSL_ASSERT(dependencies != 0 && classFile != 0); + std::vector< TypeInfo >::size_type typeInfos = typeInfo.size(); + if (typeInfos > SAL_MAX_INT32) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "UNOTYPEINFO array too big for Java class file format"))); + } + if (typeInfos != 0) { + classFile->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("UNOTYPEINFO")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "[Lcom/sun/star/lib/uno/typeinfo/TypeInfo;")), + 0, rtl::OString()); + std::auto_ptr< ClassFile::Code > code(classFile->newCode()); + code->loadIntegerConstant(static_cast< sal_Int32 >(typeInfos)); + code->instrAnewarray( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lib/uno/typeinfo/TypeInfo"))); + sal_Int32 index = 0; + sal_uInt16 stack = 0; + for (std::vector< TypeInfo >::const_iterator i(typeInfo.begin()); + i != typeInfo.end(); ++i) + { + code->instrDup(); + code->loadIntegerConstant(index++); + stack = std::max(stack, i->generateCode(*code, dependencies)); + code->instrAastore(); + } + code->instrPutstatic( + className, rtl::OString(RTL_CONSTASCII_STRINGPARAM("UNOTYPEINFO")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "[Lcom/sun/star/lib/uno/typeinfo/TypeInfo;"))); + code->instrReturn(); + if (stack > SAL_MAX_UINT16 - 4) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "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), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<clinit>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()V")), code.get(), + std::vector< rtl::OString >(), rtl::OString()); + } +} + +typedef void (* handleUnoTypeRegistryEntityFunction)( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies); + +void handleEnumType( + TypeManager const &, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies *) +{ + sal_uInt16 fields = reader.getFieldCount(); + if (fields == 0 || reader.getSuperTypeCount() != 0 + || reader.getMethodCount() != 0 || reader.getReferenceCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + rtl::OString className(codemaker::convertString(reader.getTypeName())); + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL + | ClassFile::ACC_SUPER), + className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Enum")), + rtl::OString())); + rtl::OStringBuffer buf; + buf.append('L'); + buf.append(className); + buf.append(';'); + rtl::OString classDescriptor(buf.makeStringAndClear()); + {for (sal_uInt16 i = 0; i < fields; ++i) { + RTConstValue fieldValue(reader.getFieldValue(i)); + if (fieldValue.m_type != RT_TYPE_INT32 + || reader.getFieldFlags(i) != RT_ACCESS_CONST + || reader.getFieldTypeName(i).getLength() != 0) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + rtl::OString fieldName( + codemaker::convertString(reader.getFieldName(i))); + cf->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + fieldName, classDescriptor, 0, rtl::OString()); + cf->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + fieldName + rtl::OString(RTL_CONSTASCII_STRINGPARAM("_value")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("I")), + cf->addIntegerInfo(fieldValue.m_value.aLong), rtl::OString()); + }} + std::auto_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + code->loadLocalInteger(1); + code->instrInvokespecial( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Enum")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(I)V"))); + code->instrReturn(); + code->setMaxStackAndLocals(2, 2); + cf->addMethod( + ClassFile::ACC_PRIVATE, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(I)V")), code.get(), + std::vector< rtl::OString >(), rtl::OString()); + code.reset(cf->newCode()); + code->instrGetstatic( + className, + codemaker::convertString(reader.getFieldName(0)), classDescriptor); + code->instrAreturn(); + code->setMaxStackAndLocals(1, 0); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("getDefault")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()")) + classDescriptor, + code.get(), std::vector< rtl::OString >(), rtl::OString()); + code.reset(cf->newCode()); + code->loadLocalInteger(0); + std::map< sal_Int32, rtl::OString > map; + sal_Int32 min = SAL_MAX_INT32; + sal_Int32 max = SAL_MIN_INT32; + {for (sal_uInt16 i = 0; i < fields; ++i) { + sal_Int32 value = reader.getFieldValue(i).m_value.aLong; + min = std::min(min, value); + max = std::max(max, value); + map.insert( + std::map< sal_Int32, rtl::OString >::value_type( + value, codemaker::convertString(reader.getFieldName(i)))); + }} + 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::auto_ptr< ClassFile::Code > defCode(cf->newCode()); + defCode->instrAconstNull(); + defCode->instrAreturn(); + std::list< ClassFile::Code * > blocks; + //FIXME: pointers contained in blocks may leak + sal_Int32 last = SAL_MAX_INT32; + for (std::map< sal_Int32, rtl::OString >::iterator i(map.begin()); + i != map.end(); ++i) + { + sal_Int32 value = i->first; + if (last != SAL_MAX_INT32) { + for (sal_Int32 j = last + 1; j < value; ++j) { + blocks.push_back(0); + } + } + last = value; + std::auto_ptr< ClassFile::Code > blockCode(cf->newCode()); + blockCode->instrGetstatic(className, i->second, classDescriptor); + blockCode->instrAreturn(); + blocks.push_back(blockCode.get()); + blockCode.release(); + } + code->instrTableswitch(defCode.get(), min, blocks); + {for (std::list< ClassFile::Code * >::iterator i(blocks.begin()); + i != blocks.end(); ++i) + { + delete *i; + }} + } else { + std::auto_ptr< ClassFile::Code > defCode(cf->newCode()); + defCode->instrAconstNull(); + defCode->instrAreturn(); + std::list< std::pair< sal_Int32, ClassFile::Code * > > blocks; + //FIXME: pointers contained in blocks may leak + for (std::map< sal_Int32, rtl::OString >::iterator i(map.begin()); + i != map.end(); ++i) + { + std::auto_ptr< ClassFile::Code > blockCode(cf->newCode()); + blockCode->instrGetstatic(className, i->second, classDescriptor); + blockCode->instrAreturn(); + blocks.push_back(std::make_pair(i->first, blockCode.get())); + blockCode.release(); + } + code->instrLookupswitch(defCode.get(), blocks); + {for (std::list< std::pair< sal_Int32, ClassFile::Code * > >::iterator + i(blocks.begin()); + i != blocks.end(); ++i) + { + delete i->second; + }} + } + code->setMaxStackAndLocals(1, 1); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("fromInt")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(I)")) + classDescriptor, + code.get(), std::vector< rtl::OString >(), rtl::OString()); + code.reset(cf->newCode()); + {for (sal_uInt16 i = 0; i < fields; ++i) { + code->instrNew(className); + code->instrDup(); + code->loadIntegerConstant(reader.getFieldValue(i).m_value.aLong); + code->instrInvokespecial( + className, rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(I)V"))); + code->instrPutstatic( + className, + codemaker::convertString(reader.getFieldName(i)), + classDescriptor); + }} + code->instrReturn(); + code->setMaxStackAndLocals(3, 0); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<clinit>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()V")), code.get(), + std::vector< rtl::OString >(), rtl::OString()); + writeClassFile(options, className, *cf.get()); +} + +void addField( + TypeManager const & manager, Dependencies * dependencies, + ClassFile * classFile, std::vector< TypeInfo > * typeInfo, + sal_Int32 typeParameterIndex, rtl::OString const & type, + rtl::OString const & name, sal_Int32 index) +{ + OSL_ASSERT(dependencies != 0 && classFile != 0 && typeInfo != 0); + rtl::OString descriptor; + rtl::OString signature; + SpecialType specialType; + PolymorphicUnoType polymorphicUnoType; + if (typeParameterIndex >= 0) { + descriptor = rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;")); + rtl::OStringBuffer buf; + buf.append('T'); + buf.append(type); + buf.append(';'); + signature = buf.makeStringAndClear(); + specialType = SPECIAL_TYPE_NONE; //TODO: SPECIAL_TYPE_TYPE_PARAMETER? + } else { + specialType = getFieldDescriptor( + manager, dependencies, type, &descriptor, &signature, + &polymorphicUnoType); + } + classFile->addField(ClassFile::ACC_PUBLIC, name, descriptor, 0, signature); + typeInfo->push_back( + TypeInfo( + name, specialType, index, polymorphicUnoType, typeParameterIndex)); +} + +sal_uInt16 addFieldInit( + TypeManager const & manager, rtl::OString const & className, + rtl::OString const & fieldName, bool typeParameter, + rtl::OString const & fieldType, Dependencies * dependencies, + ClassFile::Code * code) +{ + OSL_ASSERT(dependencies != 0 && code != 0); + if (typeParameter) { + return 0; + } else { + RTTypeClass typeClass; + rtl::OString nucleus; + sal_Int32 rank; + std::vector< rtl::OString > args; + codemaker::UnoType::Sort sort = codemaker::decomposeAndResolve( + manager, fieldType, true, false, false, &typeClass, &nucleus, &rank, + &args); + if (rank == 0) { + switch (sort) { + case codemaker::UnoType::SORT_STRING: + code->loadLocalReference(0); + code->loadStringConstant(rtl::OString()); + code->instrPutfield( + className, fieldName, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/String;"))); + return 2; + + case codemaker::UnoType::SORT_TYPE: + code->loadLocalReference(0); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("VOID")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/Type;"))); + code->instrPutfield( + className, fieldName, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/Type;"))); + return 2; + + case codemaker::UnoType::SORT_ANY: + code->loadLocalReference(0); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("VOID")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/Any;"))); + code->instrPutfield( + className, fieldName, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;"))); + return 2; + + case codemaker::UnoType::SORT_COMPLEX: + switch (typeClass) { + case RT_TYPE_ENUM: + { + code->loadLocalReference(0); + typereg::Reader reader(manager.getTypeReader(nucleus)); + if (reader.getFieldCount() == 0) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Bad type information"))); //TODO + } + rtl::OStringBuffer descBuf; + translateUnoTypeToDescriptor( + manager, sort, typeClass, nucleus, 0, + std::vector< rtl::OString >(), false, false, + dependencies, &descBuf, 0, 0, 0); + rtl::OString desc(descBuf.makeStringAndClear()); + code->instrGetstatic( + nucleus, + codemaker::convertString(reader.getFieldName(0)), + desc); + code->instrPutfield(className, fieldName, desc); + return 2; + } + + case RT_TYPE_STRUCT: + { + code->loadLocalReference(0); + code->instrNew(nucleus); + code->instrDup(); + code->instrInvokespecial( + nucleus, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()V"))); + rtl::OStringBuffer desc; + translateUnoTypeToDescriptor( + manager, sort, typeClass, nucleus, 0, + std::vector< rtl::OString >(), false, false, + dependencies, &desc, 0, 0, 0); + code->instrPutfield( + className, fieldName, desc.makeStringAndClear()); + return 3; + } + + default: + OSL_ASSERT(typeClass == RT_TYPE_INTERFACE); + return 0; + } + + default: + return 0; + } + } else { + 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, typeClass, + nucleus, 0)); + } + } else { + rtl::OStringBuffer desc; + translateUnoTypeToDescriptor( + manager, sort, typeClass, nucleus, rank - 1, + std::vector< rtl::OString >(), false, false, dependencies, + &desc, 0, 0, 0); + code->instrAnewarray(desc.makeStringAndClear()); + } + rtl::OStringBuffer desc; + translateUnoTypeToDescriptor( + manager, sort, typeClass, nucleus, rank, + std::vector< rtl::OString >(), false, false, dependencies, + &desc, 0, 0, 0); + code->instrPutfield( + className, fieldName, desc.makeStringAndClear()); + return 2; + } + } +} + +sal_uInt16 addLoadLocal( + TypeManager const & manager, ClassFile::Code * code, sal_uInt16 * index, + bool typeParameter, rtl::OString const & type, bool any, + Dependencies * dependencies) +{ + OSL_ASSERT( + code != 0 && index != 0 && !(typeParameter && any) + && dependencies != 0); + sal_uInt16 stack = 1; + sal_uInt16 size = 1; + if (typeParameter) { + code->loadLocalReference(*index); + stack = size = 1; + } else { + RTTypeClass typeClass; + rtl::OString nucleus; + sal_Int32 rank; + std::vector< rtl::OString > args; + codemaker::UnoType::Sort sort = codemaker::decomposeAndResolve( + manager, type, true, false, false, &typeClass, &nucleus, &rank, &args); + if (rank == 0) { + switch (sort) { + case codemaker::UnoType::SORT_BOOLEAN: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Boolean"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Boolean")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(Z)V"))); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + + case codemaker::UnoType::SORT_BYTE: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Byte"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Byte")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(B)V"))); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + + case codemaker::UnoType::SORT_SHORT: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Short"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Short")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(S)V"))); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + + case codemaker::UnoType::SORT_UNSIGNED_SHORT: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any"))); + code->instrDup(); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("UNSIGNED_SHORT")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Lcom/sun/star/uno/Type;"))); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Short"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Short")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(S)V"))); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Integer"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Integer")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(I)V"))); + stack = 3; + } else { + code->loadLocalInteger(*index); + stack = 1; + } + size = 1; + break; + + case codemaker::UnoType::SORT_UNSIGNED_LONG: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any"))); + code->instrDup(); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("UNSIGNED_LONG")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Lcom/sun/star/uno/Type;"))); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Integer"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Integer")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(I)V"))); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Long"))); + code->instrDup(); + code->loadLocalLong(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Long")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(J)V"))); + stack = 4; + } else { + code->loadLocalLong(*index); + stack = 2; + } + size = 2; + break; + + case codemaker::UnoType::SORT_UNSIGNED_HYPER: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any"))); + code->instrDup(); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("UNSIGNED_HYPER")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Lcom/sun/star/uno/Type;"))); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Long"))); + code->instrDup(); + code->loadLocalLong(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Long")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(J)V"))); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Float"))); + code->instrDup(); + code->loadLocalFloat(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Float")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(F)V"))); + stack = 3; + } else { + code->loadLocalFloat(*index); + stack = 1; + } + size = 1; + break; + + case codemaker::UnoType::SORT_DOUBLE: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Double"))); + code->instrDup(); + code->loadLocalDouble(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Double")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(D)V"))); + stack = 4; + } else { + code->loadLocalDouble(*index); + stack = 2; + } + size = 2; + break; + + case codemaker::UnoType::SORT_CHAR: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Character"))); + code->instrDup(); + code->loadLocalInteger(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Character")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(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_COMPLEX: + switch (typeClass) { + case RT_TYPE_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 RT_TYPE_STRUCT: + if (any) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any"))); + code->instrDup(); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type"))); + code->instrDup(); + code->loadStringConstant( + createUnoName(manager, nucleus, rank, args)); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/TypeClass")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("STRUCT")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Lcom/sun/star/uno/TypeClass;"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/TypeClass"))); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;" + "Lcom/sun/star/uno/TypeClass;)V"))); + code->loadLocalReference(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Lcom/sun/star/uno/Type;" + "Ljava/lang/Object;)V"))); + stack = 6; + } else { + code->loadLocalReference(*index); + stack = 1; + } + size = 1; + break; + + case RT_TYPE_INTERFACE: + if (any + && (nucleus + != rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/XInterface")))) + { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any"))); + code->instrDup(); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type"))); + code->instrDup(); + code->loadStringConstant(nucleus.replace('/', '.')); + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/TypeClass")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("INTERFACE")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Lcom/sun/star/uno/TypeClass;"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/TypeClass"))); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;" + "Lcom/sun/star/uno/TypeClass;)V"))); + code->loadLocalReference(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Lcom/sun/star/uno/Type;" + "Ljava/lang/Object;)V"))); + stack = 6; + } else { + code->loadLocalReference(*index); + stack = 1; + } + size = 1; + break; + + default: + OSL_ASSERT(false); + break; + } + break; + + default: + OSL_ASSERT(false); + break; + } + } else { + bool wrap = 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 + break; + + case codemaker::UnoType::SORT_UNSIGNED_SHORT: + case codemaker::UnoType::SORT_UNSIGNED_LONG: + case codemaker::UnoType::SORT_UNSIGNED_HYPER: + case codemaker::UnoType::SORT_ANY: + wrap = true; + break; + + case codemaker::UnoType::SORT_COMPLEX: + switch (typeClass) { + case RT_TYPE_ENUM: + // assuming that no Java types are derived from Java + // types that are directly derived from + // com.sun.star.uno.Enum + break; + + case RT_TYPE_STRUCT: + case RT_TYPE_INTERFACE: + wrap = true; + break; + + default: + OSL_ASSERT(false); + break; + } + break; + + default: + OSL_ASSERT(false); + break; + } + } + if (wrap) { + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any"))); + code->instrDup(); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type"))); + code->instrDup(); + code->loadStringConstant( + createUnoName(manager, nucleus, rank, args)); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("(Ljava/lang/String;)V"))); + code->loadLocalReference(*index); + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Too many local variables for Java class file format"))); + } + *index = *index + size; + return stack; +} + +void addBaseArguments( + TypeManager const & manager, Dependencies * dependencies, + MethodDescriptor * methodDescriptor, ClassFile::Code * code, + RTTypeClass typeClass, rtl::OString const & type, sal_uInt16 * index) +{ + OSL_ASSERT( + dependencies != 0 && methodDescriptor != 0 && code != 0 && index != 0); + typereg::Reader reader(manager.getTypeReader(type)); + if (!reader.isValid() || reader.getTypeClass() != typeClass + || codemaker::convertString(reader.getTypeName()) != type + || reader.getMethodCount() != 0 || reader.getReferenceCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + sal_uInt16 superTypes = reader.getSuperTypeCount(); + sal_uInt16 fields = reader.getFieldCount(); + sal_uInt16 firstField = 0; + if (type + == rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Exception"))) + { + if (typeClass != RT_TYPE_EXCEPTION || superTypes != 0 || fields != 2) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + firstField = 1; + } else { + if ( + (typeClass == RT_TYPE_STRUCT && (superTypes > 1 || fields == 0)) || + (typeClass == RT_TYPE_EXCEPTION && superTypes != 1) + ) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + if (superTypes == 1) { + addBaseArguments( + manager, dependencies, methodDescriptor, code, typeClass, + codemaker::convertString(reader.getSuperTypeName(0)), index); + } + } + for (sal_uInt16 i = firstField; i < fields; ++i) { + if (reader.getFieldFlags(i) != RT_ACCESS_READWRITE + || reader.getFieldValue(i).m_type != RT_TYPE_NONE) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + rtl::OString fieldType( + codemaker::convertString(reader.getFieldTypeName(i))); + methodDescriptor->addParameter(fieldType, false, true, 0); + addLoadLocal( + manager, code, index, false, fieldType, false, dependencies); + } +} + +sal_uInt16 addDirectArgument( + TypeManager const & manager, Dependencies * dependencies, + MethodDescriptor * methodDescriptor, ClassFile::Code * code, + sal_uInt16 * index, rtl::OString const & className, + rtl::OString const & fieldName, bool typeParameter, + rtl::OString const & fieldType) +{ + OSL_ASSERT( + dependencies != 0 && methodDescriptor != 0 && code != 0 && index != 0); + rtl::OString desc; + if (typeParameter) { + methodDescriptor->addTypeParameter(fieldType); + desc = rtl::OString(RTL_CONSTASCII_STRINGPARAM("Ljava/lang/Object;")); + } else { + methodDescriptor->addParameter(fieldType, false, true, 0); + getFieldDescriptor(manager, dependencies, fieldType, &desc, 0, 0); + } + code->loadLocalReference(0); + sal_uInt16 stack = addLoadLocal( + manager, code, index, typeParameter, fieldType, false, dependencies); + code->instrPutfield(className, fieldName, desc); + return stack + 1; +} + +void handleAggregatingType( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + if (reader.getMethodCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + RTTypeClass typeClass = reader.getTypeClass(); + rtl::OString className(codemaker::convertString(reader.getTypeName())); + sal_uInt16 superTypes = reader.getSuperTypeCount(); + sal_uInt16 fields = reader.getFieldCount(); + sal_uInt16 firstField = 0; + sal_uInt16 references = reader.getReferenceCount(); + bool runtimeException = false; + rtl::OString superClass; + if (className + == rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Exception"))) + { + if (typeClass != RT_TYPE_EXCEPTION || superTypes != 0 || fields != 2 + || references != 0) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + firstField = 1; + superClass = rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Exception")); + } else if (className + == rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/RuntimeException"))) + { + if (typeClass != RT_TYPE_EXCEPTION || superTypes != 1 || fields != 0 + || references != 0) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + superTypes = 0; + superClass = rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/RuntimeException")); + runtimeException = true; + } else { + if ( + ( + typeClass == RT_TYPE_STRUCT && + ( + fields == 0 || + (references == 0 ? superTypes > 1 : superTypes != 0) + ) + ) || + (typeClass == RT_TYPE_EXCEPTION && superTypes != 1) + ) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + if (superTypes == 0) { + superClass = rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/lang/Object")); + } else { + superClass = codemaker::convertString(reader.getSuperTypeName(0)); + dependencies->insert(superClass); + } + } + rtl::OString sig; + std::map< rtl::OString, sal_Int32 > typeParameters; + if (references != 0) { + rtl::OStringBuffer buf; + buf.append('<'); + for (sal_uInt16 i = 0; i < references; ++i) { + if (reader.getReferenceFlags(i) != RT_ACCESS_INVALID + || reader.getReferenceSort(i) != RT_REF_TYPE_PARAMETER) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + rtl::OString name( + codemaker::convertString(reader.getReferenceTypeName(i))); + buf.append(name); + buf.append(RTL_CONSTASCII_STRINGPARAM(":Ljava/lang/Object;")); + if (!typeParameters.insert( + std::map< rtl::OString, sal_Int32 >::value_type(name, i)). + second) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + } + buf.append(RTL_CONSTASCII_STRINGPARAM(">Ljava/lang/Object;")); + sig = buf.makeStringAndClear(); + } + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_SUPER), + className, superClass, sig)); + std::vector< TypeInfo > typeInfo; + {for (sal_uInt16 i = firstField; i < fields; ++i) { + RTFieldAccess flags = reader.getFieldFlags(i); + if ((flags != RT_ACCESS_READWRITE + && flags != (RT_ACCESS_READWRITE | RT_ACCESS_PARAMETERIZED_TYPE)) + || ((flags & RT_ACCESS_PARAMETERIZED_TYPE) != 0 && references == 0) + || reader.getFieldValue(i).m_type != RT_TYPE_NONE) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + rtl::OString type( + codemaker::convertString(reader.getFieldTypeName(i))); + sal_Int32 typeParameterIndex; + if ((flags & RT_ACCESS_PARAMETERIZED_TYPE) == 0) { + typeParameterIndex = -1; + } else { + std::map< rtl::OString, sal_Int32 >::iterator it( + typeParameters.find(type)); + if (it == typeParameters.end()) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + typeParameterIndex = it->second; + } + addField( + manager, dependencies, cf.get(), &typeInfo, typeParameterIndex, + type, codemaker::convertString(reader.getFieldName(i)), i - firstField); + }} + if (runtimeException) { + addField( + manager, dependencies, cf.get(), &typeInfo, -1, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XInterface")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Context")), 0); + } + std::auto_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + code->instrInvokespecial( + superClass, rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()V"))); + sal_uInt16 stack = 0; + {for (sal_uInt16 i = firstField; i < fields; ++i) { + stack = std::max( + stack, + addFieldInit( + manager, className, + codemaker::convertString(reader.getFieldName(i)), + (reader.getFieldFlags(i) & RT_ACCESS_PARAMETERIZED_TYPE) != 0, + codemaker::convertString(reader.getFieldTypeName(i)), + dependencies, code.get())); + }} + if (runtimeException) { + stack = std::max( + stack, + addFieldInit( + manager, className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Context")), false, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XInterface")), + dependencies, code.get())); + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 1, 1); + cf->addMethod( + ClassFile::ACC_PUBLIC, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()V")), code.get(), + std::vector< rtl::OString >(), rtl::OString()); + if (typeClass == RT_TYPE_EXCEPTION) { + code.reset(cf->newCode()); + code->loadLocalReference(0); + code->loadLocalReference(1); + code->instrInvokespecial( + superClass, rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(Ljava/lang/String;)V"))); + stack = 0; + for (sal_uInt16 i = firstField; i < fields; ++i) { + stack = std::max( + stack, + addFieldInit( + manager, className, + codemaker::convertString(reader.getFieldName(i)), + ((reader.getFieldFlags(i) & RT_ACCESS_PARAMETERIZED_TYPE) + != 0), + codemaker::convertString(reader.getFieldTypeName(i)), + dependencies, code.get())); + } + if (runtimeException) { + stack = std::max( + stack, + addFieldInit( + manager, className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Context")), false, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/XInterface")), + dependencies, code.get())); + } + code->instrReturn(); + code->setMaxStackAndLocals(stack + 2, 2); + cf->addMethod( + ClassFile::ACC_PUBLIC, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("(Ljava/lang/String;)V")), + code.get(), std::vector< rtl::OString >(), rtl::OString()); + } + MethodDescriptor desc( + manager, dependencies, rtl::OString(RTL_CONSTASCII_STRINGPARAM("void")), + 0, 0); + code.reset(cf->newCode()); + code->loadLocalReference(0); + sal_uInt16 index = 1; + if (typeClass == RT_TYPE_EXCEPTION) { + desc.addParameter( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("string")), false, true, 0); + code->loadLocalReference(index++); + } + if (superTypes != 0) { + addBaseArguments( + manager, dependencies, &desc, code.get(), typeClass, superClass, + &index); + } + code->instrInvokespecial( + superClass, rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + desc.getDescriptor()); + sal_uInt16 maxSize = index; + {for (sal_uInt16 i = firstField; i < fields; ++i) { + maxSize = std::max( + maxSize, + addDirectArgument( + manager, dependencies, &desc, code.get(), &index, className, + codemaker::convertString(reader.getFieldName(i)), + (reader.getFieldFlags(i) & RT_ACCESS_PARAMETERIZED_TYPE) != 0, + codemaker::convertString(reader.getFieldTypeName(i)))); + }} + if (runtimeException) { + maxSize = std::max( + maxSize, + addDirectArgument( + manager, dependencies, &desc, code.get(), &index, className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Context")), false, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/XInterface")))); + } + code->instrReturn(); + code->setMaxStackAndLocals(maxSize, index); + cf->addMethod( + ClassFile::ACC_PUBLIC, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + desc.getDescriptor(), code.get(), std::vector< rtl::OString >(), + desc.getSignature()); + addTypeInfo(className, typeInfo, dependencies, cf.get()); + writeClassFile(options, className, *cf.get()); +} + +void createExceptionsAttribute( + TypeManager const & manager, typereg::Reader const & reader, + sal_uInt16 methodIndex, Dependencies * dependencies, + std::vector< rtl::OString > * exceptions, codemaker::ExceptionTree * tree) +{ + OSL_ASSERT(dependencies != 0 && exceptions != 0); + sal_uInt16 n = reader.getMethodExceptionCount(methodIndex); + for (sal_uInt16 i = 0; i < n; ++i) { + rtl::OString type( + codemaker::convertString( + reader.getMethodExceptionTypeName(methodIndex, i))); + dependencies->insert(type); + exceptions->push_back(type); + if (tree != 0) { + tree->add(type, manager); + } + } +} + +void handleInterfaceType( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + + rtl::OString className(codemaker::convertString(reader.getTypeName())); + sal_uInt16 superTypes = reader.getSuperTypeCount(); + sal_uInt16 fields = reader.getFieldCount(); + sal_uInt16 methods = reader.getMethodCount(); + if (className + == rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XInterface"))) + { + if (superTypes != 0 || fields != 0 || methods != 3) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + methods = 0; + } else if (superTypes == 0) { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE + | ClassFile::ACC_ABSTRACT), + className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Object")), + rtl::OString())); + {for (sal_uInt16 i = 0; i < superTypes; ++i) { + rtl::OString t(codemaker::convertString(reader.getSuperTypeName(i))); + dependencies->insert(t); + cf->addInterface(t); + }} + // 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 == + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/lang/XEventListener"))) + { + cf->addInterface( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("java/util/EventListener"))); + } + std::vector< TypeInfo > typeInfo; + sal_Int32 index = 0; + {for (sal_uInt16 i = 0; i < fields; ++i) { + RTFieldAccess flags = reader.getFieldFlags(i); + //TODO: ok if both READONLY and BOUND? + if (((((flags & RT_ACCESS_READWRITE) != 0) + ^ ((flags & RT_ACCESS_READONLY) != 0)) + == 0) + || ((flags + & ~(RT_ACCESS_READWRITE | RT_ACCESS_READONLY + | RT_ACCESS_BOUND)) + != 0) + || reader.getFieldValue(i).m_type != RT_TYPE_NONE) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + //TODO: exploit the fact that attribute getter/setter methods preceed + // real methods + rtl::OUString attrNameUtf16(reader.getFieldName(i)); + sal_uInt16 getter = SAL_MAX_UINT16; + sal_uInt16 setter = SAL_MAX_UINT16; + for (sal_uInt16 j = 0; j < methods; ++j) { + RTMethodMode mflags = reader.getMethodFlags(j); + if ((mflags == RT_MODE_ATTRIBUTE_GET + || mflags == RT_MODE_ATTRIBUTE_SET) + && reader.getMethodName(j) == attrNameUtf16) + { + if (!reader.getMethodReturnTypeName(j).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("void")) + || reader.getMethodParameterCount(j) != 0 + || (mflags == RT_MODE_ATTRIBUTE_GET + ? getter != SAL_MAX_UINT16 + : (setter != SAL_MAX_UINT16 + || (flags & RT_ACCESS_READONLY) != 0))) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Bad type information"))); //TODO + } + OSL_ASSERT(j != SAL_MAX_UINT16); + (mflags == RT_MODE_ATTRIBUTE_GET ? getter : setter) = j; + } + } + rtl::OString fieldType( + codemaker::convertString(reader.getFieldTypeName(i))); + SpecialType specialType; + PolymorphicUnoType polymorphicUnoType; + MethodDescriptor gdesc( + manager, dependencies, fieldType, &specialType, + &polymorphicUnoType); + std::vector< rtl::OString > exc; + if (getter != SAL_MAX_UINT16) { + createExceptionsAttribute( + manager, reader, getter, dependencies, &exc, 0); + } + rtl::OString attrName(codemaker::convertString(attrNameUtf16)); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("get")) + attrName, + gdesc.getDescriptor(), 0, exc, gdesc.getSignature()); + if ((flags & RT_ACCESS_READONLY) == 0) { + MethodDescriptor sdesc( + manager, dependencies, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("void")), 0, 0); + sdesc.addParameter(fieldType, false, true, 0); + std::vector< rtl::OString > exc2; + if (setter != SAL_MAX_UINT16) { + createExceptionsAttribute( + manager, reader, setter, dependencies, &exc2, 0); + } + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("set")) + attrName, + sdesc.getDescriptor(), 0, exc2, sdesc.getSignature()); + } + typeInfo.push_back( + TypeInfo( + TypeInfo::KIND_ATTRIBUTE, attrName, specialType, + static_cast< TypeInfo::Flags >( + ((flags & RT_ACCESS_READONLY) == 0 + ? 0 : TypeInfo::FLAG_READONLY) + | ((flags & RT_ACCESS_BOUND) == 0 + ? 0 : TypeInfo::FLAG_BOUND)), + index, polymorphicUnoType)); + index += ((flags & RT_ACCESS_READONLY) == 0 ? 2 : 1); + }} + {for (sal_uInt16 i = 0; i < methods; ++i) { + RTMethodMode flags = reader.getMethodFlags(i); + switch (flags) { + case RT_MODE_ONEWAY: + case RT_MODE_TWOWAY: + { + rtl::OString methodName( + codemaker::convertString(reader.getMethodName(i))); + SpecialType specialReturnType; + PolymorphicUnoType polymorphicUnoReturnType; + MethodDescriptor desc( + manager, dependencies, + codemaker::convertString( + reader.getMethodReturnTypeName(i)), + &specialReturnType, &polymorphicUnoReturnType); + typeInfo.push_back( + TypeInfo( + TypeInfo::KIND_METHOD, methodName, specialReturnType, + static_cast< TypeInfo::Flags >( + flags == RT_MODE_ONEWAY + ? TypeInfo::FLAG_ONEWAY : 0), + index++, polymorphicUnoReturnType)); + for (sal_uInt16 j = 0; j < reader.getMethodParameterCount(i); + ++j) + { + bool in; + bool out; + switch (reader.getMethodParameterFlags(i, j)) { + case RT_PARAM_IN: + in = true; + out = false; + break; + + case RT_PARAM_OUT: + in = false; + out = true; + break; + + case RT_PARAM_INOUT: + in = true; + out = true; + break; + + default: + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Bad type information"))); //TODO + } + PolymorphicUnoType polymorphicUnoType; + SpecialType specialType = desc.addParameter( + codemaker::convertString( + reader.getMethodParameterTypeName(i, j)), + out, true, &polymorphicUnoType); + if (out || isSpecialType(specialType) + || (polymorphicUnoType.kind + != PolymorphicUnoType::KIND_NONE)) + { + typeInfo.push_back( + TypeInfo( + codemaker::convertString( + reader.getMethodParameterName(i, j)), + specialType, in, out, methodName, j, + polymorphicUnoType)); + } + } + std::vector< rtl::OString > exc2; + createExceptionsAttribute( + manager, reader, i, dependencies, &exc2, 0); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_ABSTRACT), + methodName, desc.getDescriptor(), 0, exc2, + desc.getSignature()); + break; + } + + case RT_MODE_ATTRIBUTE_GET: + case RT_MODE_ATTRIBUTE_SET: + { + //TODO: exploit the fact that attribute getter/setter methods + // are ordered the same way as the attribute fields themselves + rtl::OUString methodNameUtf16(reader.getMethodName(i)); + bool found = false; + for (sal_uInt16 j = 0; j < fields; ++j) { + if (reader.getFieldName(j) == methodNameUtf16) { + found = true; + break; + } + } + if (found) { + break; + } + } + default: + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + }} + addTypeInfo(className, typeInfo, dependencies, cf.get()); + writeClassFile(options, className, *cf.get()); +} + +void handleTypedef( + TypeManager const & manager, JavaOptions /*TODO const*/ &, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + if (reader.getSuperTypeCount() != 1 || reader.getFieldCount() != 0 + || reader.getMethodCount() != 0 || reader.getReferenceCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + RTTypeClass typeClass; + rtl::OString nucleus; + sal_Int32 rank; + std::vector< rtl::OString > args; + if (codemaker::decomposeAndResolve( + manager, codemaker::convertString(reader.getSuperTypeName(0)), + false, false, false, &typeClass, &nucleus, &rank, &args) + == codemaker::UnoType::SORT_COMPLEX) + { + switch (typeClass) { + case RT_TYPE_STRUCT: + if (!args.empty()) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + case RT_TYPE_ENUM: + case RT_TYPE_INTERFACE: + case RT_TYPE_TYPEDEF: + dependencies->insert(nucleus); + break; + + default: + OSL_ASSERT(false); + break; + } + } +} + +void addConstant( + TypeManager const & manager, typereg::Reader const & reader, + bool publishable, sal_uInt16 index, Dependencies * dependencies, + ClassFile * classFile) +{ + OSL_ASSERT(dependencies != 0 && classFile != 0); + RTFieldAccess flags = reader.getFieldFlags(index); + if (flags != RT_ACCESS_CONST + && (!publishable || flags != (RT_ACCESS_CONST | RT_ACCESS_PUBLISHED))) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + RTConstValue fieldValue(reader.getFieldValue(index)); + sal_uInt16 valueIndex; + RTTypeClass typeClass; + rtl::OString nucleus; + sal_Int32 rank; + std::vector< rtl::OString > args; + switch (codemaker::decomposeAndResolve( + manager, + codemaker::convertString(reader.getFieldTypeName(index)), + true, false, false, &typeClass, &nucleus, &rank, &args)) + { + case codemaker::UnoType::SORT_BOOLEAN: + if (fieldValue.m_type != RT_TYPE_BOOL) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addIntegerInfo(fieldValue.m_value.aBool); + break; + + case codemaker::UnoType::SORT_BYTE: + if (fieldValue.m_type != RT_TYPE_BYTE) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addIntegerInfo(fieldValue.m_value.aByte); + break; + + case codemaker::UnoType::SORT_SHORT: + if (fieldValue.m_type != RT_TYPE_INT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addIntegerInfo(fieldValue.m_value.aShort); + break; + + case codemaker::UnoType::SORT_UNSIGNED_SHORT: + case codemaker::UnoType::SORT_CHAR: + if (fieldValue.m_type != RT_TYPE_UINT16) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addIntegerInfo(fieldValue.m_value.aUShort); + break; + + case codemaker::UnoType::SORT_LONG: + if (fieldValue.m_type != RT_TYPE_INT32) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addIntegerInfo(fieldValue.m_value.aLong); + break; + + case codemaker::UnoType::SORT_UNSIGNED_LONG: + if (fieldValue.m_type != RT_TYPE_UINT32) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addIntegerInfo( + static_cast< sal_Int32 >(fieldValue.m_value.aULong)); + break; + + case codemaker::UnoType::SORT_HYPER: + if (fieldValue.m_type != RT_TYPE_INT64) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addLongInfo(fieldValue.m_value.aHyper); + break; + + case codemaker::UnoType::SORT_UNSIGNED_HYPER: + if (fieldValue.m_type != RT_TYPE_UINT64) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addLongInfo( + static_cast< sal_Int64 >(fieldValue.m_value.aUHyper)); + break; + + case codemaker::UnoType::SORT_FLOAT: + if (fieldValue.m_type != RT_TYPE_FLOAT) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addFloatInfo(fieldValue.m_value.aFloat); + break; + + case codemaker::UnoType::SORT_DOUBLE: + if (fieldValue.m_type != RT_TYPE_DOUBLE) { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); //TODO + } + valueIndex = classFile->addDoubleInfo(fieldValue.m_value.aDouble); + break; + + default: + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + rtl::OString desc; + rtl::OString sig; + getFieldDescriptor( + manager, dependencies, + codemaker::convertString(reader.getFieldTypeName(index)), + &desc, &sig, 0); + classFile->addField( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC + | ClassFile::ACC_FINAL), + codemaker::convertString(reader.getFieldName(index)), + desc, valueIndex, sig); +} + +void handleConstantGroup( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + if (reader.getSuperTypeCount() != 0 || reader.getMethodCount() != 0 + || reader.getReferenceCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + rtl::OString className(codemaker::convertString(reader.getTypeName())); + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE + | ClassFile::ACC_ABSTRACT), + className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Object")), + rtl::OString())); + sal_uInt16 fields = reader.getFieldCount(); + for (sal_uInt16 i = 0; i < fields; ++i) { + addConstant(manager, reader, false, i, dependencies, cf.get()); + } + writeClassFile(options, className, *cf.get()); +} + +void handleModule( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + if (reader.getSuperTypeCount() != 0 || reader.getMethodCount() != 0 + || reader.getReferenceCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + rtl::OStringBuffer buf(codemaker::convertString(reader.getTypeName())); + buf.append('/'); + rtl::OString prefix(buf.makeStringAndClear()); + sal_uInt16 fields = reader.getFieldCount(); + for (sal_uInt16 i = 0; i < fields; ++i) { + rtl::OString className( + prefix + codemaker::convertString(reader.getFieldName(i))); + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_INTERFACE + | ClassFile::ACC_ABSTRACT), + className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Object")), + rtl::OString())); + addConstant(manager, reader, true, i, dependencies, cf.get()); + writeClassFile(options, className, *cf.get()); + } +} + +void addExceptionHandlers( + codemaker::ExceptionTreeNode const * node, + ClassFile::Code::Position start, ClassFile::Code::Position end, + ClassFile::Code::Position handler, ClassFile::Code * code) +{ + OSL_ASSERT(node != 0 && code != 0); + if (node->present) { + code->addException(start, end, handler, node->name); + } else { + for (codemaker::ExceptionTreeNode::Children::const_iterator i( + node->children.begin()); + i != node->children.end(); ++i) + { + addExceptionHandlers(*i, start, end, handler, code); + } + } +} + +void addConstructor( + TypeManager const & manager, rtl::OString const & realJavaBaseName, + rtl::OString const & unoName, rtl::OString const & className, + typereg::Reader const & reader, sal_uInt16 methodIndex, + rtl::OString const & methodName, rtl::OString const & returnType, + bool defaultConstructor, Dependencies * dependencies, ClassFile * classFile) +{ + OSL_ASSERT(dependencies != 0 && classFile != 0); + MethodDescriptor desc(manager, dependencies, returnType, 0, 0); + desc.addParameter( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XComponentContext")), + false, false, 0); + std::auto_ptr< ClassFile::Code > code(classFile->newCode()); + code->loadLocalReference(0); + // stack: context + code->instrInvokestatic( + className, rtl::OString(RTL_CONSTASCII_STRINGPARAM("$getFactory")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Lcom/sun/star/uno/XComponentContext;)" + "Lcom/sun/star/lang/XMultiComponentFactory;"))); + // stack: factory + code->loadStringConstant(unoName); + // stack: factory serviceName + codemaker::ExceptionTree tree; + ClassFile::Code::Position tryStart; + ClassFile::Code::Position tryEnd; + std::vector< rtl::OString > exc; + sal_uInt16 stack; + sal_uInt16 localIndex = 1; + ClassFile::AccessFlags access = static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_STATIC); + if (defaultConstructor) { + code->loadLocalReference(0); + // stack: factory serviceName context + tryStart = code->getPosition(); + code->instrInvokeinterface( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lang/XMultiComponentFactory")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "createInstanceWithContext")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Lcom/sun/star/uno/XComponentContext;)" + "Ljava/lang/Object;")), + 3); + tryEnd = code->getPosition(); + // stack: instance + stack = 3; + } else { + sal_uInt16 parameters = reader.getMethodParameterCount(methodIndex); + if (parameters == 1 + && (reader.getMethodParameterFlags(methodIndex, 0) + == (RT_PARAM_IN | RT_PARAM_REST)) + && (reader.getMethodParameterTypeName(methodIndex, 0) + == rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("any")))) + { + desc.addParameter( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("any")), true, true, 0); + code->loadLocalReference(localIndex++); + // stack: factory serviceName args + stack = 4; + access = static_cast< ClassFile::AccessFlags >( + access | ClassFile::ACC_VARARGS); + } else { + code->loadIntegerConstant(parameters); + // stack: factory serviceName N + code->instrAnewarray( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Object"))); + // stack: factory serviceName args + stack = 0; + for (sal_uInt16 i = 0; i < parameters; ++i) { + RTParamMode flags = reader.getMethodParameterFlags( + methodIndex, i); + rtl::OString paramType( + codemaker::convertString( + reader.getMethodParameterTypeName(methodIndex, i))); + if ((flags != RT_PARAM_IN + && flags != (RT_PARAM_IN | RT_PARAM_REST)) + || ((flags & RT_PARAM_REST) != 0 + && (parameters != 1 + || (paramType + != rtl::OString( + RTL_CONSTASCII_STRINGPARAM("any")))))) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Bad type information"))); //TODO + } + desc.addParameter(paramType, false, true, 0); + code->instrDup(); + // stack: factory serviceName args args + code->loadIntegerConstant(i); + // stack: factory serviceName args args i + stack = std::max( + stack, + addLoadLocal( + manager, code.get(), &localIndex, false, paramType, + 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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lang/XMultiComponentFactory")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "createInstanceWithArgumentsAndContext")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;[Ljava/lang/Object;" + "Lcom/sun/star/uno/XComponentContext;)Ljava/lang/Object;")), + 4); + tryEnd = code->getPosition(); + // stack: instance + createExceptionsAttribute( + manager, reader, methodIndex, dependencies, &exc, &tree); + } + code->loadLocalReference(0); + // stack: instance context + code->instrInvokestatic( + className, rtl::OString(RTL_CONSTASCII_STRINGPARAM("$castInstance")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/Object;Lcom/sun/star/uno/XComponentContext;)" + "Ljava/lang/Object;"))); + // stack: instance + code->instrCheckcast(returnType); + // stack: instance + code->instrAreturn(); + if (!tree.getRoot()->present) { + ClassFile::Code::Position pos1 = code->getPosition(); + // stack: e + code->instrInvokevirtual( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Throwable")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("toString")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()Ljava/lang/String;"))); + // stack: str + localIndex = std::max< sal_uInt16 >(localIndex, 2); + code->storeLocalReference(1); + // stack: - + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException"))); + // stack: ex + code->instrDup(); + // stack: ex ex + rtl::OStringBuffer msg; + msg.append( + RTL_CONSTASCII_STRINGPARAM( + "component context fails to supply service ")); + msg.append(unoName); + msg.append(RTL_CONSTASCII_STRINGPARAM(" of type ")); + msg.append(realJavaBaseName); + msg.append(RTL_CONSTASCII_STRINGPARAM(": ")); + code->loadStringConstant(msg.makeStringAndClear()); + // stack: ex ex "..." + code->loadLocalReference(1); + // stack: ex ex "..." str + code->instrInvokevirtual( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/String")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("concat")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;)Ljava/lang/String;"))); + // stack: ex ex "..." + code->loadLocalReference(0); + // stack: ex ex "..." context + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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, + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Exception"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Exception"))); + stack = std::max< sal_uInt16 >(stack, 4); + } + code->setMaxStackAndLocals(stack, localIndex); + classFile->addMethod( + access, methodName, desc.getDescriptor(), code.get(), exc, + desc.getSignature()); +} + +void handleService( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + sal_uInt16 superTypes = reader.getSuperTypeCount(); + sal_uInt16 methods = reader.getMethodCount(); + if (superTypes == 0 + ? methods != 0 + : (superTypes != 1 || reader.getFieldCount() != 0 + || reader.getReferenceCount() != 0)) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + if (superTypes == 0) { + return; + } + rtl::OString unoName(codemaker::convertString(reader.getTypeName())); + rtl::OString className( + translateUnoTypeToJavaFullyQualifiedName( + unoName, rtl::OString(RTL_CONSTASCII_STRINGPARAM("service")))); + unoName = unoName.replace('/', '.'); + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL + | ClassFile::ACC_SUPER), + className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Object")), + rtl::OString())); + if (methods > 0) { + rtl::OString base(codemaker::convertString( + reader.getSuperTypeName(0))); + rtl::OString realJavaBaseName(base.replace('/', '.')); + dependencies->insert(base); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/lang/XMultiComponentFactory"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/XComponentContext"))); + for (sal_uInt16 i = 0; i < methods; ++i) { + rtl::OString name(codemaker::convertString( + reader.getMethodName(i))); + bool defaultCtor = name.getLength() == 0; + if (reader.getMethodFlags(i) != RT_MODE_TWOWAY + || (!reader.getMethodReturnTypeName(i).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("void"))) + || (defaultCtor + && (methods != 1 || reader.getMethodParameterCount(i) != 0 + || reader.getMethodExceptionCount(i) != 0))) + { + throw CannotDumpException( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + if (defaultCtor) { + name = rtl::OString(RTL_CONSTASCII_STRINGPARAM("create")); + } else { + name = codemaker::java::translateUnoToJavaIdentifier( + name, rtl::OString(RTL_CONSTASCII_STRINGPARAM("method"))); + } + addConstructor( + manager, realJavaBaseName, unoName, className, reader, i, name, + base, defaultCtor, dependencies, cf.get()); + } + // Synthetic getFactory method: + { + std::auto_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + // stack: context + code->instrInvokeinterface( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/XComponentContext")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("getServiceManager")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "()Lcom/sun/star/lang/XMultiComponentFactory;")), + 1); + // stack: factory + code->instrDup(); + // stack: factory factory + ClassFile::Code::Branch branch = code->instrIfnull(); + // stack: factory + code->instrAreturn(); + code->branchHere(branch); + code->instrPop(); + // stack: - + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException"))); + // stack: ex + code->instrDup(); + // stack: ex ex + code->loadStringConstant( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "component context fails to supply service manager"))); + // stack: ex ex "..." + code->loadLocalReference(0); + // stack: ex ex "..." context + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Ljava/lang/Object;)V"))); + // stack: ex + code->instrAthrow(); + code->setMaxStackAndLocals(4, 1); + cf->addMethod( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PRIVATE | ClassFile::ACC_STATIC + | ClassFile::ACC_SYNTHETIC), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("$getFactory")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Lcom/sun/star/uno/XComponentContext;)" + "Lcom/sun/star/lang/XMultiComponentFactory;")), + code.get(), std::vector< rtl::OString >(), rtl::OString()); + } + // Synthetic castInstance method: + { + std::auto_ptr< ClassFile::Code > code(cf->newCode()); + code->instrNew( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type"))); + // stack: type + code->instrDup(); + // stack: type type + code->loadStringConstant(realJavaBaseName); + // stack: type type "..." + code->instrGetstatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("INTERFACE")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "Lcom/sun/star/uno/TypeClass;"))); + // stack: type type "..." INTERFACE + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"))); + // stack: type + code->loadLocalReference(0); + // stack: type instance + code->instrInvokestatic( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/UnoRuntime")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("queryInterface")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException"))); + // stack: ex + code->instrDup(); + // stack: ex ex + rtl::OStringBuffer msg; + msg.append( + RTL_CONSTASCII_STRINGPARAM( + "component context fails to supply service ")); + msg.append(unoName); + msg.append(RTL_CONSTASCII_STRINGPARAM(" of type ")); + msg.append(realJavaBaseName); + code->loadStringConstant(msg.makeStringAndClear()); + // stack: ex ex "..." + code->loadLocalReference(1); + // stack: ex ex "..." context + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("$castInstance")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/Object;Lcom/sun/star/uno/" + "XComponentContext;)Ljava/lang/Object;")), + code.get(), std::vector< rtl::OString >(), rtl::OString()); + } + } + writeClassFile(options, className, *cf.get()); +} + +void handleSingleton( + TypeManager const & manager, JavaOptions /*TODO const*/ & options, + typereg::Reader const & reader, Dependencies * dependencies) +{ + OSL_ASSERT(dependencies != 0); + if (reader.getSuperTypeCount() != 1 || reader.getFieldCount() != 0 + || reader.getMethodCount() != 0 || reader.getReferenceCount() != 0) + { + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + rtl::OString base(codemaker::convertString(reader.getSuperTypeName(0))); + rtl::OString realJavaBaseName(base.replace('/', '.')); + switch (manager.getTypeReader(base).getTypeClass()) { + case RT_TYPE_INTERFACE: + break; + + case RT_TYPE_SERVICE: + return; + + default: + throw CannotDumpException( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("Bad type information"))); + //TODO + } + dependencies->insert(base); + rtl::OString unoName(codemaker::convertString(reader.getTypeName())); + rtl::OString className( + translateUnoTypeToJavaFullyQualifiedName( + unoName, rtl::OString(RTL_CONSTASCII_STRINGPARAM("singleton")))); + unoName = unoName.replace('/', '.'); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException"))); + dependencies->insert( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass"))); + dependencies->insert( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XComponentContext"))); + std::auto_ptr< ClassFile > cf( + new ClassFile( + static_cast< ClassFile::AccessFlags >( + ClassFile::ACC_PUBLIC | ClassFile::ACC_FINAL + | ClassFile::ACC_SUPER), + className, + rtl::OString(RTL_CONSTASCII_STRINGPARAM("java/lang/Object")), + rtl::OString())); + MethodDescriptor desc(manager, dependencies, base, 0, 0); + desc.addParameter( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XComponentContext")), + false, false, 0); + std::auto_ptr< ClassFile::Code > code(cf->newCode()); + code->loadLocalReference(0); + // stack: context + code->loadStringConstant( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("/singletons/")) + unoName); + // stack: context "..." + code->instrInvokeinterface( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/XComponentContext")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("getValueByName")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;)Ljava/lang/Object;")), + 2); + // stack: value + code->instrDup(); + // stack: value value + code->instrInstanceof( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any"))); + // stack: value 0/1 + ClassFile::Code::Branch branch1 = code->instrIfeq(); + // stack: value + code->instrCheckcast( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any"))); + // stack: value + code->instrDup(); + // stack: value value + code->instrInvokevirtual( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("getType")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()Lcom/sun/star/uno/Type;"))); + // stack: value type + code->instrInvokevirtual( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("getTypeClass")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("()Lcom/sun/star/uno/TypeClass;"))); + // stack: value typeClass + code->instrGetstatic( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("INTERFACE")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/TypeClass;"))); + // stack: value typeClass INTERFACE + ClassFile::Code::Branch branch2 = code->instrIfAcmpne(); + // stack: value + code->instrInvokevirtual( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Any")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("getObject")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("()Ljava/lang/Object;"))); + // stack: value + code->branchHere(branch1); + code->instrNew( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type"))); + // stack: value type + code->instrDup(); + // stack: value type type + code->loadStringConstant(realJavaBaseName); + // stack: value type type "..." + code->instrGetstatic( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/TypeClass")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("INTERFACE")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("Lcom/sun/star/uno/TypeClass;"))); + // stack: value type type "..." INTERFACE + code->instrInvokespecial( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/Type")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(Ljava/lang/String;Lcom/sun/star/uno/TypeClass;)V"))); + // stack: value type + code->instrSwap(); + // stack: type value + code->instrInvokestatic( + rtl::OString(RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/UnoRuntime")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("queryInterface")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "com/sun/star/uno/DeploymentException"))); + // stack: ex + code->instrDup(); + // stack: ex ex + rtl::OStringBuffer msg; + msg.append( + RTL_CONSTASCII_STRINGPARAM( + "component context fails to supply singleton ")); + msg.append(unoName); + msg.append(RTL_CONSTASCII_STRINGPARAM(" of type ")); + msg.append(realJavaBaseName); + code->loadStringConstant(msg.makeStringAndClear()); + // stack: ex ex "..." + code->loadLocalReference(0); + // stack: ex ex "..." context + code->instrInvokespecial( + rtl::OString( + RTL_CONSTASCII_STRINGPARAM("com/sun/star/uno/DeploymentException")), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("<init>")), + rtl::OString( + RTL_CONSTASCII_STRINGPARAM( + "(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), + rtl::OString(RTL_CONSTASCII_STRINGPARAM("get")), desc.getDescriptor(), + code.get(), std::vector< rtl::OString >(), desc.getSignature()); + writeClassFile(options, className, *cf.get()); +} + +} + +bool produceType( + rtl::OString const & type, TypeManager const & manager, + codemaker::GeneratedTypeSet & generated, JavaOptions * options) +{ + OSL_ASSERT(options != 0); + if (type.equals("/") + || type.equals(manager.getBase()) + || generated.contains(type)) + { + return true; + } + sal_Bool extra = sal_False; + typereg::Reader reader(manager.getTypeReader(type, &extra)); + if (extra) { + generated.add(type); + return true; + } + if (!reader.isValid()) { + return false; + } + + handleUnoTypeRegistryEntityFunction handler; + switch (reader.getTypeClass()) { + case RT_TYPE_ENUM: + handler = handleEnumType; + break; + + case RT_TYPE_STRUCT: + case RT_TYPE_EXCEPTION: + handler = handleAggregatingType; + break; + + case RT_TYPE_INTERFACE: + handler = handleInterfaceType; + break; + + case RT_TYPE_TYPEDEF: + handler = handleTypedef; + break; + + case RT_TYPE_CONSTANTS: + handler = handleConstantGroup; + break; + + case RT_TYPE_MODULE: + handler = handleModule; + break; + + case RT_TYPE_SERVICE: + handler = handleService; + break; + + case RT_TYPE_SINGLETON: + handler = handleSingleton; + break; + + default: + return false; + } + Dependencies deps; + handler(manager, *options, reader, &deps); + generated.add(type); + if (!options->isValid(rtl::OString(RTL_CONSTASCII_STRINGPARAM("-nD")))) { + for (Dependencies::iterator i(deps.begin()); i != deps.end(); ++i) { + if (!produceType(*i, manager, generated, options)) { + return false; + } + } + } + return true; +} + +bool produceType( + RegistryKey & rTypeKey, bool bIsExtraType, TypeManager const & manager, + codemaker::GeneratedTypeSet & generated, JavaOptions * options) +{ + ::rtl::OString typeName = manager.getTypeName(rTypeKey); + + OSL_ASSERT(options != 0); + if (typeName.equals("/") + || typeName.equals(manager.getBase()) + || generated.contains(typeName)) + { + return true; + } + typereg::Reader reader(manager.getTypeReader(rTypeKey)); + if (bIsExtraType) { + generated.add(typeName); + return true; + } + if (!reader.isValid()) { + return false; + } + handleUnoTypeRegistryEntityFunction handler; + switch (reader.getTypeClass()) { + case RT_TYPE_ENUM: + handler = handleEnumType; + break; + + case RT_TYPE_STRUCT: + case RT_TYPE_EXCEPTION: + handler = handleAggregatingType; + break; + + case RT_TYPE_INTERFACE: + handler = handleInterfaceType; + break; + + case RT_TYPE_TYPEDEF: + handler = handleTypedef; + break; + + case RT_TYPE_CONSTANTS: + handler = handleConstantGroup; + break; + + case RT_TYPE_MODULE: + handler = handleModule; + break; + + case RT_TYPE_SERVICE: + handler = handleService; + break; + + case RT_TYPE_SINGLETON: + handler = handleSingleton; + break; + + default: + return false; + } + Dependencies deps; + handler(manager, *options, reader, &deps); + generated.add(typeName); + if (!options->isValid(rtl::OString(RTL_CONSTASCII_STRINGPARAM("-nD")))) { + for (Dependencies::iterator i(deps.begin()); i != deps.end(); ++i) { + if (!produceType(*i, manager, generated, options)) { + return false; + } + } + } + return true; +} diff --git a/codemaker/source/javamaker/javatype.hxx b/codemaker/source/javamaker/javatype.hxx new file mode 100644 index 000000000000..fd08ee286fb6 --- /dev/null +++ b/codemaker/source/javamaker/javatype.hxx @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_JAVATYPE_HXX +#define INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_JAVATYPE_HXX + +namespace codemaker { class GeneratedTypeSet; } +namespace rtl { class OString; } +class JavaOptions; +class TypeManager; +class RegistryKey; + +bool produceType( + rtl::OString const & type, TypeManager const & manager, + codemaker::GeneratedTypeSet & generated, JavaOptions * pOptions); + +bool produceType(RegistryKey& typeName, bool bIsExtraType, TypeManager const & typeMgr, + codemaker::GeneratedTypeSet & generated, + JavaOptions* pOptions); + +#endif // INCLUDED_CODEMAKER_SOURCE_JAVAMAKER_JAVATYPE_HXX diff --git a/codemaker/source/javamaker/makefile.mk b/codemaker/source/javamaker/makefile.mk new file mode 100644 index 000000000000..297f35bd0329 --- /dev/null +++ b/codemaker/source/javamaker/makefile.mk @@ -0,0 +1,58 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=codemaker +TARGET=javamaker +TARGETTYPE=CUI +LIBTARGET=NO + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/codemaker.pmk + +# --- Files -------------------------------------------------------- + +OBJFILES = \ + $(OBJ)$/classfile.obj \ + $(OBJ)$/javamaker.obj \ + $(OBJ)$/javaoptions.obj \ + $(OBJ)$/javatype.obj + +APP1TARGET= $(TARGET) +APP1RPATH=SDK +APP1OBJS = $(OBJFILES) + +APP1DEPN= $(OUT)$/lib$/$(CODEMAKERLIBDEPN) $(OUT)$/lib$/$(COMMONJAVALIBDEPN) +APP1STDLIBS= $(SALLIB) $(SALHELPERLIB) $(REGLIB) $(CODEMAKERLIBST) $(COMMONJAVALIBST) + +.INCLUDE : target.mk + |