diff options
Diffstat (limited to 'src/cuchaz/enigma/bytecode')
14 files changed, 2123 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java new file mode 100644 index 0000000..aadbeb2 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode; | ||
| 12 | |||
| 13 | import java.util.Iterator; | ||
| 14 | |||
| 15 | import javassist.bytecode.BadBytecode; | ||
| 16 | import javassist.bytecode.Bytecode; | ||
| 17 | import javassist.bytecode.CodeAttribute; | ||
| 18 | import javassist.bytecode.CodeIterator; | ||
| 19 | import javassist.bytecode.Opcode; | ||
| 20 | |||
| 21 | public class BytecodeIndexIterator implements Iterator<BytecodeIndexIterator.Index> | ||
| 22 | { | ||
| 23 | public static class Index | ||
| 24 | { | ||
| 25 | private CodeIterator m_iter; | ||
| 26 | private int m_pos; | ||
| 27 | private boolean m_isWide; | ||
| 28 | |||
| 29 | protected Index( CodeIterator iter, int pos, boolean isWide ) | ||
| 30 | { | ||
| 31 | m_iter = iter; | ||
| 32 | m_pos = pos; | ||
| 33 | m_isWide = isWide; | ||
| 34 | } | ||
| 35 | |||
| 36 | public int getIndex( ) | ||
| 37 | { | ||
| 38 | if( m_isWide ) | ||
| 39 | { | ||
| 40 | return m_iter.s16bitAt( m_pos ); | ||
| 41 | } | ||
| 42 | else | ||
| 43 | { | ||
| 44 | return m_iter.byteAt( m_pos ); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | public void setIndex( int val ) | ||
| 49 | throws BadBytecode | ||
| 50 | { | ||
| 51 | if( m_isWide ) | ||
| 52 | { | ||
| 53 | m_iter.write16bit( val, m_pos ); | ||
| 54 | } | ||
| 55 | else | ||
| 56 | { | ||
| 57 | if( val < 256 ) | ||
| 58 | { | ||
| 59 | // we can write the byte | ||
| 60 | m_iter.writeByte( val, m_pos ); | ||
| 61 | } | ||
| 62 | else | ||
| 63 | { | ||
| 64 | // we need to upgrade this instruction to LDC_W | ||
| 65 | assert( m_iter.byteAt( m_pos - 1 ) == Opcode.LDC ); | ||
| 66 | m_iter.insertGap( m_pos - 1, 1 ); | ||
| 67 | m_iter.writeByte( Opcode.LDC_W, m_pos - 1 ); | ||
| 68 | m_iter.write16bit( val, m_pos ); | ||
| 69 | m_isWide = true; | ||
| 70 | |||
| 71 | // move the iterator to the next opcode | ||
| 72 | m_iter.move( m_pos + 2 ); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | // sanity check | ||
| 77 | assert( val == getIndex() ); | ||
| 78 | } | ||
| 79 | |||
| 80 | public boolean isValid( Bytecode bytecode ) | ||
| 81 | { | ||
| 82 | return getIndex() >= 0 && getIndex() < bytecode.getConstPool().getSize(); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | private Bytecode m_bytecode; | ||
| 87 | private CodeAttribute m_attribute; | ||
| 88 | private CodeIterator m_iter; | ||
| 89 | private Index m_next; | ||
| 90 | |||
| 91 | public BytecodeIndexIterator( Bytecode bytecode ) | ||
| 92 | throws BadBytecode | ||
| 93 | { | ||
| 94 | m_bytecode = bytecode; | ||
| 95 | m_attribute = bytecode.toCodeAttribute(); | ||
| 96 | m_iter = m_attribute.iterator(); | ||
| 97 | |||
| 98 | m_next = getNext(); | ||
| 99 | } | ||
| 100 | |||
| 101 | @Override | ||
| 102 | public boolean hasNext( ) | ||
| 103 | { | ||
| 104 | return m_next != null; | ||
| 105 | } | ||
| 106 | |||
| 107 | @Override | ||
| 108 | public Index next( ) | ||
| 109 | { | ||
| 110 | Index out = m_next; | ||
| 111 | try | ||
| 112 | { | ||
| 113 | m_next = getNext(); | ||
| 114 | } | ||
| 115 | catch( BadBytecode ex ) | ||
| 116 | { | ||
| 117 | throw new Error( ex ); | ||
| 118 | } | ||
| 119 | return out; | ||
| 120 | } | ||
| 121 | |||
| 122 | @Override | ||
| 123 | public void remove( ) | ||
| 124 | { | ||
| 125 | throw new UnsupportedOperationException(); | ||
| 126 | } | ||
| 127 | |||
| 128 | private Index getNext( ) | ||
| 129 | throws BadBytecode | ||
| 130 | { | ||
| 131 | while( m_iter.hasNext() ) | ||
| 132 | { | ||
| 133 | int pos = m_iter.next(); | ||
| 134 | int opcode = m_iter.byteAt( pos ); | ||
| 135 | switch( opcode ) | ||
| 136 | { | ||
| 137 | // for only these opcodes, the next two bytes are a const pool reference | ||
| 138 | case Opcode.ANEWARRAY: | ||
| 139 | case Opcode.CHECKCAST: | ||
| 140 | case Opcode.INSTANCEOF: | ||
| 141 | case Opcode.INVOKEDYNAMIC: | ||
| 142 | case Opcode.INVOKEINTERFACE: | ||
| 143 | case Opcode.INVOKESPECIAL: | ||
| 144 | case Opcode.INVOKESTATIC: | ||
| 145 | case Opcode.INVOKEVIRTUAL: | ||
| 146 | case Opcode.LDC_W: | ||
| 147 | case Opcode.LDC2_W: | ||
| 148 | case Opcode.MULTIANEWARRAY: | ||
| 149 | case Opcode.NEW: | ||
| 150 | case Opcode.PUTFIELD: | ||
| 151 | case Opcode.PUTSTATIC: | ||
| 152 | case Opcode.GETFIELD: | ||
| 153 | case Opcode.GETSTATIC: | ||
| 154 | return new Index( m_iter, pos + 1, true ); | ||
| 155 | |||
| 156 | case Opcode.LDC: | ||
| 157 | return new Index( m_iter, pos + 1, false ); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | return null; | ||
| 162 | } | ||
| 163 | |||
| 164 | public Iterable<Index> indices( ) | ||
| 165 | { | ||
| 166 | return new Iterable<Index>( ) | ||
| 167 | { | ||
| 168 | @Override | ||
| 169 | public Iterator<Index> iterator( ) | ||
| 170 | { | ||
| 171 | return BytecodeIndexIterator.this; | ||
| 172 | } | ||
| 173 | }; | ||
| 174 | } | ||
| 175 | |||
| 176 | public void saveChangesToBytecode( ) | ||
| 177 | { | ||
| 178 | BytecodeTools.setBytecode( m_bytecode, m_attribute.getCode() ); | ||
| 179 | } | ||
| 180 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/BytecodeTools.java b/src/cuchaz/enigma/bytecode/BytecodeTools.java new file mode 100644 index 0000000..664350e --- /dev/null +++ b/src/cuchaz/enigma/bytecode/BytecodeTools.java | |||
| @@ -0,0 +1,269 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode; | ||
| 12 | |||
| 13 | import java.io.ByteArrayInputStream; | ||
| 14 | import java.io.ByteArrayOutputStream; | ||
| 15 | import java.io.DataInputStream; | ||
| 16 | import java.io.DataOutputStream; | ||
| 17 | import java.io.IOException; | ||
| 18 | import java.util.Map; | ||
| 19 | import java.util.Set; | ||
| 20 | |||
| 21 | import javassist.CtBehavior; | ||
| 22 | import javassist.bytecode.BadBytecode; | ||
| 23 | import javassist.bytecode.Bytecode; | ||
| 24 | import javassist.bytecode.CodeAttribute; | ||
| 25 | import javassist.bytecode.ConstPool; | ||
| 26 | import javassist.bytecode.ExceptionTable; | ||
| 27 | |||
| 28 | import com.google.common.collect.Maps; | ||
| 29 | import com.google.common.collect.Sets; | ||
| 30 | |||
| 31 | import cuchaz.enigma.Util; | ||
| 32 | import cuchaz.enigma.bytecode.BytecodeIndexIterator.Index; | ||
| 33 | import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; | ||
| 34 | |||
| 35 | public class BytecodeTools | ||
| 36 | { | ||
| 37 | public static byte[] writeBytecode( Bytecode bytecode ) | ||
| 38 | throws IOException | ||
| 39 | { | ||
| 40 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); | ||
| 41 | DataOutputStream out = new DataOutputStream( buf ); | ||
| 42 | try | ||
| 43 | { | ||
| 44 | // write the constant pool | ||
| 45 | new ConstPoolEditor( bytecode.getConstPool() ).writePool( out ); | ||
| 46 | |||
| 47 | // write metadata | ||
| 48 | out.writeShort( bytecode.getMaxStack() ); | ||
| 49 | out.writeShort( bytecode.getMaxLocals() ); | ||
| 50 | out.writeShort( bytecode.getStackDepth() ); | ||
| 51 | |||
| 52 | // write the code | ||
| 53 | out.writeShort( bytecode.getSize() ); | ||
| 54 | out.write( bytecode.get() ); | ||
| 55 | |||
| 56 | // write the exception table | ||
| 57 | int numEntries = bytecode.getExceptionTable().size(); | ||
| 58 | out.writeShort( numEntries ); | ||
| 59 | for( int i=0; i<numEntries; i++ ) | ||
| 60 | { | ||
| 61 | out.writeShort( bytecode.getExceptionTable().startPc( i ) ); | ||
| 62 | out.writeShort( bytecode.getExceptionTable().endPc( i ) ); | ||
| 63 | out.writeShort( bytecode.getExceptionTable().handlerPc( i ) ); | ||
| 64 | out.writeShort( bytecode.getExceptionTable().catchType( i ) ); | ||
| 65 | } | ||
| 66 | |||
| 67 | out.close(); | ||
| 68 | return buf.toByteArray(); | ||
| 69 | } | ||
| 70 | catch( Exception ex ) | ||
| 71 | { | ||
| 72 | Util.closeQuietly( out ); | ||
| 73 | throw new Error( ex ); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | public static Bytecode readBytecode( byte[] bytes ) | ||
| 78 | throws IOException | ||
| 79 | { | ||
| 80 | ByteArrayInputStream buf = new ByteArrayInputStream( bytes ); | ||
| 81 | DataInputStream in = new DataInputStream( buf ); | ||
| 82 | try | ||
| 83 | { | ||
| 84 | // read the constant pool entries and update the class | ||
| 85 | ConstPool pool = ConstPoolEditor.readPool( in ); | ||
| 86 | |||
| 87 | // read metadata | ||
| 88 | int maxStack = in.readShort(); | ||
| 89 | int maxLocals = in.readShort(); | ||
| 90 | int stackDepth = in.readShort(); | ||
| 91 | |||
| 92 | Bytecode bytecode = new Bytecode( pool, maxStack, maxLocals ); | ||
| 93 | bytecode.setStackDepth( stackDepth ); | ||
| 94 | |||
| 95 | // read the code | ||
| 96 | int size = in.readShort(); | ||
| 97 | byte[] code = new byte[size]; | ||
| 98 | in.read( code ); | ||
| 99 | setBytecode( bytecode, code ); | ||
| 100 | |||
| 101 | // read the exception table | ||
| 102 | int numEntries = in.readShort(); | ||
| 103 | for( int i=0; i<numEntries; i++ ) | ||
| 104 | { | ||
| 105 | bytecode.getExceptionTable().add( in.readShort(), in.readShort(), in.readShort(), in.readShort() ); | ||
| 106 | } | ||
| 107 | |||
| 108 | in.close(); | ||
| 109 | return bytecode; | ||
| 110 | } | ||
| 111 | catch( Exception ex ) | ||
| 112 | { | ||
| 113 | Util.closeQuietly( in ); | ||
| 114 | throw new Error( ex ); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | public static Bytecode prepareMethodForBytecode( CtBehavior behavior, Bytecode bytecode ) | ||
| 119 | throws BadBytecode | ||
| 120 | { | ||
| 121 | // update the destination class const pool | ||
| 122 | bytecode = copyBytecodeToConstPool( behavior.getMethodInfo().getConstPool(), bytecode ); | ||
| 123 | |||
| 124 | // update method locals and stack | ||
| 125 | CodeAttribute attribute = behavior.getMethodInfo().getCodeAttribute(); | ||
| 126 | if( bytecode.getMaxLocals() > attribute.getMaxLocals() ) | ||
| 127 | { | ||
| 128 | attribute.setMaxLocals( bytecode.getMaxLocals() ); | ||
| 129 | } | ||
| 130 | if( bytecode.getMaxStack() > attribute.getMaxStack() ) | ||
| 131 | { | ||
| 132 | attribute.setMaxStack( bytecode.getMaxStack() ); | ||
| 133 | } | ||
| 134 | |||
| 135 | return bytecode; | ||
| 136 | } | ||
| 137 | |||
| 138 | public static Bytecode copyBytecodeToConstPool( ConstPool dest, Bytecode bytecode ) | ||
| 139 | throws BadBytecode | ||
| 140 | { | ||
| 141 | // get the entries this bytecode needs from the const pool | ||
| 142 | Set<Integer> indices = Sets.newTreeSet(); | ||
| 143 | ConstPoolEditor editor = new ConstPoolEditor( bytecode.getConstPool() ); | ||
| 144 | BytecodeIndexIterator iterator = new BytecodeIndexIterator( bytecode ); | ||
| 145 | for( Index index : iterator.indices() ) | ||
| 146 | { | ||
| 147 | assert( index.isValid( bytecode ) ); | ||
| 148 | InfoType.gatherIndexTree( indices, editor, index.getIndex() ); | ||
| 149 | } | ||
| 150 | |||
| 151 | Map<Integer,Integer> indexMap = Maps.newTreeMap(); | ||
| 152 | |||
| 153 | ConstPool src = bytecode.getConstPool(); | ||
| 154 | ConstPoolEditor editorSrc = new ConstPoolEditor( src ); | ||
| 155 | ConstPoolEditor editorDest = new ConstPoolEditor( dest ); | ||
| 156 | |||
| 157 | // copy entries over in order of level so the index mapping is easier | ||
| 158 | for( InfoType type : InfoType.getSortedByLevel() ) | ||
| 159 | { | ||
| 160 | for( int index : indices ) | ||
| 161 | { | ||
| 162 | ConstInfoAccessor entry = editorSrc.getItem( index ); | ||
| 163 | |||
| 164 | // skip entries that aren't this type | ||
| 165 | if( entry.getType() != type ) | ||
| 166 | { | ||
| 167 | continue; | ||
| 168 | } | ||
| 169 | |||
| 170 | // make sure the source entry is valid before we copy it | ||
| 171 | assert( type.subIndicesAreValid( entry, editorSrc ) ); | ||
| 172 | assert( type.selfIndexIsValid( entry, editorSrc ) ); | ||
| 173 | |||
| 174 | // make a copy of the entry so we can modify it safely | ||
| 175 | ConstInfoAccessor entryCopy = editorSrc.getItem( index ).copy(); | ||
| 176 | assert( type.subIndicesAreValid( entryCopy, editorSrc ) ); | ||
| 177 | assert( type.selfIndexIsValid( entryCopy, editorSrc ) ); | ||
| 178 | |||
| 179 | // remap the indices | ||
| 180 | type.remapIndices( indexMap, entryCopy ); | ||
| 181 | assert( type.subIndicesAreValid( entryCopy, editorDest ) ); | ||
| 182 | |||
| 183 | // put the copy in the destination pool | ||
| 184 | int newIndex = editorDest.addItem( entryCopy.getItem() ); | ||
| 185 | entryCopy.setIndex( newIndex ); | ||
| 186 | assert( type.selfIndexIsValid( entryCopy, editorDest ) ) : type + ", self: " + entryCopy + " dest: " + editorDest.getItem( entryCopy.getIndex() ); | ||
| 187 | |||
| 188 | // make sure the source entry is unchanged | ||
| 189 | assert( type.subIndicesAreValid( entry, editorSrc ) ); | ||
| 190 | assert( type.selfIndexIsValid( entry, editorSrc ) ); | ||
| 191 | |||
| 192 | // add the index mapping so we can update the bytecode later | ||
| 193 | if( indexMap.containsKey( index ) ) | ||
| 194 | { | ||
| 195 | throw new Error( "Entry at index " + index + " already copied!" ); | ||
| 196 | } | ||
| 197 | indexMap.put( index, newIndex ); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | // make a new bytecode | ||
| 202 | Bytecode newBytecode = new Bytecode( dest, bytecode.getMaxStack(), bytecode.getMaxLocals() ); | ||
| 203 | bytecode.setStackDepth( bytecode.getStackDepth() ); | ||
| 204 | setBytecode( newBytecode, bytecode.get() ); | ||
| 205 | setExceptionTable( newBytecode, bytecode.getExceptionTable() ); | ||
| 206 | |||
| 207 | // apply the mappings to the bytecode | ||
| 208 | BytecodeIndexIterator iter = new BytecodeIndexIterator( newBytecode ); | ||
| 209 | for( Index index : iter.indices() ) | ||
| 210 | { | ||
| 211 | int oldIndex = index.getIndex(); | ||
| 212 | Integer newIndex = indexMap.get( oldIndex ); | ||
| 213 | if( newIndex != null ) | ||
| 214 | { | ||
| 215 | // make sure this mapping makes sense | ||
| 216 | InfoType typeSrc = editorSrc.getItem( oldIndex ).getType(); | ||
| 217 | InfoType typeDest = editorDest.getItem( newIndex ).getType(); | ||
| 218 | assert( typeSrc == typeDest ); | ||
| 219 | |||
| 220 | // apply the mapping | ||
| 221 | index.setIndex( newIndex ); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | iter.saveChangesToBytecode(); | ||
| 225 | |||
| 226 | // make sure all the indices are valid | ||
| 227 | iter = new BytecodeIndexIterator( newBytecode ); | ||
| 228 | for( Index index : iter.indices() ) | ||
| 229 | { | ||
| 230 | assert( index.isValid( newBytecode ) ); | ||
| 231 | } | ||
| 232 | |||
| 233 | return newBytecode; | ||
| 234 | } | ||
| 235 | |||
| 236 | public static void setBytecode( Bytecode dest, byte[] src ) | ||
| 237 | { | ||
| 238 | if( src.length > dest.getSize() ) | ||
| 239 | { | ||
| 240 | dest.addGap( src.length - dest.getSize() ); | ||
| 241 | } | ||
| 242 | assert( dest.getSize() == src.length ); | ||
| 243 | for( int i=0; i<src.length; i++ ) | ||
| 244 | { | ||
| 245 | dest.write( i, src[i] ); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | public static void setExceptionTable( Bytecode dest, ExceptionTable src ) | ||
| 250 | { | ||
| 251 | // clear the dest exception table | ||
| 252 | int size = dest.getExceptionTable().size(); | ||
| 253 | for( int i=size-1; i>=0; i-- ) | ||
| 254 | { | ||
| 255 | dest.getExceptionTable().remove( i ); | ||
| 256 | } | ||
| 257 | |||
| 258 | // copy the exception table | ||
| 259 | for( int i=0; i<src.size(); i++ ) | ||
| 260 | { | ||
| 261 | dest.getExceptionTable().add( | ||
| 262 | src.startPc( i ), | ||
| 263 | src.endPc( i ), | ||
| 264 | src.handlerPc( i ), | ||
| 265 | src.catchType( i ) | ||
| 266 | ); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java new file mode 100644 index 0000000..3b5beeb --- /dev/null +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode; | ||
| 12 | |||
| 13 | import java.util.HashSet; | ||
| 14 | import java.util.Set; | ||
| 15 | |||
| 16 | import javassist.ClassMap; | ||
| 17 | import javassist.CtBehavior; | ||
| 18 | import javassist.CtClass; | ||
| 19 | import javassist.CtField; | ||
| 20 | import javassist.CtMethod; | ||
| 21 | import javassist.bytecode.ConstPool; | ||
| 22 | import javassist.bytecode.Descriptor; | ||
| 23 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 24 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 25 | import cuchaz.enigma.mapping.MethodEntry; | ||
| 26 | import cuchaz.enigma.mapping.Translator; | ||
| 27 | |||
| 28 | public class ClassTranslator | ||
| 29 | { | ||
| 30 | private Translator m_translator; | ||
| 31 | |||
| 32 | public ClassTranslator( Translator translator ) | ||
| 33 | { | ||
| 34 | m_translator = translator; | ||
| 35 | } | ||
| 36 | |||
| 37 | public void translate( CtClass c ) | ||
| 38 | { | ||
| 39 | // NOTE: the order of these translations is very important | ||
| 40 | |||
| 41 | // translate all the field and method references in the code by editing the constant pool | ||
| 42 | ConstPool constants = c.getClassFile().getConstPool(); | ||
| 43 | ConstPoolEditor editor = new ConstPoolEditor( constants ); | ||
| 44 | for( int i=1; i<constants.getSize(); i++ ) | ||
| 45 | { | ||
| 46 | switch( constants.getTag( i ) ) | ||
| 47 | { | ||
| 48 | case ConstPool.CONST_Fieldref: | ||
| 49 | { | ||
| 50 | // translate the name | ||
| 51 | FieldEntry entry = new FieldEntry( | ||
| 52 | new ClassEntry( Descriptor.toJvmName( constants.getFieldrefClassName( i ) ) ), | ||
| 53 | constants.getFieldrefName( i ) | ||
| 54 | ); | ||
| 55 | String translatedName = m_translator.translate( entry ); | ||
| 56 | if( translatedName == null ) | ||
| 57 | { | ||
| 58 | translatedName = entry.getName(); | ||
| 59 | } | ||
| 60 | |||
| 61 | // translate the type | ||
| 62 | String type = constants.getFieldrefType( i ); | ||
| 63 | String translatedType = m_translator.translateSignature( type ); | ||
| 64 | |||
| 65 | if( !entry.getName().equals( translatedName ) || !type.equals( translatedType ) ) | ||
| 66 | { | ||
| 67 | editor.changeMemberrefNameAndType( i, translatedName, translatedType ); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | break; | ||
| 71 | |||
| 72 | case ConstPool.CONST_Methodref: | ||
| 73 | case ConstPool.CONST_InterfaceMethodref: | ||
| 74 | { | ||
| 75 | // translate the name and type | ||
| 76 | MethodEntry entry = new MethodEntry( | ||
| 77 | new ClassEntry( Descriptor.toJvmName( editor.getMemberrefClassname( i ) ) ), | ||
| 78 | editor.getMemberrefName( i ), | ||
| 79 | editor.getMemberrefType( i ) | ||
| 80 | ); | ||
| 81 | String translatedName = m_translator.translate( entry ); | ||
| 82 | if( translatedName == null ) | ||
| 83 | { | ||
| 84 | translatedName = entry.getName(); | ||
| 85 | } | ||
| 86 | String translatedSignature = m_translator.translateSignature( entry.getSignature() ); | ||
| 87 | |||
| 88 | if( !entry.getName().equals( translatedName ) || !entry.getSignature().equals( translatedSignature ) ) | ||
| 89 | { | ||
| 90 | editor.changeMemberrefNameAndType( i, translatedName, translatedSignature ); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); | ||
| 98 | |||
| 99 | // translate all the fields | ||
| 100 | for( CtField field : c.getDeclaredFields() ) | ||
| 101 | { | ||
| 102 | // translate the name | ||
| 103 | FieldEntry entry = new FieldEntry( classEntry, field.getName() ); | ||
| 104 | String translatedName = m_translator.translate( entry ); | ||
| 105 | if( translatedName != null ) | ||
| 106 | { | ||
| 107 | field.setName( translatedName ); | ||
| 108 | } | ||
| 109 | |||
| 110 | // translate the type | ||
| 111 | String translatedType = m_translator.translateSignature( field.getFieldInfo().getDescriptor() ); | ||
| 112 | field.getFieldInfo().setDescriptor( translatedType ); | ||
| 113 | } | ||
| 114 | |||
| 115 | // translate all the methods and constructors | ||
| 116 | for( CtBehavior behavior : c.getDeclaredBehaviors() ) | ||
| 117 | { | ||
| 118 | // translate the name | ||
| 119 | MethodEntry entry = new MethodEntry( classEntry, behavior.getName(), behavior.getSignature() ); | ||
| 120 | String translatedName = m_translator.translate( entry ); | ||
| 121 | if( translatedName != null ) | ||
| 122 | { | ||
| 123 | if( behavior instanceof CtMethod ) | ||
| 124 | { | ||
| 125 | ((CtMethod)behavior).setName( translatedName ); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | // translate the type | ||
| 130 | String translatedSignature = m_translator.translateSignature( behavior.getMethodInfo().getDescriptor() ); | ||
| 131 | behavior.getMethodInfo().setDescriptor( translatedSignature ); | ||
| 132 | } | ||
| 133 | |||
| 134 | // translate all the class names referenced in the code | ||
| 135 | // the above code only changed method/field/reference names and types, but not the class names themselves | ||
| 136 | Set<String> classNames = getAllClassNames( c ); | ||
| 137 | ClassMap map = new ClassMap(); | ||
| 138 | for( String className : classNames ) | ||
| 139 | { | ||
| 140 | String translatedName = m_translator.translateClass( className ); | ||
| 141 | if( translatedName != null ) | ||
| 142 | { | ||
| 143 | map.put( className, translatedName ); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | if( !map.isEmpty() ) | ||
| 147 | { | ||
| 148 | c.replaceClassName( map ); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | private Set<String> getAllClassNames( CtClass c ) | ||
| 153 | { | ||
| 154 | final Set<String> names = new HashSet<String>(); | ||
| 155 | ClassMap map = new ClassMap( ) | ||
| 156 | { | ||
| 157 | @Override | ||
| 158 | public Object get( Object obj ) | ||
| 159 | { | ||
| 160 | if( obj instanceof String ) | ||
| 161 | { | ||
| 162 | names.add( (String)obj ); | ||
| 163 | } | ||
| 164 | return null; | ||
| 165 | } | ||
| 166 | private static final long serialVersionUID = -202160293602070641L; | ||
| 167 | }; | ||
| 168 | c.replaceClassName( map ); | ||
| 169 | return names; | ||
| 170 | } | ||
| 171 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java new file mode 100644 index 0000000..aa6149c --- /dev/null +++ b/src/cuchaz/enigma/bytecode/ConstPoolEditor.java | |||
| @@ -0,0 +1,316 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode; | ||
| 12 | |||
| 13 | import java.io.DataInputStream; | ||
| 14 | import java.io.DataOutputStream; | ||
| 15 | import java.lang.reflect.Constructor; | ||
| 16 | import java.lang.reflect.Field; | ||
| 17 | import java.lang.reflect.Method; | ||
| 18 | import java.util.HashMap; | ||
| 19 | |||
| 20 | import javassist.bytecode.ConstPool; | ||
| 21 | import javassist.bytecode.Descriptor; | ||
| 22 | import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; | ||
| 23 | import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; | ||
| 24 | import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; | ||
| 25 | |||
| 26 | public class ConstPoolEditor | ||
| 27 | { | ||
| 28 | private static Method m_getItem; | ||
| 29 | private static Method m_addItem; | ||
| 30 | private static Method m_addItem0; | ||
| 31 | private static Field m_items; | ||
| 32 | private static Field m_cache; | ||
| 33 | private static Field m_numItems; | ||
| 34 | private static Field m_objects; | ||
| 35 | private static Field m_elements; | ||
| 36 | private static Method m_methodWritePool; | ||
| 37 | private static Constructor<ConstPool> m_constructorPool; | ||
| 38 | |||
| 39 | static | ||
| 40 | { | ||
| 41 | try | ||
| 42 | { | ||
| 43 | m_getItem = ConstPool.class.getDeclaredMethod( "getItem", int.class ); | ||
| 44 | m_getItem.setAccessible( true ); | ||
| 45 | |||
| 46 | m_addItem = ConstPool.class.getDeclaredMethod( "addItem", Class.forName( "javassist.bytecode.ConstInfo" ) ); | ||
| 47 | m_addItem.setAccessible( true ); | ||
| 48 | |||
| 49 | m_addItem0 = ConstPool.class.getDeclaredMethod( "addItem0", Class.forName( "javassist.bytecode.ConstInfo" ) ); | ||
| 50 | m_addItem0.setAccessible( true ); | ||
| 51 | |||
| 52 | m_items = ConstPool.class.getDeclaredField( "items" ); | ||
| 53 | m_items.setAccessible( true ); | ||
| 54 | |||
| 55 | m_cache = ConstPool.class.getDeclaredField( "itemsCache" ); | ||
| 56 | m_cache.setAccessible( true ); | ||
| 57 | |||
| 58 | m_numItems = ConstPool.class.getDeclaredField( "numOfItems" ); | ||
| 59 | m_numItems.setAccessible( true ); | ||
| 60 | |||
| 61 | m_objects = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "objects" ); | ||
| 62 | m_objects.setAccessible( true ); | ||
| 63 | |||
| 64 | m_elements = Class.forName( "javassist.bytecode.LongVector" ).getDeclaredField( "elements" ); | ||
| 65 | m_elements.setAccessible( true ); | ||
| 66 | |||
| 67 | m_methodWritePool = ConstPool.class.getDeclaredMethod( "write", DataOutputStream.class ); | ||
| 68 | m_methodWritePool.setAccessible( true ); | ||
| 69 | |||
| 70 | m_constructorPool = ConstPool.class.getDeclaredConstructor( DataInputStream.class ); | ||
| 71 | m_constructorPool.setAccessible( true ); | ||
| 72 | } | ||
| 73 | catch( Exception ex ) | ||
| 74 | { | ||
| 75 | throw new Error( ex ); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | private ConstPool m_pool; | ||
| 80 | |||
| 81 | public ConstPoolEditor( ConstPool pool ) | ||
| 82 | { | ||
| 83 | m_pool = pool; | ||
| 84 | } | ||
| 85 | |||
| 86 | public void writePool( DataOutputStream out ) | ||
| 87 | { | ||
| 88 | try | ||
| 89 | { | ||
| 90 | m_methodWritePool.invoke( m_pool, out ); | ||
| 91 | } | ||
| 92 | catch( Exception ex ) | ||
| 93 | { | ||
| 94 | throw new Error( ex ); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | public static ConstPool readPool( DataInputStream in ) | ||
| 99 | { | ||
| 100 | try | ||
| 101 | { | ||
| 102 | return m_constructorPool.newInstance( in ); | ||
| 103 | } | ||
| 104 | catch( Exception ex ) | ||
| 105 | { | ||
| 106 | throw new Error( ex ); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | public String getMemberrefClassname( int memberrefIndex ) | ||
| 111 | { | ||
| 112 | return Descriptor.toJvmName( m_pool.getClassInfo( m_pool.getMemberClass( memberrefIndex ) ) ); | ||
| 113 | } | ||
| 114 | |||
| 115 | public String getMemberrefName( int memberrefIndex ) | ||
| 116 | { | ||
| 117 | return m_pool.getUtf8Info( m_pool.getNameAndTypeName( m_pool.getMemberNameAndType( memberrefIndex ) ) ); | ||
| 118 | } | ||
| 119 | |||
| 120 | public String getMemberrefType( int memberrefIndex ) | ||
| 121 | { | ||
| 122 | return m_pool.getUtf8Info( m_pool.getNameAndTypeDescriptor( m_pool.getMemberNameAndType( memberrefIndex ) ) ); | ||
| 123 | } | ||
| 124 | |||
| 125 | public ConstInfoAccessor getItem( int index ) | ||
| 126 | { | ||
| 127 | try | ||
| 128 | { | ||
| 129 | Object entry = m_getItem.invoke( m_pool, index ); | ||
| 130 | if( entry == null ) | ||
| 131 | { | ||
| 132 | return null; | ||
| 133 | } | ||
| 134 | return new ConstInfoAccessor( entry ); | ||
| 135 | } | ||
| 136 | catch( Exception ex ) | ||
| 137 | { | ||
| 138 | throw new Error( ex ); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | public int addItem( Object item ) | ||
| 143 | { | ||
| 144 | try | ||
| 145 | { | ||
| 146 | return (Integer)m_addItem.invoke( m_pool, item ); | ||
| 147 | } | ||
| 148 | catch( Exception ex ) | ||
| 149 | { | ||
| 150 | throw new Error( ex ); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | public int addItemForceNew( Object item ) | ||
| 155 | { | ||
| 156 | try | ||
| 157 | { | ||
| 158 | return (Integer)m_addItem0.invoke( m_pool, item ); | ||
| 159 | } | ||
| 160 | catch( Exception ex ) | ||
| 161 | { | ||
| 162 | throw new Error( ex ); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | @SuppressWarnings( "rawtypes" ) | ||
| 166 | public void removeLastItem( ) | ||
| 167 | { | ||
| 168 | try | ||
| 169 | { | ||
| 170 | // remove the item from the cache | ||
| 171 | HashMap cache = getCache(); | ||
| 172 | if( cache != null ) | ||
| 173 | { | ||
| 174 | Object item = getItem( m_pool.getSize() - 1 ); | ||
| 175 | cache.remove( item ); | ||
| 176 | } | ||
| 177 | |||
| 178 | // remove the actual item | ||
| 179 | // based off of LongVector.addElement() | ||
| 180 | Object items = m_items.get( m_pool ); | ||
| 181 | Object[][] objects = (Object[][])m_objects.get( items ); | ||
| 182 | int numElements = (Integer)m_elements.get( items ) - 1; | ||
| 183 | int nth = numElements >> 7; | ||
| 184 | int offset = numElements & (128 - 1); | ||
| 185 | objects[nth][offset] = null; | ||
| 186 | |||
| 187 | // decrement the number of items | ||
| 188 | m_elements.set( items, numElements ); | ||
| 189 | m_numItems.set( m_pool, (Integer)m_numItems.get( m_pool ) - 1 ); | ||
| 190 | } | ||
| 191 | catch( Exception ex ) | ||
| 192 | { | ||
| 193 | throw new Error( ex ); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | @SuppressWarnings( "rawtypes" ) | ||
| 198 | /* TEMP */public HashMap getCache( ) | ||
| 199 | { | ||
| 200 | try | ||
| 201 | { | ||
| 202 | return (HashMap)m_cache.get( m_pool ); | ||
| 203 | } | ||
| 204 | catch( Exception ex ) | ||
| 205 | { | ||
| 206 | throw new Error( ex ); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | @SuppressWarnings( { "rawtypes", "unchecked" } ) | ||
| 211 | public void changeMemberrefNameAndType( int memberrefIndex, String newName, String newType ) | ||
| 212 | { | ||
| 213 | // NOTE: when changing values, we always need to copy-on-write | ||
| 214 | try | ||
| 215 | { | ||
| 216 | // get the memberref item | ||
| 217 | Object item = getItem( memberrefIndex ).getItem(); | ||
| 218 | |||
| 219 | // update the cache | ||
| 220 | HashMap cache = getCache(); | ||
| 221 | if( cache != null ) | ||
| 222 | { | ||
| 223 | cache.remove( item ); | ||
| 224 | } | ||
| 225 | |||
| 226 | new MemberRefInfoAccessor( item ).setNameAndTypeIndex( m_pool.addNameAndTypeInfo( newName, newType ) ); | ||
| 227 | |||
| 228 | // update the cache | ||
| 229 | if( cache != null ) | ||
| 230 | { | ||
| 231 | cache.put( item, item ); | ||
| 232 | } | ||
| 233 | } | ||
| 234 | catch( Exception ex ) | ||
| 235 | { | ||
| 236 | throw new Error( ex ); | ||
| 237 | } | ||
| 238 | |||
| 239 | // make sure the change worked | ||
| 240 | assert( newName.equals( getMemberrefName( memberrefIndex ) ) ); | ||
| 241 | assert( newType.equals( getMemberrefType( memberrefIndex ) ) ); | ||
| 242 | } | ||
| 243 | |||
| 244 | @SuppressWarnings( { "rawtypes", "unchecked" } ) | ||
| 245 | public void changeClassName( int classNameIndex, String newName ) | ||
| 246 | { | ||
| 247 | // NOTE: when changing values, we always need to copy-on-write | ||
| 248 | try | ||
| 249 | { | ||
| 250 | // get the class item | ||
| 251 | Object item = getItem( classNameIndex ).getItem(); | ||
| 252 | |||
| 253 | // update the cache | ||
| 254 | HashMap cache = getCache(); | ||
| 255 | if( cache != null ) | ||
| 256 | { | ||
| 257 | cache.remove( item ); | ||
| 258 | } | ||
| 259 | |||
| 260 | // add the new name and repoint the name-and-type to it | ||
| 261 | new ClassInfoAccessor( item ).setNameIndex( m_pool.addUtf8Info( newName ) ); | ||
| 262 | |||
| 263 | // update the cache | ||
| 264 | if( cache != null ) | ||
| 265 | { | ||
| 266 | cache.put( item, item ); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | catch( Exception ex ) | ||
| 270 | { | ||
| 271 | throw new Error( ex ); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | public static ConstPool newConstPool( ) | ||
| 276 | { | ||
| 277 | // const pool expects the name of a class to initialize itself | ||
| 278 | // but we want an empty pool | ||
| 279 | // so give it a bogus name, and then clear the entries afterwards | ||
| 280 | ConstPool pool = new ConstPool( "a" ); | ||
| 281 | |||
| 282 | ConstPoolEditor editor = new ConstPoolEditor( pool ); | ||
| 283 | int size = pool.getSize(); | ||
| 284 | for( int i=0; i<size-1; i++ ) | ||
| 285 | { | ||
| 286 | editor.removeLastItem(); | ||
| 287 | } | ||
| 288 | |||
| 289 | // make sure the pool is actually empty | ||
| 290 | // although, in this case "empty" means one thing in it | ||
| 291 | // the JVM spec says index 0 should be reserved | ||
| 292 | assert( pool.getSize() == 1 ); | ||
| 293 | assert( editor.getItem( 0 ) == null ); | ||
| 294 | assert( editor.getItem( 1 ) == null ); | ||
| 295 | assert( editor.getItem( 2 ) == null ); | ||
| 296 | assert( editor.getItem( 3 ) == null ); | ||
| 297 | |||
| 298 | // also, clear the cache | ||
| 299 | editor.getCache().clear(); | ||
| 300 | |||
| 301 | return pool; | ||
| 302 | } | ||
| 303 | |||
| 304 | public String dump( ) | ||
| 305 | { | ||
| 306 | StringBuilder buf = new StringBuilder(); | ||
| 307 | for( int i=1; i<m_pool.getSize(); i++ ) | ||
| 308 | { | ||
| 309 | buf.append( String.format( "%4d", i ) ); | ||
| 310 | buf.append( " " ); | ||
| 311 | buf.append( getItem( i ).toString() ); | ||
| 312 | buf.append( "\n" ); | ||
| 313 | } | ||
| 314 | return buf.toString(); | ||
| 315 | } | ||
| 316 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/InfoType.java b/src/cuchaz/enigma/bytecode/InfoType.java new file mode 100644 index 0000000..fe03006 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/InfoType.java | |||
| @@ -0,0 +1,364 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode; | ||
| 12 | |||
| 13 | import java.util.Collection; | ||
| 14 | import java.util.List; | ||
| 15 | import java.util.Map; | ||
| 16 | |||
| 17 | import com.google.common.collect.Lists; | ||
| 18 | import com.google.common.collect.Maps; | ||
| 19 | |||
| 20 | import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; | ||
| 21 | import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; | ||
| 22 | import cuchaz.enigma.bytecode.accessors.InvokeDynamicInfoAccessor; | ||
| 23 | import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; | ||
| 24 | import cuchaz.enigma.bytecode.accessors.MethodHandleInfoAccessor; | ||
| 25 | import cuchaz.enigma.bytecode.accessors.MethodTypeInfoAccessor; | ||
| 26 | import cuchaz.enigma.bytecode.accessors.NameAndTypeInfoAccessor; | ||
| 27 | import cuchaz.enigma.bytecode.accessors.StringInfoAccessor; | ||
| 28 | |||
| 29 | public enum InfoType | ||
| 30 | { | ||
| 31 | Utf8Info( 1, 0 ), | ||
| 32 | IntegerInfo( 3, 0 ), | ||
| 33 | FloatInfo( 4, 0 ), | ||
| 34 | LongInfo( 5, 0 ), | ||
| 35 | DoubleInfo( 6, 0 ), | ||
| 36 | ClassInfo( 7, 1 ) | ||
| 37 | { | ||
| 38 | @Override | ||
| 39 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 40 | { | ||
| 41 | ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); | ||
| 42 | gatherIndexTree( indices, editor, accessor.getNameIndex() ); | ||
| 43 | } | ||
| 44 | |||
| 45 | @Override | ||
| 46 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 47 | { | ||
| 48 | ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); | ||
| 49 | accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); | ||
| 50 | } | ||
| 51 | |||
| 52 | @Override | ||
| 53 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 54 | { | ||
| 55 | ClassInfoAccessor accessor = new ClassInfoAccessor( entry.getItem() ); | ||
| 56 | ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); | ||
| 57 | return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); | ||
| 58 | } | ||
| 59 | }, | ||
| 60 | StringInfo( 8, 1 ) | ||
| 61 | { | ||
| 62 | @Override | ||
| 63 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 64 | { | ||
| 65 | StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); | ||
| 66 | gatherIndexTree( indices, editor, accessor.getStringIndex() ); | ||
| 67 | } | ||
| 68 | |||
| 69 | @Override | ||
| 70 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 71 | { | ||
| 72 | StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); | ||
| 73 | accessor.setStringIndex( remapIndex( map, accessor.getStringIndex() ) ); | ||
| 74 | } | ||
| 75 | |||
| 76 | @Override | ||
| 77 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 78 | { | ||
| 79 | StringInfoAccessor accessor = new StringInfoAccessor( entry.getItem() ); | ||
| 80 | ConstInfoAccessor stringEntry = pool.getItem( accessor.getStringIndex() ); | ||
| 81 | return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); | ||
| 82 | } | ||
| 83 | }, | ||
| 84 | FieldRefInfo( 9, 2 ) | ||
| 85 | { | ||
| 86 | @Override | ||
| 87 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 88 | { | ||
| 89 | MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); | ||
| 90 | gatherIndexTree( indices, editor, accessor.getClassIndex() ); | ||
| 91 | gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() ); | ||
| 92 | } | ||
| 93 | |||
| 94 | @Override | ||
| 95 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 96 | { | ||
| 97 | MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); | ||
| 98 | accessor.setClassIndex( remapIndex( map, accessor.getClassIndex() ) ); | ||
| 99 | accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) ); | ||
| 100 | } | ||
| 101 | |||
| 102 | @Override | ||
| 103 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 104 | { | ||
| 105 | MemberRefInfoAccessor accessor = new MemberRefInfoAccessor( entry.getItem() ); | ||
| 106 | ConstInfoAccessor classEntry = pool.getItem( accessor.getClassIndex() ); | ||
| 107 | ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); | ||
| 108 | return classEntry != null && classEntry.getTag() == ClassInfo.getTag() | ||
| 109 | && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); | ||
| 110 | } | ||
| 111 | }, | ||
| 112 | MethodRefInfo( 10, 2 ) // same as FieldRefInfo | ||
| 113 | { | ||
| 114 | @Override | ||
| 115 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 116 | { | ||
| 117 | FieldRefInfo.gatherIndexTree( indices, editor, entry ); | ||
| 118 | } | ||
| 119 | |||
| 120 | @Override | ||
| 121 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 122 | { | ||
| 123 | FieldRefInfo.remapIndices( map, entry ); | ||
| 124 | } | ||
| 125 | |||
| 126 | @Override | ||
| 127 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 128 | { | ||
| 129 | return FieldRefInfo.subIndicesAreValid( entry, pool ); | ||
| 130 | } | ||
| 131 | }, | ||
| 132 | InterfaceMethodRefInfo( 11, 2 ) // same as FieldRefInfo | ||
| 133 | { | ||
| 134 | @Override | ||
| 135 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 136 | { | ||
| 137 | FieldRefInfo.gatherIndexTree( indices, editor, entry ); | ||
| 138 | } | ||
| 139 | |||
| 140 | @Override | ||
| 141 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 142 | { | ||
| 143 | FieldRefInfo.remapIndices( map, entry ); | ||
| 144 | } | ||
| 145 | |||
| 146 | @Override | ||
| 147 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 148 | { | ||
| 149 | return FieldRefInfo.subIndicesAreValid( entry, pool ); | ||
| 150 | } | ||
| 151 | }, | ||
| 152 | NameAndTypeInfo( 12, 1 ) | ||
| 153 | { | ||
| 154 | @Override | ||
| 155 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 156 | { | ||
| 157 | NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); | ||
| 158 | gatherIndexTree( indices, editor, accessor.getNameIndex() ); | ||
| 159 | gatherIndexTree( indices, editor, accessor.getTypeIndex() ); | ||
| 160 | } | ||
| 161 | |||
| 162 | @Override | ||
| 163 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 164 | { | ||
| 165 | NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); | ||
| 166 | accessor.setNameIndex( remapIndex( map, accessor.getNameIndex() ) ); | ||
| 167 | accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); | ||
| 168 | } | ||
| 169 | |||
| 170 | @Override | ||
| 171 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 172 | { | ||
| 173 | NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor( entry.getItem() ); | ||
| 174 | ConstInfoAccessor nameEntry = pool.getItem( accessor.getNameIndex() ); | ||
| 175 | ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); | ||
| 176 | return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() | ||
| 177 | && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); | ||
| 178 | } | ||
| 179 | }, | ||
| 180 | MethodHandleInfo( 15, 3 ) | ||
| 181 | { | ||
| 182 | @Override | ||
| 183 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 184 | { | ||
| 185 | MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); | ||
| 186 | gatherIndexTree( indices, editor, accessor.getTypeIndex() ); | ||
| 187 | gatherIndexTree( indices, editor, accessor.getMethodRefIndex() ); | ||
| 188 | } | ||
| 189 | |||
| 190 | @Override | ||
| 191 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 192 | { | ||
| 193 | MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); | ||
| 194 | accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); | ||
| 195 | accessor.setMethodRefIndex( remapIndex( map, accessor.getMethodRefIndex() ) ); | ||
| 196 | } | ||
| 197 | |||
| 198 | @Override | ||
| 199 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 200 | { | ||
| 201 | MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor( entry.getItem() ); | ||
| 202 | ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); | ||
| 203 | ConstInfoAccessor methodRefEntry = pool.getItem( accessor.getMethodRefIndex() ); | ||
| 204 | return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() | ||
| 205 | && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); | ||
| 206 | } | ||
| 207 | }, | ||
| 208 | MethodTypeInfo( 16, 1 ) | ||
| 209 | { | ||
| 210 | @Override | ||
| 211 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 212 | { | ||
| 213 | MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); | ||
| 214 | gatherIndexTree( indices, editor, accessor.getTypeIndex() ); | ||
| 215 | } | ||
| 216 | |||
| 217 | @Override | ||
| 218 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 219 | { | ||
| 220 | MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); | ||
| 221 | accessor.setTypeIndex( remapIndex( map, accessor.getTypeIndex() ) ); | ||
| 222 | } | ||
| 223 | |||
| 224 | @Override | ||
| 225 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 226 | { | ||
| 227 | MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor( entry.getItem() ); | ||
| 228 | ConstInfoAccessor typeEntry = pool.getItem( accessor.getTypeIndex() ); | ||
| 229 | return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); | ||
| 230 | } | ||
| 231 | }, | ||
| 232 | InvokeDynamicInfo( 18, 2 ) | ||
| 233 | { | ||
| 234 | @Override | ||
| 235 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 236 | { | ||
| 237 | InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); | ||
| 238 | gatherIndexTree( indices, editor, accessor.getBootstrapIndex() ); | ||
| 239 | gatherIndexTree( indices, editor, accessor.getNameAndTypeIndex() ); | ||
| 240 | } | ||
| 241 | |||
| 242 | @Override | ||
| 243 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 244 | { | ||
| 245 | InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); | ||
| 246 | accessor.setBootstrapIndex( remapIndex( map, accessor.getBootstrapIndex() ) ); | ||
| 247 | accessor.setNameAndTypeIndex( remapIndex( map, accessor.getNameAndTypeIndex() ) ); | ||
| 248 | } | ||
| 249 | |||
| 250 | @Override | ||
| 251 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 252 | { | ||
| 253 | InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor( entry.getItem() ); | ||
| 254 | ConstInfoAccessor bootstrapEntry = pool.getItem( accessor.getBootstrapIndex() ); | ||
| 255 | ConstInfoAccessor nameAndTypeEntry = pool.getItem( accessor.getNameAndTypeIndex() ); | ||
| 256 | return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() | ||
| 257 | && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); | ||
| 258 | } | ||
| 259 | }; | ||
| 260 | |||
| 261 | private static Map<Integer,InfoType> m_types; | ||
| 262 | |||
| 263 | static | ||
| 264 | { | ||
| 265 | m_types = Maps.newTreeMap(); | ||
| 266 | for( InfoType type : values() ) | ||
| 267 | { | ||
| 268 | m_types.put( type.getTag(), type ); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | private int m_tag; | ||
| 273 | private int m_level; | ||
| 274 | |||
| 275 | private InfoType( int tag, int level ) | ||
| 276 | { | ||
| 277 | m_tag = tag; | ||
| 278 | m_level = level; | ||
| 279 | } | ||
| 280 | |||
| 281 | public int getTag( ) | ||
| 282 | { | ||
| 283 | return m_tag; | ||
| 284 | } | ||
| 285 | |||
| 286 | public int getLevel( ) | ||
| 287 | { | ||
| 288 | return m_level; | ||
| 289 | } | ||
| 290 | |||
| 291 | public void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, ConstInfoAccessor entry ) | ||
| 292 | { | ||
| 293 | // by default, do nothing | ||
| 294 | } | ||
| 295 | |||
| 296 | public void remapIndices( Map<Integer,Integer> map, ConstInfoAccessor entry ) | ||
| 297 | { | ||
| 298 | // by default, do nothing | ||
| 299 | } | ||
| 300 | |||
| 301 | public boolean subIndicesAreValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 302 | { | ||
| 303 | // by default, everything is good | ||
| 304 | return true; | ||
| 305 | } | ||
| 306 | |||
| 307 | public boolean selfIndexIsValid( ConstInfoAccessor entry, ConstPoolEditor pool ) | ||
| 308 | { | ||
| 309 | ConstInfoAccessor entryCheck = pool.getItem( entry.getIndex() ); | ||
| 310 | if( entryCheck == null ) | ||
| 311 | { | ||
| 312 | return false; | ||
| 313 | } | ||
| 314 | return entryCheck.getItem().equals( entry.getItem() ); | ||
| 315 | } | ||
| 316 | |||
| 317 | public static InfoType getByTag( int tag ) | ||
| 318 | { | ||
| 319 | return m_types.get( tag ); | ||
| 320 | } | ||
| 321 | |||
| 322 | public static List<InfoType> getByLevel( int level ) | ||
| 323 | { | ||
| 324 | List<InfoType> types = Lists.newArrayList(); | ||
| 325 | for( InfoType type : values() ) | ||
| 326 | { | ||
| 327 | if( type.getLevel() == level ) | ||
| 328 | { | ||
| 329 | types.add( type ); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | return types; | ||
| 333 | } | ||
| 334 | |||
| 335 | public static List<InfoType> getSortedByLevel( ) | ||
| 336 | { | ||
| 337 | List<InfoType> types = Lists.newArrayList(); | ||
| 338 | types.addAll( getByLevel( 0 ) ); | ||
| 339 | types.addAll( getByLevel( 1 ) ); | ||
| 340 | types.addAll( getByLevel( 2 ) ); | ||
| 341 | types.addAll( getByLevel( 3 ) ); | ||
| 342 | return types; | ||
| 343 | } | ||
| 344 | |||
| 345 | public static void gatherIndexTree( Collection<Integer> indices, ConstPoolEditor editor, int index ) | ||
| 346 | { | ||
| 347 | // add own index | ||
| 348 | indices.add( index ); | ||
| 349 | |||
| 350 | // recurse | ||
| 351 | ConstInfoAccessor entry = editor.getItem( index ); | ||
| 352 | entry.getType().gatherIndexTree( indices, editor, entry ); | ||
| 353 | } | ||
| 354 | |||
| 355 | private static int remapIndex( Map<Integer,Integer> map, int index ) | ||
| 356 | { | ||
| 357 | Integer newIndex = map.get( index ); | ||
| 358 | if( newIndex == null ) | ||
| 359 | { | ||
| 360 | newIndex = index; | ||
| 361 | } | ||
| 362 | return newIndex; | ||
| 363 | } | ||
| 364 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java new file mode 100644 index 0000000..41e1d04 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class ClassInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_nameIndex; | ||
| 19 | |||
| 20 | static | ||
| 21 | { | ||
| 22 | try | ||
| 23 | { | ||
| 24 | m_class = Class.forName( "javassist.bytecode.ClassInfo" ); | ||
| 25 | m_nameIndex = m_class.getDeclaredField( "name" ); | ||
| 26 | m_nameIndex.setAccessible( true ); | ||
| 27 | } | ||
| 28 | catch( Exception ex ) | ||
| 29 | { | ||
| 30 | throw new Error( ex ); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 35 | { | ||
| 36 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 37 | } | ||
| 38 | |||
| 39 | private Object m_item; | ||
| 40 | |||
| 41 | public ClassInfoAccessor( Object item ) | ||
| 42 | { | ||
| 43 | m_item = item; | ||
| 44 | } | ||
| 45 | |||
| 46 | public int getNameIndex( ) | ||
| 47 | { | ||
| 48 | try | ||
| 49 | { | ||
| 50 | return (Integer)m_nameIndex.get( m_item ); | ||
| 51 | } | ||
| 52 | catch( Exception ex ) | ||
| 53 | { | ||
| 54 | throw new Error( ex ); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | public void setNameIndex( int val ) | ||
| 59 | { | ||
| 60 | try | ||
| 61 | { | ||
| 62 | m_nameIndex.set( m_item, val ); | ||
| 63 | } | ||
| 64 | catch( Exception ex ) | ||
| 65 | { | ||
| 66 | throw new Error( ex ); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java new file mode 100644 index 0000000..3c3d3fa --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.io.ByteArrayInputStream; | ||
| 14 | import java.io.ByteArrayOutputStream; | ||
| 15 | import java.io.DataInputStream; | ||
| 16 | import java.io.DataOutputStream; | ||
| 17 | import java.io.IOException; | ||
| 18 | import java.io.PrintWriter; | ||
| 19 | import java.lang.reflect.Constructor; | ||
| 20 | import java.lang.reflect.Field; | ||
| 21 | import java.lang.reflect.Method; | ||
| 22 | |||
| 23 | import cuchaz.enigma.bytecode.InfoType; | ||
| 24 | |||
| 25 | public class ConstInfoAccessor | ||
| 26 | { | ||
| 27 | private static Class<?> m_class; | ||
| 28 | private static Field m_index; | ||
| 29 | private static Method m_getTag; | ||
| 30 | |||
| 31 | static | ||
| 32 | { | ||
| 33 | try | ||
| 34 | { | ||
| 35 | m_class = Class.forName( "javassist.bytecode.ConstInfo" ); | ||
| 36 | m_index = m_class.getDeclaredField( "index" ); | ||
| 37 | m_index.setAccessible( true ); | ||
| 38 | m_getTag = m_class.getMethod( "getTag" ); | ||
| 39 | m_getTag.setAccessible( true ); | ||
| 40 | } | ||
| 41 | catch( Exception ex ) | ||
| 42 | { | ||
| 43 | throw new Error( ex ); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | private Object m_item; | ||
| 48 | |||
| 49 | public ConstInfoAccessor( Object item ) | ||
| 50 | { | ||
| 51 | if( item == null ) | ||
| 52 | { | ||
| 53 | throw new IllegalArgumentException( "item cannot be null!" ); | ||
| 54 | } | ||
| 55 | m_item = item; | ||
| 56 | } | ||
| 57 | |||
| 58 | public ConstInfoAccessor( DataInputStream in ) | ||
| 59 | throws IOException | ||
| 60 | { | ||
| 61 | try | ||
| 62 | { | ||
| 63 | // read the entry | ||
| 64 | String className = in.readUTF(); | ||
| 65 | int oldIndex = in.readInt(); | ||
| 66 | |||
| 67 | // NOTE: ConstInfo instances write a type id (a "tag"), but they don't read it back | ||
| 68 | // so we have to read it here | ||
| 69 | in.readByte(); | ||
| 70 | |||
| 71 | Constructor<?> constructor = Class.forName( className ).getConstructor( DataInputStream.class, int.class ); | ||
| 72 | constructor.setAccessible( true ); | ||
| 73 | m_item = constructor.newInstance( in, oldIndex ); | ||
| 74 | } | ||
| 75 | catch( IOException ex ) | ||
| 76 | { | ||
| 77 | throw ex; | ||
| 78 | } | ||
| 79 | catch( Exception ex ) | ||
| 80 | { | ||
| 81 | throw new Error( ex ); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public Object getItem( ) | ||
| 86 | { | ||
| 87 | return m_item; | ||
| 88 | } | ||
| 89 | |||
| 90 | public int getIndex( ) | ||
| 91 | { | ||
| 92 | try | ||
| 93 | { | ||
| 94 | return (Integer)m_index.get( m_item ); | ||
| 95 | } | ||
| 96 | catch( Exception ex ) | ||
| 97 | { | ||
| 98 | throw new Error( ex ); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | public void setIndex( int val ) | ||
| 103 | { | ||
| 104 | try | ||
| 105 | { | ||
| 106 | m_index.set( m_item, val ); | ||
| 107 | } | ||
| 108 | catch( Exception ex ) | ||
| 109 | { | ||
| 110 | throw new Error( ex ); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | public int getTag( ) | ||
| 115 | { | ||
| 116 | try | ||
| 117 | { | ||
| 118 | return (Integer)m_getTag.invoke( m_item ); | ||
| 119 | } | ||
| 120 | catch( Exception ex ) | ||
| 121 | { | ||
| 122 | throw new Error( ex ); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | public ConstInfoAccessor copy( ) | ||
| 127 | { | ||
| 128 | return new ConstInfoAccessor( copyItem() ); | ||
| 129 | } | ||
| 130 | |||
| 131 | public Object copyItem( ) | ||
| 132 | { | ||
| 133 | // I don't know of a simpler way to copy one of these silly things... | ||
| 134 | try | ||
| 135 | { | ||
| 136 | // serialize the item | ||
| 137 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); | ||
| 138 | DataOutputStream out = new DataOutputStream( buf ); | ||
| 139 | write( out ); | ||
| 140 | |||
| 141 | // deserialize the item | ||
| 142 | DataInputStream in = new DataInputStream( new ByteArrayInputStream( buf.toByteArray() ) ); | ||
| 143 | Object item = new ConstInfoAccessor( in ).getItem(); | ||
| 144 | in.close(); | ||
| 145 | |||
| 146 | return item; | ||
| 147 | } | ||
| 148 | catch( Exception ex ) | ||
| 149 | { | ||
| 150 | throw new Error( ex ); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | public void write( DataOutputStream out ) | ||
| 155 | throws IOException | ||
| 156 | { | ||
| 157 | try | ||
| 158 | { | ||
| 159 | out.writeUTF( m_item.getClass().getName() ); | ||
| 160 | out.writeInt( getIndex() ); | ||
| 161 | |||
| 162 | Method method = m_item.getClass().getMethod( "write", DataOutputStream.class ); | ||
| 163 | method.setAccessible( true ); | ||
| 164 | method.invoke( m_item, out ); | ||
| 165 | } | ||
| 166 | catch( IOException ex ) | ||
| 167 | { | ||
| 168 | throw ex; | ||
| 169 | } | ||
| 170 | catch( Exception ex ) | ||
| 171 | { | ||
| 172 | throw new Error( ex ); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | @Override | ||
| 177 | public String toString( ) | ||
| 178 | { | ||
| 179 | try | ||
| 180 | { | ||
| 181 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); | ||
| 182 | PrintWriter out = new PrintWriter( buf ); | ||
| 183 | Method print = m_item.getClass().getMethod( "print", PrintWriter.class ); | ||
| 184 | print.setAccessible( true ); | ||
| 185 | print.invoke( m_item, out ); | ||
| 186 | out.close(); | ||
| 187 | return buf.toString().replace( "\n", "" ); | ||
| 188 | } | ||
| 189 | catch( Exception ex ) | ||
| 190 | { | ||
| 191 | throw new Error( ex ); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | public InfoType getType( ) | ||
| 196 | { | ||
| 197 | return InfoType.getByTag( getTag() ); | ||
| 198 | } | ||
| 199 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java new file mode 100644 index 0000000..169306a --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class InvokeDynamicInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_bootstrapIndex; | ||
| 19 | private static Field m_nameAndTypeIndex; | ||
| 20 | |||
| 21 | static | ||
| 22 | { | ||
| 23 | try | ||
| 24 | { | ||
| 25 | m_class = Class.forName( "javassist.bytecode.InvokeDynamicInfo" ); | ||
| 26 | m_bootstrapIndex = m_class.getDeclaredField( "bootstrap" ); | ||
| 27 | m_bootstrapIndex.setAccessible( true ); | ||
| 28 | m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndType" ); | ||
| 29 | m_nameAndTypeIndex.setAccessible( true ); | ||
| 30 | } | ||
| 31 | catch( Exception ex ) | ||
| 32 | { | ||
| 33 | throw new Error( ex ); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 38 | { | ||
| 39 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 40 | } | ||
| 41 | |||
| 42 | private Object m_item; | ||
| 43 | |||
| 44 | public InvokeDynamicInfoAccessor( Object item ) | ||
| 45 | { | ||
| 46 | m_item = item; | ||
| 47 | } | ||
| 48 | |||
| 49 | public int getBootstrapIndex( ) | ||
| 50 | { | ||
| 51 | try | ||
| 52 | { | ||
| 53 | return (Integer)m_bootstrapIndex.get( m_item ); | ||
| 54 | } | ||
| 55 | catch( Exception ex ) | ||
| 56 | { | ||
| 57 | throw new Error( ex ); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | public void setBootstrapIndex( int val ) | ||
| 62 | { | ||
| 63 | try | ||
| 64 | { | ||
| 65 | m_bootstrapIndex.set( m_item, val ); | ||
| 66 | } | ||
| 67 | catch( Exception ex ) | ||
| 68 | { | ||
| 69 | throw new Error( ex ); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | public int getNameAndTypeIndex( ) | ||
| 74 | { | ||
| 75 | try | ||
| 76 | { | ||
| 77 | return (Integer)m_nameAndTypeIndex.get( m_item ); | ||
| 78 | } | ||
| 79 | catch( Exception ex ) | ||
| 80 | { | ||
| 81 | throw new Error( ex ); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public void setNameAndTypeIndex( int val ) | ||
| 86 | { | ||
| 87 | try | ||
| 88 | { | ||
| 89 | m_nameAndTypeIndex.set( m_item, val ); | ||
| 90 | } | ||
| 91 | catch( Exception ex ) | ||
| 92 | { | ||
| 93 | throw new Error( ex ); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java new file mode 100644 index 0000000..2ee3aff --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class MemberRefInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_classIndex; | ||
| 19 | private static Field m_nameAndTypeIndex; | ||
| 20 | |||
| 21 | static | ||
| 22 | { | ||
| 23 | try | ||
| 24 | { | ||
| 25 | m_class = Class.forName( "javassist.bytecode.MemberrefInfo" ); | ||
| 26 | m_classIndex = m_class.getDeclaredField( "classIndex" ); | ||
| 27 | m_classIndex.setAccessible( true ); | ||
| 28 | m_nameAndTypeIndex = m_class.getDeclaredField( "nameAndTypeIndex" ); | ||
| 29 | m_nameAndTypeIndex.setAccessible( true ); | ||
| 30 | } | ||
| 31 | catch( Exception ex ) | ||
| 32 | { | ||
| 33 | throw new Error( ex ); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 38 | { | ||
| 39 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 40 | } | ||
| 41 | |||
| 42 | private Object m_item; | ||
| 43 | |||
| 44 | public MemberRefInfoAccessor( Object item ) | ||
| 45 | { | ||
| 46 | m_item = item; | ||
| 47 | } | ||
| 48 | |||
| 49 | public int getClassIndex( ) | ||
| 50 | { | ||
| 51 | try | ||
| 52 | { | ||
| 53 | return (Integer)m_classIndex.get( m_item ); | ||
| 54 | } | ||
| 55 | catch( Exception ex ) | ||
| 56 | { | ||
| 57 | throw new Error( ex ); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | public void setClassIndex( int val ) | ||
| 62 | { | ||
| 63 | try | ||
| 64 | { | ||
| 65 | m_classIndex.set( m_item, val ); | ||
| 66 | } | ||
| 67 | catch( Exception ex ) | ||
| 68 | { | ||
| 69 | throw new Error( ex ); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | public int getNameAndTypeIndex( ) | ||
| 74 | { | ||
| 75 | try | ||
| 76 | { | ||
| 77 | return (Integer)m_nameAndTypeIndex.get( m_item ); | ||
| 78 | } | ||
| 79 | catch( Exception ex ) | ||
| 80 | { | ||
| 81 | throw new Error( ex ); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public void setNameAndTypeIndex( int val ) | ||
| 86 | { | ||
| 87 | try | ||
| 88 | { | ||
| 89 | m_nameAndTypeIndex.set( m_item, val ); | ||
| 90 | } | ||
| 91 | catch( Exception ex ) | ||
| 92 | { | ||
| 93 | throw new Error( ex ); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java new file mode 100644 index 0000000..27b7aee --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class MethodHandleInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_kindIndex; | ||
| 19 | private static Field m_indexIndex; | ||
| 20 | |||
| 21 | static | ||
| 22 | { | ||
| 23 | try | ||
| 24 | { | ||
| 25 | m_class = Class.forName( "javassist.bytecode.MethodHandleInfo" ); | ||
| 26 | m_kindIndex = m_class.getDeclaredField( "refKind" ); | ||
| 27 | m_kindIndex.setAccessible( true ); | ||
| 28 | m_indexIndex = m_class.getDeclaredField( "refIndex" ); | ||
| 29 | m_indexIndex.setAccessible( true ); | ||
| 30 | } | ||
| 31 | catch( Exception ex ) | ||
| 32 | { | ||
| 33 | throw new Error( ex ); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 38 | { | ||
| 39 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 40 | } | ||
| 41 | |||
| 42 | private Object m_item; | ||
| 43 | |||
| 44 | public MethodHandleInfoAccessor( Object item ) | ||
| 45 | { | ||
| 46 | m_item = item; | ||
| 47 | } | ||
| 48 | |||
| 49 | public int getTypeIndex( ) | ||
| 50 | { | ||
| 51 | try | ||
| 52 | { | ||
| 53 | return (Integer)m_kindIndex.get( m_item ); | ||
| 54 | } | ||
| 55 | catch( Exception ex ) | ||
| 56 | { | ||
| 57 | throw new Error( ex ); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | public void setTypeIndex( int val ) | ||
| 62 | { | ||
| 63 | try | ||
| 64 | { | ||
| 65 | m_kindIndex.set( m_item, val ); | ||
| 66 | } | ||
| 67 | catch( Exception ex ) | ||
| 68 | { | ||
| 69 | throw new Error( ex ); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | public int getMethodRefIndex( ) | ||
| 74 | { | ||
| 75 | try | ||
| 76 | { | ||
| 77 | return (Integer)m_indexIndex.get( m_item ); | ||
| 78 | } | ||
| 79 | catch( Exception ex ) | ||
| 80 | { | ||
| 81 | throw new Error( ex ); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public void setMethodRefIndex( int val ) | ||
| 86 | { | ||
| 87 | try | ||
| 88 | { | ||
| 89 | m_indexIndex.set( m_item, val ); | ||
| 90 | } | ||
| 91 | catch( Exception ex ) | ||
| 92 | { | ||
| 93 | throw new Error( ex ); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java new file mode 100644 index 0000000..4cba6a2 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class MethodTypeInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_descriptorIndex; | ||
| 19 | |||
| 20 | static | ||
| 21 | { | ||
| 22 | try | ||
| 23 | { | ||
| 24 | m_class = Class.forName( "javassist.bytecode.MethodTypeInfo" ); | ||
| 25 | m_descriptorIndex = m_class.getDeclaredField( "descriptor" ); | ||
| 26 | m_descriptorIndex.setAccessible( true ); | ||
| 27 | } | ||
| 28 | catch( Exception ex ) | ||
| 29 | { | ||
| 30 | throw new Error( ex ); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 35 | { | ||
| 36 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 37 | } | ||
| 38 | |||
| 39 | private Object m_item; | ||
| 40 | |||
| 41 | public MethodTypeInfoAccessor( Object item ) | ||
| 42 | { | ||
| 43 | m_item = item; | ||
| 44 | } | ||
| 45 | |||
| 46 | public int getTypeIndex( ) | ||
| 47 | { | ||
| 48 | try | ||
| 49 | { | ||
| 50 | return (Integer)m_descriptorIndex.get( m_item ); | ||
| 51 | } | ||
| 52 | catch( Exception ex ) | ||
| 53 | { | ||
| 54 | throw new Error( ex ); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | public void setTypeIndex( int val ) | ||
| 59 | { | ||
| 60 | try | ||
| 61 | { | ||
| 62 | m_descriptorIndex.set( m_item, val ); | ||
| 63 | } | ||
| 64 | catch( Exception ex ) | ||
| 65 | { | ||
| 66 | throw new Error( ex ); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java new file mode 100644 index 0000000..03b4de3 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class NameAndTypeInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_nameIndex; | ||
| 19 | private static Field m_typeIndex; | ||
| 20 | |||
| 21 | static | ||
| 22 | { | ||
| 23 | try | ||
| 24 | { | ||
| 25 | m_class = Class.forName( "javassist.bytecode.NameAndTypeInfo" ); | ||
| 26 | m_nameIndex = m_class.getDeclaredField( "memberName" ); | ||
| 27 | m_nameIndex.setAccessible( true ); | ||
| 28 | m_typeIndex = m_class.getDeclaredField( "typeDescriptor" ); | ||
| 29 | m_typeIndex.setAccessible( true ); | ||
| 30 | } | ||
| 31 | catch( Exception ex ) | ||
| 32 | { | ||
| 33 | throw new Error( ex ); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 38 | { | ||
| 39 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 40 | } | ||
| 41 | |||
| 42 | private Object m_item; | ||
| 43 | |||
| 44 | public NameAndTypeInfoAccessor( Object item ) | ||
| 45 | { | ||
| 46 | m_item = item; | ||
| 47 | } | ||
| 48 | |||
| 49 | public int getNameIndex( ) | ||
| 50 | { | ||
| 51 | try | ||
| 52 | { | ||
| 53 | return (Integer)m_nameIndex.get( m_item ); | ||
| 54 | } | ||
| 55 | catch( Exception ex ) | ||
| 56 | { | ||
| 57 | throw new Error( ex ); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | public void setNameIndex( int val ) | ||
| 62 | { | ||
| 63 | try | ||
| 64 | { | ||
| 65 | m_nameIndex.set( m_item, val ); | ||
| 66 | } | ||
| 67 | catch( Exception ex ) | ||
| 68 | { | ||
| 69 | throw new Error( ex ); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | public int getTypeIndex( ) | ||
| 74 | { | ||
| 75 | try | ||
| 76 | { | ||
| 77 | return (Integer)m_typeIndex.get( m_item ); | ||
| 78 | } | ||
| 79 | catch( Exception ex ) | ||
| 80 | { | ||
| 81 | throw new Error( ex ); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public void setTypeIndex( int val ) | ||
| 86 | { | ||
| 87 | try | ||
| 88 | { | ||
| 89 | m_typeIndex.set( m_item, val ); | ||
| 90 | } | ||
| 91 | catch( Exception ex ) | ||
| 92 | { | ||
| 93 | throw new Error( ex ); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java new file mode 100644 index 0000000..5cdfce4 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | import java.lang.reflect.Field; | ||
| 14 | |||
| 15 | public class StringInfoAccessor | ||
| 16 | { | ||
| 17 | private static Class<?> m_class; | ||
| 18 | private static Field m_stringIndex; | ||
| 19 | |||
| 20 | static | ||
| 21 | { | ||
| 22 | try | ||
| 23 | { | ||
| 24 | m_class = Class.forName( "javassist.bytecode.StringInfo" ); | ||
| 25 | m_stringIndex = m_class.getDeclaredField( "string" ); | ||
| 26 | m_stringIndex.setAccessible( true ); | ||
| 27 | } | ||
| 28 | catch( Exception ex ) | ||
| 29 | { | ||
| 30 | throw new Error( ex ); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 35 | { | ||
| 36 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 37 | } | ||
| 38 | |||
| 39 | private Object m_item; | ||
| 40 | |||
| 41 | public StringInfoAccessor( Object item ) | ||
| 42 | { | ||
| 43 | m_item = item; | ||
| 44 | } | ||
| 45 | |||
| 46 | public int getStringIndex( ) | ||
| 47 | { | ||
| 48 | try | ||
| 49 | { | ||
| 50 | return (Integer)m_stringIndex.get( m_item ); | ||
| 51 | } | ||
| 52 | catch( Exception ex ) | ||
| 53 | { | ||
| 54 | throw new Error( ex ); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | public void setStringIndex( int val ) | ||
| 59 | { | ||
| 60 | try | ||
| 61 | { | ||
| 62 | m_stringIndex.set( m_item, val ); | ||
| 63 | } | ||
| 64 | catch( Exception ex ) | ||
| 65 | { | ||
| 66 | throw new Error( ex ); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java new file mode 100644 index 0000000..1cadd83 --- /dev/null +++ b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.bytecode.accessors; | ||
| 12 | |||
| 13 | public class Utf8InfoAccessor | ||
| 14 | { | ||
| 15 | private static Class<?> m_class; | ||
| 16 | |||
| 17 | static | ||
| 18 | { | ||
| 19 | try | ||
| 20 | { | ||
| 21 | m_class = Class.forName( "javassist.bytecode.Utf8Info" ); | ||
| 22 | } | ||
| 23 | catch( Exception ex ) | ||
| 24 | { | ||
| 25 | throw new Error( ex ); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | public static boolean isType( ConstInfoAccessor accessor ) | ||
| 30 | { | ||
| 31 | return m_class.isAssignableFrom( accessor.getItem().getClass() ); | ||
| 32 | } | ||
| 33 | } | ||