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