• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package proguard.classfile.editor;
22 
23 import proguard.classfile.*;
24 import proguard.classfile.attribute.*;
25 import proguard.classfile.attribute.visitor.AttributeVisitor;
26 import proguard.classfile.constant.Utf8Constant;
27 import proguard.classfile.util.*;
28 import proguard.classfile.visitor.ClassVisitor;
29 
30 import java.util.Arrays;
31 
32 /**
33  * This ClassVisitor sorts the interfaces of the program classes that it visits.
34  *
35  * @author Eric Lafortune
36  */
37 public class InterfaceSorter
38 extends      SimplifiedVisitor
39 implements   ClassVisitor,
40              AttributeVisitor
41 {
42     // Implementations for ClassVisitor.
43 
visitProgramClass(ProgramClass programClass)44     public void visitProgramClass(ProgramClass programClass)
45     {
46         int[] interfaces      = programClass.u2interfaces;
47         int   interfacesCount = programClass.u2interfacesCount;
48 
49         if (interfacesCount > 1)
50         {
51             // Sort the interfaces.
52             Arrays.sort(interfaces, 0, interfacesCount);
53 
54             // Update the signature.
55             programClass.attributesAccept(this);
56 
57             // Remove any duplicate entries.
58             boolean[] delete = null;
59             for (int index = 1; index < interfacesCount; index++)
60             {
61                 Clazz interfaceClass = programClass.getInterface(index);
62                 if (interfaces[index] == interfaces[index - 1])
63                 {
64                     // Lazily create the array.
65                     if (delete == null)
66                     {
67                         delete = new boolean[interfacesCount];
68                     }
69 
70                     delete[index] = true;
71                 }
72             }
73 
74             if (delete != null)
75             {
76                 new InterfaceDeleter(delete).visitProgramClass(programClass);
77             }
78         }
79     }
80 
81 
82     // Implementations for AttributeVisitor.
83 
visitAnyAttribute(Clazz clazz, Attribute attribute)84     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
85 
86 
visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)87     public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
88     {
89         // Process the generic definitions, superclass, and implemented
90         // interfaces.
91         String signature = signatureAttribute.getSignature(clazz);
92 
93         // Count the signature types.
94         InternalTypeEnumeration internalTypeEnumeration =
95             new InternalTypeEnumeration(signature);
96 
97         int count           =  0;
98         int interfacesCount = -1;
99         while (internalTypeEnumeration.hasMoreTypes())
100         {
101             String internalType = internalTypeEnumeration.nextType();
102 
103             count++;
104 
105             if (ClassUtil.isInternalClassType(internalType))
106             {
107                 interfacesCount++;
108             }
109         }
110 
111         // Put the signature types in an array.
112         internalTypeEnumeration =
113             new InternalTypeEnumeration(signature);
114 
115         String[] internalTypes = new String[count];
116 
117         for (int index = 0; index < count; index++)
118         {
119             String internalType = internalTypeEnumeration.nextType();
120 
121             internalTypes[index] = internalType;
122         }
123 
124         // Sort the interface types in the array.
125         Arrays.sort(internalTypes, count - interfacesCount, count);
126 
127         // Recompose the signature types in a string.
128         StringBuffer newSignatureBuffer = new StringBuffer();
129 
130         for (int index = 0; index < count; index++)
131         {
132             newSignatureBuffer.append(internalTypes[index]);
133         }
134 
135         String newSignature = newSignatureBuffer.toString();
136 
137         // Did the signature change?
138         if (!newSignature.equals(signature))
139         {
140             // Update the signature.
141             ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString());
142 
143             // Clear the referenced classes.
144             // TODO: Properly update the referenced classes.
145             signatureAttribute.referencedClasses = null;
146         }
147     }
148 }
149