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.bytecode; 018 019import java.io.DataOutputStream; 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.List; 024 025import org.apache.commons.compress.harmony.pack200.Pack200Exception; 026 027/** 028 * Local variable type table. 029 */ 030public class LocalVariableTypeTableAttribute extends BCIRenumberedAttribute { 031 032 private static CPUTF8 attributeName; 033 public static void setAttributeName(final CPUTF8 cpUTF8Value) { 034 attributeName = cpUTF8Value; 035 } 036 private final int localVariableTypeTableLength; 037 private final int[] startPcs; 038 private final int[] lengths; 039 private int[] nameIndexes; 040 private int[] signatureIndexes; 041 private final int[] indexes; 042 private final CPUTF8[] names; 043 private final CPUTF8[] signatures; 044 045 private int codeLength; 046 047 public LocalVariableTypeTableAttribute(final int localVariableTypeTableLength, final int[] startPcs, 048 final int[] lengths, final CPUTF8[] names, final CPUTF8[] signatures, final int[] indexes) { 049 super(attributeName); 050 this.localVariableTypeTableLength = localVariableTypeTableLength; 051 this.startPcs = startPcs; 052 this.lengths = lengths; 053 this.names = names; 054 this.signatures = signatures; 055 this.indexes = indexes; 056 } 057 058 @Override 059 protected int getLength() { 060 return 2 + (10 * localVariableTypeTableLength); 061 } 062 063 @Override 064 protected ClassFileEntry[] getNestedClassFileEntries() { 065 final List<CPUTF8> nestedEntries = new ArrayList<>(); 066 nestedEntries.add(getAttributeName()); 067 for (int i = 0; i < localVariableTypeTableLength; i++) { 068 nestedEntries.add(names[i]); 069 nestedEntries.add(signatures[i]); 070 } 071 return nestedEntries.toArray(ClassFileEntry.NONE); 072 } 073 074 @Override 075 protected int[] getStartPCs() { 076 return startPcs; 077 } 078 079 /* 080 * (non-Javadoc) 081 * 082 * @see org.apache.commons.compress.harmony.unpack200.bytecode.BCIRenumberedAttribute#renumber(java.util.List) 083 */ 084 @Override 085 public void renumber(final List<Integer> byteCodeOffsets) throws Pack200Exception { 086 // Remember the unrenumbered startPcs, since that's used later 087 // to calculate end position. 088 final int[] unrenumberedStartPcs = Arrays.copyOf(startPcs, startPcs.length); 089 090 // Next renumber startPcs in place 091 super.renumber(byteCodeOffsets); 092 093 // lengths are BRANCH5 encoded, not BCI-encoded. 094 // In other words: 095 // startPc is BCI5 startPc 096 // endPc is byteCodeOffset[(index of startPc in byteCodeOffset) + 097 // (encoded length)] 098 // real length = endPc - startPc 099 // special case if endPc is beyond end of bytecode array 100 101 final int maxSize = codeLength; 102 103 // Iterate through the lengths and update each in turn. 104 // This is done in place in the lengths array. 105 for (int index = 0; index < lengths.length; index++) { 106 final int startPc = startPcs[index]; 107 int revisedLength = -1; 108 final int encodedLength = lengths[index]; 109 110 // First get the index of the startPc in the byteCodeOffsets 111 final int indexOfStartPC = unrenumberedStartPcs[index]; 112 // Given the index of the startPc, we can now add 113 // the encodedLength to it to get the stop index. 114 final int stopIndex = indexOfStartPC + encodedLength; 115 if (stopIndex < 0) { 116 throw new Pack200Exception("Error renumbering bytecode indexes"); 117 } 118 // Length can either be an index into the byte code offsets, or one 119 // beyond the 120 // end of the byte code offsets. Need to determine which this is. 121 if (stopIndex == byteCodeOffsets.size()) { 122 // Pointing to one past the end of the byte code array 123 revisedLength = maxSize - startPc; 124 } else { 125 // We're indexed into the byte code array 126 final int stopValue = byteCodeOffsets.get(stopIndex).intValue(); 127 revisedLength = stopValue - startPc; 128 } 129 lengths[index] = revisedLength; 130 } 131 } 132 133 @Override 134 protected void resolve(final ClassConstantPool pool) { 135 super.resolve(pool); 136 nameIndexes = new int[localVariableTypeTableLength]; 137 signatureIndexes = new int[localVariableTypeTableLength]; 138 for (int i = 0; i < localVariableTypeTableLength; i++) { 139 names[i].resolve(pool); 140 signatures[i].resolve(pool); 141 nameIndexes[i] = pool.indexOf(names[i]); 142 signatureIndexes[i] = pool.indexOf(signatures[i]); 143 } 144 } 145 146 public void setCodeLength(final int length) { 147 codeLength = length; 148 } 149 150 @Override 151 public String toString() { 152 return "LocalVariableTypeTable: " + +localVariableTypeTableLength + " varaibles"; 153 } 154 155 @Override 156 protected void writeBody(final DataOutputStream dos) throws IOException { 157 dos.writeShort(localVariableTypeTableLength); 158 for (int i = 0; i < localVariableTypeTableLength; i++) { 159 dos.writeShort(startPcs[i]); 160 dos.writeShort(lengths[i]); 161 dos.writeShort(nameIndexes[i]); 162 dos.writeShort(signatureIndexes[i]); 163 dos.writeShort(indexes[i]); 164 } 165 } 166 167}