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