1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) 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 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 33 DNSOutput() { 34 this(32); 35 } 36 37 /** 38 * Returns the current position. 39 */ 40 public int 41 current() { 42 return pos; 43 } 44 45 private void 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 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 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 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 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 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 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 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 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 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 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 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 [] 197 toByteArray() { 198 byte [] out = new byte[pos]; 199 System.arraycopy(array, 0, out, 0, pos); 200 return out; 201 } 202 203 } 204