001: // Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: /**
006: * An class for parsing DNS messages.
007: *
008: * @author Brian Wellington
009: */
010:
011: public class DNSInput {
012:
013: private byte[] array;
014: private int pos;
015: private int end;
016: private int saved_pos;
017: private int saved_end;
018:
019: /**
020: * Creates a new DNSInput
021: * @param input The byte array to read from
022: */
023: public DNSInput(byte[] input) {
024: array = input;
025: pos = 0;
026: end = array.length;
027: saved_pos = -1;
028: saved_end = -1;
029: }
030:
031: /**
032: * Returns the current position.
033: */
034: public int current() {
035: return pos;
036: }
037:
038: /**
039: * Returns the number of bytes that can be read from this stream before
040: * reaching the end.
041: */
042: public int remaining() {
043: return end - pos;
044: }
045:
046: private void require(int n) throws WireParseException {
047: if (n > remaining()) {
048: throw new WireParseException("end of input");
049: }
050: }
051:
052: /**
053: * Marks the following bytes in the stream as active.
054: * @param len The number of bytes in the active region.
055: * @throws IllegalArgumentException The number of bytes in the active region
056: * is longer than the remainder of the input.
057: */
058: public void setActive(int len) {
059: if (len > array.length - pos) {
060: throw new IllegalArgumentException("cannot set active "
061: + "region past end of input");
062: }
063: end = pos + len;
064: }
065:
066: /**
067: * Clears the active region of the string. Further operations are not
068: * restricted to part of the input.
069: */
070: public void clearActive() {
071: end = array.length;
072: }
073:
074: /**
075: * Resets the current position of the input stream to the specified index,
076: * and clears the active region.
077: * @param index The position to continue parsing at.
078: * @throws IllegalArgumentException The index is not within the input.
079: */
080: public void jump(int index) {
081: if (index >= array.length) {
082: throw new IllegalArgumentException("cannot jump past "
083: + "end of input");
084: }
085: pos = index;
086: end = array.length;
087: }
088:
089: /**
090: * Saves the current state of the input stream. Both the current position and
091: * the end of the active region are saved.
092: * @throws IllegalArgumentException The index is not within the input.
093: */
094: public void save() {
095: saved_pos = pos;
096: saved_end = end;
097: }
098:
099: /**
100: * Restores the input stream to its state before the call to {@link #save}.
101: */
102: public void restore() {
103: if (saved_pos < 0) {
104: throw new IllegalStateException("no previous state");
105: }
106: pos = saved_pos;
107: end = saved_end;
108: saved_pos = -1;
109: saved_end = -1;
110: }
111:
112: /**
113: * Reads an unsigned 8 bit value from the stream, as an int.
114: * @return An unsigned 8 bit value.
115: * @throws WireParseException The end of the stream was reached.
116: */
117: public int readU8() throws WireParseException {
118: require(1);
119: return (array[pos++] & 0xFF);
120: }
121:
122: /**
123: * Reads an unsigned 16 bit value from the stream, as an int.
124: * @return An unsigned 16 bit value.
125: * @throws WireParseException The end of the stream was reached.
126: */
127: public int readU16() throws WireParseException {
128: require(2);
129: int b1 = array[pos++] & 0xFF;
130: int b2 = array[pos++] & 0xFF;
131: return ((b1 << 8) + b2);
132: }
133:
134: /**
135: * Reads an unsigned 32 bit value from the stream, as a long.
136: * @return An unsigned 32 bit value.
137: * @throws WireParseException The end of the stream was reached.
138: */
139: public long readU32() throws WireParseException {
140: require(4);
141: int b1 = array[pos++] & 0xFF;
142: int b2 = array[pos++] & 0xFF;
143: int b3 = array[pos++] & 0xFF;
144: int b4 = array[pos++] & 0xFF;
145: return (((long) b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
146: }
147:
148: /**
149: * Reads a byte array of a specified length from the stream into an existing
150: * array.
151: * @param b The array to read into.
152: * @param off The offset of the array to start copying data into.
153: * @param len The number of bytes to copy.
154: * @throws WireParseException The end of the stream was reached.
155: */
156: public void readByteArray(byte[] b, int off, int len)
157: throws WireParseException {
158: require(len);
159: System.arraycopy(array, pos, b, off, len);
160: pos += len;
161: }
162:
163: /**
164: * Reads a byte array of a specified length from the stream.
165: * @return The byte array.
166: * @throws WireParseException The end of the stream was reached.
167: */
168: public byte[] readByteArray(int len) throws WireParseException {
169: require(len);
170: byte[] out = new byte[len];
171: System.arraycopy(array, pos, out, 0, len);
172: pos += len;
173: return out;
174: }
175:
176: /**
177: * Reads a byte array consisting of the remainder of the stream (or the
178: * active region, if one is set.
179: * @return The byte array.
180: */
181: public byte[] readByteArray() {
182: int len = remaining();
183: byte[] out = new byte[len];
184: System.arraycopy(array, pos, out, 0, len);
185: pos += len;
186: return out;
187: }
188:
189: /**
190: * Reads a counted string from the stream. A counted string is a one byte
191: * value indicating string length, followed by bytes of data.
192: * @return A byte array containing the string.
193: * @throws WireParseException The end of the stream was reached.
194: */
195: public byte[] readCountedString() throws WireParseException {
196: require(1);
197: int len = array[pos++] & 0xFF;
198: return readByteArray(len);
199: }
200:
201: }
|