1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import org.apache.bcel.Constants;
23
24 /***
25 * This class represents a table of line numbers for debugging
26 * purposes. This attribute is used by the <em>Code</em> attribute. It
27 * contains pairs of PCs and line numbers.
28 *
29 * @version $Id: LineNumberTable.java 386056 2006-03-15 11:31:56Z tcurdt $
30 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
31 * @see Code
32 * @see LineNumber
33 */
34 public final class LineNumberTable extends Attribute {
35
36 private int line_number_table_length;
37 private LineNumber[] line_number_table;
38
39
40
41
42
43
44 public LineNumberTable(LineNumberTable c) {
45 this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool());
46 }
47
48
49
50
51
52
53
54
55 public LineNumberTable(int name_index, int length, LineNumber[] line_number_table,
56 ConstantPool constant_pool) {
57 super(Constants.ATTR_LINE_NUMBER_TABLE, name_index, length, constant_pool);
58 setLineNumberTable(line_number_table);
59 }
60
61
62 /***
63 * Construct object from file stream.
64 * @param name_index Index of name
65 * @param length Content length in bytes
66 * @param file Input stream
67 * @param constant_pool Array of constants
68 * @throws IOException
69 */
70 LineNumberTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
71 throws IOException {
72 this(name_index, length, (LineNumber[]) null, constant_pool);
73 line_number_table_length = (file.readUnsignedShort());
74 line_number_table = new LineNumber[line_number_table_length];
75 for (int i = 0; i < line_number_table_length; i++) {
76 line_number_table[i] = new LineNumber(file);
77 }
78 }
79
80
81 /***
82 * Called by objects that are traversing the nodes of the tree implicitely
83 * defined by the contents of a Java class. I.e., the hierarchy of methods,
84 * fields, attributes, etc. spawns a tree of objects.
85 *
86 * @param v Visitor object
87 */
88 public void accept( Visitor v ) {
89 v.visitLineNumberTable(this);
90 }
91
92
93 /***
94 * Dump line number table attribute to file stream in binary format.
95 *
96 * @param file Output file stream
97 * @throws IOException
98 */
99 public final void dump( DataOutputStream file ) throws IOException {
100 super.dump(file);
101 file.writeShort(line_number_table_length);
102 for (int i = 0; i < line_number_table_length; i++) {
103 line_number_table[i].dump(file);
104 }
105 }
106
107
108 /***
109 * @return Array of (pc offset, line number) pairs.
110 */
111 public final LineNumber[] getLineNumberTable() {
112 return line_number_table;
113 }
114
115
116 /***
117 * @param line_number_table the line number entries for this table
118 */
119 public final void setLineNumberTable( LineNumber[] line_number_table ) {
120 this.line_number_table = line_number_table;
121 line_number_table_length = (line_number_table == null) ? 0 : line_number_table.length;
122 }
123
124
125 /***
126 * @return String representation.
127 */
128 public final String toString() {
129 StringBuffer buf = new StringBuffer();
130 StringBuffer line = new StringBuffer();
131 String newLine = System.getProperty("line.separator", "\n");
132 for (int i = 0; i < line_number_table_length; i++) {
133 line.append(line_number_table[i].toString());
134 if (i < line_number_table_length - 1) {
135 line.append(", ");
136 }
137 if (line.length() > 72) {
138 line.append(newLine);
139 buf.append(line.toString());
140 line.setLength(0);
141 }
142 }
143 buf.append(line);
144 return buf.toString();
145 }
146
147
148 /***
149 * Map byte code positions to source code lines.
150 *
151 * @param pos byte code offset
152 * @return corresponding line in source code
153 */
154 public int getSourceLine( int pos ) {
155 int l = 0, r = line_number_table_length - 1;
156 if (r < 0) {
157 return -1;
158 }
159 int min_index = -1, min = -1;
160
161
162 do {
163 int i = (l + r) / 2;
164 int j = line_number_table[i].getStartPC();
165 if (j == pos) {
166 return line_number_table[i].getLineNumber();
167 } else if (pos < j) {
168 r = i - 1;
169 } else {
170 l = i + 1;
171 }
172
173
174
175
176 if (j < pos && j > min) {
177 min = j;
178 min_index = i;
179 }
180 } while (l <= r);
181
182
183
184 if (min_index < 0) {
185 return -1;
186 }
187 return line_number_table[min_index].getLineNumber();
188 }
189
190
191 /***
192 * @return deep copy of this attribute
193 */
194 public Attribute copy( ConstantPool _constant_pool ) {
195 LineNumberTable c = (LineNumberTable) clone();
196 c.line_number_table = new LineNumber[line_number_table_length];
197 for (int i = 0; i < line_number_table_length; i++) {
198 c.line_number_table[i] = line_number_table[i].copy();
199 }
200 c.constant_pool = _constant_pool;
201 return c;
202 }
203
204
205 public final int getTableLength() {
206 return line_number_table_length;
207 }
208 }