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 */ 21package proguard.classfile.editor; 22 23import proguard.classfile.*; 24import proguard.classfile.constant.*; 25 26/** 27 * This class can add constant pool entries to a given class. 28 * 29 * @author Eric Lafortune 30 */ 31public 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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