001: /* ===========================================================================
002: * $RCSfile: StackMapFrameInfo.java,v $
003: * ===========================================================================
004: *
005: * RetroGuard -- an obfuscation package for Java classfiles.
006: *
007: * Copyright (c) 1998-2007 Mark Welsh (markw@retrologic.com)
008: *
009: * This program can be redistributed and/or modified under the terms of the
010: * Version 2 of the GNU General Public License as published by the Free
011: * Software Foundation.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: */
019:
020: package COM.rl.obf.classfile;
021:
022: import java.io.*;
023: import java.util.*;
024:
025: /**
026: * Representation of an Stack Map Frame entry.
027: *
028: * @author Mark Welsh
029: */
030: public class StackMapFrameInfo {
031: // Constants -------------------------------------------------------------
032: private static final int SAME_MIN = 0;
033: private static final int SAME_MAX = 63;
034: private static final int SAME_LOCALS_1_STACK_ITEM_MIN = 64;
035: private static final int SAME_LOCALS_1_STACK_ITEM_MAX = 127;
036: private static final int SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247;
037: private static final int CHOP_MIN = 248;
038: private static final int CHOP_MAX = 250;
039: private static final int SAME_FRAME_EXTENDED = 251;
040: private static final int APPEND_MIN = 252;
041: private static final int APPEND_MAX = 254;
042: private static final int FULL_FRAME = 255;
043:
044: // Fields ----------------------------------------------------------------
045: private int u1frameType;
046: private int u2offsetDelta;
047: private int u2numberOfStackItems;
048: private VerificationTypeInfo stack[];
049: private int u2numberOfLocals;
050: private VerificationTypeInfo locals[];
051:
052: // Class Methods ---------------------------------------------------------
053: public static StackMapFrameInfo create(DataInput din)
054: throws Exception {
055: StackMapFrameInfo smfi = new StackMapFrameInfo();
056: smfi.read(din);
057: return smfi;
058: }
059:
060: // Instance Methods ------------------------------------------------------
061: private StackMapFrameInfo() {
062: }
063:
064: private void read(DataInput din) throws Exception {
065: u1frameType = din.readUnsignedByte();
066: if (SAME_MIN <= u1frameType && u1frameType <= SAME_MAX) {
067: // nothing else to read
068: } else if (SAME_LOCALS_1_STACK_ITEM_MIN <= u1frameType
069: && u1frameType <= SAME_LOCALS_1_STACK_ITEM_MAX) {
070: u2numberOfStackItems = 1;
071: readStackItems(din);
072: } else if (u1frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
073: u2offsetDelta = din.readUnsignedShort();
074: u2numberOfStackItems = 1;
075: readStackItems(din);
076: } else if (CHOP_MIN <= u1frameType && u1frameType <= CHOP_MAX) {
077: u2offsetDelta = din.readUnsignedShort();
078: } else if (u1frameType == SAME_FRAME_EXTENDED) {
079: u2offsetDelta = din.readUnsignedShort();
080: } else if (APPEND_MIN <= u1frameType
081: && u1frameType <= APPEND_MAX) {
082: u2offsetDelta = din.readUnsignedShort();
083: u2numberOfLocals = 1 + u1frameType - APPEND_MIN;
084: readLocals(din);
085: } else if (u1frameType == FULL_FRAME) {
086: u2offsetDelta = din.readUnsignedShort();
087: u2numberOfLocals = din.readUnsignedShort();
088: readLocals(din);
089: u2numberOfStackItems = din.readUnsignedShort();
090: readStackItems(din);
091: }
092: }
093:
094: /** Check for Utf8 references to constant pool and mark them. */
095: protected void markUtf8Refs(ConstantPool pool) throws Exception {
096: for (int i = 0; i < u2numberOfStackItems; i++) {
097: stack[i].markUtf8Refs(pool);
098: }
099: for (int i = 0; i < u2numberOfLocals; i++) {
100: locals[i].markUtf8Refs(pool);
101: }
102: }
103:
104: /** Export the representation to a DataOutput stream. */
105: public void write(DataOutput dout) throws Exception {
106: dout.writeByte(u1frameType);
107: if (SAME_MIN <= u1frameType && u1frameType <= SAME_MAX) {
108: // nothing else to write
109: } else if (SAME_LOCALS_1_STACK_ITEM_MIN <= u1frameType
110: && u1frameType <= SAME_LOCALS_1_STACK_ITEM_MAX) {
111: writeStackItems(dout);
112: } else if (u1frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
113: dout.writeShort(u2offsetDelta);
114: writeStackItems(dout);
115: } else if (CHOP_MIN <= u1frameType && u1frameType <= CHOP_MAX) {
116: dout.writeShort(u2offsetDelta);
117: } else if (u1frameType == SAME_FRAME_EXTENDED) {
118: dout.writeShort(u2offsetDelta);
119: } else if (APPEND_MIN <= u1frameType
120: && u1frameType <= APPEND_MAX) {
121: dout.writeShort(u2offsetDelta);
122: writeLocals(dout);
123: } else if (u1frameType == FULL_FRAME) {
124: dout.writeShort(u2offsetDelta);
125: dout.writeShort(u2numberOfLocals);
126: writeLocals(dout);
127: dout.writeShort(u2numberOfStackItems);
128: writeStackItems(dout);
129: }
130: }
131:
132: // Read 'locals' VerificationTypeInfo
133: private void readLocals(DataInput din) throws Exception {
134: locals = new VerificationTypeInfo[u2numberOfLocals];
135: for (int i = 0; i < u2numberOfLocals; i++) {
136: locals[i] = VerificationTypeInfo.create(din);
137: }
138: }
139:
140: // Write 'locals' VerificationTypeInfo
141: private void writeLocals(DataOutput dout) throws Exception {
142: for (int i = 0; i < u2numberOfLocals; i++) {
143: locals[i].write(dout);
144: }
145: }
146:
147: // Read 'stack items' VerificationTypeInfo
148: private void readStackItems(DataInput din) throws Exception {
149: stack = new VerificationTypeInfo[u2numberOfStackItems];
150: for (int i = 0; i < u2numberOfStackItems; i++) {
151: stack[i] = VerificationTypeInfo.create(din);
152: }
153: }
154:
155: // Write 'stack items' VerificationTypeInfo
156: private void writeStackItems(DataOutput dout) throws Exception {
157: for (int i = 0; i < u2numberOfStackItems; i++) {
158: stack[i].write(dout);
159: }
160: }
161: }
|