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