diff options
| author | 2014-07-27 22:33:21 -0400 | |
|---|---|---|
| committer | 2014-07-27 22:33:21 -0400 | |
| commit | d7321b5b0d38c575e54c770f7aa18dacbacab3c8 (patch) | |
| tree | ef4b3e0f83b1fe89125c2674fec023871e70c0d8 /src/cuchaz/enigma/bytecode | |
| parent | made gui responsive to caret position and show identifier info (diff) | |
| download | enigma-fork-d7321b5b0d38c575e54c770f7aa18dacbacab3c8.tar.gz enigma-fork-d7321b5b0d38c575e54c770f7aa18dacbacab3c8.tar.xz enigma-fork-d7321b5b0d38c575e54c770f7aa18dacbacab3c8.zip | |
added identifier renaming capability
copied some code over from M3L to handle the heavy bytecode magic.
It's ok... M3L will eventually depend on Enigma.
Completely restructured the mappings though. This way is better. =)
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 | } | ||