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