/* * Copied from the DnsJava project * * Copyright (c) 1998-2011, Brian Wellington. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package io.milton.dns.record; /** * A class for rendering DNS messages. * * @author Brian Wellington */ public class DNSOutput { private byte [] array; private int pos; private int saved_pos; /** * Create a new DNSOutput with a specified size. * @param size The initial size */ public DNSOutput(int size) { array = new byte[size]; pos = 0; saved_pos = -1; } /** * Create a new DNSOutput */ public DNSOutput() { this(32); } /** * Returns the current position. */ public int current() { return pos; } private void check(long val, int bits) { long max = 1; max <<= bits; if (val < 0 || val > max) { throw new IllegalArgumentException(val + " out of range for " + bits + " bit value"); } } private void need(int n) { if (array.length - pos >= n) { return; } int newsize = array.length * 2; if (newsize < pos + n) { newsize = pos + n; } byte [] newarray = new byte[newsize]; System.arraycopy(array, 0, newarray, 0, pos); array = newarray; } /** * Resets the current position of the output stream to the specified index. * @param index The new current position. * @throws IllegalArgumentException The index is not within the output. */ public void jump(int index) { if (index > pos) { throw new IllegalArgumentException("cannot jump past " + "end of data"); } pos = index; } /** * Saves the current state of the output stream. * @throws IllegalArgumentException The index is not within the output. */ public void save() { saved_pos = pos; } /** * 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; saved_pos = -1; } /** * Writes an unsigned 8 bit value to the stream. * @param val The value to be written */ public void writeU8(int val) { check(val, 8); need(1); array[pos++] = (byte)(val & 0xFF); } /** * Writes an unsigned 16 bit value to the stream. * @param val The value to be written */ public void writeU16(int val) { check(val, 16); need(2); array[pos++] = (byte)((val >>> 8) & 0xFF); array[pos++] = (byte)(val & 0xFF); } /** * Writes an unsigned 16 bit value to the specified position in the stream. * @param val The value to be written * @param where The position to write the value. */ public void writeU16At(int val, int where) { check(val, 16); if (where > pos - 2) throw new IllegalArgumentException("cannot write past " + "end of data"); array[where++] = (byte)((val >>> 8) & 0xFF); array[where++] = (byte)(val & 0xFF); } /** * Writes an unsigned 32 bit value to the stream. * @param val The value to be written */ public void writeU32(long val) { check(val, 32); need(4); array[pos++] = (byte)((val >>> 24) & 0xFF); array[pos++] = (byte)((val >>> 16) & 0xFF); array[pos++] = (byte)((val >>> 8) & 0xFF); array[pos++] = (byte)(val & 0xFF); } /** * Writes a byte array to the stream. * @param b The array to write. * @param off The offset of the array to start copying data from. * @param len The number of bytes to write. */ public void writeByteArray(byte [] b, int off, int len) { need(len); System.arraycopy(b, off, array, pos, len); pos += len; } /** * Writes a byte array to the stream. * @param b The array to write. */ public void writeByteArray(byte [] b) { writeByteArray(b, 0, b.length); } /** * Writes a counted string from the stream. A counted string is a one byte * value indicating string length, followed by bytes of data. * @param s The string to write. */ public void writeCountedString(byte [] s) { if (s.length > 0xFF) { throw new IllegalArgumentException("Invalid counted string"); } need(1 + s.length); array[pos++] = (byte)(s.length & 0xFF); writeByteArray(s, 0, s.length); } /** * Returns a byte array containing the current contents of the stream. */ public byte [] toByteArray() { byte [] out = new byte[pos]; System.arraycopy(array, 0, out, 0, pos); return out; } }