KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > yworks > yguard > obf > classfile > ClassFile


1 /**
2  * YGuard -- an obfuscation library for Java(TM) classfiles.
3  *
4  * Original Copyright (c) 1999 Mark Welsh (markw@retrologic.com)
5  * Modifications Copyright (c) 2002 yWorks GmbH (yguard@yworks.com)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * The author may be contacted at yguard@yworks.com
22  *
23  * Java and all Java-based marks are trademarks or registered
24  * trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
25  */

26 package com.yworks.yguard.obf.classfile;
27
28 import java.io.*;
29 import java.util.*;
30 import com.yworks.yguard.obf.*;
31 import java.lang.reflect.Modifier JavaDoc;
32 import com.yworks.yguard.Conversion;
33 import com.yworks.yguard.ParseException;
34
35 /**
36  * This is a representation of the data in a Java class-file (*.class).
37  * A ClassFile instance representing a *.class file can be generated
38  * using the static create(DataInput) method, manipulated using various
39  * operators, and persisted back using the write(DataOutput) method.
40  *
41  * @author Mark Welsh
42  */

43 public class ClassFile implements ClassConstants
44 {
45     // Constants -------------------------------------------------------------
46
public static final String JavaDoc SEP_REGULAR = "/";
47     public static final String JavaDoc SEP_INNER = "$";
48     public static final String JavaDoc LOG_DANGER_HEADER1 = "Methods are called which may break in obfuscated version at runtime.";
49     public static final String JavaDoc LOG_DANGER_HEADER2 = "Please review your source code to ensure that the dangerous methods are not intended";
50     public static final String JavaDoc LOG_DANGER_HEADER3 = "to act on classes which have been obfuscated.";
51     private static final String JavaDoc[] SEMI_DANGEROUS_CLASS_SIMPLENAME_DESCRIPTOR_ARRAY = {
52         "forName(Ljava/lang/String;)Ljava/lang/Class;",
53         "forName(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
54     };
55     private static final String JavaDoc[] DANGEROUS_CLASS_SIMPLENAME_DESCRIPTOR_ARRAY = {
56         "forName(Ljava/lang/String;)Ljava/lang/Class;",
57         "forName(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
58         "getDeclaredField(Ljava/lang/String;)Ljava/lang/reflect/Field;",
59         "getField(Ljava/lang/String;)Ljava/lang/reflect/Field;",
60         "getDeclaredMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
61         "getMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"
62     };
63     private static final String JavaDoc LOG_DANGER_CLASS_PRE = " Your class ";
64     private static final String JavaDoc LOG_DANGER_CLASS_MID = " calls the java.lang.Class method ";
65     private static final String JavaDoc[] DANGEROUS_CLASSLOADER_SIMPLENAME_DESCRIPTOR_ARRAY = {
66         "defineClass(Ljava/lang/String;[BII)Ljava/lang/Class;",
67         "findLoadedClass(Ljava/lang/String;)Ljava/lang/Class;",
68         "findSystemClass(Ljava/lang/String;)Ljava/lang/Class;",
69         "loadClass(Ljava/lang/String;)Ljava/lang/Class;",
70         "loadClass(Ljava/lang/String;Z)Ljava/lang/Class;"
71     };
72     private static final String JavaDoc LOG_DANGER_CLASSLOADER_PRE = " Your class ";
73     private static final String JavaDoc LOG_DANGER_CLASSLOADER_MID = " calls the java.lang.ClassLoader method ";
74
75
76     // Fields ----------------------------------------------------------------
77
private int u4magic;
78     private int u2minorVersion;
79     private int u2majorVersion;
80     private ConstantPool constantPool;
81     private int u2accessFlags;
82     private int u2thisClass;
83     private int u2superClass;
84     private int u2interfacesCount;
85     private int u2interfaces[];
86     private int u2fieldsCount;
87     private FieldInfo fields[];
88     private int u2methodsCount;
89     private MethodInfo methods[];
90     private int u2attributesCount;
91     private AttrInfo attributes[];
92
93     private boolean isUnkAttrGone = false;
94
95     private static boolean writeIdString = false;
96     private static CpInfo cpIdString = null;
97
98
99     // Class Methods ---------------------------------------------------------
100
/**
101      * Define a constant String to include in every output class file.
102      */

103     public static void defineIdString(String JavaDoc id)
104     {
105         if (id != null) {
106             writeIdString = true;
107             cpIdString = new Utf8CpInfo(id);
108         } else {
109             writeIdString = false;
110             cpIdString = null;
111         }
112     }
113
114     /**
115      * Create a new ClassFile from the class file format data in the DataInput
116      * stream.
117      *
118      * @throws IOException if class file is corrupt or incomplete
119      */

120     public static ClassFile create(DataInput din) throws java.io.IOException JavaDoc
121     {
122         if (din == null) throw new NullPointerException JavaDoc("No input stream was provided.");
123         ClassFile cf = new ClassFile();
124         cf.read(din);
125         return cf;
126     }
127
128     /** Parse a method or field descriptor into a list of parameter names (for methods)
129      * and a return type, in same format as the Class.forName() method returns . */

130     public static String JavaDoc[] parseDescriptor(String JavaDoc descriptor)
131     {
132         return parseDescriptor(descriptor, false);
133     }
134
135     /** Parse a method or field descriptor into a list of parameter names (for methods)
136      * and a return type, in same format as the Class.forName() method returns . */

137     public static String JavaDoc[] parseDescriptor(String JavaDoc descriptor, boolean isDisplay)
138     {
139         // Check for field descriptor
140
String JavaDoc[] names = null;
141         if (descriptor.charAt(0) != '(')
142         {
143             names = new String JavaDoc[1];
144             names[0] = descriptor;
145         }
146         else
147         {
148             // Method descriptor
149
Vector namesVec = new Vector();
150             descriptor = descriptor.substring(1);
151             String JavaDoc type = "";
152             while (descriptor.length() > 0)
153             {
154                 switch (descriptor.charAt(0))
155                 {
156                 case '[':
157                     type = type + "[";
158                     descriptor = descriptor.substring(1);
159                     break;
160
161                 case 'B':
162                 case 'C':
163                 case 'D':
164                 case 'F':
165                 case 'I':
166                 case 'J':
167                 case 'S':
168                 case 'Z':
169                 case 'V':
170                     namesVec.addElement(type + descriptor.substring(0, 1));
171                     descriptor = descriptor.substring(1);
172                     type = "";
173                     break;
174
175                 case ')':
176                     descriptor = descriptor.substring(1);
177                     break;
178
179                 case 'L':
180                     {
181                         int pos = descriptor.indexOf(';') + 1;
182                         namesVec.addElement(type + descriptor.substring(0, pos));
183                         descriptor = descriptor.substring(pos);
184                         type = "";
185                     }
186                     break;
187
188                 default:
189                     throw new IllegalArgumentException JavaDoc("Illegal field or method descriptor: " + descriptor);
190                 }
191             }
192             names = new String JavaDoc[namesVec.size()];
193             for (int i = 0; i < names.length; i++)
194             {
195                 names[i] = (String JavaDoc)namesVec.elementAt(i);
196             }
197         }
198
199         // Translate the names from JVM to Class.forName() format.
200
String JavaDoc[] translatedNames = new String JavaDoc[names.length];
201         for (int i = 0; i < names.length; i++)
202         {
203             translatedNames[i] = translateType(names[i], isDisplay);
204         }
205         return translatedNames;
206     }
207
208     /** Translate a type specifier from the internal JVM convention to the Class.forName() one. */
209     public static String JavaDoc translateType(String JavaDoc inName, boolean isDisplay)
210     {
211         String JavaDoc outName = null;
212         switch (inName.charAt(0))
213         {
214         case '[': // For array types, Class.forName() inconsistently uses the internal type name
215
// but with '/' --> '.'
216
if (!isDisplay)
217             {
218                 // return the Class.forName() form
219
outName = translate(inName);
220             }
221             else
222             {
223                 // return the pretty display form
224
outName = translateType(inName.substring(1), true) + "[]";
225             }
226             break;
227
228         case 'B':
229             outName = Byte.TYPE.getName();
230             break;
231
232         case 'C':
233             outName = Character.TYPE.getName();
234             break;
235
236         case 'D':
237             outName = Double.TYPE.getName();
238             break;
239
240         case 'F':
241             outName = Float.TYPE.getName();
242             break;
243
244         case 'I':
245             outName = Integer.TYPE.getName();
246             break;
247
248         case 'J':
249             outName = Long.TYPE.getName();
250             break;
251
252         case 'S':
253             outName = Short.TYPE.getName();
254             break;
255
256         case 'Z':
257             outName = Boolean.TYPE.getName();
258             break;
259
260         case 'V':
261             outName = Void.TYPE.getName();
262             break;
263
264         case 'L':
265             {
266                 int pos = inName.indexOf(';');
267                 outName = translate(inName.substring(1, inName.indexOf(';')));
268             }
269             break;
270
271         default:
272             throw new IllegalArgumentException JavaDoc("Illegal field or method name: " + inName);
273         }
274         return outName;
275     }
276
277     /** Translate a class name from the internal '/' convention to the regular '.' one. */
278     public static String JavaDoc translate(String JavaDoc name)
279     {
280         return name.replace('/', '.');
281     }
282
283
284     // Instance Methods ------------------------------------------------------
285
// Private constructor.
286
private ClassFile() {}
287
288     // Import the class data to internal representation.
289
private void read(DataInput din) throws java.io.IOException JavaDoc
290     {
291         // Read the class file
292
u4magic = din.readInt();
293         u2minorVersion = din.readUnsignedShort();
294         u2majorVersion = din.readUnsignedShort();
295
296         // Check this is a valid classfile that we can handle
297
if (u4magic != MAGIC)
298         {
299             throw new IOException("Invalid magic number in class file.");
300         }
301         if (u2majorVersion > MAJOR_VERSION)
302         {
303             throw new IOException("Incompatible version number for class file format: " + u2majorVersion+"."+u2minorVersion);
304         }
305
306
307         int u2constantPoolCount = din.readUnsignedShort();
308         CpInfo[] cpInfo = new CpInfo[u2constantPoolCount];
309         // Fill the constant pool, recalling the zero entry
310
// is not persisted, nor are the entries following a Long or Double
311
for (int i = 1; i < u2constantPoolCount; i++)
312         {
313             cpInfo[i] = CpInfo.create(din);
314             if ((cpInfo[i] instanceof LongCpInfo) ||
315                 (cpInfo[i] instanceof DoubleCpInfo))
316             {
317                 i++;
318             }
319         }
320         constantPool = new ConstantPool(this, cpInfo);
321
322         u2accessFlags = din.readUnsignedShort();
323         u2thisClass = din.readUnsignedShort();
324         u2superClass = din.readUnsignedShort();
325         u2interfacesCount = din.readUnsignedShort();
326         u2interfaces = new int[u2interfacesCount];
327         for (int i = 0; i < u2interfacesCount; i++)
328         {
329             u2interfaces[i] = din.readUnsignedShort();
330         }
331         u2fieldsCount = din.readUnsignedShort();
332         fields = new FieldInfo[u2fieldsCount];
333         for (int i = 0; i < u2fieldsCount; i++)
334         {
335             fields[i] = FieldInfo.create(din, this);
336         }
337         u2methodsCount = din.readUnsignedShort();
338         methods = new MethodInfo[u2methodsCount];
339         for (int i = 0; i < u2methodsCount; i++)
340         {
341             methods[i] = MethodInfo.create(din, this);
342         }
343         u2attributesCount = din.readUnsignedShort();
344         attributes = new AttrInfo[u2attributesCount];
345         for (int i = 0; i < u2attributesCount; i++)
346         {
347             attributes[i] = AttrInfo.create(din, this);
348         }
349     }
350     
351     public int getClassFileAccess(){
352       return u2accessFlags;
353     }
354    
355     public int getModifiers(){
356       int mods = 0;
357       if ((u2accessFlags & 0x0001) == 0x0001) mods |= Modifier.PUBLIC;
358       if ((u2accessFlags & 0x0010) == 0x0010) mods |= Modifier.FINAL;
359       if ((u2accessFlags & 0x0200) == 0x0200) mods |= Modifier.INTERFACE;
360       if ((u2accessFlags & 0x0400) == 0x0400) mods |= Modifier.ABSTRACT;
361       return mods;
362     }
363     
364     /** Return the name of this classfile. */
365     public String JavaDoc getName()
366     {
367         return toName(u2thisClass);
368     }
369
370     /** Return the name of this class's superclass. */
371     public String JavaDoc getSuper()
372     {
373         // This may be java/lang/Object, in which case there is no super
374
return (u2superClass == 0) ? null : toName(u2superClass);
375     }
376
377     /** Return the names of this class's interfaces. */
378     public String JavaDoc[] getInterfaces()
379     {
380         String JavaDoc[] interfaces = new String JavaDoc[u2interfacesCount];
381         for (int i = 0; i < u2interfacesCount; i++)
382         {
383             interfaces[i] = toName(u2interfaces[i]);
384         }
385         return interfaces;
386     }
387
388     // Convert a CP index to a class name.
389
private String JavaDoc toName(int u2index)
390     {
391         CpInfo classEntry = getCpEntry(u2index);
392         if (classEntry instanceof ClassCpInfo)
393         {
394             CpInfo nameEntry = getCpEntry(((ClassCpInfo)classEntry).getNameIndex());
395             if (nameEntry instanceof Utf8CpInfo)
396             {
397                 return ((Utf8CpInfo)nameEntry).getString();
398             }
399             else
400             {
401                 throw new ParseException("Inconsistent Constant Pool in class file.");
402             }
403         }
404         else
405         {
406             throw new ParseException("Inconsistent Constant Pool in class file.");
407         }
408     }
409
410     /** Return an enumeration of method name/descriptor pairs. */
411     public Enumeration getMethodEnum()
412     {
413         Vector vec = new Vector();
414         for (int i = 0; i < methods.length; i++)
415         {
416             vec.addElement(new Cons(new Cons(new Boolean JavaDoc(methods[i].isSynthetic()),
417                                              methods[i].getName()),
418                                     new Cons(methods[i].getDescriptor(),
419                                              new Integer JavaDoc(methods[i].getAccessFlags()))));
420         }
421         return vec.elements();
422     }
423
424     /** Return an enumeration of field name/descriptor pairs. */
425     public Enumeration getFieldEnum()
426     {
427         Vector vec = new Vector();
428         for (int i = 0; i < fields.length; i++)
429         {
430             vec.addElement(new Cons(new Cons(new Boolean JavaDoc(fields[i].isSynthetic()),
431                                              fields[i].getName()),
432                                     new Cons(fields[i].getDescriptor(),
433                                              new Integer JavaDoc(fields[i].getAccessFlags()))));
434         }
435         return vec.elements();
436     }
437
438     /** Lookup the entry in the constant pool and return as an Object. */
439     protected CpInfo getCpEntry(int cpIndex)
440     {
441         return constantPool.getCpEntry(cpIndex);
442     }
443
444     /** Check for methods which can break the obfuscated code, and log them to a String[]. */
445     public String JavaDoc[] logDangerousMethods(boolean replaceClassNameStrings)
446     {
447         Vector warningVec = new Vector();
448
449         // Need only check CONSTANT_Methodref entries of constant pool since
450
// dangerous methods belong to classes 'Class' and 'ClassLoader', not to interfaces.
451
for (Enumeration enumeration = constantPool.elements(); enumeration.hasMoreElements(); )
452         {
453             Object JavaDoc o = enumeration.nextElement();
454             if (o instanceof MethodrefCpInfo)
455             {
456                 // Get the method class name, simple name and descriptor
457
MethodrefCpInfo entry = (MethodrefCpInfo)o;
458                 ClassCpInfo classEntry = (ClassCpInfo)getCpEntry(entry.getClassIndex());
459                 String JavaDoc className = ((Utf8CpInfo)getCpEntry(classEntry.getNameIndex())).getString();
460                 NameAndTypeCpInfo ntEntry = (NameAndTypeCpInfo)getCpEntry(entry.getNameAndTypeIndex());
461                 String JavaDoc name = ((Utf8CpInfo)getCpEntry(ntEntry.getNameIndex())).getString();
462                 String JavaDoc descriptor = ((Utf8CpInfo)getCpEntry(ntEntry.getDescriptorIndex())).getString();
463
464                 // Check if this is on the proscribed list
465
if (className.equals("java/lang/Class") &&
466                     Tools.isInArray(name + descriptor, DANGEROUS_CLASS_SIMPLENAME_DESCRIPTOR_ARRAY))
467                 {
468                   if (replaceClassNameStrings){
469                     if (!Tools.isInArray(name+descriptor, SEMI_DANGEROUS_CLASS_SIMPLENAME_DESCRIPTOR_ARRAY)){
470                       String JavaDoc jMethod = Conversion.toJavaMethod(name, descriptor);
471                         warningVec.addElement(LOG_DANGER_CLASS_PRE + Conversion.toJavaClass(getName()) + LOG_DANGER_CLASS_MID + jMethod);
472                     }
473                   }
474                 }
475                 else if (Tools.isInArray(name + descriptor, DANGEROUS_CLASSLOADER_SIMPLENAME_DESCRIPTOR_ARRAY))
476                 {
477                   String JavaDoc jMethod = Conversion.toJavaMethod(name, descriptor);
478                     warningVec.addElement(LOG_DANGER_CLASSLOADER_PRE + Conversion.toJavaClass(getName()) + LOG_DANGER_CLASSLOADER_MID + jMethod);
479                 } else if ("class$(Ljava/lang/String;)Ljava/lang/Class;".equals(name+descriptor)){
480                   if (!replaceClassNameStrings){
481                      warningVec.addElement(LOG_DANGER_CLASS_PRE + Conversion.toJavaClass(getName()) +" seems to be using the '.class' construct!");
482                   }
483                 }
484             }
485         }
486
487         // Copy any warnings to a String[]
488
String JavaDoc[] warnings = new String JavaDoc[warningVec.size()];
489         for (int i = 0; i < warnings.length; i++)
490         {
491             warnings[i] = (String JavaDoc)warningVec.elementAt(i);
492         }
493         return warnings;
494     }
495
496     /** Check for methods which can break the obfuscated code, and log them. */
497     private static boolean hasHeader = false;
498     
499     public static void resetDangerHeader() {hasHeader = false;}
500     public void logDangerousMethods(PrintWriter log, boolean replaceClassNameStrings)
501     {
502         // Get any warnings and print them to the logfile
503
String JavaDoc[] warnings = logDangerousMethods(replaceClassNameStrings);
504         if (warnings != null && warnings.length > 0)
505         {
506             if (!hasHeader)
507             {
508                 log.println("<!-- WARNING");
509                 log.println(LOG_DANGER_HEADER1);
510                 log.println(LOG_DANGER_HEADER2);
511                 log.println(LOG_DANGER_HEADER3);
512                 
513                 Logger logger = Logger.getInstance();
514                 logger.warning(LOG_DANGER_HEADER1+'\n'+
515                                LOG_DANGER_HEADER2+'\n'+
516                                LOG_DANGER_HEADER3+'\n'+
517                                "See the logfile for a list of these classes and methods.");
518                 
519                 log.println("-->");
520                 hasHeader = true;
521             }
522             if (warnings.length > 0){
523               log.println("<!--");
524               for (int i = 0; i < warnings.length; i++)
525               {
526                   log.println(" " + warnings[i]);
527               }
528               log.println("-->");
529             }
530         }
531     }
532
533     /** Check for direct references to Utf8 constant pool entries. */
534     public void markUtf8Refs(ConstantPool pool)
535     {
536         try
537         {
538             // Check for references to Utf8 from outside the constant pool
539
for (int i = 0; i < fields.length; i++)
540             {
541                 fields[i].markUtf8Refs(pool);
542             }
543             for (int i = 0; i < methods.length; i++)
544             {
545                 methods[i].markUtf8Refs(pool); // also checks Code/LVT attrs here
546
}
547             for (int i = 0; i < attributes.length; i++)
548             {
549                 attributes[i].markUtf8Refs(pool); // checks InnerClasses, SourceFile and all attr names
550
}
551
552             // Now check for references from other CP entries
553
for (Enumeration enumeration = pool.elements(); enumeration.hasMoreElements(); )
554             {
555                 Object JavaDoc o = enumeration.nextElement();
556                 if (o instanceof NameAndTypeCpInfo ||
557                     o instanceof ClassCpInfo ||
558                     o instanceof StringCpInfo)
559                 {
560                     ((CpInfo)o).markUtf8Refs(pool);
561                 }
562             }
563         }
564         catch (ArrayIndexOutOfBoundsException JavaDoc e)
565         {
566             throw new ParseException("Inconsistent reference to constant pool.");
567         }
568     }
569
570     /** Check for direct references to NameAndType constant pool entries. */
571     public void markNTRefs(ConstantPool pool)
572     {
573         try
574         {
575             // Now check the method and field CP entries
576
for (Enumeration enumeration = pool.elements(); enumeration.hasMoreElements(); )
577             {
578                 Object JavaDoc o = enumeration.nextElement();
579                 if (o instanceof RefCpInfo)
580                 {
581                     ((CpInfo)o).markNTRefs(pool);
582                 }
583             }
584         }
585         catch (ArrayIndexOutOfBoundsException JavaDoc e)
586         {
587             throw new ParseException("Inconsistent reference to constant pool.");
588         }
589     }
590
591     /**
592      * Trim attributes from the classfile ('Code', 'Exceptions', 'ConstantValue'
593      * are preserved, all others except the list in the String[] are killed).
594      */

595     public void trimAttrsExcept(String JavaDoc[] extraAttrs)
596     {
597         // Merge additional attributes with required list
598
String JavaDoc[] keepAttrs = REQUIRED_ATTRS;
599         if (extraAttrs != null && extraAttrs.length > 0)
600         {
601             String JavaDoc[] tmp = new String JavaDoc[keepAttrs.length + extraAttrs.length];
602             System.arraycopy(keepAttrs, 0, tmp, 0, keepAttrs.length);
603             System.arraycopy(extraAttrs, 0, tmp, keepAttrs.length, extraAttrs.length);
604             keepAttrs = tmp;
605         }
606
607         // Traverse all attributes, removing all except those on 'keep' list
608
for (int i = 0; i < fields.length; i++)
609         {
610             fields[i].trimAttrsExcept(keepAttrs);
611         }
612         for (int i = 0; i < methods.length; i++)
613         {
614             methods[i].trimAttrsExcept(keepAttrs);
615         }
616         for (int i = 0; i < attributes.length; i++)
617         {
618             if (Tools.isInArray(attributes[i].getAttrName(), keepAttrs))
619             {
620                 attributes[i].trimAttrsExcept(keepAttrs);
621             }
622             else
623             {
624                 attributes[i] = null;
625             }
626         }
627
628         // Delete the marked attributes
629
AttrInfo[] left = new AttrInfo[attributes.length];
630         int j = 0;
631         for (int i = 0; i < attributes.length; i++)
632         {
633             if (attributes[i] != null)
634             {
635                 left[j++] = attributes[i];
636             }
637         }
638         attributes = new AttrInfo[j];
639         System.arraycopy(left, 0, attributes, 0, j);
640         u2attributesCount = j;
641
642         // Signal that unknown attributes are gone
643
isUnkAttrGone = true;
644
645         // Update the constant pool reference counts
646
constantPool.updateRefCount();
647     }
648     
649     public Map getInnerClassModifiers() {
650       Map map = new HashMap();
651         for (int i = 0; i < u2attributesCount; i++)
652         {
653             AttrInfo attrInfo = attributes[i];
654             if (attrInfo instanceof InnerClassesAttrInfo)
655             {
656                 InnerClassesInfo[] info = ((InnerClassesAttrInfo)attrInfo).getInfo();
657                 for (int j = 0; j < info.length; j++)
658                 {
659                   InnerClassesInfo ici = info[j];
660                   int index = info[j].getInnerNameIndex();
661                   if (index == 0){ // unnamed inner class
662
continue;
663                   }
664                   CpInfo cpInfo = getCpEntry(info[j].getInnerNameIndex());
665                   if (cpInfo instanceof Utf8CpInfo)
666                   {
667                       Utf8CpInfo utf = (Utf8CpInfo)cpInfo;
668                       String JavaDoc origClass = utf.getString();
669                       map.put(origClass, new Integer JavaDoc(ici.getModifiers()));
670                   }
671                 }
672             }
673         }
674         return map;
675     }
676     
677     /**
678      * Trim attributes from the classfile ('Code', 'Exceptions', 'ConstantValue'
679      * are preserved, all others are killed).
680      */

681     public void trimAttrs() {trimAttrsExcept(null);}
682     
683     private boolean containsDotClassMethodReference(){
684       // Need only check CONSTANT_Methodref entries of constant pool since
685
// dangerous methods belong to classes 'Class' and 'ClassLoader', not to interfaces.
686
for (Enumeration enumeration = constantPool.elements(); enumeration.hasMoreElements(); )
687         {
688             Object JavaDoc o = enumeration.nextElement();
689             if (o instanceof MethodrefCpInfo)
690             {
691                 // Get the method class name, simple name and descriptor
692
MethodrefCpInfo entry = (MethodrefCpInfo)o;
693                 ClassCpInfo classEntry = (ClassCpInfo)getCpEntry(entry.getClassIndex());
694                 String JavaDoc className = ((Utf8CpInfo)getCpEntry(classEntry.getNameIndex())).getString();
695                 NameAndTypeCpInfo ntEntry = (NameAndTypeCpInfo)getCpEntry(entry.getNameAndTypeIndex());
696                 String JavaDoc name = ((Utf8CpInfo)getCpEntry(ntEntry.getNameIndex())).getString();
697
698                 if (name.equals("class$")){
699                   String JavaDoc descriptor = ((Utf8CpInfo)getCpEntry(ntEntry.getDescriptorIndex())).getString();
700                   if (descriptor.equals("(Ljava/lang/String;)Ljava/lang/Class;")){
701                     return true;
702                   }
703                 }
704             }
705         }
706         return false;
707     }
708     
709     private boolean containsClassMethodReference(String JavaDoc cName, String JavaDoc des){
710       // Need only check CONSTANT_Methodref entries of constant pool since
711
// dangerous methods belong to classes 'Class' and 'ClassLoader', not to interfaces.
712
for (Enumeration enumeration = constantPool.elements(); enumeration.hasMoreElements(); )
713         {
714             Object JavaDoc o = enumeration.nextElement();
715             if (o instanceof MethodrefCpInfo)
716             {
717                 // Get the method class name, simple name and descriptor
718
MethodrefCpInfo entry = (MethodrefCpInfo)o;
719                 ClassCpInfo classEntry = (ClassCpInfo)getCpEntry(entry.getClassIndex());
720                 String JavaDoc className = ((Utf8CpInfo)getCpEntry(classEntry.getNameIndex())).getString();
721                 NameAndTypeCpInfo ntEntry = (NameAndTypeCpInfo)getCpEntry(entry.getNameAndTypeIndex());
722                 String JavaDoc name = ((Utf8CpInfo)getCpEntry(ntEntry.getNameIndex())).getString();
723                 String JavaDoc descriptor = ((Utf8CpInfo)getCpEntry(ntEntry.getDescriptorIndex())).getString();
724
725                 // Check if this is on the proscribed list
726
if (className.equals(cName) && (name+descriptor).equals(des)){
727                   return true;
728                 }
729             }
730         }
731         return false;
732     }
733
734     /** Remap the entities in the specified ClassFile. */
735     public void remap(NameMapper nm, boolean replaceClassNameStrings, PrintWriter log)
736     {
737         // Remap all the package/interface/class/method/field names
738
//
739
String JavaDoc thisClassName = ((Utf8CpInfo)getCpEntry(((ClassCpInfo)getCpEntry(u2thisClass)).getNameIndex())).getString();
740
741         // Remove unnecessary attributes from the class
742
final String JavaDoc[] attributesToKeep = nm.getAttrsToKeep(thisClassName);
743         if (attributesToKeep.length > 0)
744         {
745             trimAttrsExcept(attributesToKeep);
746         }
747         else
748         {
749             trimAttrs();
750         }
751
752         // Remap the 'inner name' reference of the 'InnerClasses' attribute
753
for (int i = 0; i < u2attributesCount; i++)
754         {
755             AttrInfo attrInfo = attributes[i];
756             if (attrInfo instanceof RuntimeVisibleAnnotationsAttrInfo){
757               remapAnnotations((RuntimeVisibleAnnotationsAttrInfo)attrInfo, nm);
758             } else if (attrInfo instanceof InnerClassesAttrInfo) {
759                 // For each inner class referemce,
760
InnerClassesInfo[] info = ((InnerClassesAttrInfo)attrInfo).getInfo();
761                 for (int j = 0; j < info.length; j++)
762                 {
763                     // Get the 'inner name' (it is a CONSTANT_Utf8)
764
CpInfo cpInfo = getCpEntry(info[j].getInnerNameIndex());
765                     if (cpInfo instanceof Utf8CpInfo)
766                     {
767                         // Get the remapped class name
768
Utf8CpInfo utf = (Utf8CpInfo)cpInfo;
769                         String JavaDoc origClass = utf.getString();
770
771                         // Only remap non-anonymous classes (anon are "")
772
if (!origClass.equals(""))
773                         {
774                             // Get the full inner class name
775
ClassCpInfo innerClassInfo = (ClassCpInfo)getCpEntry(info[j].getInnerClassIndex());
776                             String JavaDoc innerClassName = ((Utf8CpInfo)getCpEntry(innerClassInfo.getNameIndex())).getString();
777
778                             // It is the remapped simple name that must be stored, so truncate it
779
String JavaDoc remapClass = nm.mapClass(innerClassName);
780                             remapClass = remapClass.substring(remapClass.lastIndexOf('$') + 1);
781                             int remapIndex = constantPool.remapUtf8To(remapClass, info[j].getInnerNameIndex());
782                             info[j].setInnerNameIndex(remapIndex);
783                         }
784                     }
785                 }
786             } else if (attrInfo instanceof EnclosingMethodAttrInfo){
787               EnclosingMethodAttrInfo eam = (EnclosingMethodAttrInfo) attrInfo;
788               
789               // get the class name of the enclosing file:
790
CpInfo cpi = getCpEntry(eam.getClassIndex());
791               if (cpi instanceof ClassCpInfo){
792                 ClassCpInfo ccpi = (ClassCpInfo) cpi;
793                 cpi = getCpEntry(ccpi.getNameIndex());
794                 if (cpi instanceof Utf8CpInfo){
795                   Utf8CpInfo utf = (Utf8CpInfo) cpi;
796                   String JavaDoc origClass = utf.getString();
797
798                   // do not remap the ClassCpInfo now, it will be remapped automatically, later!
799
String JavaDoc remapClass = nm.mapClass(origClass);
800
801                   // if NT > 0 there is a valid NT to be remapped
802
if (eam.getNameAndTypeIndex() > 0) {
803                     cpi = getCpEntry(eam.getNameAndTypeIndex());
804                     if (cpi instanceof NameAndTypeCpInfo){
805                       NameAndTypeCpInfo nameTypeInfo = (NameAndTypeCpInfo) cpi;
806                       Utf8CpInfo refUtf = (Utf8CpInfo)getCpEntry(nameTypeInfo.getNameIndex());
807                       Utf8CpInfo descUtf = (Utf8CpInfo)getCpEntry(nameTypeInfo.getDescriptorIndex());
808                       String JavaDoc origMethodName = refUtf.getString();
809                       String JavaDoc origDescriptor = descUtf.getString();
810                       String JavaDoc remapRef = nm.mapMethod(origClass, origMethodName, origDescriptor);
811                       String JavaDoc remapDesc = nm.mapDescriptor(descUtf.getString());
812                       eam.setNameAndTypeIndex(remapNT(refUtf, remapRef, descUtf, remapDesc, nameTypeInfo, eam.getNameAndTypeIndex()));
813                     }
814                   }
815                 }
816               }
817             } else if (attrInfo instanceof SignatureAttrInfo){
818               remapSignature(nm, (SignatureAttrInfo) attrInfo);
819             } else if (attrInfo instanceof SourceFileAttrInfo) {
820               SourceFileAttrInfo source = (SourceFileAttrInfo) attrInfo;
821               CpInfo cpInfo = getCpEntry(source.getSourceFileIndex());
822               if (cpInfo instanceof Utf8CpInfo){
823                 Utf8CpInfo utf = (Utf8CpInfo) cpInfo;
824                 String JavaDoc origName = utf.getString();
825                 if (origName != null && origName.length() > 0){
826                   String JavaDoc newName = nm.mapSourceFile(thisClassName, origName);
827                   if (!origName.equals(newName)){
828                     if (newName == null || newName.length() < 1){
829                       AttrInfo[] newAttributes = new AttrInfo[attributes.length - 1];
830                       System.arraycopy(attributes, 0, newAttributes, 0, i);
831                       if (newAttributes.length > i){
832                         System.arraycopy(attributes, i + 1, newAttributes, i, newAttributes.length - i);
833                       }
834                       attributes = newAttributes;
835                       u2attributesCount--;
836                       i--;
837                       constantPool.decRefCount(source.getAttrNameIndex());
838                       utf.decRefCount();
839                     } else {
840                       int remapIndex = constantPool.remapUtf8To(newName, source.getSourceFileIndex());
841                       source.setSourceFileIndex(remapIndex);
842                     }
843                   }
844                 }
845               }
846             }
847         }
848
849         // Remap the 'name' and 'descriptor' references of the 'LocalVariableTable'
850
// attribute, in the 'Code' attribute of method structures.
851
for (int i = 0; i < u2methodsCount; i++)
852         {
853             for (int j = 0; j < methods[i].u2attributesCount; j++)
854             {
855                 final String JavaDoc methodName = methods[i].getName();
856                 final String JavaDoc descriptor = methods[i].getDescriptor();
857                 AttrInfo attrInfo = methods[i].attributes[j];
858                 
859                 if (attrInfo instanceof AnnotationDefaultAttrInfo){
860                   remapAnnotationDefault((AnnotationDefaultAttrInfo)attrInfo, nm);
861                 } else if (attrInfo instanceof RuntimeVisibleAnnotationsAttrInfo){
862                   remapAnnotations((RuntimeVisibleAnnotationsAttrInfo)attrInfo, nm);
863                 } else if (attrInfo instanceof RuntimeVisibleParameterAnnotationsAttrInfo){
864                   remapAnnotations((RuntimeVisibleParameterAnnotationsAttrInfo)attrInfo, nm);
865                 } else if (attrInfo instanceof SignatureAttrInfo){
866                   remapSignature(nm, (SignatureAttrInfo) attrInfo);
867                 } else if (attrInfo instanceof CodeAttrInfo) {
868                     CodeAttrInfo codeAttrInfo = (CodeAttrInfo)attrInfo;
869                     for (int k = 0; k < codeAttrInfo.u2attributesCount; k++)
870                     {
871                         AttrInfo innerAttrInfo = codeAttrInfo.attributes[k];
872                         if (innerAttrInfo instanceof LocalVariableTableAttrInfo)
873                         {
874                             LocalVariableTableAttrInfo lvtAttrInfo = (LocalVariableTableAttrInfo)innerAttrInfo;
875                             LocalVariableInfo[] lvts = lvtAttrInfo.getLocalVariableTable();
876                             for (int m = 0; m < lvts.length; m++)
877                             {
878                                 // Remap name
879
Utf8CpInfo nameUtf = (Utf8CpInfo)getCpEntry(lvts[m].getNameIndex());
880                                 String JavaDoc remapName = nm.mapLocalVariable(thisClassName, methodName, descriptor, nameUtf.getString());
881                                 if (remapName == null || remapName.length() < 1){
882                                   constantPool.decRefCount(lvts[m].getNameIndex());
883                                   constantPool.decRefCount(lvts[m].getDescriptorIndex());
884                                   LocalVariableInfo[] newArray = new LocalVariableInfo[lvts.length - 1];
885                                   System.arraycopy(lvts, 0, newArray, 0, m);
886                                   if (newArray.length > m ){
887                                     System.arraycopy(lvts, m + 1, newArray, m, newArray.length - m);
888                                   }
889                                   lvts = newArray;
890                                   lvtAttrInfo.setLocalVariableTable(lvts);
891                                   m--;
892                                 } else {
893                                   lvts[m].setNameIndex(constantPool.remapUtf8To(remapName, lvts[m].getNameIndex()));
894
895                                   // Remap descriptor
896
Utf8CpInfo descUtf = (Utf8CpInfo)getCpEntry(lvts[m].getDescriptorIndex());
897                                   String JavaDoc remapDesc = nm.mapDescriptor(descUtf.getString());
898                                   lvts[m].setDescriptorIndex(constantPool.remapUtf8To(remapDesc, lvts[m].getDescriptorIndex()));
899                                 }
900                             }
901                         } else if (innerAttrInfo instanceof LocalVariableTypeTableAttrInfo){
902                             LocalVariableTypeTableAttrInfo lvttAttrInfo = (LocalVariableTypeTableAttrInfo) innerAttrInfo;
903                             LocalVariableTypeInfo[] lvts = lvttAttrInfo.getLocalVariableTypeTable();
904                             for (int m = 0; m < lvts.length; m++){
905                               // Remap name
906
Utf8CpInfo nameUtf = (Utf8CpInfo)getCpEntry(lvts[m].getNameIndex());
907                               String JavaDoc remapName = nm.mapLocalVariable(thisClassName, methodName, descriptor, nameUtf.getString());
908                               if (remapName == null || remapName.length() < 1){
909                                 constantPool.decRefCount(lvts[m].getNameIndex());
910                                 constantPool.decRefCount(lvts[m].getSignatureIndex());
911                                 LocalVariableTypeInfo[] newArray = new LocalVariableTypeInfo[lvts.length - 1];
912                                 System.arraycopy(lvts, 0, newArray, 0, m);
913                                 if (newArray.length > m ){
914                                   System.arraycopy(lvts, m + 1, newArray, m, newArray.length - m);
915                                 }
916                                 lvts = newArray;
917                                 lvttAttrInfo.setLocalVariableTypeTable(lvts);
918                                 m--;
919                               } else {
920                                 lvts[m].setNameIndex(constantPool.remapUtf8To(remapName, lvts[m].getNameIndex()));
921
922                                 // Remap descriptor
923
Utf8CpInfo signatureUtf = (Utf8CpInfo)getCpEntry(lvts[m].getSignatureIndex());
924                                 String JavaDoc remapSig = nm.mapSignature(signatureUtf.getString());
925                                 lvts[m].setSignatureIndex(constantPool.remapUtf8To(remapSig, lvts[m].getSignatureIndex()));
926                               }
927                             }
928                         } else if (innerAttrInfo instanceof LineNumberTableAttrInfo) {
929                            LineNumberTableAttrInfo ltai = (LineNumberTableAttrInfo) innerAttrInfo;
930                            if (!nm.mapLineNumberTable(thisClassName, methodName, descriptor, ltai)){
931                               AttrInfo[] newAtt = new AttrInfo[codeAttrInfo.u2attributesCount - 1];
932                               System.arraycopy(codeAttrInfo.attributes, 0, newAtt, 0, k);
933                               if (newAtt.length > k ){
934                                 System.arraycopy(codeAttrInfo.attributes, k + 1, newAtt, k, newAtt.length - k);
935                               }
936                               codeAttrInfo.attributes = newAtt;
937                               codeAttrInfo.u2attributesCount--;
938                               k--;
939                            }
940                         }
941                     }
942                 }
943             }
944         }
945
946         // Go through all of class's fields and methods mapping 'name' and 'descriptor' references
947
for (int i = 0; i < u2fieldsCount; i++)
948         {
949             // Remap field 'name', unless it is 'Synthetic'
950
FieldInfo field = fields[i];
951             Utf8CpInfo nameUtf = (Utf8CpInfo)getCpEntry(field.getNameIndex());
952             if (!field.isSynthetic() || nameUtf.getString().startsWith("class$"))
953             {
954                 String JavaDoc remapName = nm.mapField(thisClassName, nameUtf.getString());
955                 field.setNameIndex(constantPool.remapUtf8To(remapName, field.getNameIndex()));
956             }
957
958             for (int j = 0; j < field.u2attributesCount; j++){
959               AttrInfo attrInfo = field.attributes[j];
960               if (attrInfo instanceof RuntimeVisibleAnnotationsAttrInfo){
961                 remapAnnotations((RuntimeVisibleAnnotationsAttrInfo)attrInfo, nm);
962               } else if (attrInfo instanceof SignatureAttrInfo){
963                 remapSignature(nm, (SignatureAttrInfo) attrInfo);
964               }
965             }
966
967             // Remap field 'descriptor'
968
Utf8CpInfo descUtf = (Utf8CpInfo)getCpEntry(field.getDescriptorIndex());
969             String JavaDoc remapDesc = nm.mapDescriptor(descUtf.getString());
970             field.setDescriptorIndex(constantPool.remapUtf8To(remapDesc, field.getDescriptorIndex()));
971         }
972         for (int i = 0; i < u2methodsCount; i++)
973         {
974             // Remap method 'name', unless it is 'Synthetic'
975
MethodInfo method = methods[i];
976             Utf8CpInfo descUtf = (Utf8CpInfo)getCpEntry(method.getDescriptorIndex());
977             if (!method.isSynthetic())
978             {
979                 Utf8CpInfo nameUtf = (Utf8CpInfo)getCpEntry(method.getNameIndex());
980                 String JavaDoc remapName = nm.mapMethod(thisClassName, nameUtf.getString(), descUtf.getString());
981                 method.setNameIndex(constantPool.remapUtf8To(remapName, method.getNameIndex()));
982             }
983
984             // Remap method 'descriptor'
985
String JavaDoc remapDesc = nm.mapDescriptor(descUtf.getString());
986             method.setDescriptorIndex(constantPool.remapUtf8To(remapDesc, method.getDescriptorIndex()));
987         }
988         
989         // check whether .class constructs of Class.forName calls reside in the code..
990
if (replaceClassNameStrings && nm instanceof ClassTree)
991 // &&
992
// (containsClassMethodReference("java/lang/Class","forName(Ljava/lang/String;)Ljava/lang/Class;")) ||
993
// (containsClassMethodReference("java/lang/Class","forName(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;")) ||
994
// (containsDotClassMethodReference()))
995
{
996             this.replaceConstantPoolStrings((ClassTree)nm);
997         }
998
999         // Remap all field/method names and descriptors in the constant pool (depends on class names)
1000
int currentCpLength = constantPool.length(); // constant pool can be extended (never contracted) during loop
1001
for (int i = 0; i < currentCpLength; i++)
1002        {
1003            CpInfo cpInfo = getCpEntry(i);
1004            if (cpInfo != null)
1005            {
1006                // If this is a CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref
1007
// get the CONSTANT_NameAndType and remap the name and the components of the
1008
// descriptor string.
1009
if (cpInfo instanceof RefCpInfo)
1010                {
1011                    // Get the unmodified class name
1012
ClassCpInfo classInfo = (ClassCpInfo)getCpEntry(((RefCpInfo)cpInfo).getClassIndex());
1013                    Utf8CpInfo classUtf = (Utf8CpInfo)getCpEntry(classInfo.getNameIndex());
1014                    String JavaDoc className = classUtf.getString();
1015
1016                    // Get the current N&T reference and its 'name' and 'descriptor' utf's
1017
int ntIndex = ((RefCpInfo)cpInfo).getNameAndTypeIndex();
1018                    
1019                    NameAndTypeCpInfo nameTypeInfo = (NameAndTypeCpInfo)getCpEntry(ntIndex);
1020                    Utf8CpInfo refUtf = (Utf8CpInfo)getCpEntry(nameTypeInfo.getNameIndex());
1021                    Utf8CpInfo descUtf = (Utf8CpInfo)getCpEntry(nameTypeInfo.getDescriptorIndex());
1022
1023                    // Get the remapped versions of 'name' and 'descriptor'
1024
String JavaDoc remapRef;
1025                    if (cpInfo instanceof FieldrefCpInfo)
1026                    {
1027                        remapRef = nm.mapField(className, refUtf.getString());
1028                        
1029                        // check if this is a compiler generated field
1030
// supporting the JDK1.2-or-later '.class' construct
1031
if (refUtf.getString().startsWith("class$"))
1032                        {
1033                          if (!replaceClassNameStrings){
1034                            String JavaDoc internalClassName = refUtf.getString().substring(6);
1035                            String JavaDoc realClassName = internalClassName.replace('$', '.');
1036                            internalClassName = internalClassName.replace('$','/');
1037                            String JavaDoc map = nm.mapClass(internalClassName);
1038                            if (map != null && !internalClassName.equals(map)){
1039                              String JavaDoc warning = realClassName +
1040                                          " shouldn't be obfuscated: it is most likely referenced as " + realClassName + ".class from " +
1041                                          Conversion.toJavaClass(thisClassName);
1042                              Logger.getInstance().warning(warning);
1043                              log.println("<!-- WARNING: " + warning + " -->");
1044                            }
1045                          }
1046                        }
1047                    }
1048                    else
1049                    {
1050                      remapRef = nm.mapMethod(className, refUtf.getString(), descUtf.getString());
1051                    }
1052                    String JavaDoc remapDesc = nm.mapDescriptor(descUtf.getString());
1053                    ((RefCpInfo)cpInfo).setNameAndTypeIndex(remapNT(refUtf, remapRef, descUtf, remapDesc, nameTypeInfo, ((RefCpInfo)cpInfo).getNameAndTypeIndex()));
1054                }
1055            }
1056        }
1057
1058        // Finally, remap all class references to Utf
1059
for (int i = 0; i < constantPool.length(); i++)
1060        {
1061            CpInfo cpInfo = getCpEntry(i);
1062            if (cpInfo != null)
1063            {
1064                // If this is CONSTANT_Class, remap the class-name Utf8 entry
1065
if (cpInfo instanceof ClassCpInfo)
1066                {
1067                    ClassCpInfo classInfo = (ClassCpInfo)cpInfo;
1068                    Utf8CpInfo utf = (Utf8CpInfo)getCpEntry(classInfo.getNameIndex());
1069                    String JavaDoc remapClass = nm.mapClass(utf.getString());
1070                    int remapIndex = constantPool.remapUtf8To(remapClass, classInfo.getNameIndex());
1071                    classInfo.setNameIndex(remapIndex);
1072                }
1073            }
1074        }
1075    }
1076    
1077    private void remapAnnotationDefault(AnnotationDefaultAttrInfo annotationDefault, NameMapper nm){
1078      remapElementValue(annotationDefault.elementValue, nm);
1079    }
1080    
1081    private void remapAnnotations(RuntimeVisibleAnnotationsAttrInfo annotation, NameMapper nm){
1082      final AnnotationInfo[] annotations = annotation.getAnnotations();
1083      if (annotations != null){
1084        for (int i = 0; i < annotations.length; i++){
1085          remapAnnotation(annotations[i], nm);
1086        }
1087      }
1088    }
1089    
1090    private void remapAnnotations(RuntimeVisibleParameterAnnotationsAttrInfo annotation, NameMapper nm){
1091      final ParameterAnnotationInfo[] annotations = annotation.getParameterAnnotations();
1092      if (annotations != null){
1093        for (int i = 0; i < annotations.length; i++){
1094          final ParameterAnnotationInfo info = annotations[i];
1095          final AnnotationInfo[] a = info.getAnnotations();
1096          if (a != null) {
1097            for (int j = 0; j < a.length; j++){
1098              remapAnnotation(a[j], nm);
1099            }
1100          }
1101        }
1102      }
1103    }
1104    
1105    private void remapAnnotation(AnnotationInfo annotation, NameMapper nm){
1106      CpInfo info = getCpEntry(annotation.u2typeIndex);
1107      if (info instanceof Utf8CpInfo){
1108        Utf8CpInfo utf = (Utf8CpInfo) info;
1109        String JavaDoc s = utf.getString();
1110        if (s.length() > 2 && s.charAt(0) == 'L' && s.charAt(s.length() - 1) == ';'){
1111          String JavaDoc fqn = s.substring(1, s.length() - 1);
1112          String JavaDoc newFqn = nm.mapClass(fqn);
1113          if (!fqn.equals(newFqn)){
1114            annotation.u2typeIndex = constantPool.remapUtf8To('L' + newFqn + ';', annotation.u2typeIndex);
1115          }
1116          final ElementValuePairInfo[] evp = annotation.getElementValuePairs();
1117          if (evp != null){
1118            for (int i = 0; i < evp.length; i++){
1119              final ElementValuePairInfo elementValuePair = evp[i];
1120              utf = (Utf8CpInfo) getCpEntry(elementValuePair.u2ElementNameIndex);
1121              String JavaDoc remapName = nm.mapAnnotationField(fqn, utf.getString());
1122              if (!remapName.equals(utf.getString())){
1123                elementValuePair.u2ElementNameIndex = constantPool.remapUtf8To(remapName, elementValuePair.u2ElementNameIndex);
1124              }
1125              final ElementValueInfo elementValue = elementValuePair.elementValue;
1126              remapElementValue(elementValue, nm);
1127            }
1128          }
1129        }
1130      }
1131    }
1132    
1133    private void remapElementValue(ElementValueInfo elementValue, NameMapper nm){
1134      switch (elementValue.u1Tag)
1135      {
1136        case 'B':
1137        case 'C':
1138        case 'D':
1139        case 'F':
1140        case 'I':
1141        case 'J':
1142        case 'S':
1143        case 'Z':
1144        case 's':
1145          // do nothing, this is a constant
1146
break;
1147        case 'e':
1148        // remap the type...
1149
{
1150          Utf8CpInfo utf = (Utf8CpInfo) getCpEntry(elementValue.u2typeNameIndex);
1151          String JavaDoc name = utf.getString();
1152          if (name.length() > 22 & name.charAt(0) == 'L' && name.charAt(name.length() - 1) == ';'){
1153            name = name.substring(1, name.length() - 1);
1154            String JavaDoc remapName = 'L' + nm.mapClass(name) + ';';
1155            elementValue.u2typeNameIndex = constantPool.remapUtf8To(remapName, elementValue.u2typeNameIndex);
1156          }
1157        }
1158        // leave the constant value in u2constNameIndex
1159
break;
1160        case 'c':
1161        {
1162          Utf8CpInfo utf = (Utf8CpInfo) getCpEntry(elementValue.u2cpIndex);
1163          String JavaDoc name = utf.getString();
1164          if (name.length() > 22 & name.charAt(0) == 'L' && name.charAt(name.length() - 1) == ';'){
1165            name = name.substring(1, name.length() - 1);
1166            String JavaDoc remapName = 'L' + nm.mapClass(name) + ';';
1167            elementValue.u2cpIndex = constantPool.remapUtf8To(remapName, elementValue.u2cpIndex);
1168          }
1169        }
1170        break;
1171        case '@':
1172          remapAnnotation(elementValue.nestedAnnotation, nm);
1173          break;
1174        case '[':
1175          for (int j = 0; j < elementValue.arrayValues.length; j++)
1176          {
1177            final ElementValueInfo evi = elementValue.arrayValues[j];
1178            remapElementValue(evi, nm);
1179          }
1180          break;
1181        default:
1182          throw new RuntimeException JavaDoc("Unknown type tag in annotation!");
1183      }
1184    }
1185    
1186    private void remapSignature(NameMapper nm, SignatureAttrInfo signature){
1187      CpInfo cpInfo = getCpEntry(signature.getSignatureIndex());
1188      if (cpInfo instanceof Utf8CpInfo){
1189        Utf8CpInfo utf = (Utf8CpInfo) cpInfo;
1190        String JavaDoc sig = utf.getString();
1191        String JavaDoc remapSignature = nm.mapSignature(sig);
1192        if (!sig.equals(remapSignature)){
1193          int remapIndex = constantPool.remapUtf8To(remapSignature, signature.getSignatureIndex());
1194          signature.setSignatureIndex(remapIndex);
1195        }
1196      }
1197    }
1198    
1199    private int remapNT(Utf8CpInfo refUtf, String JavaDoc remapRef, Utf8CpInfo descUtf, String JavaDoc remapDesc, NameAndTypeCpInfo nameTypeInfo, int nameAndTypeIndex){
1200      // If a remap is required, make a new N&T (increment ref count on 'name' and
1201
// 'descriptor', decrement original N&T's ref count, set new N&T ref count to 1),
1202
// remap new N&T's utf's
1203
if (!remapRef.equals(refUtf.getString()) ||
1204              !remapDesc.equals(descUtf.getString()))
1205      {
1206        // Get the new N&T guy
1207
NameAndTypeCpInfo newNameTypeInfo;
1208        if (nameTypeInfo.getRefCount() == 1)
1209        {
1210          newNameTypeInfo = nameTypeInfo;
1211        }
1212        else
1213        {
1214          // Create the new N&T info
1215
newNameTypeInfo = (NameAndTypeCpInfo)nameTypeInfo.clone();
1216          
1217          // Adjust its reference counts of its utf's
1218
((CpInfo)getCpEntry(newNameTypeInfo.getNameIndex())).incRefCount();
1219          ((CpInfo)getCpEntry(newNameTypeInfo.getDescriptorIndex())).incRefCount();
1220          
1221          // Append it to the Constant Pool, and
1222
// point the RefCpInfo entry to the new N&T data
1223
nameAndTypeIndex = constantPool.addEntry(newNameTypeInfo);
1224          
1225          // Adjust reference counts from RefCpInfo
1226
newNameTypeInfo.incRefCount();
1227          nameTypeInfo.decRefCount();
1228        }
1229        
1230        // Remap the 'name' and 'descriptor' utf's in N&T
1231
newNameTypeInfo.setNameIndex(constantPool.remapUtf8To(remapRef, newNameTypeInfo.getNameIndex()));
1232        newNameTypeInfo.setDescriptorIndex(constantPool.remapUtf8To(remapDesc, newNameTypeInfo.getDescriptorIndex()));
1233      }
1234      return nameAndTypeIndex;
1235    }
1236
1237    /**
1238     * goes through the constantpool, identifies classnamestrings and replaces
1239     * them appropriately if necessary
1240     */

1241    private void replaceConstantPoolStrings(ClassTree ct){
1242      for (Enumeration enumeration = constantPool.elements(); enumeration.hasMoreElements();){
1243        CpInfo cpi = (CpInfo) enumeration.nextElement();
1244        if (cpi instanceof Utf8CpInfo){
1245          Utf8CpInfo ui = (Utf8CpInfo) cpi;
1246          String JavaDoc s = ui.getString();
1247          boolean jikes = false;
1248          if (s.length()>5 && s.startsWith("[L") && s.endsWith(";")){
1249            s = s.substring(2, s.length()-1);
1250            jikes = true;
1251          }
1252          if (s.length()>2 && Character.isJavaIdentifierPart(s.charAt(s.length()-1)) &&
1253            s.indexOf(' ')<0 && s.indexOf('.')>0){
1254            Cl cl = ct.findClassForName(s);
1255            if (cl != null){
1256              if (!cl.getFullInName().equals(cl.getFullOutName())){
1257                if (jikes){
1258                  ui.setString("[L"+cl.getFullOutName().replace('/','.')+";");
1259                } else {
1260                  ui.setString(cl.getFullOutName().replace('/','.'));
1261                }
1262              }
1263            }
1264          }
1265        }
1266      }
1267    }
1268
1269    /** Export the representation to a DataOutput stream. */
1270    public void write(DataOutput dout) throws java.io.IOException JavaDoc
1271    {
1272        if (dout == null) throw new NullPointerException JavaDoc("No output stream was provided.");
1273        dout.writeInt(u4magic);
1274        dout.writeShort(u2minorVersion);
1275        dout.writeShort(u2majorVersion);
1276        dout.writeShort(constantPool.length() + (writeIdString ? 1 : 0));
1277        for (Enumeration enumeration = constantPool.elements(); enumeration.hasMoreElements(); )
1278        {
1279            CpInfo cpInfo = (CpInfo)enumeration.nextElement();
1280            if (cpInfo != null)
1281            {
1282                cpInfo.write(dout);
1283            }
1284        }
1285    if (writeIdString) {
1286        cpIdString.write(dout);
1287    }
1288        dout.writeShort(u2accessFlags);
1289        dout.writeShort(u2thisClass);
1290        dout.writeShort(u2superClass);
1291        dout.writeShort(u2interfacesCount);
1292        for (int i = 0; i < u2interfacesCount; i++)
1293        {
1294            dout.writeShort(u2interfaces[i]);
1295        }
1296        dout.writeShort(u2fieldsCount);
1297        for (int i = 0; i < u2fieldsCount; i++)
1298        {
1299            fields[i].write(dout);
1300        }
1301        dout.writeShort(u2methodsCount);
1302        for (int i = 0; i < u2methodsCount; i++)
1303        {
1304            methods[i].write(dout);
1305        }
1306        dout.writeShort(u2attributesCount);
1307        for (int i = 0; i < u2attributesCount; i++)
1308        {
1309            attributes[i].write(dout);
1310        }
1311    }
1312
1313    /** Dump the content of the class file to the specified file (used for debugging). */
1314    public void dump(PrintWriter pw)
1315    {
1316        pw.println("_____________________________________________________________________");
1317        pw.println("CLASS: " + getName());
1318        pw.println("Magic: " + Integer.toHexString(u4magic));
1319        pw.println("Minor version: " + Integer.toHexString(u2minorVersion));
1320        pw.println("Major version: " + Integer.toHexString(u2majorVersion));
1321        pw.println();
1322        pw.println("CP length: " + Integer.toHexString(constantPool.length()));
1323        for (int i = 0; i < constantPool.length(); i++)
1324        {
1325            CpInfo cpInfo = (CpInfo)constantPool.getCpEntry(i);
1326            if (cpInfo != null)
1327            {
1328                cpInfo.dump(pw, this, i);
1329            }
1330        }
1331        pw.println("Access: " + Integer.toHexString(u2accessFlags));
1332        pw.println("This class: " + getName());
1333        pw.println("Superclass: " + getSuper());
1334        pw.println("Interfaces count: " + Integer.toHexString(u2interfacesCount));
1335        for (int i = 0; i < u2interfacesCount; i++)
1336        {
1337            CpInfo info = getCpEntry(u2interfaces[i]);
1338            if (info == null)
1339            {
1340                pw.println(" Interface " + Integer.toHexString(i) + ": (null)");
1341            }
1342            else
1343            {
1344                pw.println(" Interface " + Integer.toHexString(i) + ": " + ((Utf8CpInfo)getCpEntry(((ClassCpInfo)info).getNameIndex())).getString());
1345            }
1346        }
1347        pw.println("Fields count: " + Integer.toHexString(u2fieldsCount));
1348        for (int i = 0; i < u2fieldsCount; i++)
1349        {
1350            ClassItemInfo info = fields[i];
1351            if (info == null)
1352            {
1353                pw.println(" Field " + Integer.toHexString(i) + ": (null)");
1354            }
1355            else
1356            {
1357                pw.println(" Field " + Integer.toHexString(i) + ": " + ((Utf8CpInfo)getCpEntry(info.getNameIndex())).getString() + " " + ((Utf8CpInfo)getCpEntry(info.getDescriptorIndex())).getString());
1358            }
1359            pw.println(" Attrs count: " + Integer.toHexString(info.u2attributesCount));
1360            for (int j = 0; j < info.u2attributesCount; j++)
1361            {
1362                pw.println(info.attributes[j]);
1363            }
1364        }
1365        pw.println("Methods count: " + Integer.toHexString(u2methodsCount));
1366        for (int i = 0; i < u2methodsCount; i++)
1367        {
1368            ClassItemInfo info = methods[i];
1369            if (info == null)
1370            {
1371                pw.println(" Method " + Integer.toHexString(i) + ": (null)");
1372            }
1373            else
1374            {
1375                pw.println(" Method " + Integer.toHexString(i) + ": " + ((Utf8CpInfo)getCpEntry(info.getNameIndex())).getString() + " " + ((Utf8CpInfo)getCpEntry(info.getDescriptorIndex())).getString() + " " + Integer.toHexString(info.getAccessFlags()));
1376            }
1377            pw.println(" Attrs count: " + Integer.toHexString(info.u2attributesCount));
1378            for (int j = 0; j < info.u2attributesCount; j++)
1379            {
1380                if (info.attributes[j] instanceof CodeAttrInfo){
1381                  pw.println(info.attributes[j]);
1382                  CodeAttrInfo cai = (CodeAttrInfo) info.attributes[j];
1383                  for (int k = 0; k < cai.u2attributesCount; k++){
1384                    pw.println(cai.attributes[k]);
1385                  }
1386                } else {
1387                  pw.println(info.attributes[j]);
1388                }
1389            }
1390        }
1391        pw.println("Attrs count: " + Integer.toHexString(u2attributesCount));
1392        for (int i = 0; i < u2attributesCount; i++)
1393        {
1394            pw.println(attributes[i]);
1395        }
1396    }
1397    
1398}
1399
Popular Tags