alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/** Class that can enhance bytecode with information about alternative
 * superclass and access modifiers. It can also extract this information 
 * later when the class is about to be loaded into the VM.
 * 

* The additional information is added to attributes of the classfile (global attributes * and also member attributes) and as such the class remain compatible and * understandable for any VM. But if loaded by classloader that before defining * the class invokes: *

 *  byte[] arr = ...;
 *  arr = PatchByteCode.patch (arr); 
 * 
* The class is altered in its superclass and/or access modifiers. *

* The patching mechanism uses two attributes. ATTR_SUPERCLASS can be just * in global attributes pool (and only once), is of length 2 and contains index * into constant pool that contains definition of a Class that should become * the alternate superclass. Attribute ATTR_MEMBER can appear in global * attribute set and also in set of each member (field or method). It is of * length 2 and contains alternate value for access flags of the class or of * the field. *

* For purposes for speed, each patched class file has to end with bytes "nb". * This is achieved by finishing the patching process by adding third attribute * "org.netbeans.enhanced" with value "nb". As such the PatchByteCode.patch * can quickly check the byte array and process just those that need processing. * * @author Jaroslav Tulach */ public final class PatchByteCode { private static final String ATTR_SUPERCLASS = "org.netbeans.superclass"; // NOI18N private static final byte[] BYTE_SUPERCLASS; static { try { BYTE_SUPERCLASS = ATTR_SUPERCLASS.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException (ex.getMessage()); } } private static final String ATTR_INTERFACES = "org.netbeans.interfaces"; // NOI18N private static final byte[] BYTE_INTERFACES; static { try { BYTE_INTERFACES = ATTR_INTERFACES.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException (ex.getMessage()); } } private static final String ATTR_MEMBER = "org.netbeans.member"; // NOI18N private static final byte[] BYTE_MEMBER; static { try { BYTE_MEMBER = ATTR_MEMBER.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException (ex.getMessage()); } } private static final String ATTR_NAME = "org.netbeans.name"; // NOI18N private static final byte[] BYTE_NAME; static { try { BYTE_NAME = ATTR_NAME.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException (ex.getMessage()); } } private static final String ATTR_INIT = ""; // NOI18N private static final byte[] BYTE_INIT; static { try { BYTE_INIT = ATTR_INIT.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException (ex.getMessage()); } } private static final String ATTR_INIT_TYPE = "()V"; // NOI18N private static final byte[] BYTE_INIT_TYPE; static { try { BYTE_INIT_TYPE = ATTR_INIT_TYPE.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException (ex.getMessage()); } } private byte[] arr; private int cpCount; private int cpEnd; private int atCount; private int atEnd; /** the index of a string that matches the searched attribute */ private int superClassNameIndex; /** the possiton of found attribute */ private int superClassNameAttr; /** the index of a string that matches the searched attribute */ private int interfacesNameIndex; /** the possiton of found attribute */ private int interfacesNameAttr; /** the index of a string to patch members of a field */ private int memberNameIndex = -1; /** position of attribute the change the access rights of the class */ private int memberClassAttr = -1; /** index of UTF8 in constant pool*/ private int initIndex = -1; /** index of ()V UTF8 in constant pool */ private int initIndexType = -1; /** index of CONSTANT_NameAndType index for and ()V in pool */ private int initNameTypeIndex = -1; /** position of the method */ private int initAttr = -1; /** index of string that identifies the rename of a member */ private int renameNameIndex = -1; /** map that maps names of fields to their position in constant pool (String, int[1]) */ private HashMap nameIndexes; /** Creates a new instance of PatchByteCode * * @param nameIndexes hashmap from (String -> int[1]) */ private PatchByteCode(byte[] arr, HashMap nameIndexes) { this.arr = arr; this.nameIndexes = nameIndexes; // scan twice because of back references scan (); scan (); } /** Generates patch attribute into the classfile to * allow method patch to modify the superclass of this * class. * * @param arr the bytecode to change * @param args map with arguments. * @return new version of the bytecode if changed, otherwise null to signal that * no change has been made */ public static byte[] enhanceClass(byte[] arr, java.util.Map args) { if (isPatched (arr)) { // already patched return null; } String superClass = (String)args.get ("netbeans.superclass"); String interfaces = (String)args.get ("netbeans.interfaces"); List methods = (List)args.get ("netbeans.public"); // List List rename = (List)args.get ("netbeans.rename"); // List HashMap m; if (methods != null || rename != null) { m = new HashMap (); if (methods != null) { Iterator it = methods.iterator(); while (it.hasNext()) { m.put((String)it.next(), new int[1]); } } if (rename != null) { Iterator it = rename.iterator(); while (it.hasNext()) { m.put((String)it.next(), new int[1]); } } } else { m = null; } PatchByteCode pc = new PatchByteCode (arr, m); boolean patched = false; if (superClass != null) { int x = pc.addClass (superClass); byte[] sup = new byte[2]; writeU2 (sup, 0, x); pc.addAttribute (ATTR_SUPERCLASS, sup); patched = true; } if (interfaces != null) { java.util.ArrayList tokens = new java.util.ArrayList (); java.util.StringTokenizer tok = new java.util.StringTokenizer (interfaces, ","); while (tok.hasMoreElements()) { tokens.add (tok.nextElement()); } String[] ifaces = (String[])tokens.toArray (new String[0]); byte[] sup = new byte[2 + ifaces.length * 2]; writeU2 (sup, 0, ifaces.length); for (int i = 0; i < ifaces.length; i++) { int x = pc.addClass (ifaces[i]); writeU2 (sup, 2 + i * 2, x); } pc.addAttribute (ATTR_INTERFACES, sup); patched = true; } if (!pc.isPublic ()) { // will need patching pc.markPublic (); patched = true; } if (methods != null) { Iterator it = methods.iterator(); while (it.hasNext()) { patched |= pc.markMemberPublic((String)it.next()); } } if (rename != null) { Iterator it = rename.iterator(); while (it.hasNext()) { patched |= pc.renameMember((String)it.next(), (String)it.next()); } } if (patched) { byte[] patch = { 'n', 'b' // identification at the end of class file }; pc.addAttribute ("org.netbeans.enhanced", patch); } else { return null; } // otherwise do the patching return pc.getClassFile (); } /** Checks if the class has previously been enhanced by the * change of superclass attribute and if so, changes the bytecode * to reflect the change. * * @param arr the bytecode * @param name the class name * @return the enhanced bytecode */ public static byte[] patch (byte[] arr, String name) { if (!isPatched (arr)) return arr; /* if (System.getProperty("test.class") != null) { // NOI18N // Running in XTest (ide-mode executor). Provide a little debug info. System.err.println("Patching: " + name); // NOI18N } */ PatchByteCode pc = new PatchByteCode (arr, null); if (pc.superClassNameAttr > 0) { // let's patch int classindex = pc.readU2 (pc.superClassNameAttr + 6); writeU2 (pc.getClassFile(), pc.cpEnd + 4, classindex); if (pc.initAttr != -1) { // patch also CONSTANT_Methodref to superclass's writeU2 (pc.getClassFile (), pc.initAttr + 1, classindex); } } if (pc.memberClassAttr > 0) { // change the access rights of the class itself if (pc.readU4 (pc.memberClassAttr + 2) != 2) { throw new IllegalArgumentException ("Size of a attribute " + ATTR_MEMBER + " should be 2"); // NOI18N } // alternate access rights int access = pc.readU2 (pc.memberClassAttr + 6); int now = pc.readU2 (pc.cpEnd); writeU2 (pc.getClassFile (), pc.cpEnd, access); } if (pc.memberNameIndex > 0 || pc.renameNameIndex > 0) { // change access rights of fields pc.applyMemberAccessAndNameChanges (); } byte[] result = pc.getClassFile (); if (pc.interfacesNameAttr > 0) { // let's patch interfaces if necessary int numberOfIfaces = pc.readU2 (pc.interfacesNameAttr + 6); int currentIfaces = pc.readU2 (pc.cpEnd + 6); byte[] insert = new byte[result.length + numberOfIfaces * 2]; System.arraycopy(result, 0, insert, 0, pc.cpEnd + 6); System.arraycopy(result, pc.interfacesNameAttr + 8, insert, pc.cpEnd + 8, numberOfIfaces * 2); System.arraycopy(result, pc.cpEnd + 8, insert, pc.cpEnd + 8 + numberOfIfaces * 2, result.length - pc.cpEnd - 8); writeU2 (insert, pc.cpEnd + 6, numberOfIfaces + currentIfaces); result = insert; } return result; } /** Check if the byte code is patched. * @param arr the bytecode * @return true if patched */ private static boolean isPatched (byte[] arr) { if (arr == null || arr.length < 2) return false; int base = arr.length - 2; if (arr[base + 1] != 'b') return false; if (arr[base + 0] != 'n') return false; // // ok, looks like enhanced byte code // return true; } /** Gets the current byte array of the actual class file. * @return bytes of the class file */ private byte[] getClassFile () { return arr; } /** Creates new contant pool entry representing given class. * @param c name of the class * @return index of the entry */ private int addClass (String s) { int x = addConstant (s); byte[] t = { 7, 0, 0 }; writeU2 (t, 1, x); return addPool (t); } /** Adds a new string constant to the constant pool. * @param s the string to add * @return index of the constant */ private int addConstant (String s) { byte[] t; try { t = s.getBytes("utf-8"); // NOI18N } catch (java.io.UnsupportedEncodingException ex) { throw new IllegalStateException ("UTF-8 shall be always supported"); // NOI18N } byte[] add = new byte[t.length + 3]; System.arraycopy (t, 0, add, 3, t.length); add[0] = 1; // UTF8 contant writeU2 (add, 1, t.length); return addPool (add); } /** Adds this array of bytes as another entry into the constant pool */ private int addPool (byte[] add) { byte[] res = new byte[arr.length + add.length]; System.arraycopy (arr, 0, res, 0, cpEnd); // increments number of objects in contant pool int index = readU2 (cpCount); writeU2 (res, cpCount, index + 1); // adds the content System.arraycopy (add, 0, res, cpEnd, add.length); // and now add the rest of the original array System.arraycopy (arr, cpEnd, res, cpEnd + add.length, arr.length - cpEnd); arr = res; cpEnd += add.length; atCount += add.length; atEnd += add.length; // the index return index; } /** Checks whether the code is public. */ private boolean isPublic () { int x = readU2 (cpEnd); if ((x & 0x0001) != 0) { return true; } else { return false; } } /** Ensures that the class is public * @return true if really patched, false if not */ private boolean markPublic () { if (isPublic ()) { return false; } // make sure ATTR_MEMBER is in constant pool if (memberNameIndex == -1) { memberNameIndex = addConstant (ATTR_MEMBER); } int x = readU2 (cpEnd) | 0x0001; // make it public byte[] sup = new byte[2]; writeU2 (sup, 0, x); addAttribute (ATTR_MEMBER, sup); return true; } /** Makes method of field public and non final. * @param name name of the method to make public * @return true if really changed, false if it already was public */ private boolean markMemberPublic (String name) { int constantPoolIndex = ((int[])nameIndexes.get (name))[0]; int patchCount = 0; boolean modified = false; // make sure ATTR_MEMBER is in constant pool if (memberNameIndex == -1) { memberNameIndex = addConstant (ATTR_MEMBER); } int pos = cpEnd; pos += 6; // now add interfaces pos += 2 * readU2 (pos); // to add also the integer with interfaces pos += 2; for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) { // fields and then methods int fieldsOrMethods = readU2 (pos); pos += 2; while (fieldsOrMethods-- > 0) { // check the name int nameIndex = readU2 (pos + 2); if (nameIndex == constantPoolIndex) { // let's patch int access = readU2 (pos); if ((access & 0x0001) == 0 || (access & 0x0010) != 0) { // is not public or is final access = (access | 0x0001) & ~(0x0010 | 0x0002 | 0x0004); // increment the attributes count int cnt = readU2 (pos + 6) + 1; // byte[] res = new byte[arr.length + 2 + 6]; // copy the array before System.arraycopy(arr, 0, res, 0, pos + 6); // write the new count of attributes writeU2 (res, pos + 6, cnt); // write the attribute itself writeU2 (res, pos + 8, memberNameIndex); // name of attribute writeU4 (res, pos + 10, 2); // length writeU2 (res, pos + 14, access); // data - the "NetBeans" member modifier // copy the rest System.arraycopy(arr, pos + 8, res, pos + 8 + 6 + 2, arr.length - pos - 8); atEnd += 2 + 6; atCount += 2 + 6; arr = res; modified = true; } patchCount++; } pos += memberSize (pos, null); } } if (patchCount == 0) { throw new IllegalArgumentException ("Member " + name + " not found!"); } return modified; } /** Marks a field or method as one that should be renamed. * @param name name of the member * @param rename new name of the member * @return true if really changed, false if it already was renamed */ private boolean renameMember (String name, String rename) { int constantPoolIndex = ((int[])nameIndexes.get (name))[0]; int newPoolIndex; { int[] arr = (int[])nameIndexes.get (rename); if (arr != null && arr[0] > 0) { newPoolIndex = arr[0]; } else { newPoolIndex = addConstant (rename); nameIndexes.put (rename, new int[] { newPoolIndex }); } } int patchCount = 0; boolean modified = false; // make sure ATTR_MEMBER is in constant pool if (renameNameIndex == -1) { renameNameIndex = addConstant (ATTR_NAME); } int pos = cpEnd; pos += 6; // now add interfaces pos += 2 * readU2 (pos); // to add also the integer with interfaces pos += 2; for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) { // fields and then methods int fieldsOrMethods = readU2 (pos); pos += 2; while (fieldsOrMethods-- > 0) { // check the name int nameIndex = readU2 (pos + 2); if (nameIndex == constantPoolIndex) { // check whether the rename attribute is not there yet int[] attributes = { -1, -1 }; memberSize (pos, attributes); if (attributes[1] == -1) { // let's patch attribute is not there yet // increment the attributes count int cnt = readU2 (pos + 6) + 1; // byte[] res = new byte[arr.length + 2 + 6]; // copy the array before System.arraycopy(arr, 0, res, 0, pos + 6); // write the new count of attributes writeU2 (res, pos + 6, cnt); // write the attribute itself writeU2 (res, pos + 8, renameNameIndex); // name of attribute writeU4 (res, pos + 10, 2); // length writeU2 (res, pos + 14, newPoolIndex); // index to the new name // copy the rest System.arraycopy(arr, pos + 8, res, pos + 8 + 6 + 2, arr.length - pos - 8); atEnd += 2 + 6; atCount += 2 + 6; arr = res; modified = true; } patchCount++; } pos += memberSize (pos, null); } } if (patchCount == 0) { throw new IllegalArgumentException ("Member " + name + " not found!"); } return modified; } /** Checks all members of the class to find out whether they need patching * of access rights. If so, patches them. */ private void applyMemberAccessAndNameChanges () { int[] result = new int[2]; int pos = cpEnd; pos += 6; // now add interfaces pos += 2 * readU2 (pos); // to add also the integer with interfaces pos += 2; for (int fieldsAndMethods = 0; fieldsAndMethods < 2; fieldsAndMethods++) { // fields and then methods int fieldsOrMethods = readU2 (pos); pos += 2; while (fieldsOrMethods-- > 0) { result[0] = -1; result[1] = -1; int size = memberSize(pos, result); if (result[0] != -1) { // we will do patching if (readU4 (result[0] + 2) != 2) { throw new IllegalArgumentException ("Size of a attribute " + ATTR_MEMBER + " should be 2"); // NOI18N } // alternate access rights int access = readU2 (result[0] + 6); writeU2 (arr, pos, access); } if (result[1] != -1) { // we will do patching if (readU4 (result[1] + 2) != 2) { throw new IllegalArgumentException ("Size of a attribute " + ATTR_NAME + " should be 2"); // NOI18N } // alternate name of the member int newName = readU2 (result[1] + 6); writeU2 (arr, pos + 2, newName); } pos += size; } } } /** Adds an attribute to the class file. * @param name name of the attribute to add * @param b the bytes representing the attribute */ private void addAttribute (String name, byte[] b) { int index = -1; if (ATTR_SUPERCLASS.equals (name) && superClassNameIndex > 0) { index = superClassNameIndex; } if (ATTR_MEMBER.equals (name) && memberNameIndex > 0) { index = memberNameIndex; } if (ATTR_INTERFACES.equals (name) && interfacesNameIndex > 0) { index = interfacesNameIndex; } if (index == -1) { // register new attribute index = addConstant (name); } byte[] res = new byte[arr.length + b.length + 6]; System.arraycopy(arr, 0, res, 0, arr.length); writeU2 (res, arr.length, index); writeU4 (res, arr.length + 2, b.length); int begin = arr.length + 6; System.arraycopy(b, 0, res, begin, b.length); atEnd += b.length + 6; writeU2 (res, atCount, readU2 (atCount) + 1); arr = res; } /** Gets i-th element from the array. */ private int get (int pos) { if (pos >= arr.length) { throw new ArrayIndexOutOfBoundsException ("Size: " + arr.length + " index: " + pos); } int x = arr[pos]; return x >= 0 ? x : 256 + x; } /** Scans the file to find out important possitions * @return size of the bytecode */ private void scan () { if (get (0) != 0xCA && get (1) != 0xFE && get (2) != 0xBA && get (3) != 0xBE) { throw new IllegalStateException ("Not a class file!"); // NOI18N } int pos = 10; // count of items in CP is here cpCount = 8; int cp = readU2 (8); for (int[] i = { 1 }; i[0] < cp; i[0]++) { // i[0] can be incremented in constantPoolSize int len = constantPoolSize (pos, i); pos += len; } // list item in constant pool cpEnd = pos; pos += 6; // now add interfaces pos += 2 * readU2 (pos); // to add also the integer with interfaces pos += 2; // fields int fields = readU2 (pos); pos += 2; while (fields-- > 0) { pos += memberSize (pos, null); } int methods = readU2 (pos); pos += 2; while (methods-- > 0) { pos += memberSize (pos, null); } // count of items in Attributes is here int[] memberAccess = { -1, -1 }; atCount = pos; int attrs = readU2 (pos); pos += 2; while (attrs-- > 0) { pos += attributeSize (pos, memberAccess); } if (memberAccess[0] != -1) { // we need to update the name of class memberClassAttr = memberAccess[0]; } // end of attributes atEnd = pos; } private int readU2 (int pos) { int b1 = get (pos); int b2 = get (pos + 1); return b1 * 256 + b2; } private int readU4 (int pos) { return readU2 (pos) * 256 * 256 + readU2 (pos + 2); } private static void writeU2 (byte[] arr, int pos, int value) { int v1 = (value & 0xff00) >> 8; int v2 = value & 0xff; if (v1 < 0) v1 += 256; if (v2 < 0) v2 += 256; arr[pos] = (byte)v1; arr[pos + 1] = (byte)v2; } private static void writeU4 (byte[] arr, int pos, int value) { writeU2 (arr, pos, (value & 0xff00) >> 16); writeU2 (arr, pos + 2, value & 0x00ff); } /** @param pos position to read from * @param cnt[0] index in the pool that we are now reading */ private int constantPoolSize (int pos, int[] cnt) { switch (get (pos)) { case 7: // CONSTANT_Class case 8: // CONSTANT_String return 3; case 12: // CONSTANT_NameAndType // check for and ()V invocation int nameIndex = readU2 (pos + 1); if (nameIndex == initIndex) { int descriptorIndex = readU2 (pos + 3); if (descriptorIndex == initIndexType) { if (initNameTypeIndex > 0 && initNameTypeIndex != cnt[0]) { throw new IllegalArgumentException ("Second initialization of name type index"); // NOI18N } initNameTypeIndex = cnt[0]; } } return 5; case 10: // CONSTANT_Methodref // special check for invocation int classname = readU2 (pos + 1); int nameAndType = readU2 (pos + 3); if (nameAndType == initNameTypeIndex) { // found call to int superclass = readU2 (cpEnd + 4); if (superclass == classname) { // it is call to our superclass if (initAttr > 0 && initAttr != pos) { throw new IllegalStateException ("Second initialization of position of invocation"); // NOI18N } initAttr = pos; } } return 5; case 9: // CONSTANT_Fieldref case 11: // CONSTANT_InterfaceMethodref case 3: // CONSTANT_Integer case 4: // CONSTANT_Float return 5; case 5: // CONSTANT_Long case 6: // CONSTANT_Double // after long and double the next entry in CP is unusable cnt[0]++; return 9; case 1: // CONSTANT_Utf8 int len = readU2 (pos + 1); if (compareUtfEntry (BYTE_INIT, pos)) { if (initIndex > 0 && initIndex != cnt[0]) { throw new IllegalArgumentException ("Second initialization of " + ATTR_INIT); // NOI18N } initIndex = cnt[0]; } if (compareUtfEntry (BYTE_INIT_TYPE, pos)) { if (initIndexType > 0 && initIndexType != cnt[0]) { throw new IllegalArgumentException ("Second initialization of " + ATTR_INIT_TYPE); // NOI18N } initIndexType = cnt[0]; } if (compareUtfEntry (BYTE_SUPERCLASS, pos)) { // we have found the attribute if (superClassNameIndex > 0 && superClassNameIndex != cnt[0]) { throw new IllegalStateException (ATTR_SUPERCLASS + " registered for the second time!"); // NOI18N } superClassNameIndex = cnt[0]; } if (compareUtfEntry (BYTE_INTERFACES, pos)) { // we have found the attribute if (interfacesNameIndex > 0 && interfacesNameIndex != cnt[0]) { throw new IllegalStateException (ATTR_INTERFACES + " registered for the second time!"); // NOI18N } interfacesNameIndex = cnt[0]; } if (compareUtfEntry (BYTE_MEMBER, pos)) { // we have found the attribute if (memberNameIndex > 0 && memberNameIndex != cnt[0]) { throw new IllegalStateException (ATTR_MEMBER + " registered for the second time!"); // NOI18N } memberNameIndex = cnt[0]; } if (compareUtfEntry (BYTE_NAME, pos)) { // we have found the attribute if (renameNameIndex > 0 && renameNameIndex != cnt[0]) { throw new IllegalStateException (ATTR_NAME + " registered for the second time!"); // NOI18N } renameNameIndex = cnt[0]; } if (nameIndexes != null) { // check the name in the table String s; try { s = new String (arr, pos + 3, len, "utf-8"); // NOI18N } catch (UnsupportedEncodingException ex) { throw new IllegalStateException ("utf-8 is always supported"); // NOI18N } int[] index = (int[])nameIndexes.get (s); if (index != null) { index[0] = cnt[0]; } } // ok, exit return len + 3; default: throw new IllegalStateException ("Unknown pool type: " + get (pos)); // NOI18N } } private int memberSize (int pos, int[] containsPatchAttributeAndRename) { int s = 8; int name = readU2 (pos + 2); int cnt = readU2 (pos + 6); while (cnt-- > 0) { s += attributeSize (pos + s, containsPatchAttributeAndRename); } return s; } /** Into the containsPatchAttribute (if not null) it adds the * index of structure of attribute ATTR_MEMBER. */ private int attributeSize (int pos, int[] containsPatchAttributeAndRename) { // index to the name attr int name = readU2 (pos); if (name == superClassNameIndex) { if (superClassNameAttr > 0 && superClassNameAttr != pos) { throw new IllegalStateException ("Two attributes with name " + ATTR_SUPERCLASS); // NOI18N } // we found the attribute superClassNameAttr = pos; } if (name == interfacesNameIndex) { if (interfacesNameAttr > 0 && interfacesNameAttr != pos) { throw new IllegalStateException ("Two attributes with name " + ATTR_INTERFACES); // NOI18N } // we found the attribute interfacesNameAttr = pos; } if (name == memberNameIndex && containsPatchAttributeAndRename != null) { if (containsPatchAttributeAndRename[0] != -1) { throw new IllegalStateException ("Second attribute " + ATTR_MEMBER); // NOI18N } containsPatchAttributeAndRename[0] = pos; } if (name == renameNameIndex && containsPatchAttributeAndRename != null) { if (containsPatchAttributeAndRename[1] != -1) { throw new IllegalStateException ("Second attribute " + ATTR_NAME); // NOI18N } containsPatchAttributeAndRename[1] = pos; } int len = readU4 (pos + 2); return len + 6; } /** Compares arrays. */ private boolean compareUtfEntry (byte[] pattern, int pos) { int len = readU2 (pos + 1); if (pattern.length != len) { return false; } int base = pos + 3; // we are searching for an attribute with given name for (int i = 0; i < len; i++) { if (pattern[i] != arr[base + i]) { // regular exit return false; } } return true; } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.