KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > obfuscator > ClassIdentifier


1 /* ClassIdentifier Copyright (C) 1999-2002 Jochen Hoenicke.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; see the file COPYING. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: ClassIdentifier.java.in,v 1.6.2.5 2002/05/28 17:34:14 hoenicke Exp $
18  */

19
20 package jode.obfuscator;
21 import jode.GlobalOptions;
22 import jode.bytecode.*;
23 import jode.obfuscator.modules.ModifierMatcher;
24 import java.util.Comparator JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.LinkedList JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.lang.UnsupportedOperationException JavaDoc;
34
35 import java.lang.reflect.Modifier JavaDoc;
36 import java.security.MessageDigest JavaDoc;
37 import java.security.NoSuchAlgorithmException JavaDoc;
38 import java.io.OutputStream JavaDoc;
39 import java.io.DataOutputStream JavaDoc;
40 import java.io.IOException JavaDoc;
41
42 public class ClassIdentifier extends Identifier {
43     PackageIdentifier pack;
44     String JavaDoc name;
45     String JavaDoc fullName;
46     ClassInfo info;
47     String JavaDoc superName;
48     String JavaDoc[] ifaceNames;
49
50     List JavaDoc fieldIdents, methodIdents;
51     List JavaDoc knownSubClasses = new LinkedList JavaDoc();
52     List JavaDoc virtualReachables = new LinkedList JavaDoc();
53
54     public ClassIdentifier(PackageIdentifier pack, String JavaDoc fullName,
55                String JavaDoc name, ClassInfo info) {
56     super(name);
57     this.pack = pack;
58     this.fullName = fullName;
59     this.name = name;
60     this.info = info;
61     }
62
63     public void addSubClass(ClassIdentifier ci) {
64     knownSubClasses.add(ci);
65     for(Iterator JavaDoc i = virtualReachables.iterator(); i.hasNext(); )
66         ci.reachableReference((Reference) i.next(), true);
67     }
68
69     private FieldIdentifier findField(String JavaDoc name, String JavaDoc typeSig) {
70     for (Iterator JavaDoc i = fieldIdents.iterator(); i.hasNext(); ) {
71         FieldIdentifier ident = (FieldIdentifier) i.next();
72         if (ident.getName().equals(name)
73         && ident.getType().equals(typeSig))
74         return ident;
75     }
76     return null;
77     }
78
79     private MethodIdentifier findMethod(String JavaDoc name, String JavaDoc typeSig) {
80     for (Iterator JavaDoc i = methodIdents.iterator(); i.hasNext(); ) {
81         MethodIdentifier ident = (MethodIdentifier) i.next();
82         if (ident.getName().equals(name)
83         && ident.getType().equals(typeSig))
84         return ident;
85     }
86     return null;
87     }
88
89     public void reachableReference(Reference ref, boolean isVirtual) {
90     boolean found = false;
91     for (Iterator JavaDoc i = getChilds(); i.hasNext(); ) {
92         Identifier ident = (Identifier) i.next();
93         if (ref.getName().equals(ident.getName())
94         && ref.getType().equals(ident.getType())) {
95         ident.setReachable();
96         found = true;
97         }
98     }
99     if (!found) {
100         // This means that the method is inherited from parent and
101
// must be marked as reachable there, (but not virtual).
102
// Consider following:
103
// A method in Collection and AbstractCollection is not reachable
104
// but it is reachable in Set and not implemented in AbstractSet
105
// In that case the method must be marked reachable in
106
// AbstractCollection.
107
ClassIdentifier superIdent = Main.getClassBundle()
108         .getClassIdentifier(info.getSuperclass().getName());
109         if (superIdent != null)
110         superIdent.reachableReference(ref, false);
111     }
112         
113     if (isVirtual) {
114         for(Iterator JavaDoc i = virtualReachables.iterator(); i.hasNext(); ) {
115         Reference prevRef = (Reference) i.next();
116         if (prevRef.getName().equals(ref.getName())
117             && prevRef.getType().equals(ref.getType()))
118             // already handled.
119
return;
120         }
121         for (Iterator JavaDoc i = knownSubClasses.iterator(); i.hasNext(); )
122         ((ClassIdentifier)i.next())
123             .reachableReference(ref, false);
124         virtualReachables.add(ref);
125     }
126     }
127
128     public void chainMethodIdentifier(Identifier chainIdent) {
129     String JavaDoc name = chainIdent.getName();
130     String JavaDoc typeSig = chainIdent.getType();
131     for (Iterator JavaDoc i = methodIdents.iterator(); i.hasNext(); ) {
132         Identifier ident = (Identifier) i.next();
133         if (ident.getName().equals(name)
134         && ident.getType().equals(typeSig))
135         chainIdent.addShadow(ident);
136     }
137     }
138
139     /**
140      * This is partly taken from the classpath project.
141      */

142     public long calcSerialVersionUID() {
143     final MessageDigest JavaDoc md;
144     try {
145         md = MessageDigest.getInstance("SHA");
146     } catch (NoSuchAlgorithmException JavaDoc ex) {
147         ex.printStackTrace();
148         GlobalOptions.err.println("Can't calculate serialVersionUID");
149         return 0L;
150     }
151     OutputStream JavaDoc digest = new OutputStream JavaDoc() {
152
153         public void write(int b) {
154         md.update((byte) b);
155         }
156
157         public void write(byte[] data, int offset, int length) {
158         md.update(data, offset, length);
159         }
160     };
161     DataOutputStream JavaDoc out = new DataOutputStream JavaDoc(digest);
162     try {
163         out.writeUTF(info.getName());
164         
165         int modifiers = info.getModifiers();
166         // just look at interesting bits
167
modifiers = modifiers & ( Modifier.ABSTRACT | Modifier.FINAL
168                       | Modifier.INTERFACE | Modifier.PUBLIC );
169         out.writeInt(modifiers);
170         
171         ClassInfo[] interfaces
172         = (ClassInfo[]) info.getInterfaces().clone();
173         Arrays.sort(interfaces, new Comparator JavaDoc() {
174         public int compare( Object JavaDoc o1, Object JavaDoc o2 ) {
175             return ((ClassInfo)o1).getName()
176             .compareTo(((ClassInfo)o2).getName());
177         }
178         });
179         for( int i=0; i < interfaces.length; i++ ) {
180         out.writeUTF(interfaces[i].getName());
181         }
182         
183         
184         Comparator JavaDoc identCmp = new Comparator JavaDoc() {
185         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
186             Identifier i1 = (Identifier)o1;
187             Identifier i2 = (Identifier)o2;
188             String JavaDoc name1 = i1.getName();
189             String JavaDoc name2 = i2.getName();
190             boolean special1 = (name1.equals("<init>")
191                     || name1.equals("<clinit>"));
192             boolean special2 = (name2.equals("<init>")
193                     || name2.equals("<clinit>"));
194             // Put constructors at the beginning
195
if (special1 != special2) {
196             return special1 ? -1 : 1;
197             }
198
199             int comp = i1.getName().compareTo(i2.getName());
200             if (comp != 0) {
201             return comp;
202             } else {
203             return i1.getType().compareTo(i2.getType());
204             }
205         }
206         };
207
208         List JavaDoc fields = Arrays.asList(fieldIdents.toArray());
209         List JavaDoc methods = Arrays.asList(methodIdents.toArray());
210         Collections.sort(fields, identCmp);
211         Collections.sort(methods, identCmp);
212         
213         for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
214         FieldIdentifier field = (FieldIdentifier) i.next();
215         modifiers = field.info.getModifiers();
216         if ((modifiers & Modifier.PRIVATE) != 0
217             && (modifiers & (Modifier.STATIC
218                      | Modifier.TRANSIENT)) != 0)
219             continue;
220         
221         out.writeUTF(field.getName());
222         out.writeInt(modifiers);
223         out.writeUTF(field.getType());
224         }
225         for (Iterator JavaDoc i = methods.iterator(); i.hasNext(); ) {
226         MethodIdentifier method = (MethodIdentifier) i.next();
227         modifiers = method.info.getModifiers();
228         if( Modifier.isPrivate(modifiers))
229             continue;
230         
231         out.writeUTF(method.getName());
232         out.writeInt(modifiers);
233         
234         // the replacement of '/' with '.' was needed to make computed
235
// SUID's agree with those computed by JDK
236
out.writeUTF(method.getType().replace('/', '.'));
237         }
238         
239         out.close();
240
241         byte[] sha = md.digest();
242         long result = 0;
243         for (int i=0; i < 8; i++) {
244         result += (long)(sha[i] & 0xFF) << (8 * i);
245         }
246         return result;
247     } catch (IOException JavaDoc ex) {
248         ex.printStackTrace();
249         GlobalOptions.err.println("Can't calculate serialVersionUID");
250         return 0L;
251     }
252     }
253
254     public void addSUID() {
255     /* add a field serializableVersionUID if not existent */
256     long serialVersion = calcSerialVersionUID();
257     FieldInfo UIDField = new FieldInfo
258         (info, "serialVersionUID", "J",
259          Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
260     UIDField.setConstant(new Long JavaDoc(serialVersion));
261     FieldIdentifier UIDident = new FieldIdentifier(this, UIDField);
262     fieldIdents.add(UIDident);
263     UIDident.setPreserved();
264     }
265
266     public boolean isSerializable() {
267     return ClassInfo.forName("java.io.Serializable")
268         .implementedBy(info);
269     }
270     public boolean hasSUID() {
271     return (findField("serialVersionUID", "J") != null);
272     }
273         
274     /**
275      * Marks the package as preserved, too.
276      */

277     protected void setSinglePreserved() {
278     pack.setPreserved();
279     }
280
281     public void setSingleReachable() {
282     super.setSingleReachable();
283     Main.getClassBundle().analyzeIdentifier(this);
284     }
285     
286     public void analyzeSuperClasses(ClassInfo superclass) {
287     while (superclass != null) {
288         
289         ClassIdentifier superident = Main.getClassBundle()
290         .getClassIdentifier(superclass.getName());
291         if (superident != null) {
292         superident.addSubClass(this);
293         } else {
294         // all virtual methods in superclass are reachable now!
295
String JavaDoc clazzType = ("L"+superclass.getName().replace('.', '/')
296                     +";").intern();
297         MethodInfo[] topmethods = superclass.getMethods();
298         for (int i=0; i< topmethods.length; i++) {
299             int modif = topmethods[i].getModifiers();
300             if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
301              & modif) == 0
302             && !topmethods[i].getName().equals("<init>")) {
303             reachableReference
304                 (Reference.getReference(clazzType,
305                             topmethods[i].getName(),
306                             topmethods[i].getType()),
307                  true);
308             }
309         }
310         }
311         ClassInfo[] ifaces = superclass.getInterfaces();
312         for (int i=0; i < ifaces.length; i++)
313         analyzeSuperClasses(ifaces[i]);
314         superclass = superclass.getSuperclass();
315     }
316     }
317
318     public void analyze() {
319     if (GlobalOptions.verboseLevel > 0)
320         GlobalOptions.err.println("Reachable: "+this);
321
322     ClassInfo[] ifaces = info.getInterfaces();
323     for (int i=0; i < ifaces.length; i++)
324         analyzeSuperClasses(ifaces[i]);
325     analyzeSuperClasses(info.getSuperclass());
326     }
327
328     public void initSuperClasses(ClassInfo superclass) {
329     while (superclass != null) {
330         ClassIdentifier superident = Main.getClassBundle()
331         .getClassIdentifier(superclass.getName());
332         if (superident != null) {
333         for (Iterator JavaDoc i = superident.getMethodIdents().iterator();
334              i.hasNext(); ) {
335             MethodIdentifier mid = (MethodIdentifier) i.next();
336             // all virtual methods in superclass must be chained.
337
int modif = mid.info.getModifiers();
338             if (((Modifier.PRIVATE
339               | Modifier.STATIC
340               | Modifier.FINAL) & modif) == 0
341             && !(mid.getName().equals("<init>"))) {
342             // chain the preserved/same name lists.
343
chainMethodIdentifier(mid);
344             }
345         }
346         } else {
347         // all methods and fields in superclass are preserved!
348
MethodInfo[] topmethods = superclass.getMethods();
349         for (int i=0; i< topmethods.length; i++) {
350             // all virtual methods in superclass may be
351
// virtually reachable
352
int modif = topmethods[i].getModifiers();
353             if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
354              & modif) == 0
355             && !topmethods[i].getName().equals("<init>")) {
356             Identifier method = findMethod
357                 (topmethods[i].getName(), topmethods[i].getType());
358             if (method != null)
359                 method.setPreserved();
360             }
361         }
362         }
363         ClassInfo[] ifaces = superclass.getInterfaces();
364         for (int i=0; i < ifaces.length; i++)
365         initSuperClasses(ifaces[i]);
366         superclass = superclass.getSuperclass();
367     }
368     }
369
370     public void initClass() {
371     info.loadInfo(info.FULLINFO);
372
373     FieldInfo[] finfos = info.getFields();
374     MethodInfo[] minfos = info.getMethods();
375     if (Main.swapOrder) {
376         Collections.shuffle(Arrays.asList(finfos), Main.rand);
377         Collections.shuffle(Arrays.asList(minfos), Main.rand);
378     }
379     fieldIdents = new ArrayList JavaDoc(finfos.length);
380     methodIdents = new ArrayList JavaDoc(minfos.length);
381     for (int i=0; i< finfos.length; i++)
382         fieldIdents.add(new FieldIdentifier(this, finfos[i]));
383
384     for (int i=0; i< minfos.length; i++) {
385         MethodIdentifier ident = new MethodIdentifier(this, minfos[i]);
386         methodIdents.add(ident);
387         if (ident.getName().equals("<clinit>")) {
388         /* If there is a static initializer, it is automatically
389          * reachable (even if this class wouldn't be otherwise).
390          */

391         ident.setPreserved();
392         ident.setReachable();
393         } else if (ident.getName().equals("<init>"))
394         ident.setPreserved();
395     }
396
397     // preserve / chain inherited methods and fields.
398
ClassInfo[] ifaces = info.getInterfaces();
399     ifaceNames = new String JavaDoc[ifaces.length];
400     for (int i=0; i < ifaces.length; i++) {
401         ifaceNames[i] = ifaces[i].getName();
402         initSuperClasses(ifaces[i]);
403     }
404
405     if (info.getSuperclass() != null) {
406         superName = info.getSuperclass().getName();
407         initSuperClasses(info.getSuperclass());
408     }
409
410     if ((Main.stripping & Main.STRIP_SOURCE) != 0) {
411         info.setSourceFile(null);
412     }
413     if ((Main.stripping & Main.STRIP_INNERINFO) != 0) {
414         info.setInnerClasses(new InnerClassInfo[0]);
415         info.setOuterClasses(new InnerClassInfo[0]);
416         info.setExtraClasses(new InnerClassInfo[0]);
417     }
418     // load inner classes
419
InnerClassInfo[] innerClasses = info.getInnerClasses();
420     InnerClassInfo[] outerClasses = info.getOuterClasses();
421     InnerClassInfo[] extraClasses = info.getExtraClasses();
422     if (outerClasses != null) {
423         for (int i=0; i < outerClasses.length; i++) {
424         if (outerClasses[i].outer != null) {
425             Main.getClassBundle()
426             .getClassIdentifier(outerClasses[i].outer);
427         }
428         }
429     }
430     if (innerClasses != null) {
431         for (int i=0; i < innerClasses.length; i++) {
432         Main.getClassBundle()
433             .getClassIdentifier(innerClasses[i].inner);
434         }
435     }
436     if (extraClasses != null) {
437         for (int i=0; i < extraClasses.length; i++) {
438         Main.getClassBundle()
439             .getClassIdentifier(extraClasses[i].inner);
440         if (extraClasses[i].outer != null)
441             Main.getClassBundle()
442             .getClassIdentifier(extraClasses[i].outer);
443         }
444     }
445     }
446
447     /**
448      * Add the ClassInfo objects of the interfaces of ancestor. But if
449      * an interface of ancestor is not reachable it will add its interfaces
450      * instead.
451      * @param result The Collection where the interfaces should be added to.
452      * @param ancestor The ancestor whose interfaces should be added.
453      */

