summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java')
-rw-r--r--src/cuchaz/enigma/bytecode/BytecodeIndexIterator.java180
1 files changed, 180 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 ******************************************************************************/
11package cuchaz.enigma.bytecode;
12
13import java.util.Iterator;
14
15import javassist.bytecode.BadBytecode;
16import javassist.bytecode.Bytecode;
17import javassist.bytecode.CodeAttribute;
18import javassist.bytecode.CodeIterator;
19import javassist.bytecode.Opcode;
20
21public 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}