001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: /**
006: * A class for rendering DNS messages.
007: *
008: * @author Brian Wellington
009: */
010:
011: public class DNSOutput {
012:
013: private byte[] array;
014: private int pos;
015: private int saved_pos;
016:
017: /**
018: * Create a new DNSOutput with a specified size.
019: * @param size The initial size
020: */
021: public DNSOutput(int size) {
022: array = new byte[size];
023: pos = 0;
024: saved_pos = -1;
025: }
026:
027: /**
028: * Create a new DNSOutput
029: */
030: public DNSOutput() {
031: this (32);
032: }
033:
034: /**
035: * Returns the current position.
036: */
037: public int current() {
038: return pos;
039: }
040:
041: private void check(long val, int bits) {
042: long max = 1;
043: max <<= bits;
044: if (val < 0 || val > max) {
045: throw new IllegalArgumentException(val
046: + " out of range for " + bits + " bit value");
047: }
048: }
049:
050: private void need(int n) {
051: if (array.length - pos >= n) {
052: return;
053: }
054: int newsize = array.length * 2;
055: if (newsize < pos + n) {
056: newsize = pos + n;
057: }
058: byte[] newarray = new byte[newsize];
059: System.arraycopy(array, 0, newarray, 0, pos);
060: array = newarray;
061: }
062:
063: /**
064: * Resets the current position of the output stream to the specified index.
065: * @param index The new current position.
066: * @throws IllegalArgumentException The index is not within the output.
067: */
068: public void jump(int index) {
069: if (index > pos) {
070: throw new IllegalArgumentException("cannot jump past "
071: + "end of data");
072: }
073: pos = index;
074: }
075:
076: /**
077: * Saves the current state of the output stream.
078: * @throws IllegalArgumentException The index is not within the output.
079: */
080: public void save() {
081: saved_pos = pos;
082: }
083:
084: /**
085: * Restores the input stream to its state before the call to {@link #save}.
086: */
087: public void restore() {
088: if (saved_pos < 0) {
089: throw new IllegalStateException("no previous state");
090: }
091: pos = saved_pos;
092: saved_pos = -1;
093: }
094:
095: /**
096: * Writes an unsigned 8 bit value to the stream.
097: * @param val The value to be written
098: */
099: public void writeU8(int val) {
100: check(val, 8);
101: need(1);
102: array[pos++] = (byte) (val & 0xFF);
103: }
104:
105: /**
106: * Writes an unsigned 16 bit value to the stream.
107: * @param val The value to be written
108: */
109: public void writeU16(int val) {
110: check(val, 16);
111: need(2);
112: array[pos++] = (byte) ((val >>> 8) & 0xFF);
113: array[pos++] = (byte) (val & 0xFF);
114: }
115:
116: /**
117: * Writes an unsigned 32 bit value to the stream.
118: * @param val The value to be written
119: */
120: public void writeU32(long val) {
121: check(val, 32);
122: need(4);
123: array[pos++] = (byte) ((val >>> 24) & 0xFF);
124: array[pos++] = (byte) ((val >>> 16) & 0xFF);
125: array[pos++] = (byte) ((val >>> 8) & 0xFF);
126: array[pos++] = (byte) (val & 0xFF);
127: }
128:
129: /**
130: * Writes a byte array to the stream.
131: * @param b The array to write.
132: * @param off The offset of the array to start copying data from.
133: * @param len The number of bytes to write.
134: */
135: public void writeByteArray(byte[] b, int off, int len) {
136: need(len);
137: System.arraycopy(b, off, array, pos, len);
138: pos += len;
139: }
140:
141: /**
142: * Writes a byte array to the stream.
143: * @param b The array to write.
144: */
145: public void writeByteArray(byte[] b) {
146: writeByteArray(b, 0, b.length);
147: }
148:
149: /**
150: * Writes a counted string from the stream. A counted string is a one byte
151: * value indicating string length, followed by bytes of data.
152: * @param s The string to write.
153: */
154: public void writeCountedString(byte[] s) {
155: if (s.length > 0xFF) {
156: throw new IllegalArgumentException("Invalid counted string");
157: }
158: need(1 + s.length);
159: array[pos++] = (byte) (s.length & 0xFF);
160: writeByteArray(s, 0, s.length);
161: }
162:
163: /**
164: * Returns a byte array containing the current contents of the stream.
165: */
166: public byte[] toByteArray() {
167: byte[] out = new byte[pos];
168: System.arraycopy(array, 0, out, 0, pos);
169: return out;
170: }
171:
172: }
|