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 major version numberss to use for each 200 * 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 minor version numberss to use for each 210 * 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, AttributeLayout.CONTEXT_CLASS); 345 346 final AttributeLayout sourceFileLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS); 347 final int sourceFileCount = SegmentUtils.countMatches(classFlags, sourceFileLayout); 348 final int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, Codec.UNSIGNED5, sourceFileCount); 349 350 final AttributeLayout enclosingMethodLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS); 351 final int enclosingMethodCount = SegmentUtils.countMatches(classFlags, enclosingMethodLayout); 352 final int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, Codec.UNSIGNED5, enclosingMethodCount); 353 final int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, Codec.UNSIGNED5, enclosingMethodCount); 354 355 final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_CLASS); 356 final int signatureCount = SegmentUtils.countMatches(classFlags, signatureLayout); 357 final int[] classSignature = decodeBandInt("class_Signature_RS", in, Codec.UNSIGNED5, signatureCount); 358 359 final int backwardsCallsUsed = parseClassMetadataBands(in, classAttrCalls); 360 361 final AttributeLayout innerClassLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES, AttributeLayout.CONTEXT_CLASS); 362 final int innerClassCount = SegmentUtils.countMatches(classFlags, innerClassLayout); 363 final int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, Codec.UNSIGNED5, innerClassCount); 364 final int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5, classInnerClassesN); 365 final int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5, classInnerClassesN); 366 int flagsCount = 0; 367 for (final int[] element : classInnerClassesF) { 368 for (final int element2 : element) { 369 if (element2 != 0) { 370 flagsCount++; 371 } 372 } 373 } 374 final int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, flagsCount); 375 final int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, flagsCount); 376 377 final AttributeLayout versionLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, AttributeLayout.CONTEXT_CLASS); 378 final int versionCount = SegmentUtils.countMatches(classFlags, versionLayout); 379 final int[] classFileVersionMinorH = decodeBandInt("class_file_version_minor_H", in, Codec.UNSIGNED5, versionCount); 380 final int[] classFileVersionMajorH = decodeBandInt("class_file_version_major_H", in, Codec.UNSIGNED5, versionCount); 381 if (versionCount > 0) { 382 classVersionMajor = new int[classCount]; 383 classVersionMinor = new int[classCount]; 384 } 385 final int defaultVersionMajor = header.getDefaultClassMajorVersion(); 386 final int defaultVersionMinor = header.getDefaultClassMinorVersion(); 387 388 // Parse non-predefined attribute bands 389 int backwardsCallIndex = backwardsCallsUsed; 390 final int limit = options.hasClassFlagsHi() ? 62 : 31; 391 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 392 final int[] counts = new int[limit + 1]; 393 final List<Attribute>[] otherAttributes = new List[limit + 1]; 394 for (int i = 0; i < limit; i++) { 395 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CLASS); 396 if (layout != null && !layout.isDefaultLayout()) { 397 otherLayouts[i] = layout; 398 counts[i] = SegmentUtils.countMatches(classFlags, layout); 399 } 400 } 401 for (int i = 0; i < counts.length; i++) { 402 if (counts[i] > 0) { 403 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 404 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 405 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 406 if (numBackwardsCallables > 0) { 407 final int[] backwardsCalls = new int[numBackwardsCallables]; 408 System.arraycopy(classAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 409 bands.setBackwardsCalls(backwardsCalls); 410 backwardsCallIndex += numBackwardsCallables; 411 } 412 } 413 } 414 415 // Now process the attribute bands we have parsed 416 int sourceFileIndex = 0; 417 int enclosingMethodIndex = 0; 418 int signatureIndex = 0; 419 int innerClassIndex = 0; 420 int innerClassC2NIndex = 0; 421 int versionIndex = 0; 422 icLocal = new IcTuple[classCount][]; 423 for (int i = 0; i < classCount; i++) { 424 final long flag = classFlags[i]; 425 if (deprecatedLayout.matches(classFlags[i])) { 426 classAttributes[i].add(new DeprecatedAttribute()); 427 } 428 if (sourceFileLayout.matches(flag)) { 429 final long result = classSourceFile[sourceFileIndex]; 430 ClassFileEntry value = sourceFileLayout.getValue(result, cpBands.getConstantPool()); 431 if (value == null) { 432 // Remove package prefix 433 String className = classThis[i].substring(classThis[i].lastIndexOf('/') + 1); 434 className = className.substring(className.lastIndexOf('.') + 1); 435 436 // Remove mangled nested class names 437 final char[] chars = className.toCharArray(); 438 int index = -1; 439 for (int j = 0; j < chars.length; j++) { 440 if (chars[j] <= 0x2D) { 441 index = j; 442 break; 443 } 444 } 445 if (index > -1) { 446 className = className.substring(0, index); 447 } 448 // Add .java to the end 449 value = cpBands.cpUTF8Value(className + ".java", true); 450 } 451 classAttributes[i].add(new SourceFileAttribute((CPUTF8) value)); 452 sourceFileIndex++; 453 } 454 if (enclosingMethodLayout.matches(flag)) { 455 final CPClass theClass = cpBands.cpClassValue(enclosingMethodRC[enclosingMethodIndex]); 456 CPNameAndType theMethod = null; 457 if (enclosingMethodRDN[enclosingMethodIndex] != 0) { 458 theMethod = cpBands.cpNameAndTypeValue(enclosingMethodRDN[enclosingMethodIndex] - 1); 459 } 460 classAttributes[i].add(new EnclosingMethodAttribute(theClass, theMethod)); 461 enclosingMethodIndex++; 462 } 463 if (signatureLayout.matches(flag)) { 464 final long result = classSignature[signatureIndex]; 465 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, cpBands.getConstantPool()); 466 classAttributes[i].add(new SignatureAttribute(value)); 467 signatureIndex++; 468 } 469 if (innerClassLayout.matches(flag)) { 470 // Just create the tuples for now because the attributes are 471 // decided at the end when creating class constant pools 472 icLocal[i] = new IcTuple[classInnerClassesN[innerClassIndex]]; 473 for (int j = 0; j < icLocal[i].length; j++) { 474 final int icTupleCIndex = classInnerClassesRC[innerClassIndex][j]; 475 int icTupleC2Index = -1; 476 int icTupleNIndex = -1; 477 478 final String icTupleC = cpClass[icTupleCIndex]; 479 int icTupleF = classInnerClassesF[innerClassIndex][j]; 480 String icTupleC2 = null; 481 String icTupleN = null; 482 483 if (icTupleF != 0) { 484 icTupleC2Index = classInnerClassesOuterRCN[innerClassC2NIndex]; 485 icTupleNIndex = classInnerClassesNameRUN[innerClassC2NIndex]; 486 icTupleC2 = cpClass[icTupleC2Index]; 487 icTupleN = cpUTF8[icTupleNIndex]; 488 innerClassC2NIndex++; 489 } else { 490 // Get from icBands 491 final IcBands icBands = segment.getIcBands(); 492 final IcTuple[] icAll = icBands.getIcTuples(); 493 for (final IcTuple element : icAll) { 494 if (element.getC().equals(icTupleC)) { 495 icTupleF = element.getF(); 496 icTupleC2 = element.getC2(); 497 icTupleN = element.getN(); 498 break; 499 } 500 } 501 } 502 503 final IcTuple icTuple = new IcTuple(icTupleC, icTupleF, icTupleC2, icTupleN, icTupleCIndex, icTupleC2Index, icTupleNIndex, j); 504 icLocal[i][j] = icTuple; 505 } 506 innerClassIndex++; 507 } 508 if (versionLayout.matches(flag)) { 509 classVersionMajor[i] = classFileVersionMajorH[versionIndex]; 510 classVersionMinor[i] = classFileVersionMinorH[versionIndex]; 511 versionIndex++; 512 } else if (classVersionMajor != null) { 513 // Fill in with defaults 514 classVersionMajor[i] = defaultVersionMajor; 515 classVersionMinor[i] = defaultVersionMinor; 516 } 517 // Non-predefined attributes 518 for (int j = 0; j < otherLayouts.length; j++) { 519 if (otherLayouts[j] != null && otherLayouts[j].matches(flag)) { 520 // Add the next attribute 521 classAttributes[i].add(otherAttributes[j].get(0)); 522 otherAttributes[j].remove(0); 523 } 524 } 525 } 526 } 527 528 /** 529 * Parse the class metadata bands and return the number of backwards callables. 530 * 531 * @param in TODO 532 * @param classAttrCalls TODO 533 * @return the number of backwards callables. 534 * @throws Pack200Exception TODO 535 * @throws IOException If an I/O error occurs. 536 */ 537 private int parseClassMetadataBands(final InputStream in, final int[] classAttrCalls) throws Pack200Exception, IOException { 538 int numBackwardsCalls = 0; 539 final String[] RxA = { "RVA", "RIA" }; 540 541 final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS); 542 final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS); 543 final int rvaCount = SegmentUtils.countMatches(classFlags, rvaLayout); 544 final int riaCount = SegmentUtils.countMatches(classFlags, riaLayout); 545 final int[] RxACount = { rvaCount, riaCount }; 546 final int[] backwardsCalls = { 0, 0 }; 547 if (rvaCount > 0) { 548 numBackwardsCalls++; 549 backwardsCalls[0] = classAttrCalls[0]; 550 if (riaCount > 0) { 551 numBackwardsCalls++; 552 backwardsCalls[1] = classAttrCalls[1]; 553 } 554 } else if (riaCount > 0) { 555 numBackwardsCalls++; 556 backwardsCalls[1] = classAttrCalls[0]; 557 } 558 final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, RxACount, backwardsCalls, "class"); 559 final List<Attribute> rvaAttributes = mbgs[0].getAttributes(); 560 final List<Attribute> riaAttributes = mbgs[1].getAttributes(); 561 int rvaAttributesIndex = 0; 562 int riaAttributesIndex = 0; 563 for (int i = 0; i < classFlags.length; i++) { 564 if (rvaLayout.matches(classFlags[i])) { 565 classAttributes[i].add(rvaAttributes.get(rvaAttributesIndex++)); 566 } 567 if (riaLayout.matches(classFlags[i])) { 568 classAttributes[i].add(riaAttributes.get(riaAttributesIndex++)); 569 } 570 } 571 return numBackwardsCalls; 572 } 573 574 private void parseCodeAttrBands(final InputStream in, final int codeFlagsCount) throws IOException, Pack200Exception { 575 final long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, segment.getSegmentHeader().getOptions().hasCodeFlagsHi()); 576 final int codeAttrCount = SegmentUtils.countBit16(codeFlags); 577 final int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount); 578 final int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts); 579 int callCount = 0; 580 for (final int[] element : codeAttrIndexes) { 581 for (final int index : element) { 582 final AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE); 583 callCount += layout.numBackwardsCallables(); 584 } 585 } 586 final int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount); 587 588 final AttributeLayout lineNumberTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE); 589 final int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, lineNumberTableLayout); 590 final int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, lineNumberTableCount); 591 final int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN); 592 final int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, lineNumberTableN); 593 594 final AttributeLayout localVariableTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE, 595 AttributeLayout.CONTEXT_CODE); 596 final AttributeLayout localVariableTypeTableLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE, 597 AttributeLayout.CONTEXT_CODE); 598 599 final int lengthLocalVariableNBand = SegmentUtils.countMatches(codeFlags, localVariableTableLayout); 600 final int[] localVariableTableN = decodeBandInt("code_LocalVariableTable_N", in, Codec.UNSIGNED5, lengthLocalVariableNBand); 601 final int[][] localVariableTableBciP = decodeBandInt("code_LocalVariableTable_bci_P", in, Codec.BCI5, localVariableTableN); 602 final int[][] localVariableTableSpanO = decodeBandInt("code_LocalVariableTable_span_O", in, Codec.BRANCH5, localVariableTableN); 603 final CPUTF8[][] localVariableTableNameRU = parseCPUTF8References("code_LocalVariableTable_name_RU", in, Codec.UNSIGNED5, localVariableTableN); 604 final CPUTF8[][] localVariableTableTypeRS = parseCPSignatureReferences("code_LocalVariableTable_type_RS", in, Codec.UNSIGNED5, localVariableTableN); 605 final int[][] localVariableTableSlot = decodeBandInt("code_LocalVariableTable_slot", in, Codec.UNSIGNED5, localVariableTableN); 606 607 final int lengthLocalVariableTypeTableNBand = SegmentUtils.countMatches(codeFlags, localVariableTypeTableLayout); 608 final int[] localVariableTypeTableN = decodeBandInt("code_LocalVariableTypeTable_N", in, Codec.UNSIGNED5, lengthLocalVariableTypeTableNBand); 609 final int[][] localVariableTypeTableBciP = decodeBandInt("code_LocalVariableTypeTable_bci_P", in, Codec.BCI5, localVariableTypeTableN); 610 final int[][] localVariableTypeTableSpanO = decodeBandInt("code_LocalVariableTypeTable_span_O", in, Codec.BRANCH5, localVariableTypeTableN); 611 final CPUTF8[][] localVariableTypeTableNameRU = parseCPUTF8References("code_LocalVariableTypeTable_name_RU", in, Codec.UNSIGNED5, 612 localVariableTypeTableN); 613 final CPUTF8[][] localVariableTypeTableTypeRS = parseCPSignatureReferences("code_LocalVariableTypeTable_type_RS", in, Codec.UNSIGNED5, 614 localVariableTypeTableN); 615 final int[][] localVariableTypeTableSlot = decodeBandInt("code_LocalVariableTypeTable_slot", in, Codec.UNSIGNED5, localVariableTypeTableN); 616 617 // Parse non-predefined attribute bands 618 int backwardsCallIndex = 0; 619 final int limit = options.hasCodeFlagsHi() ? 62 : 31; 620 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 621 final int[] counts = new int[limit + 1]; 622 final List<Attribute>[] otherAttributes = new List[limit + 1]; 623 for (int i = 0; i < limit; i++) { 624 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_CODE); 625 if (layout != null && !layout.isDefaultLayout()) { 626 otherLayouts[i] = layout; 627 counts[i] = SegmentUtils.countMatches(codeFlags, layout); 628 } 629 } 630 for (int i = 0; i < counts.length; i++) { 631 if (counts[i] > 0) { 632 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 633 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 634 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 635 if (numBackwardsCallables > 0) { 636 final int[] backwardsCalls = new int[numBackwardsCallables]; 637 System.arraycopy(codeAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 638 bands.setBackwardsCalls(backwardsCalls); 639 backwardsCallIndex += numBackwardsCallables; 640 } 641 } 642 } 643 644 int lineNumberIndex = 0; 645 int lvtIndex = 0; 646 int lvttIndex = 0; 647 for (int i = 0; i < codeFlagsCount; i++) { 648 if (lineNumberTableLayout.matches(codeFlags[i])) { 649 final LineNumberTableAttribute lnta = new LineNumberTableAttribute(lineNumberTableN[lineNumberIndex], lineNumberTableBciP[lineNumberIndex], 650 lineNumberTableLine[lineNumberIndex]); 651 lineNumberIndex++; 652 codeAttributes[i].add(lnta); 653 } 654 if (localVariableTableLayout.matches(codeFlags[i])) { 655 final LocalVariableTableAttribute lvta = new LocalVariableTableAttribute(localVariableTableN[lvtIndex], localVariableTableBciP[lvtIndex], 656 localVariableTableSpanO[lvtIndex], localVariableTableNameRU[lvtIndex], localVariableTableTypeRS[lvtIndex], 657 localVariableTableSlot[lvtIndex]); 658 lvtIndex++; 659 codeAttributes[i].add(lvta); 660 } 661 if (localVariableTypeTableLayout.matches(codeFlags[i])) { 662 final LocalVariableTypeTableAttribute lvtta = new LocalVariableTypeTableAttribute(localVariableTypeTableN[lvttIndex], 663 localVariableTypeTableBciP[lvttIndex], localVariableTypeTableSpanO[lvttIndex], localVariableTypeTableNameRU[lvttIndex], 664 localVariableTypeTableTypeRS[lvttIndex], localVariableTypeTableSlot[lvttIndex]); 665 lvttIndex++; 666 codeAttributes[i].add(lvtta); 667 } 668 // Non-predefined attributes 669 for (int j = 0; j < otherLayouts.length; j++) { 670 if (otherLayouts[j] != null && otherLayouts[j].matches(codeFlags[i])) { 671 // Add the next attribute 672 codeAttributes[i].add(otherAttributes[j].get(0)); 673 otherAttributes[j].remove(0); 674 } 675 } 676 } 677 678 } 679 680 private void parseCodeBands(final InputStream in) throws Pack200Exception, IOException { 681 final AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD); 682 683 final int codeCount = SegmentUtils.countMatches(methodFlags, layout); 684 final int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, codeCount); 685 686 final boolean allCodeHasFlags = segment.getSegmentHeader().getOptions().hasAllCodeFlags(); 687 if (!allCodeHasFlags) { 688 codeHasAttributes = new boolean[codeCount]; 689 } 690 int codeSpecialHeader = 0; 691 for (int i = 0; i < codeCount; i++) { 692 if (codeHeaders[i] == 0) { 693 codeSpecialHeader++; 694 if (!allCodeHasFlags) { 695 codeHasAttributes[i] = true; 696 } 697 } 698 } 699 final int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, Codec.UNSIGNED5, codeSpecialHeader); 700 final int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, Codec.UNSIGNED5, codeSpecialHeader); 701 final int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", in, Codec.UNSIGNED5, codeSpecialHeader); 702 703 codeMaxStack = new int[codeCount]; 704 codeMaxNALocals = new int[codeCount]; 705 codeHandlerCount = new int[codeCount]; 706 int special = 0; 707 for (int i = 0; i < codeCount; i++) { 708 final int header = 0xff & codeHeaders[i]; 709 if (header < 0) { 710 throw new IllegalStateException("Shouldn't get here"); 711 } 712 if (header == 0) { 713 codeMaxStack[i] = codeMaxStackSpecials[special]; 714 codeMaxNALocals[i] = codeMaxNALocalsSpecials[special]; 715 codeHandlerCount[i] = codeHandlerCountSpecials[special]; 716 special++; 717 } else if (header <= 144) { 718 codeMaxStack[i] = (header - 1) % 12; 719 codeMaxNALocals[i] = (header - 1) / 12; 720 codeHandlerCount[i] = 0; 721 } else if (header <= 208) { 722 codeMaxStack[i] = (header - 145) % 8; 723 codeMaxNALocals[i] = (header - 145) / 8; 724 codeHandlerCount[i] = 1; 725 } else if (header <= 255) { 726 codeMaxStack[i] = (header - 209) % 7; 727 codeMaxNALocals[i] = (header - 209) / 7; 728 codeHandlerCount[i] = 2; 729 } else { 730 throw new IllegalStateException("Shouldn't get here either"); 731 } 732 } 733 codeHandlerStartP = decodeBandInt("code_handler_start_P", in, Codec.BCI5, codeHandlerCount); 734 codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in, Codec.BRANCH5, codeHandlerCount); 735 codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in, Codec.BRANCH5, codeHandlerCount); 736 codeHandlerClassRCN = decodeBandInt("code_handler_class_RCN", in, Codec.UNSIGNED5, codeHandlerCount); 737 738 final int codeFlagsCount = allCodeHasFlags ? codeCount : codeSpecialHeader; 739 740 codeAttributes = new List[codeFlagsCount]; 741 Arrays.setAll(codeAttributes, i -> new ArrayList<>()); 742 parseCodeAttrBands(in, codeFlagsCount); 743 } 744 745 private void parseFieldAttrBands(final InputStream in) throws IOException, Pack200Exception { 746 fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi()); 747 final int fieldAttrCount = SegmentUtils.countBit16(fieldFlags); 748 final int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount); 749 final int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts); 750 final int callCount = getCallCount(fieldAttrIndexes, fieldFlags, AttributeLayout.CONTEXT_FIELD); 751 final int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in, Codec.UNSIGNED5, callCount); 752 753 // Assign empty field attributes 754 fieldAttributes = new ArrayList[classCount][]; 755 for (int i = 0; i < classCount; i++) { 756 fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; 757 for (int j = 0; j < fieldFlags[i].length; j++) { 758 fieldAttributes[i][j] = new ArrayList<>(); 759 } 760 } 761 762 final AttributeLayout constantValueLayout = attrMap.getAttributeLayout("ConstantValue", AttributeLayout.CONTEXT_FIELD); 763 final int constantCount = SegmentUtils.countMatches(fieldFlags, constantValueLayout); 764 final int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5, constantCount); 765 int constantValueIndex = 0; 766 767 final AttributeLayout signatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_FIELD); 768 final int signatureCount = SegmentUtils.countMatches(fieldFlags, signatureLayout); 769 final int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount); 770 int signatureIndex = 0; 771 772 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_FIELD); 773 774 for (int i = 0; i < classCount; i++) { 775 for (int j = 0; j < fieldFlags[i].length; j++) { 776 final long flag = fieldFlags[i][j]; 777 if (deprecatedLayout.matches(flag)) { 778 fieldAttributes[i][j].add(new DeprecatedAttribute()); 779 } 780 if (constantValueLayout.matches(flag)) { 781 // we've got a value to read 782 final long result = field_constantValue_KQ[constantValueIndex]; 783 final String desc = fieldDescr[i][j]; 784 final int colon = desc.indexOf(':'); 785 String type = desc.substring(colon + 1); 786 if (type.equals("B") || type.equals("S") || type.equals("C") || type.equals("Z")) { 787 type = "I"; 788 } 789 final ClassFileEntry value = constantValueLayout.getValue(result, type, cpBands.getConstantPool()); 790 fieldAttributes[i][j].add(new ConstantValueAttribute(value)); 791 constantValueIndex++; 792 } 793 if (signatureLayout.matches(flag)) { 794 // we've got a signature attribute 795 final long result = fieldSignatureRS[signatureIndex]; 796 final String desc = fieldDescr[i][j]; 797 final int colon = desc.indexOf(':'); 798 final String type = desc.substring(colon + 1); 799 final CPUTF8 value = (CPUTF8) signatureLayout.getValue(result, type, cpBands.getConstantPool()); 800 fieldAttributes[i][j].add(new SignatureAttribute(value)); 801 signatureIndex++; 802 } 803 } 804 } 805 806 // Parse non-predefined attribute bands 807 int backwardsCallIndex = parseFieldMetadataBands(in, fieldAttrCalls); 808 final int limit = options.hasFieldFlagsHi() ? 62 : 31; 809 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 810 final int[] counts = new int[limit + 1]; 811 final List<Attribute>[] otherAttributes = new List[limit + 1]; 812 for (int i = 0; i < limit; i++) { 813 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_FIELD); 814 if (layout != null && !layout.isDefaultLayout()) { 815 otherLayouts[i] = layout; 816 counts[i] = SegmentUtils.countMatches(fieldFlags, layout); 817 } 818 } 819 for (int i = 0; i < counts.length; i++) { 820 if (counts[i] > 0) { 821 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 822 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 823 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 824 if (numBackwardsCallables > 0) { 825 final int[] backwardsCalls = new int[numBackwardsCallables]; 826 System.arraycopy(fieldAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 827 bands.setBackwardsCalls(backwardsCalls); 828 backwardsCallIndex += numBackwardsCallables; 829 } 830 } 831 } 832 833 // Non-predefined attributes 834 for (int i = 0; i < classCount; i++) { 835 for (int j = 0; j < fieldFlags[i].length; j++) { 836 final long flag = fieldFlags[i][j]; 837 int othersAddedAtStart = 0; 838 for (int k = 0; k < otherLayouts.length; k++) { 839 if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) { 840 // Add the next attribute 841 if (otherLayouts[k].getIndex() < 15) { 842 fieldAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0)); 843 } else { 844 fieldAttributes[i][j].add(otherAttributes[k].get(0)); 845 } 846 otherAttributes[k].remove(0); 847 } 848 } 849 } 850 } 851 } 852 853 private void parseFieldBands(final InputStream in) throws IOException, Pack200Exception { 854 fieldDescrInts = decodeBandInt("field_descr", in, Codec.DELTA5, classFieldCount); 855 fieldDescr = getReferences(fieldDescrInts, cpBands.getCpDescriptor()); 856 parseFieldAttrBands(in); 857 } 858 859 private int parseFieldMetadataBands(final InputStream in, final int[] fieldAttrCalls) throws Pack200Exception, IOException { 860 int backwardsCallsUsed = 0; 861 final String[] RxA = { "RVA", "RIA" }; 862 863 final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD); 864 final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD); 865 866 final int rvaCount = SegmentUtils.countMatches(fieldFlags, rvaLayout); 867 final int riaCount = SegmentUtils.countMatches(fieldFlags, riaLayout); 868 final int[] RxACount = { rvaCount, riaCount }; 869 final int[] backwardsCalls = { 0, 0 }; 870 if (rvaCount > 0) { 871 backwardsCalls[0] = fieldAttrCalls[0]; 872 backwardsCallsUsed++; 873 if (riaCount > 0) { 874 backwardsCalls[1] = fieldAttrCalls[1]; 875 backwardsCallsUsed++; 876 } 877 } else if (riaCount > 0) { 878 backwardsCalls[1] = fieldAttrCalls[0]; 879 backwardsCallsUsed++; 880 } 881 final MetadataBandGroup[] mb = parseMetadata(in, RxA, RxACount, backwardsCalls, "field"); 882 final List<Attribute> rvaAttributes = mb[0].getAttributes(); 883 final List<Attribute> riaAttributes = mb[1].getAttributes(); 884 int rvaAttributesIndex = 0; 885 int riaAttributesIndex = 0; 886 for (int i = 0; i < fieldFlags.length; i++) { 887 for (int j = 0; j < fieldFlags[i].length; j++) { 888 if (rvaLayout.matches(fieldFlags[i][j])) { 889 fieldAttributes[i][j].add(rvaAttributes.get(rvaAttributesIndex++)); 890 } 891 if (riaLayout.matches(fieldFlags[i][j])) { 892 fieldAttributes[i][j].add(riaAttributes.get(riaAttributesIndex++)); 893 } 894 } 895 } 896 return backwardsCallsUsed; 897 } 898 899 private MetadataBandGroup[] parseMetadata(final InputStream in, final String[] RxA, final int[] RxACount, final int[] backwardsCallCounts, 900 final String contextName) throws IOException, Pack200Exception { 901 final MetadataBandGroup[] mbg = new MetadataBandGroup[RxA.length]; 902 for (int i = 0; i < RxA.length; i++) { 903 mbg[i] = new MetadataBandGroup(RxA[i], cpBands); 904 final String rxa = RxA[i]; 905 if (rxa.indexOf('P') >= 0) { 906 mbg[i].param_NB = decodeBandInt(contextName + "_" + rxa + "_param_NB", in, Codec.BYTE1, RxACount[i]); 907 } 908 int pairCount = 0; 909 if (!rxa.equals("AD")) { 910 mbg[i].anno_N = decodeBandInt(contextName + "_" + rxa + "_anno_N", in, Codec.UNSIGNED5, RxACount[i]); 911 mbg[i].type_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_type_RS", in, Codec.UNSIGNED5, mbg[i].anno_N); 912 mbg[i].pair_N = decodeBandInt(contextName + "_" + rxa + "_pair_N", in, Codec.UNSIGNED5, mbg[i].anno_N); 913 for (final int[] element : mbg[i].pair_N) { 914 for (final int element2 : element) { 915 pairCount += element2; 916 } 917 } 918 919 mbg[i].name_RU = parseCPUTF8References(contextName + "_" + rxa + "_name_RU", in, Codec.UNSIGNED5, pairCount); 920 } else { 921 pairCount = RxACount[i]; 922 } 923 mbg[i].T = decodeBandInt(contextName + "_" + rxa + "_T", in, Codec.BYTE1, pairCount + backwardsCallCounts[i]); 924 int ICount = 0, DCount = 0, FCount = 0, JCount = 0, cCount = 0, eCount = 0, sCount = 0, arrayCount = 0, atCount = 0; 925 for (final int element : mbg[i].T) { 926 final char c = (char) element; 927 switch (c) { 928 case 'B': 929 case 'C': 930 case 'I': 931 case 'S': 932 case 'Z': 933 ICount++; 934 break; 935 case 'D': 936 DCount++; 937 break; 938 case 'F': 939 FCount++; 940 break; 941 case 'J': 942 JCount++; 943 break; 944 case 'c': 945 cCount++; 946 break; 947 case 'e': 948 eCount++; 949 break; 950 case 's': 951 sCount++; 952 break; 953 case '[': 954 arrayCount++; 955 break; 956 case '@': 957 atCount++; 958 break; 959 } 960 } 961 mbg[i].caseI_KI = parseCPIntReferences(contextName + "_" + rxa + "_caseI_KI", in, Codec.UNSIGNED5, ICount); 962 mbg[i].caseD_KD = parseCPDoubleReferences(contextName + "_" + rxa + "_caseD_KD", in, Codec.UNSIGNED5, DCount); 963 mbg[i].caseF_KF = parseCPFloatReferences(contextName + "_" + rxa + "_caseF_KF", in, Codec.UNSIGNED5, FCount); 964 mbg[i].caseJ_KJ = parseCPLongReferences(contextName + "_" + rxa + "_caseJ_KJ", in, Codec.UNSIGNED5, JCount); 965 mbg[i].casec_RS = parseCPSignatureReferences(contextName + "_" + rxa + "_casec_RS", in, Codec.UNSIGNED5, cCount); 966 mbg[i].caseet_RS = parseReferences(contextName + "_" + rxa + "_caseet_RS", in, Codec.UNSIGNED5, eCount, cpBands.getCpSignature()); 967 mbg[i].caseec_RU = parseReferences(contextName + "_" + rxa + "_caseec_RU", in, Codec.UNSIGNED5, eCount, cpBands.getCpUTF8()); 968 mbg[i].cases_RU = parseCPUTF8References(contextName + "_" + rxa + "_cases_RU", in, Codec.UNSIGNED5, sCount); 969 mbg[i].casearray_N = decodeBandInt(contextName + "_" + rxa + "_casearray_N", in, Codec.UNSIGNED5, arrayCount); 970 mbg[i].nesttype_RS = parseCPUTF8References(contextName + "_" + rxa + "_nesttype_RS", in, Codec.UNSIGNED5, atCount); 971 mbg[i].nestpair_N = decodeBandInt(contextName + "_" + rxa + "_nestpair_N", in, Codec.UNSIGNED5, atCount); 972 int nestPairCount = 0; 973 for (final int element : mbg[i].nestpair_N) { 974 nestPairCount += element; 975 } 976 mbg[i].nestname_RU = parseCPUTF8References(contextName + "_" + rxa + "_nestname_RU", in, Codec.UNSIGNED5, nestPairCount); 977 } 978 return mbg; 979 } 980 981 private void parseMethodAttrBands(final InputStream in) throws IOException, Pack200Exception { 982 methodFlags = parseFlags("method_flags", in, classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi()); 983 final int methodAttrCount = SegmentUtils.countBit16(methodFlags); 984 final int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount); 985 final int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts); 986 final int callCount = getCallCount(methodAttrIndexes, methodFlags, AttributeLayout.CONTEXT_METHOD); 987 methodAttrCalls = decodeBandInt("method_attr_calls", in, Codec.UNSIGNED5, callCount); 988 989 // assign empty method attributes 990 methodAttributes = new ArrayList[classCount][]; 991 for (int i = 0; i < classCount; i++) { 992 methodAttributes[i] = new ArrayList[methodFlags[i].length]; 993 for (int j = 0; j < methodFlags[i].length; j++) { 994 methodAttributes[i][j] = new ArrayList<>(); 995 } 996 } 997 998 // Parse method exceptions attributes 999 final AttributeLayout methodExceptionsLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, AttributeLayout.CONTEXT_METHOD); 1000 final int count = SegmentUtils.countMatches(methodFlags, methodExceptionsLayout); 1001 final int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count); 1002 final int[][] methodExceptionsRS = decodeBandInt("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions); 1003 1004 // Parse method signature attributes 1005 final AttributeLayout methodSignatureLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_METHOD); 1006 final int count1 = SegmentUtils.countMatches(methodFlags, methodSignatureLayout); 1007 final int[] methodSignatureRS = decodeBandInt("method_signature_RS", in, Codec.UNSIGNED5, count1); 1008 1009 final AttributeLayout deprecatedLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_METHOD); 1010 1011 // Add attributes to the attribute arrays 1012 int methodExceptionsIndex = 0; 1013 int methodSignatureIndex = 0; 1014 for (int i = 0; i < methodAttributes.length; i++) { 1015 for (int j = 0; j < methodAttributes[i].length; j++) { 1016 final long flag = methodFlags[i][j]; 1017 if (methodExceptionsLayout.matches(flag)) { 1018 final int n = numExceptions[methodExceptionsIndex]; 1019 final int[] exceptions = methodExceptionsRS[methodExceptionsIndex]; 1020 final CPClass[] exceptionClasses = new CPClass[n]; 1021 for (int k = 0; k < n; k++) { 1022 exceptionClasses[k] = cpBands.cpClassValue(exceptions[k]); 1023 } 1024 methodAttributes[i][j].add(new ExceptionsAttribute(exceptionClasses)); 1025 methodExceptionsIndex++; 1026 } 1027 if (methodSignatureLayout.matches(flag)) { 1028 // We've got a signature attribute 1029 final long result = methodSignatureRS[methodSignatureIndex]; 1030 final String desc = methodDescr[i][j]; 1031 final int colon = desc.indexOf(':'); 1032 String type = desc.substring(colon + 1); 1033 // TODO Got to get better at this ... in any case, it should 1034 // be e.g. KIB or KIH 1035 if (type.equals("B") || type.equals("H")) { 1036 type = "I"; 1037 } 1038 final CPUTF8 value = (CPUTF8) methodSignatureLayout.getValue(result, type, cpBands.getConstantPool()); 1039 methodAttributes[i][j].add(new SignatureAttribute(value)); 1040 methodSignatureIndex++; 1041 } 1042 if (deprecatedLayout.matches(flag)) { 1043 methodAttributes[i][j].add(new DeprecatedAttribute()); 1044 } 1045 } 1046 } 1047 1048 // Parse non-predefined attribute bands 1049 int backwardsCallIndex = parseMethodMetadataBands(in, methodAttrCalls); 1050 final int limit = options.hasMethodFlagsHi() ? 62 : 31; 1051 final AttributeLayout[] otherLayouts = new AttributeLayout[limit + 1]; 1052 final int[] counts = new int[limit + 1]; 1053 for (int i = 0; i < limit; i++) { 1054 final AttributeLayout layout = attrMap.getAttributeLayout(i, AttributeLayout.CONTEXT_METHOD); 1055 if (layout != null && !layout.isDefaultLayout()) { 1056 otherLayouts[i] = layout; 1057 counts[i] = SegmentUtils.countMatches(methodFlags, layout); 1058 } 1059 } 1060 final List<Attribute>[] otherAttributes = new List[limit + 1]; 1061 for (int i = 0; i < counts.length; i++) { 1062 if (counts[i] > 0) { 1063 final NewAttributeBands bands = attrMap.getAttributeBands(otherLayouts[i]); 1064 otherAttributes[i] = bands.parseAttributes(in, counts[i]); 1065 final int numBackwardsCallables = otherLayouts[i].numBackwardsCallables(); 1066 if (numBackwardsCallables > 0) { 1067 final int[] backwardsCalls = new int[numBackwardsCallables]; 1068 System.arraycopy(methodAttrCalls, backwardsCallIndex, backwardsCalls, 0, numBackwardsCallables); 1069 bands.setBackwardsCalls(backwardsCalls); 1070 backwardsCallIndex += numBackwardsCallables; 1071 } 1072 } 1073 } 1074 1075 // Non-predefined attributes 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 int othersAddedAtStart = 0; 1080 for (int k = 0; k < otherLayouts.length; k++) { 1081 if (otherLayouts[k] != null && otherLayouts[k].matches(flag)) { 1082 // Add the next attribute 1083 if (otherLayouts[k].getIndex() < 15) { 1084 methodAttributes[i][j].add(othersAddedAtStart++, otherAttributes[k].get(0)); 1085 } else { 1086 methodAttributes[i][j].add(otherAttributes[k].get(0)); 1087 } 1088 otherAttributes[k].remove(0); 1089 } 1090 } 1091 } 1092 } 1093 } 1094 1095 private void parseMethodBands(final InputStream in) throws IOException, Pack200Exception { 1096 methodDescrInts = decodeBandInt("method_descr", in, Codec.MDELTA5, classMethodCount); 1097 methodDescr = getReferences(methodDescrInts, cpBands.getCpDescriptor()); 1098 parseMethodAttrBands(in); 1099 } 1100 1101 private int parseMethodMetadataBands(final InputStream in, final int[] methodAttrCalls) throws Pack200Exception, IOException { 1102 int backwardsCallsUsed = 0; 1103 final String[] RxA = { "RVA", "RIA", "RVPA", "RIPA", "AD" }; 1104 final int[] rxaCounts = { 0, 0, 0, 0, 0 }; 1105 1106 final AttributeLayout rvaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD); 1107 final AttributeLayout riaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD); 1108 final AttributeLayout rvpaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, 1109 AttributeLayout.CONTEXT_METHOD); 1110 final AttributeLayout ripaLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, 1111 AttributeLayout.CONTEXT_METHOD); 1112 final AttributeLayout adLayout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, AttributeLayout.CONTEXT_METHOD); 1113 final AttributeLayout[] rxaLayouts = { rvaLayout, riaLayout, rvpaLayout, ripaLayout, adLayout }; 1114 1115 Arrays.setAll(rxaCounts, i -> SegmentUtils.countMatches(methodFlags, rxaLayouts[i])); 1116 final int[] backwardsCalls = new int[5]; 1117 int methodAttrIndex = 0; 1118 for (int i = 0; i < backwardsCalls.length; i++) { 1119 if (rxaCounts[i] > 0) { 1120 backwardsCallsUsed++; 1121 backwardsCalls[i] = methodAttrCalls[methodAttrIndex]; 1122 methodAttrIndex++; 1123 } else { 1124 backwardsCalls[i] = 0; 1125 } 1126 } 1127 final MetadataBandGroup[] mbgs = parseMetadata(in, RxA, rxaCounts, backwardsCalls, "method"); 1128 final List<Attribute>[] attributeLists = new List[RxA.length]; 1129 final int[] attributeListIndexes = new int[RxA.length]; 1130 for (int i = 0; i < mbgs.length; i++) { 1131 attributeLists[i] = mbgs[i].getAttributes(); 1132 attributeListIndexes[i] = 0; 1133 } 1134 for (int i = 0; i < methodFlags.length; i++) { 1135 for (int j = 0; j < methodFlags[i].length; j++) { 1136 for (int k = 0; k < rxaLayouts.length; k++) { 1137 if (rxaLayouts[k].matches(methodFlags[i][j])) { 1138 methodAttributes[i][j].add(attributeLists[k].get(attributeListIndexes[k]++)); 1139 } 1140 } 1141 } 1142 } 1143 return backwardsCallsUsed; 1144 } 1145 1146 /* 1147 * (non-Javadoc) 1148 * 1149 * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream) 1150 */ 1151 @Override 1152 public void read(final InputStream in) throws IOException, Pack200Exception { 1153 final int classCount = header.getClassCount(); 1154 classThisInts = decodeBandInt("class_this", in, Codec.DELTA5, classCount); 1155 classThis = getReferences(classThisInts, cpBands.getCpClass()); 1156 classSuperInts = decodeBandInt("class_super", in, Codec.DELTA5, classCount); 1157 final int[] classInterfaceLengths = decodeBandInt("class_interface_count", in, Codec.DELTA5, classCount); 1158 classInterfacesInts = decodeBandInt("class_interface", in, Codec.DELTA5, classInterfaceLengths); 1159 classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount); 1160 classMethodCount = decodeBandInt("class_method_count", in, Codec.DELTA5, classCount); 1161 parseFieldBands(in); 1162 parseMethodBands(in); 1163 parseClassAttrBands(in); 1164 parseCodeBands(in); 1165 1166 } 1167 1168 @Override 1169 public void unpack() { 1170 1171 } 1172 1173}