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