1// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5/**
6 * A class for rendering DNS messages.
7 *
8 * @author Brian Wellington
9 */
10
11
12public class DNSOutput {
13
14private byte [] array;
15private int pos;
16private int saved_pos;
17
18/**
19 * Create a new DNSOutput with a specified size.
20 * @param size The initial size
21 */
22public
23DNSOutput(int size) {
24	array = new byte[size];
25	pos = 0;
26	saved_pos = -1;
27}
28
29/**
30 * Create a new DNSOutput
31 */
32public
33DNSOutput() {
34	this(32);
35}
36
37/**
38 * Returns the current position.
39 */
40public int
41current() {
42	return pos;
43}
44
45private void
46check(long val, int bits) {
47	long max = 1;
48	max <<= bits;
49	if (val < 0 || val > max) {
50		throw new IllegalArgumentException(val + " out of range for " +
51						   bits + " bit value");
52	}
53}
54
55private void
56need(int n) {
57	if (array.length - pos >= n) {
58		return;
59	}
60	int newsize = array.length * 2;
61	if (newsize < pos + n) {
62		newsize = pos + n;
63	}
64	byte [] newarray = new byte[newsize];
65	System.arraycopy(array, 0, newarray, 0, pos);
66	array = newarray;
67}
68
69/**
70 * Resets the current position of the output stream to the specified index.
71 * @param index The new current position.
72 * @throws IllegalArgumentException The index is not within the output.
73 */
74public void
75jump(int index) {
76	if (index > pos) {
77		throw new IllegalArgumentException("cannot jump past " +
78						   "end of data");
79	}
80	pos = index;
81}
82
83/**
84 * Saves the current state of the output stream.
85 * @throws IllegalArgumentException The index is not within the output.
86 */
87public void
88save() {
89	saved_pos = pos;
90}
91
92/**
93 * Restores the input stream to its state before the call to {@link #save}.
94 */
95public void
96restore() {
97	if (saved_pos < 0) {
98		throw new IllegalStateException("no previous state");
99	}
100	pos = saved_pos;
101	saved_pos = -1;
102}
103
104/**
105 * Writes an unsigned 8 bit value to the stream.
106 * @param val The value to be written
107 */
108public void
109writeU8(int val) {
110	check(val, 8);
111	need(1);
112	array[pos++] = (byte)(val & 0xFF);
113}
114
115/**
116 * Writes an unsigned 16 bit value to the stream.
117 * @param val The value to be written
118 */
119public void
120writeU16(int val) {
121	check(val, 16);
122	need(2);
123	array[pos++] = (byte)((val >>> 8) & 0xFF);
124	array[pos++] = (byte)(val & 0xFF);
125}
126
127/**
128 * Writes an unsigned 16 bit value to the specified position in the stream.
129 * @param val The value to be written
130 * @param where The position to write the value.
131 */
132public void
133writeU16At(int val, int where) {
134	check(val, 16);
135	if (where > pos - 2)
136		throw new IllegalArgumentException("cannot write past " +
137						   "end of data");
138	array[where++] = (byte)((val >>> 8) & 0xFF);
139	array[where++] = (byte)(val & 0xFF);
140}
141
142/**
143 * Writes an unsigned 32 bit value to the stream.
144 * @param val The value to be written
145 */
146public void
147writeU32(long val) {
148	check(val, 32);
149	need(4);
150	array[pos++] = (byte)((val >>> 24) & 0xFF);
151	array[pos++] = (byte)((val >>> 16) & 0xFF);
152	array[pos++] = (byte)((val >>> 8) & 0xFF);
153	array[pos++] = (byte)(val & 0xFF);
154}
155
156/**
157 * Writes a byte array to the stream.
158 * @param b The array to write.
159 * @param off The offset of the array to start copying data from.
160 * @param len The number of bytes to write.
161 */
162public void
163writeByteArray(byte [] b, int off, int len) {
164	need(len);
165	System.arraycopy(b, off, array, pos, len);
166	pos += len;
167}
168
169/**
170 * Writes a byte array to the stream.
171 * @param b The array to write.
172 */
173public void
174writeByteArray(byte [] b) {
175	writeByteArray(b, 0, b.length);
176}
177
178/**
179 * Writes a counted string from the stream.  A counted string is a one byte
180 * value indicating string length, followed by bytes of data.
181 * @param s The string to write.
182 */
183public void
184writeCountedString(byte [] s) {
185	if (s.length > 0xFF) {
186		throw new IllegalArgumentException("Invalid counted string");
187	}
188	need(1 + s.length);
189	array[pos++] = (byte)(s.length & 0xFF);
190	writeByteArray(s, 0, s.length);
191}
192
193/**
194 * Returns a byte array containing the current contents of the stream.
195 */
196public byte []
197toByteArray() {
198	byte [] out = new byte[pos];
199	System.arraycopy(array, 0, out, 0, pos);
200	return out;
201}
202
203}
204