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