KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > obfuscate > MemberObfuscator


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 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.obfuscate;
22
23 import proguard.classfile.*;
24 import proguard.classfile.util.*;
25 import proguard.classfile.visitor.MemberVisitor;
26
27 import java.util.*;
28
29 /**
30  * This MemberVisitor obfuscates all class members that it visits.
31  * It uses names from the given name factory. At the same time, it avoids names
32  * from the given descriptor map.
33  * <p>
34  * The class members must have been linked before applying this visitor.
35  *
36  * @see MethodLinker
37  *
38  * @author Eric Lafortune
39  */

40 public class MemberObfuscator
41 extends SimplifiedVisitor
42 implements MemberVisitor
43 {
44     private boolean allowAggressiveOverloading;
45     private NameFactory nameFactory;
46     private Map descriptorMap;
47
48
49     /**
50      * Creates a new MemberObfuscator.
51      * @param allowAggressiveOverloading a flag that specifies whether class
52      * members can be overloaded aggressively.
53      * @param nameFactory the factory that can produce
54      * obfuscated member names.
55      * @param descriptorMap the map of descriptors to
56      * [new name - old name] maps.
57      */

58     public MemberObfuscator(boolean allowAggressiveOverloading,
59                             NameFactory nameFactory,
60                             Map descriptorMap)
61     {
62         this.allowAggressiveOverloading = allowAggressiveOverloading;
63         this.nameFactory = nameFactory;
64         this.descriptorMap = descriptorMap;
65     }
66
67
68     // Implementations for MemberVisitor.
69

70     public void visitAnyMember(Clazz clazz, Member member)
71     {
72         // Special cases: <clinit> and <init> are always kept unchanged.
73
// We can ignore them here.
74
String JavaDoc name = member.getName(clazz);
75         if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT) ||
76             name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
77         {
78             return;
79         }
80
81         // Get the member's descriptor.
82
String JavaDoc descriptor = member.getDescriptor(clazz);
83
84         // Check whether we're allowed to do aggressive overloading
85
if (!allowAggressiveOverloading)
86         {
87             // Trim the return argument from the descriptor if not.
88
// Works for fields and methods alike.
89
descriptor = descriptor.substring(0, descriptor.indexOf(')')+1);
90         }
91
92         // Get the name map, creating a new one if necessary.
93
Map nameMap = retrieveNameMap(descriptorMap, descriptor);
94
95         // Get the member's new name.
96
String JavaDoc newName = newMemberName(member);
97
98         // Assign a new one, if necessary.
99
if (newName == null)
100         {
101             // Find an acceptable new name.
102
nameFactory.reset();
103
104             do
105             {
106                 newName = nameFactory.nextName();
107             }
108             while (nameMap.containsKey(newName));
109
110             // Remember not to use the new name again in this name space.
111
nameMap.put(newName, name);
112
113             // Assign the new name.
114
setNewMemberName(member, newName);
115         }
116     }
117
118
119     // Small utility methods.
120

121     /**
122      * Gets the name map, based on the given map and a given descriptor.
123      * A new empty map is created if necessary.
124      * @param descriptorMap the map of descriptors to [new name - old name] maps.
125      * @param descriptor the class member descriptor.
126      * @return the corresponding name map.
127      */

128     static Map retrieveNameMap(Map descriptorMap, String JavaDoc descriptor)
129     {
130         // See if we can find the nested map with this descriptor key.
131
Map nameMap = (Map)descriptorMap.get(descriptor);
132
133         // Create a new one if not.
134
if (nameMap == null)
135         {
136             nameMap = new HashMap();
137             descriptorMap.put(descriptor, nameMap);
138         }
139
140         return nameMap;
141     }
142
143
144     /**
145      * Assigns a fixed new name to the given class member.
146      * @param member the class member.
147      * @param name the new name.
148      */

149     static void setFixedNewMemberName(Member member, String JavaDoc name)
150     {
151         VisitorAccepter lastVisitorAccepter = MethodLinker.lastVisitorAccepter(member);
152
153         if (!(lastVisitorAccepter instanceof LibraryMember) &&
154             !(lastVisitorAccepter instanceof MyFixedName))
155         {
156             lastVisitorAccepter.setVisitorInfo(new MyFixedName(name));
157         }
158         else
159         {
160             lastVisitorAccepter.setVisitorInfo(name);
161         }
162     }
163
164
165     /**
166      * Assigns a new name to the given class member.
167      * @param member the class member.
168      * @param name the new name.
169      */

170     static void setNewMemberName(Member member, String JavaDoc name)
171     {
172         MethodLinker.lastVisitorAccepter(member).setVisitorInfo(name);
173     }
174
175
176     /**
177      * Returns whether the new name of the given class member is fixed.
178      * @param member the class member.
179      * @return whether its new name is fixed.
180      */

181     static boolean hasFixedNewMemberName(Member member)
182     {
183         VisitorAccepter lastVisitorAccepter = MethodLinker.lastVisitorAccepter(member);
184
185         return lastVisitorAccepter instanceof LibraryMember ||
186                lastVisitorAccepter instanceof MyFixedName;
187     }
188
189
190     /**
191      * Retrieves the new name of the given class member.
192      * @param member the class member.
193      * @return the class member's new name, or <code>null</code> if it doesn't
194      * have one yet.
195      */

196     static String JavaDoc newMemberName(Member member)
197     {
198         return (String JavaDoc)MethodLinker.lastVisitorAccepter(member).getVisitorInfo();
199     }
200
201
202     /**
203      * This VisitorAccepter can be used to wrap a name string, to indicate that
204      * the name is fixed.
205      */

206     private static class MyFixedName implements VisitorAccepter
207     {
208         private String JavaDoc newName;
209
210
211         public MyFixedName(String JavaDoc newName)
212         {
213             this.newName = newName;
214         }
215
216
217         // Implementations for VisitorAccepter.
218

219         public Object JavaDoc getVisitorInfo()
220         {
221             return newName;
222         }
223
224
225         public void setVisitorInfo(Object JavaDoc visitorInfo)
226         {
227             newName = (String JavaDoc)visitorInfo;
228         }
229     }
230 }
231
Popular Tags