454     public void addIfaces(Collection JavaDoc result, ClassIdentifier ancestor) {
455     ClassInfo[] ifaceInfos = ancestor.info.getInterfaces();
456     for (int i=0; i < ifaceInfos.length; i++) {
457         ClassIdentifier ifaceident
458         = Main.getClassBundle().getClassIdentifier(ifaceInfos[i].getName());
459         if (ifaceident != null && !ifaceident.isReachable())
460         addIfaces(result, ifaceident);
461         else
462         result.add(ifaceInfos[i]);
463     }
464     }
465
466     /**
467      * Generates the new super class and interfaces, removing super
468      * classes and interfaces that are not reachable.
469      * @return an array of class names (full qualified, dot separated)
470      * where the first entry is the super class (may be null) and the
471      * other entries are the interfaces.
472      */

473     public void transformSuperIfaces() {
474     if ((Main.stripping & Main.STRIP_UNREACH) == 0)
475         return;
476
477     Collection JavaDoc newIfaces = new LinkedList JavaDoc();
478     ClassIdentifier ancestor = this;
479     while(true) {
480         addIfaces(newIfaces, ancestor);
481         ClassIdentifier superident
482         = Main.getClassBundle().getClassIdentifier(ancestor.superName);
483         if (superident == null || superident.isReachable())
484         break;
485         ancestor = superident;
486     }
487     ClassInfo superInfo = ancestor.info.getSuperclass();
488     ClassInfo[] ifaces = (ClassInfo[])
489         newIfaces.toArray(new ClassInfo[newIfaces.size()]);
490     info.setSuperclass(superInfo);
491     info.setInterfaces(ifaces);
492     }
493
494     public void transformInnerClasses() {
495     InnerClassInfo[] outerClasses = info.getOuterClasses();
496     if (outerClasses != null) {
497         int newOuterCount = outerClasses.length;
498         if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
499         for (int i=0; i < outerClasses.length; i++) {
500             if (outerClasses[i].outer != null) {
501             ClassIdentifier outerIdent = Main.getClassBundle()
502                 .getClassIdentifier(outerClasses[i].outer);
503             if (outerIdent != null && !outerIdent.isReachable())
504                 newOuterCount--;
505             }
506         }
507         }
508         if (newOuterCount == 0) {
509         info.setOuterClasses(null);
510         } else {
511         InnerClassInfo[] newOuters = new InnerClassInfo[newOuterCount];
512         int pos = 0;
513         String JavaDoc lastClass = getFullAlias();
514         for (int i=0; i<outerClasses.length; i++) {
515             ClassIdentifier outerIdent = outerClasses[i].outer != null
516             ? (Main.getClassBundle()
517                .getClassIdentifier(outerClasses[i].outer))
518             : null;
519             
520             if ((Main.stripping & Main.STRIP_UNREACH) != 0
521             && outerIdent != null && !outerIdent.isReachable())
522             continue;
523             
524             String JavaDoc inner = lastClass;
525             String JavaDoc outer = outerIdent == null
526             ? outerClasses[i].outer
527             : outerIdent.getFullAlias();
528             String JavaDoc name = outerClasses[i].name == null ? null
529             : ((outer != null && inner.startsWith(outer+"$"))
530                ? inner.substring(outer.length()+1)
531                : inner.substring(inner.lastIndexOf('.')+1));
532
533             newOuters[pos++] = new InnerClassInfo
534             (inner, outer, name, outerClasses[i].modifiers);
535             lastClass = outer;
536         }
537         info.setOuterClasses(newOuters);
538         }
539     }
540
541     InnerClassInfo[] innerClasses = info.getInnerClasses();
542     if (innerClasses != null) {
543         int newInnerCount = innerClasses.length;
544         if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
545         for (int i=0; i < innerClasses.length; i++) {
546             ClassIdentifier innerIdent = Main.getClassBundle()
547             .getClassIdentifier(innerClasses[i].inner);
548             if (innerIdent != null && !innerIdent.isReachable())
549             newInnerCount--;
550         }
551         }
552         if (newInnerCount == 0) {
553         info.setInnerClasses(null);
554         } else {
555         InnerClassInfo[] newInners = new InnerClassInfo[newInnerCount];
556         int pos = 0;
557         for (int i=0; i<innerClasses.length; i++) {
558             ClassIdentifier innerIdent = Main.getClassBundle()
559             .getClassIdentifier(innerClasses[i].inner);
560             if ((Main.stripping & Main.STRIP_UNREACH) != 0
561             && innerIdent != null && !innerIdent.isReachable())
562             continue;
563             
564             String JavaDoc inner = innerIdent == null
565             ? innerClasses[i].inner
566             : innerIdent.getFullAlias();
567             String JavaDoc outer = getFullAlias();
568             String JavaDoc name = innerClasses[i].name == null ? null
569             : ((outer != null && inner.startsWith(outer+"$"))
570                ? inner.substring(outer.length()+1)
571                : inner.substring(inner.lastIndexOf('.')+1));
572             
573             newInners[pos++] = new InnerClassInfo
574             (inner, outer, name, innerClasses[i].modifiers);
575         }
576         info.setInnerClasses(newInners);
577         }
578     }
579
580     InnerClassInfo[] extraClasses = info.getExtraClasses();
581     if (extraClasses != null) {
582         int newExtraCount = extraClasses.length;
583         if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
584         for (int i=0; i < extraClasses.length; i++) {
585             ClassIdentifier outerIdent = extraClasses[i].outer != null
586             ? (Main.getClassBundle()
587                .getClassIdentifier(extraClasses[i].outer))
588             : null;
589             ClassIdentifier innerIdent = Main.getClassBundle()
590             .getClassIdentifier(extraClasses[i].inner);
591             if ((outerIdent != null && !outerIdent.isReachable())
592             || (innerIdent != null && !innerIdent.isReachable()))
593             newExtraCount--;
594         }
595         }
596
597         if (newExtraCount == 0) {
598         info.setExtraClasses(null);
599         } else {
600         InnerClassInfo[] newExtras = newExtraCount > 0
601             ? new InnerClassInfo[newExtraCount] : null;
602
603         int pos = 0;
604         for (int i=0; i<extraClasses.length; i++) {
605             ClassIdentifier outerIdent = extraClasses[i].outer != null
606             ? (Main.getClassBundle()
607                .getClassIdentifier(extraClasses[i].outer))
608             : null;
609             ClassIdentifier innerIdent = Main.getClassBundle()
610             .getClassIdentifier(extraClasses[i].inner);
611             
612             if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
613             if (innerIdent != null && !innerIdent.isReachable())
614                 continue;
615             if (outerIdent != null && !outerIdent.isReachable())
616                 continue;
617             }
618
619             String JavaDoc inner = innerIdent == null
620             ? extraClasses[i].inner
621             : innerIdent.getFullAlias();
622             String JavaDoc outer = outerIdent == null
623             ? extraClasses[i].outer
624             : outerIdent.getFullAlias();
625         
626             String JavaDoc name = extraClasses[i].name == null ? null
627             : ((outer != null && inner.startsWith(outer+"$"))
628                ? inner.substring(outer.length()+1)
629                : inner.substring(inner.lastIndexOf('.')+1));
630
631             newExtras[pos++] = new InnerClassInfo
632             (inner, outer, name, extraClasses[i].modifiers);
633         }
634         info.setExtraClasses(newExtras);
635         }
636     }
637     }
638
639     public void doTransformations() {
640     if (GlobalOptions.verboseLevel > 0)
641         GlobalOptions.err.println("Transforming "+this);
642     info.setName(getFullAlias());
643     transformSuperIfaces();
644     transformInnerClasses();
645
646     Collection JavaDoc newFields = new ArrayList JavaDoc(fieldIdents.size());
647     Collection JavaDoc newMethods = new ArrayList JavaDoc(methodIdents.size());
648
649     for (Iterator JavaDoc i = fieldIdents.iterator(); i.hasNext(); ) {
650         FieldIdentifier ident = (FieldIdentifier)i.next();
651         if ((Main.stripping & Main.STRIP_UNREACH) == 0
652         || ident.isReachable()) {
653         ident.doTransformations();
654         newFields.add(ident.info);
655         }
656     }
657     for (Iterator JavaDoc i = methodIdents.iterator(); i.hasNext(); ) {
658         MethodIdentifier ident = (MethodIdentifier)i.next();
659         if ((Main.stripping & Main.STRIP_UNREACH) == 0
660         || ident.isReachable()) {
661         ident.doTransformations();
662         newMethods.add(ident.info);
663         }
664     }
665
666     info.setFields((FieldInfo[]) newFields.toArray
667                (new FieldInfo[newFields.size()]));
668     info.setMethods((MethodInfo[]) newMethods.toArray
669             (new MethodInfo[newMethods.size()]));
670     }
671     
672     public void storeClass(DataOutputStream JavaDoc out) throws IOException JavaDoc {
673     if (GlobalOptions.verboseLevel > 0)
674         GlobalOptions.err.println("Writing "+this);
675     info.write(out);
676     info = null;
677     fieldIdents = methodIdents = null;
678     }
679
680     public Identifier getParent() {
681     return pack;
682     }
683
684     /**
685      * @return the full qualified name, excluding trailing dot.
686      */

