• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2009 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.constant.*;
25 
26 /**
27  * This class can add constant pool entries to a given class.
28  *
29  * @author Eric Lafortune
30  */
31 public class ConstantPoolEditor
32 {
33     private static final boolean DEBUG = false;
34 
35     private ProgramClass targetClass;
36 
37 
38     /**
39      * Creates a new ConstantPoolEditor that will edit constants in the given
40      * target class.
41      */
ConstantPoolEditor(ProgramClass targetClass)42     public ConstantPoolEditor(ProgramClass targetClass)
43     {
44         this.targetClass = targetClass;
45     }
46 
47 
48     /**
49      * Finds or creates a IntegerConstant constant pool entry with the given
50      * value.
51      * @return the constant pool index of the Utf8Constant.
52      */
addIntegerConstant(int value)53     public int addIntegerConstant(int value)
54     {
55         int        constantPoolCount = targetClass.u2constantPoolCount;
56         Constant[] constantPool      = targetClass.constantPool;
57 
58         // Check if the entry already exists.
59         for (int index = 1; index < constantPoolCount; index++)
60         {
61             Constant constant = constantPool[index];
62 
63             if (constant != null &&
64                 constant.getTag() == ClassConstants.CONSTANT_Integer)
65             {
66                 IntegerConstant integerConstant = (IntegerConstant)constant;
67                 if (integerConstant.getValue() == value)
68                 {
69                     return index;
70                 }
71             }
72         }
73 
74         return addConstant(new IntegerConstant(value));
75     }
76 
77 
78     /**
79      * Finds or creates a LongConstant constant pool entry with the given value.
80      * @return the constant pool index of the LongConstant.
81      */
addLongConstant(long value)82     public int addLongConstant(long value)
83     {
84         int        constantPoolCount = targetClass.u2constantPoolCount;
85         Constant[] constantPool      = targetClass.constantPool;
86 
87         // Check if the entry already exists.
88         for (int index = 1; index < constantPoolCount; index++)
89         {
90             Constant constant = constantPool[index];
91 
92             if (constant != null &&
93                 constant.getTag() == ClassConstants.CONSTANT_Long)
94             {
95                 LongConstant longConstant = (LongConstant)constant;
96                 if (longConstant.getValue() == value)
97                 {
98                     return index;
99                 }
100             }
101         }
102 
103         return addConstant(new LongConstant(value));
104     }
105 
106 
107     /**
108      * Finds or creates a FloatConstant constant pool entry with the given
109      * value.
110      * @return the constant pool index of the FloatConstant.
111      */
addFloatConstant(float value)112     public int addFloatConstant(float value)
113     {
114         int        constantPoolCount = targetClass.u2constantPoolCount;
115         Constant[] constantPool      = targetClass.constantPool;
116 
117         // Check if the entry already exists.
118         for (int index = 1; index < constantPoolCount; index++)
119         {
120             Constant constant = constantPool[index];
121 
122             if (constant != null &&
123                 constant.getTag() == ClassConstants.CONSTANT_Float)
124             {
125                 FloatConstant floatConstant = (FloatConstant)constant;
126                 if (floatConstant.getValue() == value)
127                 {
128                     return index;
129                 }
130             }
131         }
132 
133         return addConstant(new FloatConstant(value));
134     }
135 
136 
137     /**
138      * Finds or creates a DoubleConstant constant pool entry with the given
139      * value.
140      * @return the constant pool index of the DoubleConstant.
141      */
addDoubleConstant(double value)142     public int addDoubleConstant(double value)
143     {
144         int        constantPoolCount = targetClass.u2constantPoolCount;
145         Constant[] constantPool      = targetClass.constantPool;
146 
147         // Check if the entry already exists.
148         for (int index = 1; index < constantPoolCount; index++)
149         {
150             Constant constant = constantPool[index];
151 
152             if (constant != null &&
153                 constant.getTag() == ClassConstants.CONSTANT_Double)
154             {
155                 DoubleConstant doubleConstant = (DoubleConstant)constant;
156                 if (doubleConstant.getValue() == value)
157                 {
158                     return index;
159                 }
160             }
161         }
162 
163         return addConstant(new DoubleConstant(value));
164     }
165 
166 
167     /**
168      * Finds or creates a StringConstant constant pool entry with the given
169      * value.
170      * @return the constant pool index of the StringConstant.
171      */
addStringConstant(String string, Clazz referencedClass, Member referencedMember)172     public int addStringConstant(String string,
173                                  Clazz  referencedClass,
174                                  Member referencedMember)
175     {
176         int        constantPoolCount = targetClass.u2constantPoolCount;
177         Constant[] constantPool      = targetClass.constantPool;
178 
179         // Check if the entry already exists.
180         for (int index = 1; index < constantPoolCount; index++)
181         {
182             Constant constant = constantPool[index];
183 
184             if (constant != null &&
185                 constant.getTag() == ClassConstants.CONSTANT_String)
186             {
187                 StringConstant stringConstant = (StringConstant)constant;
188                 if (stringConstant.getString(targetClass).equals(string))
189                 {
190                     return index;
191                 }
192             }
193         }
194 
195         return addConstant(new StringConstant(addUtf8Constant(string),
196                                               referencedClass,
197                                               referencedMember));
198     }
199 
200 
201     /**
202      * Finds or creates a FieldrefConstant constant pool entry for the given
203      * class and field.
204      * @return the constant pool index of the FieldrefConstant.
205      */
addFieldrefConstant(Clazz referencedClass, Member referencedMember)206     public int addFieldrefConstant(Clazz  referencedClass,
207                                    Member referencedMember)
208     {
209         return addFieldrefConstant(referencedClass.getName(),
210                                    referencedMember.getName(referencedClass),
211                                    referencedMember.getDescriptor(referencedClass),
212                                    referencedClass,
213                                    referencedMember);
214     }
215 
216 
217     /**
218      * Finds or creates a FieldrefConstant constant pool entry with the given
219      * class name, field name, and descriptor.
220      * @return the constant pool index of the FieldrefConstant.
221      */
addFieldrefConstant(String className, String name, String descriptor, Clazz referencedClass, Member referencedMember)222     public int addFieldrefConstant(String className,
223                                    String name,
224                                    String descriptor,
225                                    Clazz  referencedClass,
226                                    Member referencedMember)
227     {
228         return addFieldrefConstant(className,
229                                    addNameAndTypeConstant(name, descriptor),
230                                    referencedClass,
231                                    referencedMember);
232     }
233 
234 
235     /**
236      * Finds or creates a FieldrefConstant constant pool entry with the given
237      * class name, field name, and descriptor.
238      * @return the constant pool index of the FieldrefConstant.
239      */
addFieldrefConstant(String className, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember)240     public int addFieldrefConstant(String className,
241                                    int    nameAndTypeIndex,
242                                    Clazz  referencedClass,
243                                    Member referencedMember)
244     {
245         return addFieldrefConstant(addClassConstant(className, referencedClass),
246                                    nameAndTypeIndex,
247                                    referencedClass,
248                                    referencedMember);
249     }
250 
251 
252     /**
253      * Finds or creates a FieldrefConstant constant pool entry with the given
254      * class constant pool entry index, field name, and descriptor.
255      * @return the constant pool index of the FieldrefConstant.
256      */
addFieldrefConstant(int classIndex, String name, String descriptor, Clazz referencedClass, Member referencedMember)257     public int addFieldrefConstant(int    classIndex,
258                                    String name,
259                                    String descriptor,
260                                    Clazz  referencedClass,
261                                    Member referencedMember)
262     {
263         return addFieldrefConstant(classIndex,
264                                    addNameAndTypeConstant(name, descriptor),
265                                    referencedClass,
266                                    referencedMember);
267     }
268 
269 
270     /**
271      * Finds or creates a FieldrefConstant constant pool entry with the given
272      * class constant pool entry index and name and type constant pool entry
273      * index.
274      * @return the constant pool index of the FieldrefConstant.
275      */
addFieldrefConstant(int classIndex, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember)276     public int addFieldrefConstant(int    classIndex,
277                                    int    nameAndTypeIndex,
278                                    Clazz  referencedClass,
279                                    Member referencedMember)
280     {
281         int        constantPoolCount = targetClass.u2constantPoolCount;
282         Constant[] constantPool      = targetClass.constantPool;
283 
284         // Check if the entry already exists.
285         for (int index = 1; index < constantPoolCount; index++)
286         {
287             Constant constant = constantPool[index];
288 
289             if (constant != null &&
290                 constant.getTag() == ClassConstants.CONSTANT_Fieldref)
291             {
292                 FieldrefConstant fieldrefConstant = (FieldrefConstant)constant;
293                 if (fieldrefConstant.u2classIndex         == classIndex &&
294                     fieldrefConstant.u2nameAndTypeIndex   == nameAndTypeIndex)
295                 {
296                     return index;
297                 }
298             }
299         }
300 
301         return addConstant(new FieldrefConstant(classIndex,
302                                                 nameAndTypeIndex,
303                                                 referencedClass,
304                                                 referencedMember));
305     }
306 
307 
308     /**
309      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
310      * given class name, method name, and descriptor.
311      * @return the constant pool index of the InterfaceMethodrefConstant.
312      */
addInterfaceMethodrefConstant(String className, String name, String descriptor, Clazz referencedClass, Member referencedMember)313     public int addInterfaceMethodrefConstant(String className,
314                                              String name,
315                                              String descriptor,
316                                              Clazz  referencedClass,
317                                              Member referencedMember)
318     {
319         return addInterfaceMethodrefConstant(className,
320                                              addNameAndTypeConstant(name, descriptor),
321                                              referencedClass,
322                                              referencedMember);
323     }
324 
325 
326     /**
327      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
328      * given class name, method name, and descriptor.
329      * @return the constant pool index of the InterfaceMethodrefConstant.
330      */
addInterfaceMethodrefConstant(String className, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember)331     public int addInterfaceMethodrefConstant(String className,
332                                              int    nameAndTypeIndex,
333                                              Clazz  referencedClass,
334                                              Member referencedMember)
335     {
336         return addInterfaceMethodrefConstant(addClassConstant(className, referencedClass),
337                                              nameAndTypeIndex,
338                                              referencedClass,
339                                              referencedMember);
340     }
341 
342 
343     /**
344      * Finds or creates a InterfaceMethodrefConstant constant pool entry for the
345      * given class and method.
346      * @return the constant pool index of the InterfaceMethodrefConstant.
347      */
addInterfaceMethodrefConstant(Clazz referencedClass, Member referencedMember)348     public int addInterfaceMethodrefConstant(Clazz  referencedClass,
349                                              Member referencedMember)
350     {
351         return addInterfaceMethodrefConstant(referencedClass.getName(),
352                                              referencedMember.getName(referencedClass),
353                                              referencedMember.getDescriptor(referencedClass),
354                                              referencedClass,
355                                              referencedMember);
356     }
357 
358 
359     /**
360      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
361      * given class constant pool entry index, method name, and descriptor.
362      * @return the constant pool index of the InterfaceMethodrefConstant.
363      */
addInterfaceMethodrefConstant(int classIndex, String name, String descriptor, Clazz referencedClass, Member referencedMember)364     public int addInterfaceMethodrefConstant(int    classIndex,
365                                              String name,
366                                              String descriptor,
367                                              Clazz  referencedClass,
368                                              Member referencedMember)
369     {
370         return addInterfaceMethodrefConstant(classIndex,
371                                              addNameAndTypeConstant(name, descriptor),
372                                              referencedClass,
373                                              referencedMember);
374     }
375 
376 
377     /**
378      * Finds or creates a InterfaceMethodrefConstant constant pool entry with the
379      * given class constant pool entry index and name and type constant pool
380      * entry index.
381      * @return the constant pool index of the InterfaceMethodrefConstant.
382      */
addInterfaceMethodrefConstant(int classIndex, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember)383     public int addInterfaceMethodrefConstant(int    classIndex,
384                                              int    nameAndTypeIndex,
385                                              Clazz  referencedClass,
386                                              Member referencedMember)
387     {
388         int        constantPoolCount = targetClass.u2constantPoolCount;
389         Constant[] constantPool      = targetClass.constantPool;
390 
391         // Check if the entry already exists.
392         for (int index = 1; index < constantPoolCount; index++)
393         {
394             Constant constant = constantPool[index];
395 
396             if (constant != null &&
397                             constant.getTag() == ClassConstants.CONSTANT_InterfaceMethodref)
398             {
399                 InterfaceMethodrefConstant methodrefConstant = (InterfaceMethodrefConstant)constant;
400                 if (methodrefConstant.u2classIndex       == classIndex &&
401                     methodrefConstant.u2nameAndTypeIndex == nameAndTypeIndex)
402                 {
403                     return index;
404                 }
405             }
406         }
407 
408         return addConstant(new InterfaceMethodrefConstant(classIndex,
409                                                           nameAndTypeIndex,
410                                                           referencedClass,
411                                                           referencedMember));
412     }
413 
414 
415     /**
416      * Finds or creates a MethodrefConstant constant pool entry for the given
417      * class and method.
418      * @return the constant pool index of the MethodrefConstant.
419      */
addMethodrefConstant(Clazz referencedClass, Member referencedMember)420     public int addMethodrefConstant(Clazz  referencedClass,
421                                     Member referencedMember)
422     {
423         return addMethodrefConstant(referencedClass.getName(),
424                                     referencedMember.getName(referencedClass),
425                                     referencedMember.getDescriptor(referencedClass),
426                                     referencedClass,
427                                     referencedMember);
428     }
429 
430 
431     /**
432      * Finds or creates a MethodrefConstant constant pool entry with the given
433      * class name, method name, and descriptor.
434      * @return the constant pool index of the MethodrefConstant.
435      */
addMethodrefConstant(String className, String name, String descriptor, Clazz referencedClass, Member referencedMember)436     public int addMethodrefConstant(String className,
437                                     String name,
438                                     String descriptor,
439                                     Clazz  referencedClass,
440                                     Member referencedMember)
441     {
442         return addMethodrefConstant(className,
443                                     addNameAndTypeConstant(name, descriptor),
444                                     referencedClass,
445                                     referencedMember);
446     }
447 
448 
449     /**
450      * Finds or creates a MethodrefConstant constant pool entry with the given
451      * class name, method name, and descriptor.
452      * @return the constant pool index of the MethodrefConstant.
453      */
addMethodrefConstant(String className, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember)454     public int addMethodrefConstant(String className,
455                                     int    nameAndTypeIndex,
456                                     Clazz  referencedClass,
457                                     Member referencedMember)
458     {
459         return addMethodrefConstant(addClassConstant(className, referencedClass),
460                                     nameAndTypeIndex,
461                                     referencedClass,
462                                     referencedMember);
463     }
464 
465 
466     /**
467      * Finds or creates a MethodrefConstant constant pool entry with the given
468      * class constant pool entry index, method name, and descriptor.
469      * @return the constant pool index of the MethodrefConstant.
470      */
addMethodrefConstant(int classIndex, String name, String descriptor, Clazz referencedClass, Member referencedMember)471     public int addMethodrefConstant(int    classIndex,
472                                     String name,
473                                     String descriptor,
474                                     Clazz  referencedClass,
475                                     Member referencedMember)
476     {
477         return addMethodrefConstant(classIndex,
478                                     addNameAndTypeConstant(name, descriptor),
479                                     referencedClass,
480                                     referencedMember);
481     }
482 
483 
484     /**
485      * Finds or creates a MethodrefConstant constant pool entry with the given
486      * class constant pool entry index and name and type constant pool entry
487      * index.
488      * @return the constant pool index of the MethodrefConstant.
489      */
addMethodrefConstant(int classIndex, int nameAndTypeIndex, Clazz referencedClass, Member referencedMember)490     public int addMethodrefConstant(int    classIndex,
491                                     int    nameAndTypeIndex,
492                                     Clazz  referencedClass,
493                                     Member referencedMember)
494     {
495         int        constantPoolCount = targetClass.u2constantPoolCount;
496         Constant[] constantPool      = targetClass.constantPool;
497 
498         // Check if the entry already exists.
499         for (int index = 1; index < constantPoolCount; index++)
500         {
501             Constant constant = constantPool[index];
502 
503             if (constant != null &&
504                 constant.getTag() == ClassConstants.CONSTANT_Methodref)
505             {
506                 MethodrefConstant methodrefConstant = (MethodrefConstant)constant;
507                 if (methodrefConstant.u2classIndex       == classIndex &&
508                     methodrefConstant.u2nameAndTypeIndex == nameAndTypeIndex)
509                 {
510                     return index;
511                 }
512             }
513         }
514 
515         return addConstant(new MethodrefConstant(classIndex,
516                                                  nameAndTypeIndex,
517                                                  referencedClass,
518                                                  referencedMember));
519     }
520 
521 
522     /**
523      * Finds or creates a ClassConstant constant pool entry for the given class.
524      * @return the constant pool index of the ClassConstant.
525      */
addClassConstant(Clazz referencedClass)526     public int addClassConstant(Clazz referencedClass)
527     {
528         return addClassConstant(referencedClass.getName(),
529                                 referencedClass);
530     }
531 
532 
533     /**
534      * Finds or creates a ClassConstant constant pool entry with the given name.
535      * @return the constant pool index of the ClassConstant.
536      */
addClassConstant(String name, Clazz referencedClass)537     public int addClassConstant(String name,
538                                 Clazz  referencedClass)
539     {
540         int        constantPoolCount = targetClass.u2constantPoolCount;
541         Constant[] constantPool      = targetClass.constantPool;
542 
543         // Check if the entry already exists.
544         for (int index = 1; index < constantPoolCount; index++)
545         {
546             Constant constant = constantPool[index];
547 
548             if (constant != null &&
549                 constant.getTag() == ClassConstants.CONSTANT_Class)
550             {
551                 ClassConstant classConstant = (ClassConstant)constant;
552                 if (classConstant.getName(targetClass).equals(name))
553                 {
554                     return index;
555                 }
556             }
557         }
558 
559         int nameIndex = addUtf8Constant(name);
560 
561         return addConstant(new ClassConstant(nameIndex, referencedClass));
562     }
563 
564 
565     /**
566      * Finds or creates a NameAndTypeConstant constant pool entry with the given
567      * name and type.
568      * @return the constant pool index of the NameAndTypeConstant.
569      */
addNameAndTypeConstant(String name, String type)570     public int addNameAndTypeConstant(String name,
571                                       String type)
572     {
573         int        constantPoolCount = targetClass.u2constantPoolCount;
574         Constant[] constantPool      = targetClass.constantPool;
575 
576         // Check if the entry already exists.
577         for (int index = 1; index < constantPoolCount; index++)
578         {
579             Constant constant = constantPool[index];
580 
581             if (constant != null &&
582                 constant.getTag() == ClassConstants.CONSTANT_NameAndType)
583             {
584                 NameAndTypeConstant nameAndTypeConstant = (NameAndTypeConstant)constant;
585                 if (nameAndTypeConstant.getName(targetClass).equals(name) &&
586                     nameAndTypeConstant.getType(targetClass).equals(type))
587                 {
588                     return index;
589                 }
590             }
591         }
592 
593         return addConstant(new NameAndTypeConstant(addUtf8Constant(name),
594                                                    addUtf8Constant(type)));
595     }
596 
597 
598     /**
599      * Finds or creates a Utf8Constant constant pool entry for the given string.
600      * @return the constant pool index of the Utf8Constant.
601      */
addUtf8Constant(String string)602     public int addUtf8Constant(String string)
603     {
604         int        constantPoolCount = targetClass.u2constantPoolCount;
605         Constant[] constantPool      = targetClass.constantPool;
606 
607         // Check if the entry already exists.
608         for (int index = 1; index < constantPoolCount; index++)
609         {
610             Constant constant = constantPool[index];
611 
612             if (constant != null &&
613                 constant.getTag() == ClassConstants.CONSTANT_Utf8)
614             {
615                 Utf8Constant utf8Constant = (Utf8Constant)constant;
616                 if (utf8Constant.getString().equals(string))
617                 {
618                     return index;
619                 }
620             }
621         }
622 
623         return addConstant(new Utf8Constant(string));
624     }
625 
626 
627     /**
628      * Adds a given constant pool entry to the end of the constant pool/
629      * @return the constant pool index for the added entry.
630      */
addConstant(Constant constant)631     public int addConstant(Constant constant)
632     {
633         int        constantPoolCount = targetClass.u2constantPoolCount;
634         Constant[] constantPool      = targetClass.constantPool;
635 
636         // Make sure there is enough space for another constant pool entry.
637         if (constantPool.length < constantPoolCount+2)
638         {
639             targetClass.constantPool = new Constant[constantPoolCount+2];
640             System.arraycopy(constantPool, 0,
641                              targetClass.constantPool, 0,
642                              constantPoolCount);
643             constantPool = targetClass.constantPool;
644         }
645 
646         if (DEBUG)
647         {
648             System.out.println(targetClass.getName()+": adding ["+constant.getClass().getName()+"] at index "+targetClass.u2constantPoolCount);
649         }
650 
651         // Create a new Utf8Constant for the given string.
652         constantPool[targetClass.u2constantPoolCount++] = constant;
653 
654         // Long constants and double constants take up two entries in the
655         // constant pool.
656         int tag = constant.getTag();
657         if (tag == ClassConstants.CONSTANT_Long ||
658             tag == ClassConstants.CONSTANT_Double)
659         {
660             constantPool[targetClass.u2constantPoolCount++] = null;
661         }
662 
663         return constantPoolCount;
664     }
665 }
666