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