1// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5/**
6 * An class for parsing DNS messages.
7 *
8 * @author Brian Wellington
9 */
10
11public class DNSInput {
12
13private byte [] array;
14private int pos;
15private int end;
16private int saved_pos;
17private int saved_end;
18
19/**
20 * Creates a new DNSInput
21 * @param input The byte array to read from
22 */
23public
24DNSInput(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 */
35public int
36current() {
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 */
44public int
45remaining() {
46	return end - pos;
47}
48
49private void
50require(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 */
62public void
63setActive(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 */
75public void
76clearActive() {
77	end = array.length;
78}
79
80/**
81 * Returns the position of the end of the current active region.
82 */
83public int
84saveActive() {
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 */
94public void
95restoreActive(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 */
109public void
110jump(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 */
124public void
125save() {
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 */
133public void
134restore() {
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 */
149public int
150readU8() 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 */
160public int
161readU16() 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 */
173public long
174readU32() 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 */
191public void
192readByteArray(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 */
203public byte []
204readByteArray(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 */
217public byte []
218readByteArray() {
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 */
232public byte []
233readCountedString() throws WireParseException {
234	require(1);
235	int len = array[pos++] & 0xFF;
236	return readByteArray(len);
237}
238
239}
240