687     public String JavaDoc getFullName() {
688     return fullName;
689     }
690
691     /**
692      * @return the full qualified alias, excluding trailing dot.
693      */

694     public String JavaDoc getFullAlias() {
695     if (pack.parent == null)
696         return getAlias();
697     else
698         return pack.getFullAlias() + "." + getAlias();
699     }
700
701     public String JavaDoc getName() {
702     return name;
703     }
704
705     public String JavaDoc getType() {
706     return "Ljava/lang/Class;";
707     }
708     
709     public int getModifiers() {
710     return info.getModifiers();
711     }
712
713     public List JavaDoc getFieldIdents() {
714     return fieldIdents;
715     }
716
717     public List JavaDoc getMethodIdents() {
718     return methodIdents;
719     }
720
721     public Iterator JavaDoc getChilds() {
722     final Iterator JavaDoc fieldIter = fieldIdents.iterator();
723     final Iterator JavaDoc methodIter = methodIdents.iterator();
724         
725     return new Iterator JavaDoc() {
726         boolean fieldsNext = fieldIter.hasNext();
727         public boolean hasNext() {
728         return fieldsNext ? true : methodIter.hasNext();
729         }
730
731         public Object JavaDoc next() {
732         if (fieldsNext) {
733             Object JavaDoc result = fieldIter.next();
734             fieldsNext = fieldIter.hasNext();
735             return result;
736         }
737         return methodIter.next();
738         }
739
740         public void remove() {
741         throw new UnsupportedOperationException JavaDoc();
742         }
743     };
744     }
745
746     public String JavaDoc toString() {
747     return "ClassIdentifier "+getFullName();
748     }
749
750     public Identifier getIdentifier(String JavaDoc fieldName, String JavaDoc typeSig) {
751     for (Iterator JavaDoc i = getChilds(); i.hasNext(); ) {
752         Identifier ident = (Identifier) i.next();
753         if (ident.getName().equals(fieldName)
754         && ident.getType().startsWith(typeSig))
755         return ident;
756     }
757     
758     if (superName != null) {
759         ClassIdentifier superident = Main.getClassBundle()
760         .getClassIdentifier(superName);
761         if (superident != null) {
762         Identifier ident
763             = superident.getIdentifier(fieldName, typeSig);
764         if (ident != null)
765             return ident;
766         }
767     }
768     return null;
769     }
770
771     public boolean containsFieldAliasDirectly(String JavaDoc fieldName, String JavaDoc typeSig,
772                           IdentifierMatcher matcher) {
773     for (Iterator JavaDoc i = fieldIdents.iterator(); i.hasNext(); ) {
774         Identifier ident = (Identifier) i.next();
775         if (((Main.stripping & Main.STRIP_UNREACH) == 0
776          || ident.isReachable())
777         && ident.wasAliased()
778         && ident.getAlias().equals(fieldName)
779         && ident.getType().startsWith(typeSig)
780         && matcher.matches(ident))
781         return true;
782     }
783     return false;
784     }
785
786     public boolean containsMethodAliasDirectly(String JavaDoc methodName,
787                            String JavaDoc paramType,
788                            IdentifierMatcher matcher) {
789     for (Iterator JavaDoc i = methodIdents.iterator(); i.hasNext(); ) {
790         Identifier ident = (Identifier) i.next();
791         if (((Main.stripping & Main.STRIP_UNREACH) == 0
792          || ident.isReachable())
793         && ident.wasAliased()
794         && ident.getAlias().equals(methodName)
795         && ident.getType().startsWith(paramType)
796         && matcher.matches(ident))
797         return true;
798     }
799     return false;
800     }
801
802     public boolean fieldConflicts(FieldIdentifier field, String JavaDoc newAlias) {
803     String JavaDoc typeSig = (Main.options & Main.OPTION_STRONGOVERLOAD) != 0
804         ? field.getType() : "";
805
806     /* Fields are similar to static methods: They are not
807      * overriden but hidden. We must only take care, that the
808      * reference of every getfield/putfield opcode points to the
809      * exact class, afterwards we can use doubled name as much as
810      * we want (event the decompiler can handle this). */

811
812
813     ModifierMatcher mm = ModifierMatcher.allowAll;
814     if (containsFieldAliasDirectly(newAlias, typeSig, mm))
815         return true;
816     return false;
817     }
818
819     public boolean methodConflicts(MethodIdentifier method, String JavaDoc newAlias) {
820     String JavaDoc paramType = method.getType();
821     if ((Main.options & Main.OPTION_STRONGOVERLOAD) == 0)
822         paramType = paramType.substring(0, paramType.indexOf(')')+1);
823
824     ModifierMatcher matcher = ModifierMatcher.allowAll;
825     if (containsMethodAliasDirectly(newAlias, paramType, matcher))
826         return true;
827     
828     ModifierMatcher packMatcher = matcher.forceAccess(0, true);
829     if (method.info.isStatic()) {
830         /* A static method does not conflict with static methods
831          * in super classes or sub classes.
832          */

833         packMatcher.forbidModifier(Modifier.STATIC);
834     }
835     /* We don't have to check interfaces: sub classes must always
836      * implement all methods in the interface (maybe abstract, but
837      * they must be there!).
838      */

839     ClassInfo superInfo = info.getSuperclass();
840     ClassIdentifier superIdent = this;
841     while (superInfo != null) {
842         ClassIdentifier superident = Main.getClassBundle()
843         .getClassIdentifier(superInfo.getName());
844         if (superident != null) {
845         if (superident.containsMethodAliasDirectly
846             (newAlias, paramType, packMatcher))
847             return true;
848         } else {
849         MethodInfo[] minfos = superInfo.getMethods();
850         for (int i=0; i< minfos.length; i++) {
851             if (minfos[i].getName().equals(newAlias)
852             && minfos[i].getType().startsWith(paramType)
853             && packMatcher.matches(minfos[i].getModifiers()))
854             return true;
855         }
856         }
857         superInfo = superInfo.getSuperclass();
858     }
859     if (packMatcher.matches(method)) {
860         for (Iterator JavaDoc i = knownSubClasses.iterator(); i.hasNext(); ) {
861         ClassIdentifier ci = (ClassIdentifier) i.next();
862         if (ci.containsMethodAliasDirectly(newAlias, paramType,
863                            packMatcher))
864             return true;
865         }
866     }
867     return false;
868     }
869     
870     public boolean conflicting(String JavaDoc newAlias) {
871     return pack.contains(newAlias, this);
872     }
873 }
874
Popular Tags