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