/* * Player Java Client 3 - XdrBufferEncodingStream.java * Copyright (C) 2002-2006 Radu Bogdan Rusu, Maxim Batalin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ * */ /* * Copyright (c) 1999, 2000 * Lehrstuhl fuer Prozessleittechnik (PLT), RWTH Aachen * D-52064 Aachen, Germany. * All rights reserved. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program (see the file COPYING.LIB for more * details); if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ package javaclient3.xdr; import java.io.IOException; import java.net.InetAddress; /** * The <code>XdrBufferEncodingStream</code> class provides a buffer-based * XDR stream. * * @version $Revision$ $Date$ $State$ $Locker$ * @author Harald Albrecht */ public class XdrBufferEncodingStream extends XdrEncodingStream { /** * Constructs a new <code>XdrBufferEncodingStream</code> with a buffer * to encode data into of the given size. * * @param bufferSize Size of buffer to store encoded data in. */ public XdrBufferEncodingStream(int bufferSize) { if ( (bufferSize < 0) || (bufferSize & 3) != 0 ) { throw(new IllegalArgumentException("size of buffer must be a multiple of four and must not be negative")); } this.buffer = new byte[bufferSize]; bufferIndex = 0; bufferHighmark = buffer.length - 4; } /** * Constructs a new <code>XdrBufferEncodingStream</code> with a given * buffer. * * @param buffer Buffer to store encoded information in. * * @throws IllegalArgumentException if <code>encodedLength</code> is not * a multiple of four. */ public XdrBufferEncodingStream(byte [] buffer) { // // Make sure that the buffer size is a multiple of four, otherwise // throw an exception. // if ( (buffer.length & 3) != 0 ) { throw(new IllegalArgumentException("size of buffer must be a multiple of four")); } this.buffer = buffer; bufferIndex = 0; bufferHighmark = buffer.length - 4; } /** * Returns the amount of encoded data in the buffer. * * @return length of data encoded in buffer. */ public int getXdrLength() { return bufferIndex; } /** * Returns the buffer holding encoded data. * * @return Buffer with encoded data. */ public byte [] getXdrData() { return buffer; } /** * Begins encoding a new XDR record. This involves resetting this * encoding XDR stream back into a known state. * * @param receiverAddress Indicates the receiver of the XDR data. This can be * <code>null</code> for XDR streams connected permanently to a * receiver (like in case of TCP/IP based XDR streams). * @param receiverPort Port number of the receiver. * * @throws OncRpcException if an ONC/RPC error occurs. * @throws IOException if an I/O error occurs. */ public void beginEncoding(InetAddress receiverAddress, int receiverPort) throws OncRpcException, IOException { bufferIndex = 0; } /** * Flushes this encoding XDR stream and forces any buffered output bytes * to be written out. The general contract of <code>endEncoding</code> is that * calling it is an indication that the current record is finished and any * bytes previously encoded should immediately be written to their intended * destination. * * @throws OncRpcException if an ONC/RPC error occurs. * @throws IOException if an I/O error occurs. */ public void endEncoding() throws OncRpcException, IOException { } /** * Closes this encoding XDR stream and releases any system resources * associated with this stream. The general contract of <code>close</code> * is that it closes the encoding XDR stream. A closed XDR stream cannot * perform encoding operations and cannot be reopened. * * @throws OncRpcException if an ONC/RPC error occurs. * @throws IOException if an I/O error occurs. */ public void close() throws OncRpcException, IOException { buffer = null; } /** * Encodes (aka "serializes") a "XDR int" value and writes it down a * XDR stream. A XDR int is 32 bits wide -- the same width Java's "int" * data type has. This method is one of the basic methods all other * methods can rely on. * * @throws OncRpcException if an ONC/RPC error occurs. * @throws IOException if an I/O error occurs. */ public void xdrEncodeInt(int value) throws OncRpcException, IOException { if ( bufferIndex <= bufferHighmark ) { // // There's enough space in the buffer, so encode this int as // four bytes (french octets) in big endian order (that is, the // most significant byte comes first. // buffer[bufferIndex++] = (byte)(value >>> 24); buffer[bufferIndex++] = (byte)(value >>> 16); buffer[bufferIndex++] = (byte)(value >>> 8); buffer[bufferIndex++] = (byte) value; } else { throw(new OncRpcException(OncRpcException.RPC_BUFFEROVERFLOW)); } } /** * Encodes (aka "serializes") a XDR opaque value, which is represented * by a vector of byte values, and starts at <code>offset</code> with a * length of <code>length</code>. Only the opaque value is encoded, but * no length indication is preceeding the opaque value, so the receiver * has to know how long the opaque value will be. The encoded data is * always padded to be a multiple of four. If the given length is not a * multiple of four, zero bytes will be used for padding. * * @throws OncRpcException if an ONC/RPC error occurs. * @throws IOException if an I/O error occurs. */ public void xdrEncodeOpaque(byte [] value, int offset, int length) throws OncRpcException, IOException { // // First calculate the number of bytes needed for padding. // int padding = (4 - (length & 3)) & 3; if ( bufferIndex <= bufferHighmark - (length + padding) ) { System.arraycopy(value, offset, buffer, bufferIndex, length); bufferIndex += length; if ( padding != 0 ) { // // If the length of the opaque data was not a multiple, then // pad with zeros, so the write pointer (argh! how comes Java // has a pointer...?!) points to a byte, which has an index // of a multiple of four. // System.arraycopy(paddingZeros, 0, buffer, bufferIndex, padding); bufferIndex += padding; } } else { throw(new OncRpcException(OncRpcException.RPC_BUFFEROVERFLOW)); } } /** * The buffer which will receive the encoded information, before it * is sent via a datagram socket. */ private byte [] buffer; /** * The write pointer is an index into the <code>buffer</code>. */ private int bufferIndex; /** * Index of the last four byte word in the buffer. */ private int bufferHighmark; /** * Some zeros, only needed for padding -- like in real life. */ private static final byte [] paddingZeros = { 0, 0, 0, 0 }; } // End of XdrBufferEncodingStream.java