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