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.DataInput;
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import java.util.Arrays;
23 import java.util.Iterator;
24 import java.util.stream.Stream;
25
26 import org.apache.bcel.Const;
27 import org.apache.bcel.util.Args;
28
29
30
31
32
33
34
35
36 public final class LineNumberTable extends Attribute implements Iterable<LineNumber> {
37
38 private static final int MAX_LINE_LENGTH = 72;
39 private LineNumber[] lineNumberTable;
40
41
42
43
44
45
46
47
48
49
50 LineNumberTable(final int nameIndex, final int length, final DataInput input, final ConstantPool constantPool) throws IOException {
51 this(nameIndex, length, (LineNumber[]) null, constantPool);
52 final int lineNumberTableLength = input.readUnsignedShort();
53 lineNumberTable = new LineNumber[lineNumberTableLength];
54 for (int i = 0; i < lineNumberTableLength; i++) {
55 lineNumberTable[i] = new LineNumber(input);
56 }
57 }
58
59
60
61
62
63
64
65
66
67
68 public LineNumberTable(final int nameIndex, final int length, final LineNumber[] lineNumberTable, final ConstantPool constantPool) {
69 super(Const.ATTR_LINE_NUMBER_TABLE, nameIndex, length, constantPool);
70 this.lineNumberTable = lineNumberTable != null ? lineNumberTable : LineNumber.EMPTY_ARRAY;
71 Args.requireU2(this.lineNumberTable.length, "lineNumberTable.length");
72 }
73
74
75
76
77
78 public LineNumberTable(final LineNumberTable c) {
79 this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool());
80 }
81
82
83
84
85
86
87
88 @Override
89 public void accept(final Visitor v) {
90 v.visitLineNumberTable(this);
91 }
92
93
94
95
96 @Override
97 public Attribute copy(final ConstantPool constantPool) {
98
99
100 final LineNumberTable c = (LineNumberTable) clone();
101 c.lineNumberTable = new LineNumber[lineNumberTable.length];
102 Arrays.setAll(c.lineNumberTable, i -> lineNumberTable[i].copy());
103 c.setConstantPool(constantPool);
104 return c;
105 }
106
107
108
109
110
111
112
113 @Override
114 public void dump(final DataOutputStream file) throws IOException {
115 super.dump(file);
116 file.writeShort(lineNumberTable.length);
117 for (final LineNumber lineNumber : lineNumberTable) {
118 lineNumber.dump(file);
119 }
120 }
121
122
123
124
125 public LineNumber[] getLineNumberTable() {
126 return lineNumberTable;
127 }
128
129
130
131
132
133
134
135 public int getSourceLine(final int pos) {
136 int l = 0;
137 int r = lineNumberTable.length - 1;
138 if (r < 0) {
139 return -1;
140 }
141 int minIndex = -1;
142 int min = -1;
143
144
145
146 do {
147 final int i = l + r >>> 1;
148 final int j = lineNumberTable[i].getStartPC();
149 if (j == pos) {
150 return lineNumberTable[i].getLineNumber();
151 }
152 if (pos < j) {
153 r = i - 1;
154 } else {
155 l = i + 1;
156 }
157
158
159
160
161 if (j < pos && j > min) {
162 min = j;
163 minIndex = i;
164 }
165 } while (l <= r);
166
167
168
169 if (minIndex < 0) {
170 return -1;
171 }
172 return lineNumberTable[minIndex].getLineNumber();
173 }
174
175 public int getTableLength() {
176 return lineNumberTable == null ? 0 : lineNumberTable.length;
177 }
178
179 @Override
180 public Iterator<LineNumber> iterator() {
181 return Stream.of(lineNumberTable).iterator();
182 }
183
184
185
186
187 public void setLineNumberTable(final LineNumber[] lineNumberTable) {
188 this.lineNumberTable = lineNumberTable;
189 }
190
191
192
193
194 @Override
195 public String toString() {
196 final StringBuilder buf = new StringBuilder();
197 final StringBuilder line = new StringBuilder();
198 final String newLine = System.getProperty("line.separator", "\n");
199 for (int i = 0; i < lineNumberTable.length; i++) {
200 line.append(lineNumberTable[i].toString());
201 if (i < lineNumberTable.length - 1) {
202 line.append(", ");
203 }
204 if (line.length() > MAX_LINE_LENGTH && i < lineNumberTable.length - 1) {
205 line.append(newLine);
206 buf.append(line);
207 line.setLength(0);
208 }
209 }
210 buf.append(line);
211 return buf.toString();
212 }
213 }