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 final SegmentConstantPool pool = new SegmentConstantPool(this); 046 047 private String[] cpClass; 048 049 private int[] cpClassInts; 050 private int[] cpDescriptorNameInts; 051 private int[] cpDescriptorTypeInts; 052 private String[] cpDescriptor; 053 private double[] cpDouble; 054 private String[] cpFieldClass; 055 private String[] cpFieldDescriptor; 056 private int[] cpFieldClassInts; 057 private int[] cpFieldDescriptorInts; 058 private float[] cpFloat; 059 private String[] cpIMethodClass; 060 private String[] cpIMethodDescriptor; 061 private int[] cpIMethodClassInts; 062 private int[] cpIMethodDescriptorInts; 063 private int[] cpInt; 064 private long[] cpLong; 065 private String[] cpMethodClass; 066 private String[] cpMethodDescriptor; 067 private int[] cpMethodClassInts; 068 private int[] cpMethodDescriptorInts; 069 private String[] cpSignature; 070 private int[] cpSignatureInts; 071 private String[] cpString; 072 private int[] cpStringInts; 073 private String[] cpUTF8; 074 private final Map<String, CPUTF8> stringsToCPUTF8 = new HashMap<>(); 075 076 private final Map<String, CPString> stringsToCPStrings = new HashMap<>(); 077 private final Map<Long, CPLong> longsToCPLongs = new HashMap<>(); 078 private final Map<Integer, CPInteger> integersToCPIntegers = new HashMap<>(); 079 private final Map<Float, CPFloat> floatsToCPFloats = new HashMap<>(); 080 private final Map<String, CPClass> stringsToCPClass = new HashMap<>(); 081 private final Map<Double, CPDouble> doublesToCPDoubles = new HashMap<>(); 082 private final Map<String, CPNameAndType> descriptorsToCPNameAndTypes = new HashMap<>(); 083 private Map<String, Integer> mapClass; 084 085 private Map<String, Integer> mapDescriptor; 086 private Map<String, Integer> mapUTF8; 087 // TODO: Not used 088 private Map<String, Integer> mapSignature; 089 090 private int intOffset; 091 092 private int floatOffset; 093 private int longOffset; 094 private int doubleOffset; 095 private int stringOffset; 096 private int classOffset; 097 private int signatureOffset; 098 private int descrOffset; 099 private int fieldOffset; 100 private int methodOffset; 101 private int imethodOffset; 102 public CpBands(final Segment segment) { 103 super(segment); 104 } 105 106 public CPClass cpClassValue(final int index) { 107 final String string = cpClass[index]; 108 final int utf8Index = cpClassInts[index]; 109 final int globalIndex = classOffset + index; 110 return stringsToCPClass.computeIfAbsent(string, k -> new CPClass(cpUTF8Value(utf8Index), globalIndex)); 111 } 112 113 public CPClass cpClassValue(final String string) { 114 CPClass cpString = stringsToCPClass.get(string); 115 if (cpString == null) { 116 final Integer index = mapClass.get(string); 117 if (index != null) { 118 return cpClassValue(index.intValue()); 119 } 120 cpString = new CPClass(cpUTF8Value(string, false), -1); 121 stringsToCPClass.put(string, cpString); 122 } 123 return cpString; 124 } 125 126 public CPDouble cpDoubleValue(final int index) { 127 final Double dbl = Double.valueOf(cpDouble[index]); 128 CPDouble cpDouble = doublesToCPDoubles.get(dbl); 129 if (cpDouble == null) { 130 cpDouble = new CPDouble(dbl, index + doubleOffset); 131 doublesToCPDoubles.put(dbl, cpDouble); 132 } 133 return cpDouble; 134 } 135 136 public CPFieldRef cpFieldValue(final int index) { 137 return new CPFieldRef(cpClassValue(cpFieldClassInts[index]), cpNameAndTypeValue(cpFieldDescriptorInts[index]), 138 index + fieldOffset); 139 } 140 141 public CPFloat cpFloatValue(final int index) { 142 final Float f = Float.valueOf(cpFloat[index]); 143 CPFloat cpFloat = floatsToCPFloats.get(f); 144 if (cpFloat == null) { 145 cpFloat = new CPFloat(f, index + floatOffset); 146 floatsToCPFloats.put(f, cpFloat); 147 } 148 return cpFloat; 149 } 150 151 public CPInterfaceMethodRef cpIMethodValue(final int index) { 152 return new CPInterfaceMethodRef(cpClassValue(cpIMethodClassInts[index]), 153 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]), 178 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 335 * {@link #cpUTF8}. 336 * 337 * @param in the input stream to read from 338 * @throws IOException if a problem occurs during reading from the underlying stream 339 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 340 */ 341 private void parseCpClass(final InputStream in) throws IOException, Pack200Exception { 342 final int cpClassCount = header.getCpClassCount(); 343 cpClassInts = decodeBandInt("cp_Class", in, Codec.UDELTA5, cpClassCount); 344 cpClass = new String[cpClassCount]; 345 mapClass = new HashMap<>(cpClassCount); 346 for (int i = 0; i < cpClassCount; i++) { 347 cpClass[i] = cpUTF8[cpClassInts[i]]; 348 mapClass.put(cpClass[i], Integer.valueOf(i)); 349 } 350 } 351 352 /** 353 * Parses the constant pool descriptor definitions, using {@link #cpDescriptorCount} to populate 354 * {@link #cpDescriptor}. For ease of use, the cpDescriptor is stored as a string of the form <i>name:type</i>, 355 * largely to make it easier for representing field and method descriptors (e.g. 356 * {@code out:java.lang.PrintStream}) in a way that is compatible with passing String arrays. 357 * 358 * @param in the input stream to read from 359 * @throws IOException if a problem occurs during reading from the underlying stream 360 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 361 */ 362 private void parseCpDescriptor(final InputStream in) throws IOException, Pack200Exception { 363 final int cpDescriptorCount = header.getCpDescriptorCount(); 364 cpDescriptorNameInts = decodeBandInt("cp_Descr_name", in, Codec.DELTA5, cpDescriptorCount); 365 cpDescriptorTypeInts = decodeBandInt("cp_Descr_type", in, Codec.UDELTA5, cpDescriptorCount); 366 final String[] cpDescriptorNames = getReferences(cpDescriptorNameInts, cpUTF8); 367 final String[] cpDescriptorTypes = getReferences(cpDescriptorTypeInts, cpSignature); 368 cpDescriptor = new String[cpDescriptorCount]; 369 mapDescriptor = new HashMap<>(cpDescriptorCount); 370 for (int i = 0; i < cpDescriptorCount; i++) { 371 cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i]; //$NON-NLS-1$ 372 mapDescriptor.put(cpDescriptor[i], Integer.valueOf(i)); 373 } 374 } 375 376 private void parseCpDouble(final InputStream in) throws IOException, Pack200Exception { 377 final int cpDoubleCount = header.getCpDoubleCount(); 378 final long[] band = parseFlags("cp_Double", in, cpDoubleCount, Codec.UDELTA5, Codec.DELTA5); 379 cpDouble = new double[band.length]; 380 Arrays.setAll(cpDouble, i -> Double.longBitsToDouble(band[i])); 381 } 382 383 /** 384 * Parses the constant pool field definitions, using {@link #cpFieldCount} to populate {@link #cpFieldClass} and 385 * {@link #cpFieldDescriptor}. 386 * 387 * @param in the input stream to read from 388 * @throws IOException if a problem occurs during reading from the underlying stream 389 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 390 */ 391 private void parseCpField(final InputStream in) throws IOException, Pack200Exception { 392 final int cpFieldCount = header.getCpFieldCount(); 393 cpFieldClassInts = decodeBandInt("cp_Field_class", in, Codec.DELTA5, cpFieldCount); 394 cpFieldDescriptorInts = decodeBandInt("cp_Field_desc", in, Codec.UDELTA5, cpFieldCount); 395 cpFieldClass = new String[cpFieldCount]; 396 cpFieldDescriptor = new String[cpFieldCount]; 397 for (int i = 0; i < cpFieldCount; i++) { 398 cpFieldClass[i] = cpClass[cpFieldClassInts[i]]; 399 cpFieldDescriptor[i] = cpDescriptor[cpFieldDescriptorInts[i]]; 400 } 401 } 402 403 private void parseCpFloat(final InputStream in) throws IOException, Pack200Exception { 404 final int cpFloatCount = header.getCpFloatCount(); 405 cpFloat = new float[cpFloatCount]; 406 final int[] floatBits = decodeBandInt("cp_Float", in, Codec.UDELTA5, cpFloatCount); 407 for (int i = 0; i < cpFloatCount; i++) { 408 cpFloat[i] = Float.intBitsToFloat(floatBits[i]); 409 } 410 } 411 412 /** 413 * Parses the constant pool interface method definitions, using {@link #cpIMethodCount} to populate 414 * {@link #cpIMethodClass} and {@link #cpIMethodDescriptor}. 415 * 416 * @param in the input stream to read from 417 * @throws IOException if a problem occurs during reading from the underlying stream 418 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 419 */ 420 private void parseCpIMethod(final InputStream in) throws IOException, Pack200Exception { 421 final int cpIMethodCount = header.getCpIMethodCount(); 422 cpIMethodClassInts = decodeBandInt("cp_Imethod_class", in, Codec.DELTA5, cpIMethodCount); 423 cpIMethodDescriptorInts = decodeBandInt("cp_Imethod_desc", in, Codec.UDELTA5, cpIMethodCount); 424 cpIMethodClass = new String[cpIMethodCount]; 425 cpIMethodDescriptor = new String[cpIMethodCount]; 426 for (int i = 0; i < cpIMethodCount; i++) { 427 cpIMethodClass[i] = cpClass[cpIMethodClassInts[i]]; 428 cpIMethodDescriptor[i] = cpDescriptor[cpIMethodDescriptorInts[i]]; 429 } 430 } 431 432 private void parseCpInt(final InputStream in) throws IOException, Pack200Exception { 433 final int cpIntCount = header.getCpIntCount(); 434 cpInt = decodeBandInt("cpInt", in, Codec.UDELTA5, cpIntCount); 435 } 436 437 private void parseCpLong(final InputStream in) throws IOException, Pack200Exception { 438 final int cpLongCount = header.getCpLongCount(); 439 cpLong = parseFlags("cp_Long", in, cpLongCount, Codec.UDELTA5, Codec.DELTA5); 440 } 441 442 /** 443 * Parses the constant pool method definitions, using {@link #cpMethodCount} to populate {@link #cpMethodClass} and 444 * {@link #cpMethodDescriptor}. 445 * 446 * @param in the input stream to read from 447 * @throws IOException if a problem occurs during reading from the underlying stream 448 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 449 */ 450 private void parseCpMethod(final InputStream in) throws IOException, Pack200Exception { 451 final int cpMethodCount = header.getCpMethodCount(); 452 cpMethodClassInts = decodeBandInt("cp_Method_class", in, Codec.DELTA5, cpMethodCount); 453 cpMethodDescriptorInts = decodeBandInt("cp_Method_desc", in, Codec.UDELTA5, cpMethodCount); 454 cpMethodClass = new String[cpMethodCount]; 455 cpMethodDescriptor = new String[cpMethodCount]; 456 for (int i = 0; i < cpMethodCount; i++) { 457 cpMethodClass[i] = cpClass[cpMethodClassInts[i]]; 458 cpMethodDescriptor[i] = cpDescriptor[cpMethodDescriptorInts[i]]; 459 } 460 } 461 462 /** 463 * Parses the constant pool signature classes, using {@link #cpSignatureCount} to populate {@link #cpSignature}. A 464 * signature form is akin to the bytecode representation of a class; Z for boolean, I for int, [ for array etc. 465 * However, although classes are started with L, the class name does not follow the form; instead, there is a 466 * separate array of classes. So an array corresponding to {@code public static void main(String args[])} has a 467 * form of {@code [L(V)} and a classes array of {@code [java.lang.String]}. The {@link #cpSignature} is a 468 * string representation identical to the bytecode equivalent {@code [Ljava/lang/String;(V)} TODO Check that 469 * the form is as above and update other types e.g. J 470 * 471 * @param in the input stream to read from 472 * @throws IOException if a problem occurs during reading from the underlying stream 473 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 474 */ 475 private void parseCpSignature(final InputStream in) throws IOException, Pack200Exception { 476 final int cpSignatureCount = header.getCpSignatureCount(); 477 cpSignatureInts = decodeBandInt("cp_Signature_form", in, Codec.DELTA5, cpSignatureCount); 478 final String[] cpSignatureForm = getReferences(cpSignatureInts, cpUTF8); 479 cpSignature = new String[cpSignatureCount]; 480 mapSignature = new HashMap<>(); 481 int lCount = 0; 482 for (int i = 0; i < cpSignatureCount; i++) { 483 final String form = cpSignatureForm[i]; 484 final char[] chars = form.toCharArray(); 485 for (final char element : chars) { 486 if (element == 'L') { 487 cpSignatureInts[i] = -1; 488 lCount++; 489 } 490 } 491 } 492 final String[] cpSignatureClasses = parseReferences("cp_Signature_classes", in, Codec.UDELTA5, lCount, cpClass); 493 int index = 0; 494 for (int i = 0; i < cpSignatureCount; i++) { 495 final String form = cpSignatureForm[i]; 496 final int len = form.length(); 497 final StringBuilder signature = new StringBuilder(64); 498 final ArrayList<String> list = new ArrayList<>(); 499 for (int j = 0; j < len; j++) { 500 final char c = form.charAt(j); 501 signature.append(c); 502 if (c == 'L') { 503 final String className = cpSignatureClasses[index]; 504 list.add(className); 505 signature.append(className); 506 index++; 507 } 508 } 509 cpSignature[i] = signature.toString(); 510 mapSignature.put(signature.toString(), Integer.valueOf(i)); 511 } 512// for (int i = 0; i < cpSignatureInts.length; i++) { 513// if (cpSignatureInts[i] == -1) { 514// cpSignatureInts[i] = search(cpUTF8, cpSignature[i]); 515// } 516// } 517 } 518 519 /** 520 * Parses the constant pool strings, using {@link #cpStringCount} to populate {@link #cpString} from indexes into 521 * {@link #cpUTF8}. 522 * 523 * @param in the input stream to read from 524 * @throws IOException if a problem occurs during reading from the underlying stream 525 * @throws Pack200Exception if a problem occurs with an unexpected value or unsupported codec 526 */ 527 private void parseCpString(final InputStream in) throws IOException, Pack200Exception { 528 final int cpStringCount = header.getCpStringCount(); 529 cpStringInts = decodeBandInt("cp_String", in, Codec.UDELTA5, cpStringCount); 530 cpString = new String[cpStringCount]; 531 Arrays.setAll(cpString, i -> cpUTF8[cpStringInts[i]]); 532 } 533 534 private void parseCpUtf8(final InputStream in) throws IOException, Pack200Exception { 535 final int cpUTF8Count = header.getCpUTF8Count(); 536 cpUTF8 = new String[cpUTF8Count]; 537 mapUTF8 = new HashMap<>(cpUTF8Count + 1); 538 cpUTF8[0] = ""; //$NON-NLS-1$ 539 mapUTF8.put("", Integer.valueOf(0)); 540 final int[] prefix = decodeBandInt("cpUTF8Prefix", in, Codec.DELTA5, cpUTF8Count - 2); 541 int charCount = 0; 542 int bigSuffixCount = 0; 543 final int[] suffix = decodeBandInt("cpUTF8Suffix", in, Codec.UNSIGNED5, cpUTF8Count - 1); 544 545 for (final int element : suffix) { 546 if (element == 0) { 547 bigSuffixCount++; 548 } else { 549 charCount += element; 550 } 551 } 552 final char[] data = new char[charCount]; 553 final int[] dataBand = decodeBandInt("cp_Utf8_chars", in, Codec.CHAR3, charCount); 554 for (int i = 0; i < data.length; i++) { 555 data[i] = (char) dataBand[i]; 556 } 557 558 // Read in the big suffix data 559 final int[] bigSuffixCounts = decodeBandInt("cp_Utf8_big_suffix", in, Codec.DELTA5, bigSuffixCount); 560 final int[][] bigSuffixDataBand = new int[bigSuffixCount][]; 561 for (int i = 0; i < bigSuffixDataBand.length; i++) { 562 bigSuffixDataBand[i] = decodeBandInt("cp_Utf8_big_chars " + i, in, Codec.DELTA5, bigSuffixCounts[i]); 563 } 564 565 // Convert big suffix data to characters 566 final char[][] bigSuffixData = new char[bigSuffixCount][]; 567 for (int i = 0; i < bigSuffixDataBand.length; i++) { 568 bigSuffixData[i] = new char[bigSuffixDataBand[i].length]; 569 for (int j = 0; j < bigSuffixDataBand[i].length; j++) { 570 bigSuffixData[i][j] = (char) bigSuffixDataBand[i][j]; 571 } 572 } 573 // Go through the strings 574 charCount = 0; 575 bigSuffixCount = 0; 576 for (int i = 1; i < cpUTF8Count; i++) { 577 final String lastString = cpUTF8[i - 1]; 578 if (suffix[i - 1] == 0) { 579 // The big suffix stuff hasn't been tested, and I'll be 580 // surprised if it works first time w/o errors ... 581 cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0) 582 + new String(bigSuffixData[bigSuffixCount++]); 583 mapUTF8.put(cpUTF8[i], Integer.valueOf(i)); 584 } else { 585 cpUTF8[i] = lastString.substring(0, i > 1 ? prefix[i - 2] : 0) 586 + new String(data, charCount, suffix[i - 1]); 587 charCount += suffix[i - 1]; 588 mapUTF8.put(cpUTF8[i], Integer.valueOf(i)); 589 } 590 } 591 } 592 593 @Override 594 public void read(final InputStream in) throws IOException, Pack200Exception { 595 parseCpUtf8(in); 596 parseCpInt(in); 597 parseCpFloat(in); 598 parseCpLong(in); 599 parseCpDouble(in); 600 parseCpString(in); 601 parseCpClass(in); 602 parseCpSignature(in); 603 parseCpDescriptor(in); 604 parseCpField(in); 605 parseCpMethod(in); 606 parseCpIMethod(in); 607 608 intOffset = cpUTF8.length; 609 floatOffset = intOffset + cpInt.length; 610 longOffset = floatOffset + cpFloat.length; 611 doubleOffset = longOffset + cpLong.length; 612 stringOffset = doubleOffset + cpDouble.length; 613 classOffset = stringOffset + cpString.length; 614 signatureOffset = classOffset + cpClass.length; 615 descrOffset = signatureOffset + cpSignature.length; 616 fieldOffset = descrOffset + cpDescriptor.length; 617 methodOffset = fieldOffset + cpFieldClass.length; 618 imethodOffset = methodOffset + cpMethodClass.length; 619 } 620 621 @Override 622 public void unpack() { 623 624 } 625 626}