• 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 
26 /**
27  * This class can add and delete attributes to and from classes, fields,
28  * methods, and code attributes. Attributes to be added must be filled out
29  * beforehand, including their references to the constant pool. Existing
30  * attributes of the same type are always replaced.
31  *
32  * @author Eric Lafortune
33  */
34 public class AttributesEditor
35 {
36     private final ProgramClass  targetClass;
37     private final ProgramMember targetMember;
38     private final CodeAttribute targetAttribute;
39     private final boolean       replaceAttributes;
40 
41 
42     /**
43      * Creates a new AttributeAdder that will edit attributes in the given
44      * target class.
45      */
AttributesEditor(ProgramClass targetClass, boolean replaceAttributes)46     public AttributesEditor(ProgramClass targetClass,
47                             boolean      replaceAttributes)
48     {
49         this(targetClass, null, null, replaceAttributes);
50     }
51 
52 
53     /**
54      * Creates a new AttributeAdder that will edit attributes in the given
55      * target class member.
56      */
AttributesEditor(ProgramClass targetClass, ProgramMember targetMember, boolean replaceAttributes)57     public AttributesEditor(ProgramClass  targetClass,
58                             ProgramMember targetMember,
59                             boolean       replaceAttributes)
60     {
61         this(targetClass, targetMember, null, replaceAttributes);
62     }
63 
64 
65     /**
66      * Creates a new AttributeAdder that will edit attributes in the given
67      * target code attribute.
68      */
AttributesEditor(ProgramClass targetClass, ProgramMember targetMember, CodeAttribute targetAttribute, boolean replaceAttributes)69     public AttributesEditor(ProgramClass  targetClass,
70                             ProgramMember targetMember,
71                             CodeAttribute targetAttribute,
72                             boolean       replaceAttributes)
73     {
74         this.targetClass       = targetClass;
75         this.targetMember      = targetMember;
76         this.targetAttribute   = targetAttribute;
77         this.replaceAttributes = replaceAttributes;
78     }
79 
80 
81     /**
82      * Finds the specified attribute in the target.
83      */
findAttribute(String attributeName)84     public Attribute findAttribute(String attributeName)
85     {
86         // What's the target?
87         return
88             targetAttribute != null ?
89                 findAttribute(targetAttribute.u2attributesCount,
90                               targetAttribute.attributes,
91                               attributeName) :
92             targetMember != null ?
93                 findAttribute(targetMember.u2attributesCount,
94                               targetMember.attributes,
95                               attributeName) :
96                 findAttribute(targetClass.u2attributesCount,
97                               targetClass.attributes,
98                               attributeName);
99     }
100 
101 
102     /**
103      * Adds the given attribute to the target.
104      */
addAttribute(Attribute attribute)105     public void addAttribute(Attribute attribute)
106     {
107         // What's the target?
108         if (targetAttribute != null)
109         {
110             // Try to replace an existing attribute.
111             if (!replaceAttributes ||
112                 !replaceAttribute(targetAttribute.u2attributesCount,
113                                   targetAttribute.attributes,
114                                   attribute))
115             {
116                 // Otherwise append the attribute.
117                 targetAttribute.attributes =
118                     addAttribute(targetAttribute.u2attributesCount,
119                                  targetAttribute.attributes,
120                                  attribute);
121 
122                 targetAttribute.u2attributesCount++;
123             }
124         }
125         else if (targetMember != null)
126         {
127             // Try to replace an existing attribute.
128             if (!replaceAttributes ||
129                 !replaceAttribute(targetMember.u2attributesCount,
130                                   targetMember.attributes,
131                                   attribute))
132             {
133                 // Otherwise append the attribute.
134                 targetMember.attributes =
135                     addAttribute(targetMember.u2attributesCount,
136                                  targetMember.attributes,
137                                  attribute);
138 
139                 targetMember.u2attributesCount++;
140             }
141         }
142         else
143         {
144             // Try to replace an existing attribute.
145             if (!replaceAttributes ||
146                 !replaceAttribute(targetClass.u2attributesCount,
147                                   targetClass.attributes,
148                                   attribute))
149             {
150                 // Otherwise append the attribute.
151                 targetClass.attributes =
152                     addAttribute(targetClass.u2attributesCount,
153                                  targetClass.attributes,
154                                  attribute);
155 
156                 targetClass.u2attributesCount++;
157             }
158         }
159     }
160 
161 
162     /**
163      * Deletes the specified attribute from the target.
164      */
deleteAttribute(String attributeName)165     public void deleteAttribute(String attributeName)
166     {
167         // What's the target?
168         if (targetAttribute != null)
169         {
170             targetAttribute.u2attributesCount =
171                 deleteAttribute(targetAttribute.u2attributesCount,
172                                 targetAttribute.attributes,
173                                 attributeName);
174         }
175         else if (targetMember != null)
176         {
177             targetMember.u2attributesCount =
178                 deleteAttribute(targetMember.u2attributesCount,
179                                 targetMember.attributes,
180                                 attributeName);
181         }
182         else
183         {
184             targetClass.u2attributesCount =
185                 deleteAttribute(targetClass.u2attributesCount,
186                                 targetClass.attributes,
187                                 attributeName);
188         }
189     }
190 
191 
192     // Small utility methods.
193 
194     /**
195      * Tries to put the given attribute in place of an existing attribute of
196      * the same name, returning whether it was present.
197      */
replaceAttribute(int attributesCount, Attribute[] attributes, Attribute attribute)198     private boolean replaceAttribute(int         attributesCount,
199                                      Attribute[] attributes,
200                                      Attribute   attribute)
201     {
202         // Find the attribute with the same name.
203         int index = findAttributeIndex(attributesCount,
204                                        attributes,
205                                        attribute.getAttributeName(targetClass));
206         if (index < 0)
207         {
208             return false;
209         }
210 
211         attributes[index] = attribute;
212 
213         return true;
214     }
215 
216 
217     /**
218      * Appends the given attribute to the given array of attributes, creating a
219      * new array if necessary.
220      */
addAttribute(int attributesCount, Attribute[] attributes, Attribute attribute)221     private Attribute[] addAttribute(int         attributesCount,
222                                      Attribute[] attributes,
223                                      Attribute   attribute)
224     {
225         // Is the array too small to contain the additional attribute?
226         if (attributes.length <= attributesCount)
227         {
228             // Create a new array and copy the attributes into it.
229             Attribute[] newAttributes = new Attribute[attributesCount + 1];
230             System.arraycopy(attributes, 0,
231                              newAttributes, 0,
232                              attributesCount);
233             attributes = newAttributes;
234         }
235 
236         // Append the attribute.
237         attributes[attributesCount] = attribute;
238 
239         return attributes;
240     }
241 
242 
243     /**
244      * Deletes the attributes with the given name from the given array of
245      * attributes, returning the new number of attributes.
246      */
deleteAttribute(int attributesCount, Attribute[] attributes, String attributeName)247     private int deleteAttribute(int         attributesCount,
248                                 Attribute[] attributes,
249                                 String      attributeName)
250     {
251         // Find the attribute.
252         int index = findAttributeIndex(attributesCount,
253                                        attributes,
254                                        attributeName);
255         if (index < 0)
256         {
257             return attributesCount;
258         }
259 
260         // Shift the other attributes in the array.
261         System.arraycopy(attributes, index + 1,
262                          attributes, index,
263                          attributesCount - index - 1);
264 
265         // Clear the last entry in the array.
266         attributes[--attributesCount] = null;
267 
268         return attributesCount;
269     }
270 
271 
272     /**
273      * Finds the index of the attribute with the given name in the given
274      * array of attributes.
275      */
findAttributeIndex(int attributesCount, Attribute[] attributes, String attributeName)276     private int findAttributeIndex(int         attributesCount,
277                                    Attribute[] attributes,
278                                    String      attributeName)
279     {
280         for (int index = 0; index < attributesCount; index++)
281         {
282             Attribute attribute = attributes[index];
283 
284             if (attribute.getAttributeName(targetClass).equals(attributeName))
285             {
286                 return index;
287             }
288         }
289 
290         return -1;
291     }
292 
293 
294     /**
295      * Finds the attribute with the given name in the given
296      * array of attributes.
297      */
findAttribute(int attributesCount, Attribute[] attributes, String attributeName)298     private Attribute findAttribute(int         attributesCount,
299                                     Attribute[] attributes,
300                                     String      attributeName)
301     {
302         for (int index = 0; index < attributesCount; index++)
303         {
304             Attribute attribute = attributes[index];
305 
306             if (attribute.getAttributeName(targetClass).equals(attributeName))
307             {
308                 return attribute;
309             }
310         }
311 
312         return null;
313     }
314 }
315