Home | History | Annotate | Download | only in DNS
      1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) xbill.org)
      2 
      3 package org.xbill.DNS;
      4 
      5 /**
      6  * A class for rendering DNS messages.
      7  *
      8  * @author Brian Wellington
      9  */
     10 
     11 
     12 public class DNSOutput {
     13 
     14 private byte [] array;
     15 private int pos;
     16 private int saved_pos;
     17 
     18 /**
     19  * Create a new DNSOutput with a specified size.
     20  * @param size The initial size
     21  */
     22 public
     23 DNSOutput(int size) {
     24 	array = new byte[size];
     25 	pos = 0;
     26 	saved_pos = -1;
     27 }
     28 
     29 /**
     30  * Create a new DNSOutput
     31  */
     32 public
     33 DNSOutput() {
     34 	this(32);
     35 }
     36 
     37 /**
     38  * Returns the current position.
     39  */
     40 public int
     41 current() {
     42 	return pos;
     43 }
     44 
     45 private void
     46 check(long val, int bits) {
     47 	long max = 1;
     48 	max <<= bits;
     49 	if (val < 0 || val > max) {
     50 		throw new IllegalArgumentException(val + " out of range for " +
     51 						   bits + " bit value");
     52 	}
     53 }
     54 
     55 private void
     56 need(int n) {
     57 	if (array.length - pos >= n) {
     58 		return;
     59 	}
     60 	int newsize = array.length * 2;
     61 	if (newsize < pos + n) {
     62 		newsize = pos + n;
     63 	}
     64 	byte [] newarray = new byte[newsize];
     65 	System.arraycopy(array, 0, newarray, 0, pos);
     66 	array = newarray;
     67 }
     68 
     69 /**
     70  * Resets the current position of the output stream to the specified index.
     71  * @param index The new current position.
     72  * @throws IllegalArgumentException The index is not within the output.
     73  */
     74 public void
     75 jump(int index) {
     76 	if (index > pos) {
     77 		throw new IllegalArgumentException("cannot jump past " +
     78 						   "end of data");
     79 	}
     80 	pos = index;
     81 }
     82 
     83 /**
     84  * Saves the current state of the output stream.
     85  * @throws IllegalArgumentException The index is not within the output.
     86  */
     87 public void
     88 save() {
     89 	saved_pos = pos;
     90 }
     91 
     92 /**
     93  * Restores the input stream to its state before the call to {@link #save}.
     94  */
     95 public void
     96 restore() {
     97 	if (saved_pos < 0) {
     98 		throw new IllegalStateException("no previous state");
     99 	}
    100 	pos = saved_pos;
    101 	saved_pos = -1;
    102 }
    103 
    104 /**
    105  * Writes an unsigned 8 bit value to the stream.
    106  * @param val The value to be written
    107  */
    108 public void
    109 writeU8(int val) {
    110 	check(val, 8);
    111 	need(1);
    112 	array[pos++] = (byte)(val & 0xFF);
    113 }
    114 
    115 /**
    116  * Writes an unsigned 16 bit value to the stream.
    117  * @param val The value to be written
    118  */
    119 public void
    120 writeU16(int val) {
    121 	check(val, 16);
    122 	need(2);
    123 	array[pos++] = (byte)((val >>> 8) & 0xFF);
    124 	array[pos++] = (byte)(val & 0xFF);
    125 }
    126 
    127 /**
    128  * Writes an unsigned 16 bit value to the specified position in the stream.
    129  * @param val The value to be written
    130  * @param where The position to write the value.
    131  */
    132 public void
    133 writeU16At(int val, int where) {
    134 	check(val, 16);
    135 	if (where > pos - 2)
    136 		throw new IllegalArgumentException("cannot write past " +
    137 						   "end of data");
    138 	array[where++] = (byte)((val >>> 8) & 0xFF);
    139 	array[where++] = (byte)(val & 0xFF);
    140 }
    141 
    142 /**
    143  * Writes an unsigned 32 bit value to the stream.
    144  * @param val The value to be written
    145  */
    146 public void
    147 writeU32(long val) {
    148 	check(val, 32);
    149 	need(4);
    150 	array[pos++] = (byte)((val >>> 24) & 0xFF);
    151 	array[pos++] = (byte)((val >>> 16) & 0xFF);
    152 	array[pos++] = (byte)((val >>> 8) & 0xFF);
    153 	array[pos++] = (byte)(val & 0xFF);
    154 }
    155 
    156 /**
    157  * Writes a byte array to the stream.
    158  * @param b The array to write.
    159  * @param off The offset of the array to start copying data from.
    160  * @param len The number of bytes to write.
    161  */
    162 public void
    163 writeByteArray(byte [] b, int off, int len) {
    164 	need(len);
    165 	System.arraycopy(b, off, array, pos, len);
    166 	pos += len;
    167 }
    168 
    169 /**
    170  * Writes a byte array to the stream.
    171  * @param b The array to write.
    172  */
    173 public void
    174 writeByteArray(byte [] b) {
    175 	writeByteArray(b, 0, b.length);
    176 }
    177 
    178 /**
    179  * Writes a counted string from the stream.  A counted string is a one byte
    180  * value indicating string length, followed by bytes of data.
    181  * @param s The string to write.
    182  */
    183 public void
    184 writeCountedString(byte [] s) {
    185 	if (s.length > 0xFF) {
    186 		throw new IllegalArgumentException("Invalid counted string");
    187 	}
    188 	need(1 + s.length);
    189 	array[pos++] = (byte)(s.length & 0xFF);
    190 	writeByteArray(s, 0, s.length);
    191 }
    192 
    193 /**
    194  * Returns a byte array containing the current contents of the stream.
    195  */
    196 public byte []
    197 toByteArray() {
    198 	byte [] out = new byte[pos];
    199 	System.arraycopy(array, 0, out, 0, pos);
    200 	return out;
    201 }
    202 
    203 }
    204