1 // Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
2
3 package org.xbill.DNS;
4
5 /**
6 * An class for parsing DNS messages.
7 *
8 * @author Brian Wellington
9 */
10
11 public class DNSInput {
12
13 private byte [] array;
14 private int pos;
15 private int end;
16 private int saved_pos;
17 private int saved_end;
18
19 /**
20 * Creates a new DNSInput
21 * @param input The byte array to read from
22 */
23 public
DNSInput(byte [] input)24 DNSInput(byte [] input) {
25 array = input;
26 pos = 0;
27 end = array.length;
28 saved_pos = -1;
29 saved_end = -1;
30 }
31
32 /**
33 * Returns the current position.
34 */
35 public int
current()36 current() {
37 return pos;
38 }
39
40 /**
41 * Returns the number of bytes that can be read from this stream before
42 * reaching the end.
43 */
44 public int
remaining()45 remaining() {
46 return end - pos;
47 }
48
49 private void
require(int n)50 require(int n) throws WireParseException{
51 if (n > remaining()) {
52 throw new WireParseException("end of input");
53 }
54 }
55
56 /**
57 * Marks the following bytes in the stream as active.
58 * @param len The number of bytes in the active region.
59 * @throws IllegalArgumentException The number of bytes in the active region
60 * is longer than the remainder of the input.
61 */
62 public void
setActive(int len)63 setActive(int len) {
64 if (len > array.length - pos) {
65 throw new IllegalArgumentException("cannot set active " +
66 "region past end of input");
67 }
68 end = pos + len;
69 }
70
71 /**
72 * Clears the active region of the string. Further operations are not
73 * restricted to part of the input.
74 */
75 public void
clearActive()76 clearActive() {
77 end = array.length;
78 }
79
80 /**
81 * Returns the position of the end of the current active region.
82 */
83 public int
saveActive()84 saveActive() {
85 return end;
86 }
87
88 /**
89 * Restores the previously set active region. This differs from setActive() in
90 * that restoreActive() takes an absolute position, and setActive takes an
91 * offset from the current location.
92 * @param pos The end of the active region.
93 */
94 public void
restoreActive(int pos)95 restoreActive(int pos) {
96 if (pos > array.length) {
97 throw new IllegalArgumentException("cannot set active " +
98 "region past end of input");
99 }
100 end = pos;
101 }
102
103 /**
104 * Resets the current position of the input stream to the specified index,
105 * and clears the active region.
106 * @param index The position to continue parsing at.
107 * @throws IllegalArgumentException The index is not within the input.
108 */
109 public void
jump(int index)110 jump(int index) {
111 if (index >= array.length) {
112 throw new IllegalArgumentException("cannot jump past " +
113 "end of input");
114 }
115 pos = index;
116 end = array.length;
117 }
118
119 /**
120 * Saves the current state of the input stream. Both the current position and
121 * the end of the active region are saved.
122 * @throws IllegalArgumentException The index is not within the input.
123 */
124 public void
save()125 save() {
126 saved_pos = pos;
127 saved_end = end;
128 }
129
130 /**
131 * Restores the input stream to its state before the call to {@link #save}.
132 */
133 public void
restore()134 restore() {
135 if (saved_pos < 0) {
136 throw new IllegalStateException("no previous state");
137 }
138 pos = saved_pos;
139 end = saved_end;
140 saved_pos = -1;
141 saved_end = -1;
142 }
143
144 /**
145 * Reads an unsigned 8 bit value from the stream, as an int.
146 * @return An unsigned 8 bit value.
147 * @throws WireParseException The end of the stream was reached.
148 */
149 public int
readU8()150 readU8() throws WireParseException {
151 require(1);
152 return (array[pos++] & 0xFF);
153 }
154
155 /**
156 * Reads an unsigned 16 bit value from the stream, as an int.
157 * @return An unsigned 16 bit value.
158 * @throws WireParseException The end of the stream was reached.
159 */
160 public int
readU16()161 readU16() throws WireParseException {
162 require(2);
163 int b1 = array[pos++] & 0xFF;
164 int b2 = array[pos++] & 0xFF;
165 return ((b1 << 8) + b2);
166 }
167
168 /**
169 * Reads an unsigned 32 bit value from the stream, as a long.
170 * @return An unsigned 32 bit value.
171 * @throws WireParseException The end of the stream was reached.
172 */
173 public long
readU32()174 readU32() throws WireParseException {
175 require(4);
176 int b1 = array[pos++] & 0xFF;
177 int b2 = array[pos++] & 0xFF;
178 int b3 = array[pos++] & 0xFF;
179 int b4 = array[pos++] & 0xFF;
180 return (((long)b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
181 }
182
183 /**
184 * Reads a byte array of a specified length from the stream into an existing
185 * array.
186 * @param b The array to read into.
187 * @param off The offset of the array to start copying data into.
188 * @param len The number of bytes to copy.
189 * @throws WireParseException The end of the stream was reached.
190 */
191 public void
readByteArray(byte [] b, int off, int len)192 readByteArray(byte [] b, int off, int len) throws WireParseException {
193 require(len);
194 System.arraycopy(array, pos, b, off, len);
195 pos += len;
196 }
197
198 /**
199 * Reads a byte array of a specified length from the stream.
200 * @return The byte array.
201 * @throws WireParseException The end of the stream was reached.
202 */
203 public byte []
readByteArray(int len)204 readByteArray(int len) throws WireParseException {
205 require(len);
206 byte [] out = new byte[len];
207 System.arraycopy(array, pos, out, 0, len);
208 pos += len;
209 return out;
210 }
211
212 /**
213 * Reads a byte array consisting of the remainder of the stream (or the
214 * active region, if one is set.
215 * @return The byte array.
216 */
217 public byte []
readByteArray()218 readByteArray() {
219 int len = remaining();
220 byte [] out = new byte[len];
221 System.arraycopy(array, pos, out, 0, len);
222 pos += len;
223 return out;
224 }
225
226 /**
227 * Reads a counted string from the stream. A counted string is a one byte
228 * value indicating string length, followed by bytes of data.
229 * @return A byte array containing the string.
230 * @throws WireParseException The end of the stream was reached.
231 */
232 public byte []
readCountedString()233 readCountedString() throws WireParseException {
234 require(1);
235 int len = array[pos++] & 0xFF;
236 return readByteArray(len);
237 }
238
239 }
240