1 // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3 package org.xbill.DNS;
4
5 /**
6 * A class for rendering DNS messages.
7 *
8 * @author Brian Wellington
9 */
10
11
12 public class DNSOutput {
13
14 private byte [] array;
15 private int pos;
16 private int saved_pos;
17
18 /**
19 * Create a new DNSOutput with a specified size.
20 * @param size The initial size
21 */
22 public
DNSOutput(int size)23 DNSOutput(int size) {
24 array = new byte[size];
25 pos = 0;
26 saved_pos = -1;
27 }
28
29 /**
30 * Create a new DNSOutput
31 */
32 public
DNSOutput()33 DNSOutput() {
34 this(32);
35 }
36
37 /**
38 * Returns the current position.
39 */
40 public int
current()41 current() {
42 return pos;
43 }
44
45 private void
check(long val, int bits)46 check(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
55 private void
need(int n)56 need(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 */
74 public void
jump(int index)75 jump(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 */
87 public void
save()88 save() {
89 saved_pos = pos;
90 }
91
92 /**
93 * Restores the input stream to its state before the call to {@link #save}.
94 */
95 public void
restore()96 restore() {
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 */
108 public void
writeU8(int val)109 writeU8(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 */
119 public void
writeU16(int val)120 writeU16(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 */
132 public void
writeU16At(int val, int where)133 writeU16At(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 */
146 public void
writeU32(long val)147 writeU32(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 */
162 public void
writeByteArray(byte [] b, int off, int len)163 writeByteArray(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 */
173 public void
writeByteArray(byte [] b)174 writeByteArray(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 */
183 public void
writeCountedString(byte [] s)184 writeCountedString(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 */
196 public byte []
toByteArray()197 toByteArray() {
198 byte [] out = new byte[pos];
199 System.arraycopy(array, 0, out, 0, pos);
200 return out;
201 }
202
203 }
204