| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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.isEmpty() ) { |
| ++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.isEmpty() ? 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.isEmpty() ? 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); |
| } |
| |
| #define CLASSFILE_FMT 49.0 // a classfile format understood by JDK 5/6/7 |
| |
| void ClassFile::write(FileStream & file) const { |
| writeU4(file, 0xCAFEBABE); |
| writeU2(file, static_cast<sal_uInt16>((CLASSFILE_FMT-(int)CLASSFILE_FMT)*100000)); |
| writeU2(file, static_cast<sal_uInt16>((int)CLASSFILE_FMT)); |
| 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.isEmpty() ) { |
| appendU2( |
| stream, |
| addUtf8Info(rtl::OString(RTL_CONSTASCII_STRINGPARAM("Signature")))); |
| appendU4(stream, 2); |
| appendU2(stream, addUtf8Info(signature)); |
| } |
| } |