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