| /* |
| * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| package ilib; |
| |
| class ClassReaderWriter implements RuntimeConstants { |
| |
| int codeAttributeIndex; |
| int lineNumberAttributeIndex; |
| int localVarAttributeIndex; |
| |
| private final byte[] orig; |
| private final byte[] gen; |
| private final int sectionLength; |
| |
| private static final int GROWTH_FACTOR = 2; |
| private static final int SECTIONS = 2; |
| private static final String codeAttributeName = "Code"; |
| private static final String lineNumberAttributeName = "LineNumberTable"; |
| private static final String localVarAttributeName = "LocalVariableTable"; |
| |
| private int[] genSectionPos = new int[SECTIONS]; |
| |
| private int inputPos = 0; |
| private int genPos = 0; |
| private int markPos = 0; |
| private int currentSection = 0; |
| |
| private String[] constantPool; |
| |
| ClassReaderWriter(byte[] orig) { |
| this.orig = orig; |
| sectionLength = orig.length * GROWTH_FACTOR; |
| gen = new byte[sectionLength * SECTIONS]; |
| for (int section = 0; section < SECTIONS; ++section) { |
| genSectionPos[section] = section * sectionLength; |
| } |
| } |
| |
| int setSection(int section) { |
| int prevSection = currentSection; |
| genSectionPos[prevSection] = genPos; |
| genPos = genSectionPos[section]; |
| currentSection = section; |
| return prevSection; |
| } |
| |
| byte[] result() { |
| int section; |
| int totalLength = 0; |
| |
| setSection(0); // save current section |
| |
| for (section = 0; section < SECTIONS; ++section) { |
| int sectionStart = section * sectionLength; |
| int sectionGenLength = genSectionPos[section] - sectionStart; |
| totalLength += sectionGenLength; |
| } |
| |
| byte[] newcf = new byte[totalLength]; |
| int written = 0; |
| for (section = 0; section < SECTIONS; ++section) { |
| int sectionStart = section * sectionLength; |
| int sectionGenLength = genSectionPos[section] - sectionStart; |
| System.arraycopy(gen, sectionStart, newcf, written, sectionGenLength); |
| written += sectionGenLength; |
| } |
| |
| return newcf; |
| } |
| |
| int readU1() { |
| return ((int)orig[inputPos++]) & 0xFF; |
| } |
| |
| int readU2() { |
| int res = readU1(); |
| return (res << 8) + readU1(); |
| } |
| |
| short readS2() { |
| int res = readU1(); |
| return (short)((res << 8) + readU1()); |
| } |
| |
| int readU4() { |
| int res = readU2(); |
| return (res << 16) + readU2(); |
| } |
| |
| void writeU1(int val) { |
| gen[genPos++] = (byte)val; |
| } |
| |
| void writeU2(int val) { |
| writeU1(val >> 8); |
| writeU1(val & 0xFF); |
| } |
| |
| void writeU4(int val) { |
| writeU2(val >> 16); |
| writeU2(val & 0xFFFF); |
| } |
| |
| int copyU1() { |
| int value = readU1(); |
| writeU1(value); |
| return value; |
| } |
| |
| int copyU2() { |
| int value = readU2(); |
| writeU2(value); |
| return value; |
| } |
| |
| int copyU4() { |
| int value = readU4(); |
| writeU4(value); |
| return value; |
| } |
| |
| void copy(int count) { |
| for (int i = 0; i < count; ++i) { |
| gen[genPos++] = orig[inputPos++]; |
| } |
| } |
| |
| void skip(int count) { |
| inputPos += count; |
| } |
| |
| byte[] readBytes(int count) { |
| byte[] bytes = new byte[count]; |
| for (int i = 0; i < count; ++i) { |
| bytes[i] = orig[inputPos++]; |
| } |
| return bytes; |
| } |
| |
| void writeBytes(byte[] bytes) { |
| for (int i = 0; i < bytes.length; ++i) { |
| gen[genPos++] = bytes[i]; |
| } |
| } |
| |
| byte[] inputBytes() { |
| return orig; |
| } |
| |
| int inputPosition() { |
| return inputPos; |
| } |
| |
| void setInputPosition(int pos) { |
| inputPos = pos; |
| } |
| |
| void markLocalPositionStart() { |
| markPos = inputPos; |
| } |
| |
| int localPosition() { |
| return inputPos - markPos; |
| } |
| |
| void rewind() { |
| setInputPosition(markPos); |
| } |
| |
| int generatedPosition() { |
| return genPos; |
| } |
| |
| void randomAccessWriteU2(int pos, int val) { |
| int savePos = genPos; |
| genPos = pos; |
| writeU2(val); |
| genPos = savePos; |
| } |
| |
| void randomAccessWriteU4(int pos, int val) { |
| int savePos = genPos; |
| genPos = pos; |
| writeU4(val); |
| genPos = savePos; |
| } |
| |
| String constantPoolString(int index) { |
| return constantPool[index]; |
| } |
| |
| void copyConstantPool(int constantPoolCount){ |
| // copy const pool |
| constantPool = new String[constantPoolCount]; |
| // index zero not in class file |
| for (int i = 1; i < constantPoolCount; ++i) { |
| int tag = readU1(); |
| writeU1(tag); |
| switch (tag) { |
| case CONSTANT_CLASS: |
| case CONSTANT_STRING: |
| copy(2); |
| break; |
| case CONSTANT_FIELD: |
| case CONSTANT_METHOD: |
| case CONSTANT_INTERFACEMETHOD: |
| case CONSTANT_INTEGER: |
| case CONSTANT_FLOAT: |
| case CONSTANT_NAMEANDTYPE: |
| copy(4); |
| break; |
| case CONSTANT_LONG: |
| case CONSTANT_DOUBLE: |
| copy(8); |
| ++i; // these take two CP entries - duh! |
| break; |
| case CONSTANT_UTF8: |
| int len = copyU2(); |
| byte[] utf8 = readBytes(len); |
| String str = null; // null to shut the compiler up |
| try { |
| str = new String(utf8, "UTF-8"); |
| } catch (Exception exc) { |
| throw new Error("CP exception: " + exc); |
| } |
| constantPool[i] = str; |
| if (str.equals(codeAttributeName)) { |
| codeAttributeIndex = i; |
| } else if (str.equals(lineNumberAttributeName)) { |
| lineNumberAttributeIndex = i; |
| } else if (str.equals(localVarAttributeName)) { |
| localVarAttributeIndex = i; |
| } |
| writeBytes(utf8); |
| break; |
| default: |
| throw new Error(i + " unexpected CP tag: " + tag); |
| } |
| } |
| } |
| |
| } |