// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org) package org.xbill.DNS; /** * An class for parsing DNS messages. * * @author Brian Wellington */ public class DNSInput { private byte [] array; private int pos; private int end; private int saved_pos; private int saved_end; /** * Creates a new DNSInput * @param input The byte array to read from */ public DNSInput(byte [] input) { array = input; pos = 0; end = array.length; saved_pos = -1; saved_end = -1; } /** * Returns the current position. */ public int current() { return pos; } /** * Returns the number of bytes that can be read from this stream before * reaching the end. */ public int remaining() { return end - pos; } private void require(int n) throws WireParseException{ if (n > remaining()) { throw new WireParseException("end of input"); } } /** * Marks the following bytes in the stream as active. * @param len The number of bytes in the active region. * @throws IllegalArgumentException The number of bytes in the active region * is longer than the remainder of the input. */ public void setActive(int len) { if (len > array.length - pos) { throw new IllegalArgumentException("cannot set active " + "region past end of input"); } end = pos + len; } /** * Clears the active region of the string. Further operations are not * restricted to part of the input. */ public void clearActive() { end = array.length; } /** * Returns the position of the end of the current active region. */ public int saveActive() { return end; } /** * Restores the previously set active region. This differs from setActive() in * that restoreActive() takes an absolute position, and setActive takes an * offset from the current location. * @param pos The end of the active region. */ public void restoreActive(int pos) { if (pos > array.length) { throw new IllegalArgumentException("cannot set active " + "region past end of input"); } end = pos; } /** * Resets the current position of the input stream to the specified index, * and clears the active region. * @param index The position to continue parsing at. * @throws IllegalArgumentException The index is not within the input. */ public void jump(int index) { if (index >= array.length) { throw new IllegalArgumentException("cannot jump past " + "end of input"); } pos = index; end = array.length; } /** * Saves the current state of the input stream. Both the current position and * the end of the active region are saved. * @throws IllegalArgumentException The index is not within the input. */ public void save() { saved_pos = pos; saved_end = end; } /** * Restores the input stream to its state before the call to {@link #save}. */ public void restore() { if (saved_pos < 0) { throw new IllegalStateException("no previous state"); } pos = saved_pos; end = saved_end; saved_pos = -1; saved_end = -1; } /** * Reads an unsigned 8 bit value from the stream, as an int. * @return An unsigned 8 bit value. * @throws WireParseException The end of the stream was reached. */ public int readU8() throws WireParseException { require(1); return (array[pos++] & 0xFF); } /** * Reads an unsigned 16 bit value from the stream, as an int. * @return An unsigned 16 bit value. * @throws WireParseException The end of the stream was reached. */ public int readU16() throws WireParseException { require(2); int b1 = array[pos++] & 0xFF; int b2 = array[pos++] & 0xFF; return ((b1 << 8) + b2); } /** * Reads an unsigned 32 bit value from the stream, as a long. * @return An unsigned 32 bit value. * @throws WireParseException The end of the stream was reached. */ public long readU32() throws WireParseException { require(4); int b1 = array[pos++] & 0xFF; int b2 = array[pos++] & 0xFF; int b3 = array[pos++] & 0xFF; int b4 = array[pos++] & 0xFF; return (((long)b1 << 24) + (b2 << 16) + (b3 << 8) + b4); } /** * Reads a byte array of a specified length from the stream into an existing * array. * @param b The array to read into. * @param off The offset of the array to start copying data into. * @param len The number of bytes to copy. * @throws WireParseException The end of the stream was reached. */ public void readByteArray(byte [] b, int off, int len) throws WireParseException { require(len); System.arraycopy(array, pos, b, off, len); pos += len; } /** * Reads a byte array of a specified length from the stream. * @return The byte array. * @throws WireParseException The end of the stream was reached. */ public byte [] readByteArray(int len) throws WireParseException { require(len); byte [] out = new byte[len]; System.arraycopy(array, pos, out, 0, len); pos += len; return out; } /** * Reads a byte array consisting of the remainder of the stream (or the * active region, if one is set. * @return The byte array. */ public byte [] readByteArray() { int len = remaining(); byte [] out = new byte[len]; System.arraycopy(array, pos, out, 0, len); pos += len; return out; } /** * Reads a counted string from the stream. A counted string is a one byte * value indicating string length, followed by bytes of data. * @return A byte array containing the string. * @throws WireParseException The end of the stream was reached. */ public byte [] readCountedString() throws WireParseException { require(1); int len = array[pos++] & 0xFF; return readByteArray(len); } }