Shuyi Chen | d7955ce | 2013-05-22 14:51:55 -0700 | [diff] [blame] | 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 |
| 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 | } |