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