001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.compress.harmony.unpack200; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.HashMap; 024import java.util.Map; 025 026import org.apache.commons.compress.harmony.pack200.Codec; 027import org.apache.commons.compress.harmony.pack200.Pack200Exception; 028import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass; 029import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble; 030import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef; 031import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat; 032import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger; 033import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef; 034import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong; 035import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef; 036import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType; 037import org.apache.commons.compress.harmony.unpack200.bytecode.CPString; 038import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8; 039 040/** 041 * Constant Pool bands 042 */ 043public class CpBands extends BandSet { 044 045 public SegmentConstantPool getConstantPool() { 046 return pool; 047 } 048 049 private final SegmentConstantPool pool = new SegmentConstantPool(this); 050 051 private String[] cpClass; 052 private int[] cpClassInts; 053 private int[] cpDescriptorNameInts; 054 private int[] cpDescriptorTypeInts; 055 private String[] cpDescriptor; 056 private double[] cpDouble; 057 private String[] cpFieldClass; 058 private String[] cpFieldDescriptor; 059 private int[] cpFieldClassInts; 060 private int[] cpFieldDescriptorInts; 061 private float[] cpFloat; 062 private String[] cpIMethodClass; 063 private String[] cpIMethodDescriptor; 064 private int[] cpIMethodClassInts; 065 private int[] cpIMethodDescriptorInts; 066 private int[] cpInt; 067 private long[] cpLong; 068 private String[] cpMethodClass; 069 private String[] cpMethodDescriptor; 070 private int[] cpMethodClassInts; 071 private int[] cpMethodDescriptorInts; 072 private String[] cpSignature; 073 private int[] cpSignatureInts; 074 private String[] cpString; 075 private int[] cpStringInts; 076 private String[] cpUTF8; 077 078 private final Map<String, CPUTF8> stringsToCPUTF8 = new HashMap<>(); 079 private final Map<String, CPString> stringsToCPStrings = new HashMap<>(); 080 private final Map<Long, CPLong> longsToCPLongs = new HashMap<>(); 081 private final Map<Integer, CPInteger> integersToCPIntegers = new HashMap<>(); 082 private final Map<Float, CPFloat> floatsToCPFloats = new HashMap<>(); 083 private final Map<String, CPClass> stringsToCPClass = new HashMap<>(); 084 private final Map<Double, CPDouble> doublesToCPDoubles = new HashMap<>(); 085 private final Map<String, CPNameAndType> descriptorsToCPNameAndTypes = new HashMap<>(); 086 087 private Map<String, Integer> mapClass; 088 private Map<String, Integer> mapDescriptor; 089 private Map<String, Integer> mapUTF8; 090 091 // TODO: Not used 092 private Map<String, Integer> mapSignature; 093 094 private int intOffset; 095 private int floatOffset; 096 private int longOffset; 097 private int doubleOffset; 098 private int stringOffset; 099 private int classOffset; 100 private int signatureOffset; 101 private int descrOffset; 102 private int fieldOffset; 103 private int methodOffset; 104 private int imethodOffset; 105 106 public CpBands(final Segment segment) { 107 super(segment); 108 } 109 110 @Override 111 public void read(final InputStream in) throws IOException, Pack200Exception { 112 parseCpUtf8(in); 113 parseCpInt(in); 114 parseCpFloat(in); 115 parseCpLong(in); 116 parseCpDouble(in); 117 parseCpString(in); 118 parseCpClass(in); 119 parseCpSignature(in); 120 parseCpDescriptor(in); 121 parseCpField(in); 122 parseCpMethod(in); 123 parseCpIMethod(in); 124 125 intOffset = cpUTF8.length; 126 floatOffset = intOffset + cpInt.length; 127 longOffset = floatOffset + cpFloat.length; 128 doubleOffset = longOffset + cpLong.length; 129 stringOffset = doubleOffset + cpDouble.length; 130 classOffset = stringOffset + cpString.length; 131 signatureOffset = classOffset + cpClass.length; 132 descrOffset = signatureOffset + cpSignature.length; 133 fieldOffset = descrOffset + cpDescriptor.length; 134 methodOffset = fieldOffset + cpFieldClass.length; 135 imethodOffset = methodOffset + cpMethodClass.length; 136 } 137 138 @Override 139 public void unpack() { 140 141 } 142 143 /** 144 * Parses the constant pool class names, using {@link #cpClassCount} to populate {@link #cpClass} from 145 * {@link #cpUTF8}. 146 * 147 * @param in the input stream to read from 148 * @throws IOException if a problem occurs during reading from the underlying stream 149 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 150 */ 151 private void parseCpClass(final InputStream in) throws IOException, Pack200Exception { 152 final int cpClassCount = header.getCpClassCount(); 153 cpClassInts = decodeBandInt("cp_Class", in, Codec.UDELTA5, cpClassCount); 154 cpClass = new String[cpClassCount]; 155 mapClass = new HashMap<>(cpClassCount); 156 for (int i = 0; i < cpClassCount; i++) { 157 cpClass[i] = cpUTF8[cpClassInts[i]]; 158 mapClass.put(cpClass[i], Integer.valueOf(i)); 159 } 160 } 161 162 /** 163 * Parses the constant pool descriptor definitions, using {@link #cpDescriptorCount} to populate 164 * {@link #cpDescriptor}. For ease of use, the cpDescriptor is stored as a string of the form <i>name:type</i>, 165 * largely to make it easier for representing field and method descriptors (e.g. 166 * {@code out:java.lang.PrintStream}) in a way that is compatible with passing String arrays. 167 * 168 * @param in the input stream to read from 169 * @throws IOException if a problem occurs during reading from the underlying stream 170 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 171 */ 172 private void parseCpDescriptor(final InputStream in) throws IOException, Pack200Exception { 173 final int cpDescriptorCount = header.getCpDescriptorCount(); 174 cpDescriptorNameInts = decodeBandInt("cp_Descr_name", in, Codec.DELTA5, cpDescriptorCount); 175 cpDescriptorTypeInts = decodeBandInt("cp_Descr_type", in, Codec.UDELTA5, cpDescriptorCount); 176 final String[] cpDescriptorNames = getReferences(cpDescriptorNameInts, cpUTF8); 177 final String[] cpDescriptorTypes = getReferences(cpDescriptorTypeInts, cpSignature); 178 cpDescriptor = new String[cpDescriptorCount]; 179 mapDescriptor = new HashMap<>(cpDescriptorCount); 180 for (int i = 0; i < cpDescriptorCount; i++) { 181 cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i]; //$NON-NLS-1$ 182 mapDescriptor.put(cpDescriptor[i], Integer.valueOf(i)); 183 } 184 } 185 186 private void parseCpDouble(final InputStream in) throws IOException, Pack200Exception { 187 final int cpDoubleCount = header.getCpDoubleCount(); 188 final long[] band = parseFlags("cp_Double", in, cpDoubleCount, Codec.UDELTA5, Codec.DELTA5); 189 cpDouble = new double[band.length]; 190 Arrays.setAll(cpDouble, i -> Double.longBitsToDouble(band[i])); 191 } 192 193 /** 194 * Parses the constant pool field definitions, using {@link #cpFieldCount} to populate {@link #cpFieldClass} and 195 * {@link #cpFieldDescriptor}. 196 * 197 * @param in the input stream to read from 198 * @throws IOException if a problem occurs during reading from the underlying stream 199 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 200 */ 201 private void parseCpField(final InputStream in) throws IOException, Pack200Exception { 202 final int cpFieldCount = header.getCpFieldCount(); 203 cpFieldClassInts = decodeBandInt("cp_Field_class", in, Codec.DELTA5, cpFieldCount); 204 cpFieldDescriptorInts = decodeBandInt("cp_Field_desc", in, Codec.UDELTA5, cpFieldCount); 205 cpFieldClass = new String[cpFieldCount]; 206 cpFieldDescriptor = new String[cpFieldCount]; 207 for (int i = 0; i < cpFieldCount; i++) { 208 cpFieldClass[i] = cpClass[cpFieldClassInts[i]]; 209 cpFieldDescriptor[i] = cpDescriptor[cpFieldDescriptorInts[i]]; 210 } 211 } 212 213 private void parseCpFloat(final InputStream in) throws IOException, Pack200Exception { 214 final int cpFloatCount = header.getCpFloatCount(); 215 cpFloat = new float[cpFloatCount]; 216 final int[] floatBits = decodeBandInt("cp_Float", in, Codec.UDELTA5, cpFloatCount); 217 for (int i = 0; i < cpFloatCount; i++) { 218 cpFloat[i] = Float.intBitsToFloat(floatBits[i]); 219 } 220 } 221 222 /** 223 * Parses the constant pool interface method definitions, using {@link #cpIMethodCount} to populate 224 * {@link #cpIMethodClass} and {@link #cpIMethodDescriptor}. 225 * 226 * @param in the input stream to read from 227 * @throws IOException if a problem occurs during reading from the underlying stream 228 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 229 */ 230 private void parseCpIMethod(final InputStream in) throws IOException, Pack200Exception { 231 final int cpIMethodCount = header.getCpIMethodCount(); 232 cpIMethodClassInts = decodeBandInt("cp_Imethod_class", in, Codec.DELTA5, cpIMethodCount); 233 cpIMethodDescriptorInts = decodeBandInt("cp_Imethod_desc", in, Codec.UDELTA5, cpIMethodCount); 234 cpIMethodClass = new String[cpIMethodCount]; 235 cpIMethodDescriptor = new String[cpIMethodCount]; 236 for (int i = 0; i < cpIMethodCount; i++) { 237 cpIMethodClass[i] = cpClass[cpIMethodClassInts[i]]; 238 cpIMethodDescriptor[i] = cpDescriptor[cpIMethodDescriptorInts[i]]; 239 } 240 } 241 242 private void parseCpInt(final InputStream in) throws IOException, Pack200Exception { 243 final int cpIntCount = header.getCpIntCount(); 244 cpInt = decodeBandInt("cpInt", in, Codec.UDELTA5, cpIntCount); 245 } 246 247 private void parseCpLong(final InputStream in) throws IOException, Pack200Exception { 248 final int cpLongCount = header.getCpLongCount(); 249 cpLong = parseFlags("cp_Long", in, cpLongCount, Codec.UDELTA5, Codec.DELTA5); 250 } 251 252 /** 253 * Parses the constant pool method definitions, using {@link #cpMethodCount} to populate {@link #cpMethodClass} and 254 * {@link #cpMethodDescriptor}. 255 * 256 * @param in the input stream to read from 257 * @throws IOException if a problem occurs during reading from the underlying stream 258 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 259 */ 260 private void parseCpMethod(final InputStream in) throws IOException, Pack200Exception { 261 final int cpMethodCount = header.getCpMethodCount(); 262 cpMethodClassInts = decodeBandInt("cp_Method_class", in, Codec.DELTA5, cpMethodCount); 263 cpMethodDescriptorInts = decodeBandInt("cp_Method_desc", in, Codec.UDELTA5, cpMethodCount); 264 cpMethodClass = new String[cpMethodCount]; 265 cpMethodDescriptor = new String[cpMethodCount]; 266 for (int i = 0; i < cpMethodCount; i++) { 267 cpMethodClass[i] = cpClass[cpMethodClassInts[i]]; 268 cpMethodDescriptor[i] = cpDescriptor[cpMethodDescriptorInts[i]]; 269 } 270 } 271 272 /** 273 * Parses the constant pool signature classes, using {@link #cpSignatureCount} to populate {@link #cpSignature}. A 274 * signature form is akin to the bytecode representation of a class; Z for boolean, I for int, [ for array etc. 275 * However, although classes are started with L, the classname does not follow the form; instead, there is a 276 * separate array of classes. So an array corresponding to {@code public static void main(String args[])} has a 277 * form of {@code [L(V)} and a classes array of {@code [java.lang.String]}. The {@link #cpSignature} is a 278 * string representation identical to the bytecode equivalent {@code [Ljava/lang/String;(V)} TODO Check that 279 * the form is as above and update other types e.g. J 280 * 281 * @param in the input stream to read from 282 * @throws IOException if a problem occurs during reading from the underlying stream 283 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 284 */ 285 private void parseCpSignature(final InputStream in) throws IOException, Pack200Exception { 286 final int cpSignatureCount = header.getCpSignatureCount(); 287 cpSignatureInts = decodeBandInt("cp_Signature_form", in, Codec.DELTA5, cpSignatureCount); 288 final String[] cpSignatureForm = getReferences(cpSignatureInts, cpUTF8); 289 cpSignature = new String[cpSignatureCount]; 290 mapSignature = new HashMap<>(); 291 int lCount = 0; 292 for (int i = 0; i < cpSignatureCount; i++) { 293 final String form = cpSignatureForm[i]; 294 final char[] chars = form.toCharArray(); 295 for (char element : chars) { 296 if (element == 'L') { 297 cpSignatureInts[i] = -1; 298 lCount++; 299 } 300 } 301 } 302 final String[] cpSignatureClasses = parseReferences("cp_Signature_classes", in, Codec.UDELTA5, lCount, cpClass); 303 int index = 0; 304 for (int i = 0; i < cpSignatureCount; i++) { 305 final String form = cpSignatureForm[i]; 306 final int len = form.length(); 307 final StringBuilder signature = new StringBuilder(64); 308 final ArrayList<String> list = new ArrayList<>(); 309 for (int j = 0; j < len; j++) { 310 final char c = form.charAt(j); 311 signature.append(c); 312 if (c == 'L') { 313 final String className = cpSignatureClasses[index]; 314 list.add(className); 315 signature.append(className); 316 index++; 317 } 318 } 319 cpSignature[i] = signature.toString(); 320 mapSignature.put(signature.toString(), Integer.valueOf(i)); 321 } 322// for (int i = 0; i < cpSignatureInts.length; i++) { 323// if(cpSignatureInts[i] == -1) { 324// cpSignatureInts[i] = search(cpUTF8, cpSignature[i]); 325// } 326// } 327 } 328 329 /** 330 * Parses the constant pool strings, using {@link #cpStringCount} to populate {@link #cpString} from indexes into 331 * {@link #cpUTF8}. 332 * 333 * @param in the input stream to read from 334 * @throws IOException if a problem occurs during reading from the underlying stream 335 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 336 */ 337 private void parseCpString(final InputStream in) throws IOException, Pack200Exception { 338 final int cpStringCount = header.getCpStringCount(); 339 cpStringInts = decodeBandInt("cp_String", in, Codec.UDELTA5, cpStringCount); 340 cpString = new String[cpStringCount]; 341 Arrays.setAll(cpString, i -> cpUTF8[cpStringInts[i]]); 342 } 343 344 private void parseCpUtf8(final InputStream in) throws IOException, Pack200Exception { 345 final int cpUTF8Count = header.getCpUTF8Count(); 346 cpUTF8 = new String[cpUTF8Count]; 347 mapUTF8 = new HashMap<>(cpUTF8Count + 1); 348 cpUTF8[0] = ""; //$NON-NLS-1$ 349 mapUTF8.put("", Integer.valueOf(0)); 350 final int[] prefix = decodeBandInt("cpUTF8Prefix", in, Codec.DELTA5, cpUTF8Count - 2); 351 int charCount = 0; 352 int bigSuffixCount = 0; 353 final int[] suffix = decodeBandInt("cpUTF8Suffix", in, Codec.UNSIGNED5, cpUTF8Count - 1); 354 355 for (int element : suffix) { 356 if (element == 0) { 357 bigSuffixCount++; 358 } else { 359 charCount += element; 360 } 361 } 362 final char[] data = new char[charCount]; 363 final int[] dataBand = decodeBandInt("cp_Utf8_chars", in, Codec.CHAR3, charCount); 364 for (int i = 0; i < data.length; i++) { 365 data[i] = (char) dataBand[i]; 366 } 367 368 // Read in the big suffix data 369 final int[] bigSuffixCounts = decodeBandInt("cp_Utf8_big_suffix", in, Codec.DELTA5, bigSuffixCount); 370 final int[][] bigSuffixDataBand = new int[bigSuffixCount][]; 371 for (int i = 0; i < bigSuffixDataBand.length; i++) { 372 bigSuffixDataBand[i] = decodeBandInt("cp_Utf8_big_chars " + i, in, Codec.DELTA5, bigSuffixCounts[i]); 373 } 374 375 // Convert big suffix data to characters 376 final char[][] bigSuffixData = new char[bigSuffixCount][]; 377 for (int i = 0; i < bigSuffixDataBand.length; i++) { 378 bigSuffixData[i] = new char[bigSuffixDataBand[i].length]; 379 for (int j = 0; j < bigSuffixDataBand[i].length; j++) { 380 bigSuffixData[i][j] = (char) bigSuffixDataBand[i][j]; 381 } 382 } 383 // Go through the strings 384 charCount = 0; 385 bigSuffixCount = 0; 386 for (int i = 1; i < cpUTF8Count; i++) { 387 final String lastString = cpUTF8[i - 1]; 388 if (suffix[i - 1] == 0) { 389 // The big suffix stuff hasn't been tested, and I'll be 390 // surprised if it works first time w/o errors ... 391 cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0) 392 + new String(bigSuffixData[bigSuffixCount++]); 393 mapUTF8.put(cpUTF8[i], Integer.valueOf(i)); 394 } else { 395 cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0) 396 + new String(data, charCount, suffix[i - 1]); 397 charCount += suffix[i - 1]; 398 mapUTF8.put(cpUTF8[i], Integer.valueOf(i)); 399 } 400 } 401 } 402 403 public String[] getCpClass() { 404 return cpClass; 405 } 406 407 public String[] getCpDescriptor() { 408 return cpDescriptor; 409 } 410 411 public String[] getCpFieldClass() { 412 return cpFieldClass; 413 } 414 415 public String[] getCpIMethodClass() { 416 return cpIMethodClass; 417 } 418 419 public int[] getCpInt() { 420 return cpInt; 421 } 422 423 public long[] getCpLong() { 424 return cpLong; 425 } 426 427 public String[] getCpMethodClass() { 428 return cpMethodClass; 429 } 430 431 public String[] getCpMethodDescriptor() { 432 return cpMethodDescriptor; 433 } 434 435 public String[] getCpSignature() { 436 return cpSignature; 437 } 438 439 public String[] getCpUTF8() { 440 return cpUTF8; 441 } 442 443 public CPUTF8 cpUTF8Value(final int index) { 444 final String string = cpUTF8[index]; 445 CPUTF8 cputf8 = stringsToCPUTF8.get(string); 446 if (cputf8 == null) { 447 cputf8 = new CPUTF8(string, index); 448 stringsToCPUTF8.put(string, cputf8); 449 } else if (cputf8.getGlobalIndex() > index) { 450 cputf8.setGlobalIndex(index); 451 } 452 return cputf8; 453 } 454 455 public CPUTF8 cpUTF8Value(final String string) { 456 return cpUTF8Value(string, true); 457 } 458 459 public CPUTF8 cpUTF8Value(final String string, final boolean searchForIndex) { 460 CPUTF8 cputf8 = stringsToCPUTF8.get(string); 461 if (cputf8 == null) { 462 Integer index = null; 463 if (searchForIndex) { 464 index = mapUTF8.get(string); 465 } 466 if (index != null) { 467 return cpUTF8Value(index.intValue()); 468 } 469 if (searchForIndex) { 470 index = mapSignature.get(string); 471 } 472 if (index != null) { 473 return cpSignatureValue(index.intValue()); 474 } 475 cputf8 = new CPUTF8(string, -1); 476 stringsToCPUTF8.put(string, cputf8); 477 } 478 return cputf8; 479 } 480 481 public CPString cpStringValue(final int index) { 482 final String string = cpString[index]; 483 final int utf8Index = cpStringInts[index]; 484 final int globalIndex = stringOffset + index; 485 CPString cpString = stringsToCPStrings.get(string); 486 if (cpString == null) { 487 cpString = new CPString(cpUTF8Value(utf8Index), globalIndex); 488 stringsToCPStrings.put(string, cpString); 489 } 490 return cpString; 491 } 492 493 public CPLong cpLongValue(final int index) { 494 final Long l = Long.valueOf(cpLong[index]); 495 CPLong cpLong = longsToCPLongs.get(l); 496 if (cpLong == null) { 497 cpLong = new CPLong(l, index + longOffset); 498 longsToCPLongs.put(l, cpLong); 499 } 500 return cpLong; 501 } 502 503 public CPInteger cpIntegerValue(final int index) { 504 final Integer i = Integer.valueOf(cpInt[index]); 505 CPInteger cpInteger = integersToCPIntegers.get(i); 506 if (cpInteger == null) { 507 cpInteger = new CPInteger(i, index + intOffset); 508 integersToCPIntegers.put(i, cpInteger); 509 } 510 return cpInteger; 511 } 512 513 public CPFloat cpFloatValue(final int index) { 514 final Float f = Float.valueOf(cpFloat[index]); 515 CPFloat cpFloat = floatsToCPFloats.get(f); 516 if (cpFloat == null) { 517 cpFloat = new CPFloat(f, index + floatOffset); 518 floatsToCPFloats.put(f, cpFloat); 519 } 520 return cpFloat; 521 } 522 523 public CPClass cpClassValue(final int index) { 524 final String string = cpClass[index]; 525 final int utf8Index = cpClassInts[index]; 526 final int globalIndex = classOffset + index; 527 CPClass cpString = stringsToCPClass.get(string); 528 if (cpString == null) { 529 cpString = new CPClass(cpUTF8Value(utf8Index), globalIndex); 530 stringsToCPClass.put(string, cpString); 531 } 532 return cpString; 533 } 534 535 public CPClass cpClassValue(final String string) { 536 CPClass cpString = stringsToCPClass.get(string); 537 if (cpString == null) { 538 final Integer index = mapClass.get(string); 539 if (index != null) { 540 return cpClassValue(index.intValue()); 541 } 542 cpString = new CPClass(cpUTF8Value(string, false), -1); 543 stringsToCPClass.put(string, cpString); 544 } 545 return cpString; 546 } 547 548 public CPDouble cpDoubleValue(final int index) { 549 final Double dbl = Double.valueOf(cpDouble[index]); 550 CPDouble cpDouble = doublesToCPDoubles.get(dbl); 551 if (cpDouble == null) { 552 cpDouble = new CPDouble(dbl, index + doubleOffset); 553 doublesToCPDoubles.put(dbl, cpDouble); 554 } 555 return cpDouble; 556 } 557 558 public CPNameAndType cpNameAndTypeValue(final int index) { 559 final String descriptor = cpDescriptor[index]; 560 CPNameAndType cpNameAndType = descriptorsToCPNameAndTypes.get(descriptor); 561 if (cpNameAndType == null) { 562 final int nameIndex = cpDescriptorNameInts[index]; 563 final int descriptorIndex = cpDescriptorTypeInts[index]; 564 565 final CPUTF8 name = cpUTF8Value(nameIndex); 566 final CPUTF8 descriptorU = cpSignatureValue(descriptorIndex); 567 cpNameAndType = new CPNameAndType(name, descriptorU, index + descrOffset); 568 descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType); 569 } 570 return cpNameAndType; 571 } 572 573 public CPInterfaceMethodRef cpIMethodValue(final int index) { 574 return new CPInterfaceMethodRef(cpClassValue(cpIMethodClassInts[index]), 575 cpNameAndTypeValue(cpIMethodDescriptorInts[index]), index + imethodOffset); 576 } 577 578 public CPMethodRef cpMethodValue(final int index) { 579 return new CPMethodRef(cpClassValue(cpMethodClassInts[index]), 580 cpNameAndTypeValue(cpMethodDescriptorInts[index]), index + methodOffset); 581 } 582 583 public CPFieldRef cpFieldValue(final int index) { 584 return new CPFieldRef(cpClassValue(cpFieldClassInts[index]), cpNameAndTypeValue(cpFieldDescriptorInts[index]), 585 index + fieldOffset); 586 } 587 588 public CPUTF8 cpSignatureValue(final int index) { 589 int globalIndex; 590 if (cpSignatureInts[index] != -1) { 591 globalIndex = cpSignatureInts[index]; 592 } else { 593 globalIndex = index + signatureOffset; 594 } 595 final String string = cpSignature[index]; 596 CPUTF8 cpUTF8 = stringsToCPUTF8.get(string); 597 if (cpUTF8 == null) { 598 cpUTF8 = new CPUTF8(string, globalIndex); 599 stringsToCPUTF8.put(string, cpUTF8); 600 } 601 return cpUTF8; 602 } 603 604 public CPNameAndType cpNameAndTypeValue(final String descriptor) { 605 CPNameAndType cpNameAndType = descriptorsToCPNameAndTypes.get(descriptor); 606 if (cpNameAndType == null) { 607 final Integer index = mapDescriptor.get(descriptor); 608 if (index != null) { 609 return cpNameAndTypeValue(index.intValue()); 610 } 611 final int colon = descriptor.indexOf(':'); 612 final String nameString = descriptor.substring(0, colon); 613 final String descriptorString = descriptor.substring(colon + 1); 614 615 final CPUTF8 name = cpUTF8Value(nameString, true); 616 final CPUTF8 descriptorU = cpUTF8Value(descriptorString, true); 617 cpNameAndType = new CPNameAndType(name, descriptorU, -1 + descrOffset); 618 descriptorsToCPNameAndTypes.put(descriptor, cpNameAndType); 619 } 620 return cpNameAndType; 621 } 622 623 public int[] getCpDescriptorNameInts() { 624 return cpDescriptorNameInts; 625 } 626 627 public int[] getCpDescriptorTypeInts() { 628 return cpDescriptorTypeInts; 629 } 630 631}