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.List; 024import java.util.stream.Collectors; 025import java.util.stream.Stream; 026 027import org.apache.commons.compress.harmony.pack200.Codec; 028import org.apache.commons.compress.harmony.pack200.Pack200Exception; 029import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute; 030import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass; 031import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType; 032import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8; 033import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry; 034import org.apache.commons.compress.harmony.unpack200.bytecode.ConstantValueAttribute; 035import org.apache.commons.compress.harmony.unpack200.bytecode.DeprecatedAttribute; 036import org.apache.commons.compress.harmony.unpack200.bytecode.EnclosingMethodAttribute; 037import org.apache.commons.compress.harmony.unpack200.bytecode.ExceptionsAttribute; 038import org.apache.commons.compress.harmony.unpack200.bytecode.LineNumberTableAttribute; 039import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTableAttribute; 040import org.apache.commons.compress.harmony.unpack200.bytecode.LocalVariableTypeTableAttribute; 041import org.apache.commons.compress.harmony.unpack200.bytecode.SignatureAttribute; 042import org.apache.commons.compress.harmony.unpack200.bytecode.SourceFileAttribute; 043 044/** 045 * Class Bands 046 */ 047public class ClassBands extends BandSet { 048 049 private int[] classFieldCount; 050 051 private long[] classFlags; 052 053 private long[] classAccessFlags; // Access flags for writing to the class 054 // file 055 056 private int[][] classInterfacesInts; 057 058 private int[] classMethodCount; 059 060 private int[] classSuperInts; 061 062 private String[] classThis; 063 064 private int[] classThisInts; 065 066 private ArrayList<Attribute>[] classAttributes; 067 068 private int[] classVersionMajor; 069 070 private int[] classVersionMinor; 071 072 private IcTuple[][] icLocal; 073 074 private List<Attribute>[] codeAttributes; 075 076 private int[] codeHandlerCount; 077 078 private int[] codeMaxNALocals; 079 080 private int[] codeMaxStack; 081 082 private ArrayList<Attribute>[][] fieldAttributes; 083 084 private String[][] fieldDescr; 085 086 private int[][] fieldDescrInts; 087 088 private long[][] fieldFlags; 089 090 private long[][] fieldAccessFlags; 091 092 private ArrayList<Attribute>[][] methodAttributes; 093 094 private String[][] methodDescr; 095 096 private int[][] methodDescrInts; 097 098 private long[][] methodFlags; 099 100 private long[][] methodAccessFlags; 101 102 private final AttributeLayoutMap attrMap; 103 104 private final CpBands cpBands; 105 106 private final SegmentOptions options; 107 108 private final int classCount; 109 110 private int[] methodAttrCalls; 111 112 private int[][] codeHandlerStartP; 113 114 private int[][] codeHandlerEndPO; 115 116 private int[][] codeHandlerCatchPO; 117 118 private int[][] codeHandlerClassRCN; 119 120 private boolean[] codeHasAttributes; 121 122 /** 123 * @param segment TODO 124 */ 125 public ClassBands(final Segment segment) { 126 super(segment); 127 this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap(); 128 this.cpBands = segment.getCpBands(); 129 this.classCount = header.getClassCount(); 130 this.options = header.getOptions(); 131 132 } 133 134 private int getCallCount(final int[][] methodAttrIndexes, final long[][] flags, final int context) { 135 int callCount = 0; 136 for (final int[] element : methodAttrIndexes) { 137 for (final int index : element) { 138 final AttributeLayout layout = attrMap.getAttributeLayout(index, context); 139 callCount += layout.numBackwardsCallables(); 140 } 141 } 142 int layoutsUsed = 0; 143 for (final long[] flag : flags) { 144 for (final long element : flag) { 145 layoutsUsed |= element; 146 } 147 } 148 for (int i = 0; i < 26; i++) { 149 if ((layoutsUsed & 1 << i) != 0) { 150 final AttributeLayout layout = attrMap.getAttributeLayout(i, context); 151 callCount += layout.numBackwardsCallables(); 152 } 153 } 154 return callCount; 155 } 156 157 public ArrayList<Attribute>[] getClassAttributes() { 158 return classAttributes; 159 } 160 161 public int[] getClassFieldCount() { 162 return classFieldCount; 163 } 164 165 public long[] getClassFlags() { 166 if (classAccessFlags == null) { 167 long mask = 0x7FFF; 168 for (int i = 0; i < 16; i++) { 169 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS); 170 if (layout != null && !layout.isDefaultLayout()) { 171 mask &= ~(1 << i); 172 } 173 } 174 classAccessFlags = new long[classFlags.length]; 175 for (int i = 0; i < classFlags.length; i++) { 176 classAccessFlags[i] = classFlags[i] & mask; 177 } 178 } 179 return classAccessFlags; 180 } 181 182 public int[][] getClassInterfacesInts() { 183 return classInterfacesInts; 184 } 185 186 public int[] getClassMethodCount() { 187 return classMethodCount; 188 } 189 190 public int[] getClassSuperInts() { 191 return classSuperInts; 192 } 193 194 public int[] getClassThisInts() { 195 return classThisInts; 196 } 197 198 /** 199 * Returns null if all classes should use the default major and minor version or an array of integers containing the 200 * major version numberss to use for each class in the segment 201 * 202 * @return Class file major version numbers, or null if none specified 203 */ 204 public int[] getClassVersionMajor() { 205 return classVersionMajor; 206 } 207 208 /** 209 * Returns null if all classes should use the default major and minor version or an array of integers containing the 210 * minor version numberss to use for each class in the segment 211 * 212 * @return Class file minor version numbers, or null if none specified 213 */ 214 public int[] getClassVersionMinor() { 215 return classVersionMinor; 216 } 217 218 public int[][] getCodeHandlerCatchPO() { 219 return codeHandlerCatchPO; 220 } 221 222 public int[][] getCodeHandlerClassRCN() { 223 return codeHandlerClassRCN; 224 } 225 226 public int[] getCodeHandlerCount() { 227 return codeHandlerCount; 228 } 229 230 public int[][] getCodeHandlerEndPO() { 231 return codeHandlerEndPO; 232 } 233 234 public int[][] getCodeHandlerStartP() { 235 return codeHandlerStartP; 236 } 237 238 public boolean[] getCodeHasAttributes() { 239 return codeHasAttributes; 240 } 241 242 public int[] getCodeMaxNALocals() { 243 return codeMaxNALocals; 244 } 245 246 public int[] getCodeMaxStack() { 247 return codeMaxStack; 248 } 249 250 public ArrayList<Attribute>[][] getFieldAttributes() { 251 return fieldAttributes; 252 } 253 254 public int[][] getFieldDescrInts() { 255 return fieldDescrInts; 256 } 257 258 public long[][] getFieldFlags() { 259 if (fieldAccessFlags == null) { 260 long mask = 0x7FFF; 261 for (int i = 0; i < 16; i++) { 262 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD); 263 if (layout != null && !layout.isDefaultLayout()) { 264 mask &= ~(1 << i); 265 } 266 } 267 fieldAccessFlags = new long[fieldFlags.length][]; 268 for (int i = 0; i < fieldFlags.length; i++) { 269 fieldAccessFlags[i] = new long[fieldFlags[i].length]; 270 for (int j = 0; j < fieldFlags[i].length; j++) { 271 fieldAccessFlags[i][j] = fieldFlags[i][j] & mask; 272 } 273 } 274 } 275 return fieldAccessFlags; 276 } 277 278 public IcTuple[][] getIcLocal() { 279 return icLocal; 280 } 281 282 public ArrayList<Attribute>[][] getMethodAttributes() { 283 return methodAttributes; 284 } 285 286 public String[][] getMethodDescr() { 287 return methodDescr; 288 } 289 290 public int[][] getMethodDescrInts() { 291 return methodDescrInts; 292 } 293 294 public long[][] getMethodFlags() { 295 if (methodAccessFlags == null) { 296 long mask = 0x7FFF; 297 for (int i = 0; i < 16; i++) { 298 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD); 299 if (layout != null && !layout.isDefaultLayout()) { 300 mask &= ~(1 << i); 301 } 302 } 303 methodAccessFlags = new long[methodFlags.length][]; 304 for (int i = 0; i < methodFlags.length; i++) { 305 methodAccessFlags[i] = new long[methodFlags[i].length]; 306 for (int j = 0; j < methodFlags[i].length; j++) { 307 methodAccessFlags[i][j] = methodFlags[i][j] & mask; 308 } 309 } 310 } 311 return methodAccessFlags; 312 } 313 314 /** 315 * Gets an ArrayList of ArrayLists which hold the code attributes corresponding to all classes in order. 316 * 317 * If a class doesn't have any attributes, the corresponding element in this list will be an empty ArrayList. 318 * 319 * @return ArrayList 320 */ 321 public ArrayList<List<Attribute>> getOrderedCodeAttributes() { 322 return Stream.of(codeAttributes).map(ArrayList::new).collect(Collectors.toCollection(ArrayList::new)); 323 } 324 325 public long[] getRawClassFlags() { 326 return classFlags; 327 } 328 329 private void parseClassAttrBands(final InputStream in) throws IOException, Pack200Exception { 330 final String[] cpUTF8 = cpBands.getCpUTF8(); 331 final String[] cpClass = cpBands.getCpClass(); 332 333 // Prepare empty attribute lists 334 classAttributes = new ArrayList[classCount]; 335 Arrays.setAll(classAttributes, i -> new ArrayList<>()); 336 337 classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5, options.hasClassFlagsHi()); 338 final int classAttrCount = SegmentUtils.countBit16(classFlags); 339 final int[] classAttrCounts = decodeBandInt("class_attr_count", in, Codec.UNSIGNED5, classAttrCount); 340 final int[][] classAttrIndexes = decodeBandInt("class_attr_indexes", in, Codec.UNSIGNED5, classAttrCounts); 341 final int callCount = getCallCount(classAttrIndexes, new long[][] {classFlags}, AttributeLayout.CONTEXT_CLASS); 342 final int[] classAttrCalls = decodeBandInt("class_attr_calls", in, Codec.UNSIGNED5, callCount); 343 344 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, 345 AttributeLayout.CONTEXT_CLASS); 346 347 final AttributeLayout sourceFileLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, 348 AttributeLayout.CONTEXT_CLASS); 349 final int sourceFileCount = SegmentUtils.countMatches(classFlags, sourceFileLayout); 350 final int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, Codec.UNSIGNED5, sourceFileCount); 351 352 final AttributeLayout enclosingMethodLayout = attrMap 353 .getAttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS); 354 final int enclosingMethodCount = SegmentUtils.countMatches(classFlags, enclosingMethodLayout); 355 final int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, Codec.UNSIGNED5, 356 enclosingMethodCount); 357 final int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, Codec.UNSIGNED5, 358 enclosingMethodCount); 359 360 final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, 361 AttributeLayout.CONTEXT_CLASS); 362 final int signatureCount = SegmentUtils.countMatches(classFlags, signatureLayout); 363 final int[] classSignature = decodeBandInt("class_Signature_RS", in, Codec.UNSIGNED5, signatureCount); 364 365 final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls); 366 367 final AttributeLayout innerClassLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES, 368 AttributeLayout.CONTEXT_CLASS); 369 final int innerClassCount = SegmentUtils.countMatches(classFlags, innerClassLayout); 370 final int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, Codec.UNSIGNED5, innerClassCount); 371 final int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5, 372 classInnerClassesN); 373 final int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5, 374 classInnerClassesN); 375 int flagsCount = 0; 376 for (final int[] element : classInnerClassesF) { 377 for (final int element2 : element) { 378 if (element2 != 0) { 379 flagsCount++; 380 } 381 } 382 } 383 final int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, 384 flagsCount); 385 final int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, 386 flagsCount); 387 388 final AttributeLayout versionLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, 389 AttributeLayout.CONTEXT_CLASS); 390 final int versionCount = SegmentUtils.countMatches(classFlags, versionLayout); 391 final int[] classFileVersionMinorH = decodeBandInt("class_file_version_minor_H", in, Codec.UNSIGNED5, 392 versionCount); 393 final int[] classFileVersionMajorH = decodeBandInt("class_file_version_major_H", in, Codec.UNSIGNED5, 394 versionCount); 395 if (versionCount > 0) { 396 classVersionMajor = new int[classCount]; 397 classVersionMinor = new int[classCount]; 398 } 399 final int defaultVersionMajor = header.getDefaultClassMajorVersion(); 400 final int defaultVersionMinor = header.getDefaultClassMinorVersion(); 401 402 // Parse non-predefined attribute bands 403 int backwardsCallIndex = backwardsCallsUsed; 404 final int limit = options.hasClassFlagsHi() ? 62 : 31; 405 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 406 final int[] counts = new int[limit + 1]; 407 final List<Attribute>[] otherAttributes = new List[limit + 1]; 408 for (int i = 0; i < limit; i++) { 409 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS); 410 if (layout != null && !layout.isDefaultLayout()) { 411 otherLayouts[i] = layout; 412 counts[i] = SegmentUtils.countMatches(classFlags, layout); 413 } 414 } 415 for (int i = 0; i < counts.length; i++) { 416 if (counts[i] > 0) { 417 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 418 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 419 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 420 if (numBackwardsCallables > 0) { 421 final int[] backwardsCalls = new int[numBackwardsCallables]; 422 System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 423 bands.setBackwardsCalls(backwardsCalls); 424 backwardsCallIndex += numBackwardsCallables; 425 } 426 } 427 } 428 429 // Now process the attribute bands we have parsed 430 int sourceFileIndex = 0; 431 int enclosingMethodIndex = 0; 432 int signatureIndex = 0; 433 int innerClassIndex = 0; 434 int innerClassC2NIndex = 0; 435 int versionIndex = 0; 436 icLocal = new IcTuple[classCount][]; 437 for (int i = 0; i < classCount; i++) { 438 final long flag = classFlags[i]; 439 if (deprecatedLayout.matches(classFlags[i])) { 440 classAttributes[i].add(new DeprecatedAttribute()); 441 } 442 if (sourceFileLayout.matches(flag)) { 443 final long result = classSourceFile[sourceFileIndex]; 444 ClassFileEntry value = sourceFileLayout.getValue(result, cpBands.getConstantPool()); 445 if (value == null) { 446 // Remove package prefix 447 String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1); 448 className = className.substring(className.lastIndexOf('.') + 1); 449 450 // Remove mangled nested class names 451 final char[] chars = className.toCharArray(); 452 int index = -1; 453 for (int j = 0; j < chars.length; j++) { 454 if (chars[j] <= 0x2D) { 455 index = j; 456 break; 457 } 458 } 459 if (index > -1) { 460 className = className.substring(0, index); 461 } 462 // Add .java to the end 463 value = cpBands.cpUTF8Value(className + ".java", true); 464 } 465 classAttributes[i].add(new SourceFileAttribute((CPUTF8) value)); 466 sourceFileIndex++; 467 } 468 if (enclosingMethodLayout.matches(flag)) { 469 final CPClass theClass = cpBands.cpClassValue(enclosingMethodRC[enclosingMethodIndex]); 470 CPNameAndType theMethod = null; 471 if (enclosingMethodRDN[enclosingMethodIndex] != 0) { 472 theMethod = cpBands.cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1); 473 } 474 classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod)); 475 enclosingMethodIndex++; 476 } 477 if (signatureLayout.matches(flag)) { 478 final long result = classSignature[signatureIndex]; 479 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands.getConstantPool()); 480 classAttributes[i].add(new SignatureAttribute(value)); 481 signatureIndex++; 482 } 483 if (innerClassLayout.matches(flag)) { 484 // Just create the tuples for now because the attributes are 485 // decided at the end when creating class constant pools 486 icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]]; 487 for (int j = 0; j < icLocal[i].length; j++) { 488 final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j]; 489 int icTupleC2Index = -1; 490 int icTupleNIndex = -1; 491 492 final String icTupleC = cpClass[icTupleCIndex]; 493 int icTupleF = classInnerClassesF[innerClassIndex][j]; 494 String icTupleC2 = null; 495 String icTupleN = null; 496 497 if (icTupleF != 0) { 498 icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex]; 499 icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex]; 500 icTupleC2 = cpClass[icTupleC2Index]; 501 icTupleN = cpUTF8[icTupleNIndex]; 502 innerClassC2NIndex++; 503 } else { 504 // Get from icBands 505 final IcBands icBands = segment.getIcBands(); 506 final IcTuple[] icAll = icBands.getIcTuples(); 507 for (final IcTuple element : icAll) { 508 if (element.getC().equals(icTupleC)) { 509 icTupleF = element.getF(); 510 icTupleC2 = element.getC2(); 511 icTupleN = element.getN(); 512 break; 513 } 514 } 515 } 516 517 final IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, icTupleCIndex, 518 icTupleC2Index, icTupleNIndex, j); 519 icLocal[i][j] = icTuple; 520 } 521 innerClassIndex++; 522 } 523 if (versionLayout.matches(flag)) { 524 classVersionMajor[i] = classFileVersionMajorH[versionIndex]; 525 classVersionMinor[i] = classFileVersionMinorH[versionIndex]; 526 versionIndex++; 527 } else if (classVersionMajor != null) { 528 // Fill in with defaults 529 classVersionMajor[i] = defaultVersionMajor; 530 classVersionMinor[i] = defaultVersionMinor; 531 } 532 // Non-predefined attributes 533 for (int j = 0; j < otherLayouts.length; j++) { 534 if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) { 535 // Add the next attribute 536 classAttributes[i].add(otherAttributes[j].get(0)); 537 otherAttributes[j].remove(0); 538 } 539 } 540 } 541 } 542 543 /** 544 * Parse the class metadata bands and return the number of backwards callables. 545 * 546 * @param in TODO 547 * @param classAttrCalls TODO 548 * @return the number of backwards callables. 549 * @throws Pack200Exception TODO 550 * @throws IOException If an I/O error occurs. 551 */ 552 private int parseClassMetadataBands(final InputStream in, final int[] classAttrCalls) 553 throws Pack200Exception, IOException { 554 int numBackwardsCalls = 0; 555 final String[] RxA = {"RVA", "RIA"}; 556 557 final AttributeLayout rvaLayout = attrMap 558 .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS); 559 final AttributeLayout riaLayout = attrMap 560 .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS); 561 final int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout); 562 final int riaCount = SegmentUtils.countMatches(classFlags, riaLayout); 563 final int[] RxACount = {rvaCount, riaCount}; 564 final int[] backwardsCalls = {0, 0}; 565 if (rvaCount > 0) { 566 numBackwardsCalls++; 567 backwardsCalls[0] = classAttrCalls[0]; 568 if (riaCount > 0) { 569 numBackwardsCalls++; 570 backwardsCalls[1] = classAttrCalls[1]; 571 } 572 } else if (riaCount > 0) { 573 numBackwardsCalls++; 574 backwardsCalls[1] = classAttrCalls[0]; 575 } 576 final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class"); 577 final List<Attribute> rvaAttributes = mbgs[0].getAttributes(); 578 final List<Attribute> riaAttributes = mbgs[1].getAttributes(); 579 int rvaAttributesIndex = 0; 580 int riaAttributesIndex = 0; 581 for (int i = 0; i < classFlags.length; i++) { 582 if (rvaLayout.matches(classFlags[i])) { 583 classAttributes[i].add(rvaAttributes.get(rvaAttributesIndex++)); 584 } 585 if (riaLayout.matches(classFlags[i])) { 586 classAttributes[i].add(riaAttributes.get(riaAttributesIndex++)); 587 } 588 } 589 return numBackwardsCalls; 590 } 591 592 private void parseCodeAttrBands(final InputStream in, final int codeFlagsCount) 593 throws IOException, Pack200Exception { 594 final long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, 595 segment.getSegmentHeader().getOptions().hasCodeFlagsHi()); 596 final int codeAttrCount = SegmentUtils.countBit16(codeFlags); 597 final int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount); 598 final int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts); 599 int callCount = 0; 600 for (final int[] element : codeAttrIndexes) { 601 for (final int index : element) { 602 final AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE); 603 callCount += layout.numBackwardsCallables(); 604 } 605 } 606 final int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount); 607 608 final AttributeLayout lineNumberTableLayout = attrMap 609 .getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE); 610 final int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, lineNumberTableLayout); 611 final int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, 612 lineNumberTableCount); 613 final int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, 614 lineNumberTableN); 615 final int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, 616 lineNumberTableN); 617 618 final AttributeLayout localVariableTableLayout = attrMap 619 .getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE, AttributeLayout.CONTEXT_CODE); 620 final AttributeLayout localVariableTypeTableLayout = attrMap 621 .getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE, AttributeLayout.CONTEXT_CODE); 622 623 final int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags, localVariableTableLayout); 624 final int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N", in, Codec.UNSIGNED5, 625 lengthLocalVariableNBand); 626 final int[][] localVariableTableBciP = decodeBandInt("code_LocalVariableTable_bci_P", in, Codec.BCI5, 627 localVariableTableN); 628 final int[][] localVariableTableSpanO = decodeBandInt("code_LocalVariableTable_span_O", in, Codec.BRANCH5, 629 localVariableTableN); 630 final CPUTF8[][] localVariableTableNameRU = parseCPUTF8References("code_LocalVariableTable_name_RU", in, 631 Codec.UNSIGNED5, localVariableTableN); 632 final CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences("code_LocalVariableTable_type_RS", in, 633 Codec.UNSIGNED5, localVariableTableN); 634 final int[][] localVariableTableSlot = decodeBandInt("code_LocalVariableTable_slot", in, Codec.UNSIGNED5, 635 localVariableTableN); 636 637 final int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(codeFlags, 638 localVariableTypeTableLayout); 639 final int[] localVariableTypeTableN = decodeBandInt("code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5, 640 lengthLocalVariableTypeTableNBand); 641 final int[][] localVariableTypeTableBciP = decodeBandInt("code_LocalVariableTypeTable_bci_P", in, Codec.BCI5, 642 localVariableTypeTableN); 643 final int[][] localVariableTypeTableSpanO = decodeBandInt("code_LocalVariableTypeTable_span_O", in, 644 Codec.BRANCH5, localVariableTypeTableN); 645 final CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References("code_LocalVariableTypeTable_name_RU", in, 646 Codec.UNSIGNED5, localVariableTypeTableN); 647 final CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences( 648 "code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5, localVariableTypeTableN); 649 final int[][] localVariableTypeTableSlot = decodeBandInt("code_LocalVariableTypeTable_slot", in, 650 Codec.UNSIGNED5, localVariableTypeTableN); 651 652 // Parse non-predefined attribute bands 653 int backwardsCallIndex = 0; 654 final int limit = options.hasCodeFlagsHi() ? 62 : 31; 655 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 656 final int[] counts = new int[limit + 1]; 657 final List<Attribute>[] otherAttributes = new List[limit + 1]; 658 for (int i = 0; i < limit; i++) { 659 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CODE); 660 if (layout != null && !layout.isDefaultLayout()) { 661 otherLayouts[i] = layout; 662 counts[i] = SegmentUtils.countMatches(codeFlags, layout); 663 } 664 } 665 for (int i = 0; i < counts.length; i++) { 666 if (counts[i] > 0) { 667 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 668 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 669 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 670 if (numBackwardsCallables > 0) { 671 final int[] backwardsCalls = new int[numBackwardsCallables]; 672 System.arraycopy(codeAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 673 bands.setBackwardsCalls(backwardsCalls); 674 backwardsCallIndex += numBackwardsCallables; 675 } 676 } 677 } 678 679 int lineNumberIndex = 0; 680 int lvtIndex = 0; 681 int lvttIndex = 0; 682 for (int i = 0; i < codeFlagsCount; i++) { 683 if (lineNumberTableLayout.matches(codeFlags[i])) { 684 final LineNumberTableAttribute lnta = new LineNumberTableAttribute(lineNumberTableN[lineNumberIndex], 685 lineNumberTableBciP[lineNumberIndex], lineNumberTableLine[lineNumberIndex]); 686 lineNumberIndex++; 687 codeAttributes[i].add(lnta); 688 } 689 if (localVariableTableLayout.matches(codeFlags[i])) { 690 final LocalVariableTableAttribute lvta = new LocalVariableTableAttribute(localVariableTableN[lvtIndex], 691 localVariableTableBciP[lvtIndex], localVariableTableSpanO[lvtIndex], 692 localVariableTableNameRU[lvtIndex], localVariableTableTypeRS[lvtIndex], 693 localVariableTableSlot[lvtIndex]); 694 lvtIndex++; 695 codeAttributes[i].add(lvta); 696 } 697 if (localVariableTypeTableLayout.matches(codeFlags[i])) { 698 final LocalVariableTypeTableAttribute lvtta = new LocalVariableTypeTableAttribute( 699 localVariableTypeTableN[lvttIndex], localVariableTypeTableBciP[lvttIndex], 700 localVariableTypeTableSpanO[lvttIndex], localVariableTypeTableNameRU[lvttIndex], 701 localVariableTypeTableTypeRS[lvttIndex], localVariableTypeTableSlot[lvttIndex]); 702 lvttIndex++; 703 codeAttributes[i].add(lvtta); 704 } 705 // Non-predefined attributes 706 for (int j = 0; j < otherLayouts.length; j++) { 707 if (otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) { 708 // Add the next attribute 709 codeAttributes[i].add(otherAttributes[j].get(0)); 710 otherAttributes[j].remove(0); 711 } 712 } 713 } 714 715 } 716 717 private void parseCodeBands(final InputStream in) throws Pack200Exception, IOException { 718 final AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CODE, 719 AttributeLayout.CONTEXT_METHOD); 720 721 final int codeCount = SegmentUtils.countMatches(methodFlags, layout); 722 final int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, codeCount); 723 724 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags(); 725 if (!allCodeHasFlags) { 726 codeHasAttributes = new boolean[codeCount]; 727 } 728 int codeSpecialHeader = 0; 729 for (int i = 0; i < codeCount; i++) { 730 if (codeHeaders[i] == 0) { 731 codeSpecialHeader++; 732 if (!allCodeHasFlags) { 733 codeHasAttributes[i] = true; 734 } 735 } 736 } 737 final int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, Codec.UNSIGNED5, codeSpecialHeader); 738 final int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, Codec.UNSIGNED5, 739 codeSpecialHeader); 740 final int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", in, Codec.UNSIGNED5, 741 codeSpecialHeader); 742 743 codeMaxStack = new int[codeCount]; 744 codeMaxNALocals = new int[codeCount]; 745 codeHandlerCount = new int[codeCount]; 746 int special = 0; 747 for (int i = 0; i < codeCount; i++) { 748 final int header = 0xff & codeHeaders[i]; 749 if (header < 0) { 750 throw new IllegalStateException("Shouldn't get here"); 751 } 752 if (header == 0) { 753 codeMaxStack[i] = codeMaxStackSpecials[special]; 754 codeMaxNALocals[i] = codeMaxNALocalsSpecials[special]; 755 codeHandlerCount[i] = codeHandlerCountSpecials[special]; 756 special++; 757 } else if (header <= 144) { 758 codeMaxStack[i] = (header - 1) % 12; 759 codeMaxNALocals[i] = (header - 1) / 12; 760 codeHandlerCount[i] = 0; 761 } else if (header <= 208) { 762 codeMaxStack[i] = (header - 145) % 8; 763 codeMaxNALocals[i] = (header - 145) / 8; 764 codeHandlerCount[i] = 1; 765 } else if (header <= 255) { 766 codeMaxStack[i] = (header - 209) % 7; 767 codeMaxNALocals[i] = (header - 209) / 7; 768 codeHandlerCount[i] = 2; 769 } else { 770 throw new IllegalStateException("Shouldn't get here either"); 771 } 772 } 773 codeHandlerStartP = decodeBandInt("code_handler_start_P", in, Codec.BCI5, codeHandlerCount); 774 codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in, Codec.BRANCH5, codeHandlerCount); 775 codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in, Codec.BRANCH5, codeHandlerCount); 776 codeHandlerClassRCN = decodeBandInt("code_handler_class_RCN", in, Codec.UNSIGNED5, codeHandlerCount); 777 778 final int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader; 779 780 codeAttributes = new List[codeFlagsCount]; 781 Arrays.setAll(codeAttributes, i -> new ArrayList<>()); 782 parseCodeAttrBands(in, codeFlagsCount); 783 } 784 785 private void parseFieldAttrBands(final InputStream in) throws IOException, Pack200Exception { 786 fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi()); 787 final int fieldAttrCount = SegmentUtils.countBit16(fieldFlags); 788 final int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount); 789 final int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts); 790 final int callCount = getCallCount(fieldAttrIndexes, fieldFlags, AttributeLayout.CONTEXT_FIELD); 791 final int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in, Codec.UNSIGNED5, callCount); 792 793 // Assign empty field attributes 794 fieldAttributes = new ArrayList[classCount][]; 795 for (int i = 0; i < classCount; i++) { 796 fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; 797 for (int j = 0; j < fieldFlags[i].length; j++) { 798 fieldAttributes[i][j] = new ArrayList<>(); 799 } 800 } 801 802 final AttributeLayout constantValueLayout = attrMap.getAttributeLayout("ConstantValue", 803 AttributeLayout.CONTEXT_FIELD); 804 final int constantCount = SegmentUtils.countMatches(fieldFlags, constantValueLayout); 805 final int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5, 806 constantCount); 807 int constantValueIndex = 0; 808 809 final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, 810 AttributeLayout.CONTEXT_FIELD); 811 final int signatureCount = SegmentUtils.countMatches(fieldFlags, signatureLayout); 812 final int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount); 813 int signatureIndex = 0; 814 815 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, 816 AttributeLayout.CONTEXT_FIELD); 817 818 for (int i = 0; i < classCount; i++) { 819 for (int j = 0; j < fieldFlags[i].length; j++) { 820 final long flag = fieldFlags[i][j]; 821 if (deprecatedLayout.matches(flag)) { 822 fieldAttributes[i][j].add(new DeprecatedAttribute()); 823 } 824 if (constantValueLayout.matches(flag)) { 825 // we've got a value to read 826 final long result = field_constantValue_KQ[constantValueIndex]; 827 final String desc = fieldDescr[i][j]; 828 final int colon = desc.indexOf(':'); 829 String type = desc.substring(colon + 1); 830 if (type.equals("B") || type.equals("S") || type.equals("C") || type.equals("Z")) { 831 type = "I"; 832 } 833 final ClassFileEntry value = constantValueLayout.getValue(result, type, cpBands.getConstantPool()); 834 fieldAttributes[i][j].add(new ConstantValueAttribute(value)); 835 constantValueIndex++; 836 } 837 if (signatureLayout.matches(flag)) { 838 // we've got a signature attribute 839 final long result = fieldSignatureRS[signatureIndex]; 840 final String desc = fieldDescr[i][j]; 841 final int colon = desc.indexOf(':'); 842 final String type = desc.substring(colon + 1); 843 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, type, cpBands.getConstantPool()); 844 fieldAttributes[i][j].add(new SignatureAttribute(value)); 845 signatureIndex++; 846 } 847 } 848 } 849 850 // Parse non-predefined attribute bands 851 int backwardsCallIndex = parseFieldMetadataBands(in, fieldAttrCalls); 852 final int limit = options.hasFieldFlagsHi() ? 62 : 31; 853 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 854 final int[] counts = new int[limit + 1]; 855 final List<Attribute>[] otherAttributes = new List[limit + 1]; 856 for (int i = 0; i < limit; i++) { 857 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD); 858 if (layout != null && !layout.isDefaultLayout()) { 859 otherLayouts[i] = layout; 860 counts[i] = SegmentUtils.countMatches(fieldFlags, layout); 861 } 862 } 863 for (int i = 0; i < counts.length; i++) { 864 if (counts[i] > 0) { 865 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 866 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 867 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 868 if (numBackwardsCallables > 0) { 869 final int[] backwardsCalls = new int[numBackwardsCallables]; 870 System.arraycopy(fieldAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 871 bands.setBackwardsCalls(backwardsCalls); 872 backwardsCallIndex += numBackwardsCallables; 873 } 874 } 875 } 876 877 // Non-predefined attributes 878 for (int i = 0; i < classCount; i++) { 879 for (int j = 0; j < fieldFlags[i].length; j++) { 880 final long flag = fieldFlags[i][j]; 881 int othersAddedAtStart = 0; 882 for (int k = 0; k < otherLayouts.length; k++) { 883 if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) { 884 // Add the next attribute 885 if (otherLayouts[k].getIndex() < 15) { 886 fieldAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0)); 887 } else { 888 fieldAttributes[i][j].add(otherAttributes[k].get(0)); 889 } 890 otherAttributes[k].remove(0); 891 } 892 } 893 } 894 } 895 } 896 897 private void parseFieldBands(final InputStream in) throws IOException, Pack200Exception { 898 fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5, classFieldCount); 899 fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor()); 900 parseFieldAttrBands(in); 901 } 902 903 private int parseFieldMetadataBands(final InputStream in, final int[] fieldAttrCalls) 904 throws Pack200Exception, IOException { 905 int backwardsCallsUsed = 0; 906 final String[] RxA = {"RVA", "RIA"}; 907 908 final AttributeLayout rvaLayout = attrMap 909 .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD); 910 final AttributeLayout riaLayout = attrMap 911 .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD); 912 913 final int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout); 914 final int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout); 915 final int[] RxACount = {rvaCount, riaCount}; 916 final int[] backwardsCalls = {0, 0}; 917 if (rvaCount > 0) { 918 backwardsCalls[0] = fieldAttrCalls[0]; 919 backwardsCallsUsed++; 920 if (riaCount > 0) { 921 backwardsCalls[1] = fieldAttrCalls[1]; 922 backwardsCallsUsed++; 923 } 924 } else if (riaCount > 0) { 925 backwardsCalls[1] = fieldAttrCalls[0]; 926 backwardsCallsUsed++; 927 } 928 final MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field"); 929 final List<Attribute> rvaAttributes = mb[0].getAttributes(); 930 final List<Attribute> riaAttributes = mb[1].getAttributes(); 931 int rvaAttributesIndex = 0; 932 int riaAttributesIndex = 0; 933 for (int i = 0; i < fieldFlags.length; i++) { 934 for (int j = 0; j < fieldFlags[i].length; j++) { 935 if (rvaLayout.matches(fieldFlags[i][j])) { 936 fieldAttributes[i][j].add(rvaAttributes.get(rvaAttributesIndex++)); 937 } 938 if (riaLayout.matches(fieldFlags[i][j])) { 939 fieldAttributes[i][j].add(riaAttributes.get(riaAttributesIndex++)); 940 } 941 } 942 } 943 return backwardsCallsUsed; 944 } 945 946 private MetadataBandGroup[] parseMetadata(final InputStream in, final String[] RxA, final int[] RxACount, 947 final int[] backwardsCallCounts, final String contextName) throws IOException, Pack200Exception { 948 final MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length]; 949 for (int i = 0; i < RxA.length; i++) { 950 mbg[i] = new MetadataBandGroup(RxA[i], cpBands); 951 final String rxa = RxA[i]; 952 if (rxa.indexOf('P') >= 0) { 953 mbg[i].param_NB = decodeBandInt(contextName + "_" + rxa + "_param_NB", in, Codec.BYTE1, RxACount[i]); 954 } 955 int pairCount = 0; 956 if (!rxa.equals("AD")) { 957 mbg[i].anno_N = decodeBandInt(contextName + "_" + rxa + "_anno_N", in, Codec.UNSIGNED5, RxACount[i]); 958 mbg[i].type_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_type_RS", in, Codec.UNSIGNED5, 959 mbg[i].anno_N); 960 mbg[i].pair_N = decodeBandInt(contextName + "_" + rxa + "_pair_N", in, Codec.UNSIGNED5, mbg[i].anno_N); 961 for (final int[] element : mbg[i].pair_N) { 962 for (final int element2 : element) { 963 pairCount += element2; 964 } 965 } 966 967 mbg[i].name_RU = parseCPUTF8References(contextName + "_" + rxa + "_name_RU", in, Codec.UNSIGNED5, 968 pairCount); 969 } else { 970 pairCount = RxACount[i]; 971 } 972 mbg[i].T = decodeBandInt(contextName + "_" + rxa + "_T", in, Codec.BYTE1, 973 pairCount + backwardsCallCounts[i]); 974 int ICount = 0, DCount = 0, FCount = 0, JCount = 0, cCount = 0, eCount = 0, sCount = 0, arrayCount = 0, 975 atCount = 0; 976 for (final int element : mbg[i].T) { 977 final char c = (char) element; 978 switch (c) { 979 case 'B': 980 case 'C': 981 case 'I': 982 case 'S': 983 case 'Z': 984 ICount++; 985 break; 986 case 'D': 987 DCount++; 988 break; 989 case 'F': 990 FCount++; 991 break; 992 case 'J': 993 JCount++; 994 break; 995 case 'c': 996 cCount++; 997 break; 998 case 'e': 999 eCount++; 1000 break; 1001 case 's': 1002 sCount++; 1003 break; 1004 case '[': 1005 arrayCount++; 1006 break; 1007 case '@': 1008 atCount++; 1009 break; 1010 } 1011 } 1012 mbg[i].caseI_KI = parseCPIntReferences(contextName + "_" + rxa + "_caseI_KI", in, Codec.UNSIGNED5, ICount); 1013 mbg[i].caseD_KD = parseCPDoubleReferences(contextName + "_" + rxa + "_caseD_KD", in, Codec.UNSIGNED5, 1014 DCount); 1015 mbg[i].caseF_KF = parseCPFloatReferences(contextName + "_" + rxa + "_caseF_KF", in, Codec.UNSIGNED5, 1016 FCount); 1017 mbg[i].caseJ_KJ = parseCPLongReferences(contextName + "_" + rxa + "_caseJ_KJ", in, Codec.UNSIGNED5, JCount); 1018 mbg[i].casec_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_casec_RS", in, Codec.UNSIGNED5, 1019 cCount); 1020 mbg[i].caseet_RS = parseReferences(contextName + "_" + rxa + "_caseet_RS", in, Codec.UNSIGNED5, eCount, 1021 cpBands.getCpSignature()); 1022 mbg[i].caseec_RU = parseReferences(contextName + "_" + rxa + "_caseec_RU", in, Codec.UNSIGNED5, eCount, 1023 cpBands.getCpUTF8()); 1024 mbg[i].cases_RU = parseCPUTF8References(contextName + "_" + rxa + "_cases_RU", in, Codec.UNSIGNED5, sCount); 1025 mbg[i].casearray_N = decodeBandInt(contextName + "_" + rxa + "_casearray_N", in, Codec.UNSIGNED5, 1026 arrayCount); 1027 mbg[i].nesttype_RS = parseCPUTF8References(contextName + "_" + rxa + "_nesttype_RS", in, Codec.UNSIGNED5, 1028 atCount); 1029 mbg[i].nestpair_N = decodeBandInt(contextName + "_" + rxa + "_nestpair_N", in, Codec.UNSIGNED5, atCount); 1030 int nestPairCount = 0; 1031 for (final int element : mbg[i].nestpair_N) { 1032 nestPairCount += element; 1033 } 1034 mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa + "_nestname_RU", in, Codec.UNSIGNED5, 1035 nestPairCount); 1036 } 1037 return mbg; 1038 } 1039 1040 private void parseMethodAttrBands(final InputStream in) throws IOException, Pack200Exception { 1041 methodFlags = parseFlags("method_flags", in, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi()); 1042 final int methodAttrCount = SegmentUtils.countBit16(methodFlags); 1043 final int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount); 1044 final int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts); 1045 final int callCount = getCallCount(methodAttrIndexes, methodFlags, AttributeLayout.CONTEXT_METHOD); 1046 methodAttrCalls = decodeBandInt("method_attr_calls", in, Codec.UNSIGNED5, callCount); 1047 1048 // assign empty method attributes 1049 methodAttributes = new ArrayList[classCount][]; 1050 for (int i = 0; i < classCount; i++) { 1051 methodAttributes[i] = new ArrayList[methodFlags[i].length]; 1052 for (int j = 0; j < methodFlags[i].length; j++) { 1053 methodAttributes[i][j] = new ArrayList<>(); 1054 } 1055 } 1056 1057 // Parse method exceptions attributes 1058 final AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, 1059 AttributeLayout.CONTEXT_METHOD); 1060 final int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout); 1061 final int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count); 1062 final int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions); 1063 1064 // Parse method signature attributes 1065 final AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, 1066 AttributeLayout.CONTEXT_METHOD); 1067 final int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout); 1068 final int[] methodSignatureRS = decodeBandInt("method_signature_RS", in, Codec.UNSIGNED5, count1); 1069 1070 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, 1071 AttributeLayout.CONTEXT_METHOD); 1072 1073 // Add attributes to the attribute arrays 1074 int methodExceptionsIndex = 0; 1075 int methodSignatureIndex = 0; 1076 for (int i = 0; i < methodAttributes.length; i++) { 1077 for (int j = 0; j < methodAttributes[i].length; j++) { 1078 final long flag = methodFlags[i][j]; 1079 if (methodExceptionsLayout.matches(flag)) { 1080 final int n = numExceptions[methodExceptionsIndex]; 1081 final int[] exceptions = methodExceptionsRS[methodExceptionsIndex]; 1082 final CPClass[] exceptionClasses = new CPClass[n]; 1083 for (int k = 0; k < n; k++) { 1084 exceptionClasses[k] = cpBands.cpClassValue(exceptions[k]); 1085 } 1086 methodAttributes[i][j].add(new ExceptionsAttribute(exceptionClasses)); 1087 methodExceptionsIndex++; 1088 } 1089 if (methodSignatureLayout.matches(flag)) { 1090 // We've got a signature attribute 1091 final long result = methodSignatureRS[methodSignatureIndex]; 1092 final String desc = methodDescr[i][j]; 1093 final int colon = desc.indexOf(':'); 1094 String type = desc.substring(colon + 1); 1095 // TODO Got to get better at this ... in any case, it should 1096 // be e.g. KIB or KIH 1097 if (type.equals("B") || type.equals("H")) { 1098 type = "I"; 1099 } 1100 final CPUTF8 value = (CPUTF8) methodSignatureLayout.getValue(result, type, 1101 cpBands.getConstantPool()); 1102 methodAttributes[i][j].add(new SignatureAttribute(value)); 1103 methodSignatureIndex++; 1104 } 1105 if (deprecatedLayout.matches(flag)) { 1106 methodAttributes[i][j].add(new DeprecatedAttribute()); 1107 } 1108 } 1109 } 1110 1111 // Parse non-predefined attribute bands 1112 int backwardsCallIndex = parseMethodMetadataBands(in, methodAttrCalls); 1113 final int limit = options.hasMethodFlagsHi() ? 62 : 31; 1114 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 1115 final int[] counts = new int[limit + 1]; 1116 for (int i = 0; i < limit; i++) { 1117 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD); 1118 if (layout != null && !layout.isDefaultLayout()) { 1119 otherLayouts[i] = layout; 1120 counts[i] = SegmentUtils.countMatches(methodFlags, layout); 1121 } 1122 } 1123 final List<Attribute>[] otherAttributes = new List[limit + 1]; 1124 for (int i = 0; i < counts.length; i++) { 1125 if (counts[i] > 0) { 1126 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 1127 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 1128 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 1129 if (numBackwardsCallables > 0) { 1130 final int[] backwardsCalls = new int[numBackwardsCallables]; 1131 System.arraycopy(methodAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 1132 bands.setBackwardsCalls(backwardsCalls); 1133 backwardsCallIndex += numBackwardsCallables; 1134 } 1135 } 1136 } 1137 1138 // Non-predefined attributes 1139 for (int i = 0; i < methodAttributes.length; i++) { 1140 for (int j = 0; j < methodAttributes[i].length; j++) { 1141 final long flag = methodFlags[i][j]; 1142 int othersAddedAtStart = 0; 1143 for (int k = 0; k < otherLayouts.length; k++) { 1144 if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) { 1145 // Add the next attribute 1146 if (otherLayouts[k].getIndex() < 15) { 1147 methodAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0)); 1148 } else { 1149 methodAttributes[i][j].add(otherAttributes[k].get(0)); 1150 } 1151 otherAttributes[k].remove(0); 1152 } 1153 } 1154 } 1155 } 1156 } 1157 1158 private void parseMethodBands(final InputStream in) throws IOException, Pack200Exception { 1159 methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5, classMethodCount); 1160 methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor()); 1161 parseMethodAttrBands(in); 1162 } 1163 1164 private int parseMethodMetadataBands(final InputStream in, final int[] methodAttrCalls) 1165 throws Pack200Exception, IOException { 1166 int backwardsCallsUsed = 0; 1167 final String[] RxA = {"RVA", "RIA", "RVPA", "RIPA", "AD"}; 1168 final int[] rxaCounts = {0, 0, 0, 0, 0}; 1169 1170 final AttributeLayout rvaLayout = attrMap 1171 .getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD); 1172 final AttributeLayout riaLayout = attrMap.getAttributeLayout( 1173 AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD); 1174 final AttributeLayout rvpaLayout = attrMap.getAttributeLayout( 1175 AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD); 1176 final AttributeLayout ripaLayout = attrMap.getAttributeLayout( 1177 AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD); 1178 final AttributeLayout adLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, 1179 AttributeLayout.CONTEXT_METHOD); 1180 final AttributeLayout[] rxaLayouts = {rvaLayout, riaLayout, rvpaLayout, ripaLayout, adLayout}; 1181 1182 Arrays.setAll(rxaCounts, i -> SegmentUtils.countMatches(methodFlags, rxaLayouts[i])); 1183 final int[] backwardsCalls = new int[5]; 1184 int methodAttrIndex = 0; 1185 for (int i = 0; i < backwardsCalls.length; i++) { 1186 if (rxaCounts[i] > 0) { 1187 backwardsCallsUsed++; 1188 backwardsCalls[i] = methodAttrCalls[methodAttrIndex]; 1189 methodAttrIndex++; 1190 } else { 1191 backwardsCalls[i] = 0; 1192 } 1193 } 1194 final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts, backwardsCalls, "method"); 1195 final List<Attribute>[] attributeLists = new List[RxA.length]; 1196 final int[] attributeListIndexes = new int[RxA.length]; 1197 for (int i = 0; i < mbgs.length; i++) { 1198 attributeLists[i] = mbgs[i].getAttributes(); 1199 attributeListIndexes[i] = 0; 1200 } 1201 for (int i = 0; i < methodFlags.length; i++) { 1202 for (int j = 0; j < methodFlags[i].length; j++) { 1203 for (int k = 0; k < rxaLayouts.length; k++) { 1204 if (rxaLayouts[k].matches(methodFlags[i][j])) { 1205 methodAttributes[i][j].add(attributeLists[k].get(attributeListIndexes[k]++)); 1206 } 1207 } 1208 } 1209 } 1210 return backwardsCallsUsed; 1211 } 1212 1213 /* 1214 * (non-Javadoc) 1215 * 1216 * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream) 1217 */ 1218 @Override 1219 public void read(final InputStream in) throws IOException, Pack200Exception { 1220 final int classCount = header.getClassCount(); 1221 classThisInts = decodeBandInt("class_this", in, Codec.DELTA5, classCount); 1222 classThis = getReferences(classThisInts, cpBands.getCpClass()); 1223 classSuperInts = decodeBandInt("class_super", in, Codec.DELTA5, classCount); 1224 final int[] classInterfaceLengths = decodeBandInt("class_interface_count", in, Codec.DELTA5, classCount); 1225 classInterfacesInts = decodeBandInt("class_interface", in, Codec.DELTA5, classInterfaceLengths); 1226 classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount); 1227 classMethodCount = decodeBandInt("class_method_count", in, Codec.DELTA5, classCount); 1228 parseFieldBands(in); 1229 parseMethodBands(in); 1230 parseClassAttrBands(in); 1231 parseCodeBands(in); 1232 1233 } 1234 1235 @Override 1236 public void unpack() { 1237 1238 } 1239 1240}