899 lines
30 KiB
C++
899 lines
30 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* 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.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#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 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));
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|