/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ using System; using System.Text; namespace Qpid.Buffer { public enum ByteOrder { BigEndian, LittleEndian } // /// // /// A buffer that manages an underlying byte oriented stream, and writes and reads to and from it in // /// BIG ENDIAN order. // /// // public abstract class ByteBuffer // { // protected const int MINIMUM_CAPACITY = 1; // // protected static Stack _containerStack = new Stack(); // // protected static Stack[] _heapBufferStacks = new Stack[] // { // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack(), // new Stack(), new Stack(), new Stack(), new Stack() // }; // // /// // /// Returns the direct or heap buffer which is capable of the specified size. // /// Currently does not support direct buffers but this will be an option in future. // /// // /// The capacity. // /// // public static ByteBuffer Allocate(int capacity) // { // // for now, just allocate a heap buffer but in future could do an optimised "direct" buffer // // that is implemented natively // return Allocate(capacity, false); // } // // public static ByteBuffer Allocate(int capacity, bool direct) // { // ByteBuffer buffer = Allocate0(capacity, direct); // RefCountingByteBuffer buf = AllocateContainer(); // buf.Init(buffer); // return buf; // } // // private static RefCountingByteBuffer AllocateContainer() // { // RefCountingByteBuffer buf = null; // lock (_containerStack) // { // if (_containerStack.Count > 0) // { // buf = (RefCountingByteBuffer) _containerStack.Pop(); // } // } // // if (buf == null) // { // buf = new RefCountingByteBuffer(); // } // return buf; // } // // protected static ByteBuffer Allocate0(int capacity, bool direct) // { // if (direct) // { // throw new NotSupportedException("Direct buffers not currently implemented"); // } // int idx = GetBufferStackIndex(_heapBufferStacks, capacity); // Stack stack = _heapBufferStacks[idx]; // ByteBuffer buf = null; // lock (stack) // { // if (stack.Count > 0) // { // buf = (ByteBuffer) stack.Pop(); // } // } // // if (buf == null) // { // buf = new HeapByteBuffer(MINIMUM_CAPACITY << idx); // } // // return buf; // } // // protected static void Release0(ByteBuffer buf) // { // Stack stack = _heapBufferStacks[GetBufferStackIndex(_heapBufferStacks, buf.Capacity)]; // lock (stack) // { // stack.Push(buf); // } // } // // private static int GetBufferStackIndex(Stack[] bufferStacks, int size) // { // int targetSize = MINIMUM_CAPACITY; // int stackIdx = 0; // // each bucket contains buffers that are double the size of the previous bucket // while (size > targetSize) // { // targetSize <<= 1; // stackIdx++; // if (stackIdx >= bufferStacks.Length) // { // throw new ArgumentOutOfRangeException("size", "Buffer size is too big: " + size); // } // } // return stackIdx; // } // // /// // /// Increases the internal reference count of this buffer to defer automatic release. You have // /// to invoke release() as many times as you invoked this method to release this buffer. // /// // public abstract void Acquire(); // // /// // /// Releases the specified buffer to the buffer pool. // /// // public abstract void Release(); // // public abstract int Capacity // { // get; // } // // public abstract bool IsAutoExpand // { // get; // set; // } // // /// // /// Changes the capacity and limit of this buffer sot his buffer gets the specified // /// expectedRemaining room from the current position. This method works even if you didn't set // /// autoExpand to true. // /// // /// Room you want from the current position // public abstract void Expand(int expectedRemaining); // // /// // /// Changes the capacity and limit of this buffer sot his buffer gets the specified // /// expectedRemaining room from the specified position. // /// // /// The pos you want the room to be available from. // /// The expected room you want available. // public abstract void Expand(int pos, int expectedRemaining); // // /// // /// Returns true if and only if this buffer is returned back to the buffer pool when released. // /// // /// true if pooled; otherwise, false. // public abstract bool Pooled // { // get; // set; // } // // public abstract int Position // { // get; // set; // } // // public abstract int Limit // { // get; // set; // } // // //public abstract void Mark(); // // //public abstract void Reset(); // // public abstract void Clear(); // // /// // /// Clears this buffer and fills its content with NULL. The position is set to zero, the limit is set to // /// capacity and the mark is discarded. // /// // public void Sweep() // { // Clear(); // FillAndReset(Remaining); // } // // public void Sweep(byte value) // { // Clear(); // FillAndReset(value, Remaining); // } // // public abstract void Flip(); // // public abstract void Rewind(); // // public abstract int Remaining // { // get; // } // // public bool HasRemaining() // { // return Remaining > 0; // } // // public abstract byte Get(); // // public abstract byte Get(int index); // // public abstract void Get(byte[] destination); // // public abstract ushort GetUnsignedShort(); // // public abstract uint GetUnsignedInt(); // // public abstract ulong GetUnsignedLong(); // // public abstract string GetString(uint length, Encoding encoder); // // public abstract void Put(byte data); // // public abstract void Put(byte[] data); // public abstract void Put(byte[] data, int offset, int size); // // public abstract void Put(ushort data); // // public abstract void Put(uint data); // // public abstract void Put(ulong data); // // public abstract void Put(ByteBuffer buf); // // public abstract void Compact(); // // public abstract byte[] ToByteArray(); // // public override string ToString() // { // StringBuilder buf = new StringBuilder(); // buf.Append("HeapBuffer"); // buf.AppendFormat("[pos={0} lim={1} cap={2} : {3}]", Position, Limit, Capacity, HexDump); // return buf.ToString(); // } // // public override int GetHashCode() // { // int h = 1; // int p = Position; // for (int i = Limit - 1; i >= p; i--) // { // h = 31 * h + Get(i); // } // // return h; // } // // public override bool Equals(object obj) // { // if (!(obj is ByteBuffer)) // { // return false; // } // ByteBuffer that = (ByteBuffer) obj; // // if (Remaining != that.Remaining) // { // return false; // } // int p = Position; // for (int i = Limit - 1, j = that.Limit - 1; i >= p; i--, j--) // { // byte v1 = this.Get(i); // byte v2 = that.Get(j); // if (v1 != v2) // { // return false; // } // } // return true; // } // // public string HexDump // { // get // { // return ByteBufferHexDumper.GetHexDump(this); // } // } // // /// // /// Fills the buffer with the specified specified value. This method moves the buffer position forward. // /// // /// The value. // /// The size. // public void Fill(byte value, int size) // { // AutoExpand(size); // int q = size >> 3; // int r = size & 7; // // if (q > 0) // { // int intValue = value | (value << 8) | (value << 16) | (value << 24); // long longValue = intValue; // longValue <<= 32; // longValue |= (ushort)intValue; // // for (int i = q; i > 0; i--) // { // Put((ulong)longValue); // } // } // // q = r >> 2; // r = r & 3; // // if (q > 0) // { // int intValue = value | (value << 8) | (value << 16) | (value << 24); // Put((uint)intValue); // } // // q = r >> 1; // r = r & 1; // // if (q > 0) // { // short shortValue = (short) (value | (value << 8)); // Put((ushort) shortValue); // } // if (r > 0) // { // Put(value); // } // } // // public void FillAndReset(byte value, int size) // { // AutoExpand(size); // int pos = Position; // try // { // Fill(value, size); // } // finally // { // Position = pos; // } // } // // public void Fill(int size) // { // AutoExpand(size); // int q = size >> 3; // int r = size & 7; // // for (int i = q; i > 0; i--) // { // Put(0L); // } // // q = r >> 2; // r = r & 3; // // if (q > 0) // { // Put(0); // } // // q = r >> 1; // r = r & 1; // // if(q > 0) // { // Put((ushort) 0); // } // // if (r > 0) // { // Put((byte) 0); // } // } // // public void FillAndReset(int size) // { // AutoExpand(size); // int pos = Position; // try // { // Fill(size); // } // finally // { // Position = pos; // } // } // // public void Skip(int size) // { // AutoExpand(size); // Position = Position + size; // } // // protected void AutoExpand(int expectedRemaining) // { // if (IsAutoExpand) // { // Expand(expectedRemaining); // } // } // // protected void AutoExpand(int pos, int expectedRemaining) // { // if (IsAutoExpand) // { // Expand(pos, expectedRemaining); // } // } // } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ //package org.apache.mina.common; // //import java.io.IOException; //import java.io.InputStream; //import java.io.ObjectInputStream; //import java.io.ObjectOutputStream; //import java.io.ObjectStreamClass; //import java.io.OutputStream; //import java.nio.BufferOverflowException; //import java.nio.BufferUnderflowException; //import java.nio.ByteOrder; //import java.nio.CharBuffer; //import java.nio.DoubleBuffer; //import java.nio.FloatBuffer; //import java.nio.IntBuffer; //import java.nio.LongBuffer; //import java.nio.ShortBuffer; //import java.nio.charset.CharacterCodingException; //import java.nio.charset.CharsetDecoder; //import java.nio.charset.CharsetEncoder; //import java.nio.charset.CoderResult; // //import org.apache.mina.common.support.ByteBufferHexDumper; //import org.apache.mina.filter.codec.ProtocolEncoderOutput; /** * A byte buffer used by MINA applications. *

* This is a replacement for {@link FixedByteBuffer}. Please refer to * {@link FixedByteBuffer} and {@link java.nio.Buffer} documentation for * usage. MINA does not use NIO {@link FixedByteBuffer} directly for two * reasons: *

*

* *

Allocation

*

* You can get a heap buffer from buffer pool: *

     * ByteBuffer buf = ByteBuffer.allocate(1024, false);
     * 
* you can also get a direct buffer from buffer pool: *
     * ByteBuffer buf = ByteBuffer.allocate(1024, true);
     * 
* or you can let MINA choose: *
     * ByteBuffer buf = ByteBuffer.allocate(1024);
     * 
*

* *

Acquire/Release

*

* Please note that you never need to release the allocated buffer * because MINA will release it automatically when: *

* And, you don't need to release any {@link ByteBuffer} which is passed as a parameter * of {@link IoHandler#messageReceived(IoSession, Object)} method. They are released * automatically when the method returns. *

* You have to release buffers manually by calling {@link #release()} when: *

*

* *

Wrapping existing NIO buffers and arrays

*

* This class provides a few wrap(...) methods that wraps * any NIO buffers and byte arrays. Wrapped MINA buffers are not returned * to the buffer pool by default to prevent unexpected memory leakage by default. * In case you want to make it pooled, you can call {@link #setPooled(bool)} * with true flag to enable pooling. * *

AutoExpand

*

* Writing variable-length data using NIO ByteBuffers is not really * easy, and it is because its size is fixed. MINA ByteBuffer * introduces autoExpand property. If autoExpand property * is true, you never get {@link BufferOverflowException} or * {@link IndexOutOfBoundsException} (except when index is negative). * It automatically expands its capacity and limit value. For example: *

     * String greeting = messageBundle.getMessage( "hello" );
     * ByteBuffer buf = ByteBuffer.allocate( 16 );
     * // Turn on autoExpand (it is off by default)
     * buf.setAutoExpand( true );
     * buf.putString( greeting, utf8encoder );
     * 
* NIO ByteBuffer is reallocated by MINA ByteBuffer behind * the scene if the encoded data is larger than 16 bytes. Its capacity will * increase by two times, and its limit will increase to the last position * the string is written. *

* *

Derived Buffers

*

* Derived buffers are the buffers which were created by * {@link #duplicate()}, {@link #slice()}, or {@link #asReadOnlyBuffer()}. * They are useful especially when you broadcast the same messages to * multiple {@link IoSession}s. Please note that the derived buffers are * neither pooled nor auto-expandable. Trying to expand a derived buffer will * raise {@link IllegalStateException}. *

* *

Changing Buffer Allocation and Management Policy

*

* MINA provides a {@link ByteBufferAllocator} interface to let you override * the default buffer management behavior. There are two allocators provided * out-of-the-box: *

* You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}. *

* * @author The Apache Directory Project (mina-dev@directory.apache.org) * @version $Rev: 451854 $, $Date: 2006-10-02 11:30:11 +0900 (월, 02 10월 2006) $ * @noinspection StaticNonFinalField * @see ByteBufferAllocator */ public abstract class ByteBuffer : IComparable { //private static ByteBufferAllocator allocator = new PooledByteBufferAllocator(); private static IByteBufferAllocator allocator = new SimpleByteBufferAllocator(); private static bool _useDirectBuffers = false; public string HexDump { get { return ByteBufferHexDumper.GetHexDump(this); } } /** * Returns the current allocator which manages the allocated buffers. */ public static IByteBufferAllocator getAllocator() { return allocator; } /** * Changes the current allocator with the specified one to manage * the allocated buffers from now. */ public static void setAllocator( IByteBufferAllocator newAllocator ) { if( newAllocator == null ) { throw new NullReferenceException("allocator cannot be null"); } IByteBufferAllocator oldAllocator = allocator; allocator = newAllocator; if( null != oldAllocator ) { oldAllocator.Dispose(); } } public static bool isUseDirectBuffers() { return _useDirectBuffers; } public static void setUseDirectBuffers( bool useDirectBuffers ) { _useDirectBuffers = useDirectBuffers; } /** * Returns the direct or heap buffer which is capable of the specified * size. This method tries to allocate direct buffer first, and then * tries heap buffer if direct buffer memory is exhausted. Please use * {@link #allocate(int, bool)} to allocate buffers of specific type. * * @param capacity the capacity of the buffer */ public static ByteBuffer allocate( int capacity ) { if( _useDirectBuffers ) { try { // first try to allocate direct buffer return allocate( capacity, true ); } catch (OutOfMemoryException) { // fall through to heap buffer } } return allocate( capacity, false ); } /** * Returns the buffer which is capable of the specified size. * * @param capacity the capacity of the buffer * @param direct true to get a direct buffer, * false to get a heap buffer. */ public static ByteBuffer allocate( int capacity, bool direct ) { return allocator.Allocate( capacity, direct ); } /** * Wraps the specified NIO {@link FixedByteBuffer} into MINA buffer. */ public static ByteBuffer wrap( FixedByteBuffer nioBuffer ) { return allocator.Wrap( nioBuffer ); } /** * Wraps the specified byte array into MINA heap buffer. */ public static ByteBuffer wrap( byte[] byteArray ) { return wrap( FixedByteBuffer.wrap( byteArray ) ); } /** * Wraps the specified byte array into MINA heap buffer. * Please note that MINA buffers are going to be pooled, and * therefore there can be waste of memory if you wrap * your byte array specifying offset and length. */ public static ByteBuffer wrap( byte[] byteArray, int offset, int length ) { return wrap( FixedByteBuffer.wrap( byteArray, offset, length ) ); } protected ByteBuffer() { } /** * Increases the internal reference count of this buffer to defer * automatic release. You have to invoke {@link #release()} as many * as you invoked this method to release this buffer. * * @throws IllegalStateException if you attempt to acquire already * released buffer. */ public abstract void acquire(); /** * Releases the specified buffer to buffer pool. * * @throws IllegalStateException if you attempt to release already * released buffer. */ public abstract void release(); /** * Returns the underlying NIO buffer instance. */ public abstract FixedByteBuffer buf(); /** * @see FixedByteBuffer#isDirect() */ public abstract bool isDirect(); /** * @see FixedByteBuffer#isReadOnly() */ public abstract bool isReadOnly(); /** * @see FixedByteBuffer#capacity() */ public abstract int capacity(); /** * Changes the capacity of this buffer. */ public abstract ByteBuffer capacity( int newCapacity ); /** * Returns true if and only if autoExpand is turned on. */ public abstract bool isAutoExpand(); /** * Turns on or off autoExpand. */ public abstract ByteBuffer setAutoExpand( bool autoExpand ); /** * Changes the capacity and limit of this buffer so this buffer get * the specified expectedRemaining room from the current position. * This method works even if you didn't set autoExpand to * true. */ public ByteBuffer expand( int expectedRemaining ) { return expand( position(), expectedRemaining ); } /** * Changes the capacity and limit of this buffer so this buffer get * the specified expectedRemaining room from the specified * pos. * This method works even if you didn't set autoExpand to * true. */ public abstract ByteBuffer expand( int pos, int expectedRemaining ); /** * Returns true if and only if this buffer is returned back * to the buffer pool when released. *

* The default value of this property is true if and only if you * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)}, * or false otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)}, * and {@link #wrap(FixedByteBuffer)}) */ public abstract bool isPooled(); /** * Sets whether this buffer is returned back to the buffer pool when released. *

* The default value of this property is true if and only if you * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)}, * or false otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)}, * and {@link #wrap(FixedByteBuffer)}) */ public abstract void setPooled( bool pooled ); /** * @see java.nio.Buffer#position() */ public abstract int position(); /** * @see java.nio.Buffer#position(int) */ public abstract ByteBuffer position( int newPosition ); /** * @see java.nio.Buffer#limit() */ public abstract int limit(); /** * @see java.nio.Buffer#limit(int) */ public abstract ByteBuffer limit( int newLimit ); /** * @see java.nio.Buffer#mark() */ public abstract ByteBuffer mark(); /** * Returns the position of the current mark. This method returns -1 if no * mark is set. */ public abstract int markValue(); /** * @see java.nio.Buffer#reset() */ public abstract ByteBuffer reset(); /** * @see java.nio.Buffer#clear() */ public abstract ByteBuffer clear(); /** * Clears this buffer and fills its content with NUL. * The position is set to zero, the limit is set to the capacity, * and the mark is discarded. */ // public ByteBuffer sweep() // { // clear(); // return fillAndReset( remaining() ); // } /** * Clears this buffer and fills its content with value. * The position is set to zero, the limit is set to the capacity, * and the mark is discarded. */ // public ByteBuffer sweep( byte value ) // { // clear(); // return fillAndReset( value, remaining() ); // } /** * @see java.nio.Buffer#flip() */ public abstract ByteBuffer flip(); /** * @see java.nio.Buffer#rewind() */ public abstract ByteBuffer rewind(); /** * @see java.nio.Buffer#remaining() */ public int remaining() { return limit() - position(); } /** * @see java.nio.Buffer#hasRemaining() */ public bool hasRemaining() { return remaining() > 0; } /** * @see FixedByteBuffer#duplicate() */ public abstract ByteBuffer duplicate(); /** * @see FixedByteBuffer#slice() */ public abstract ByteBuffer slice(); /** * @see FixedByteBuffer#asReadOnlyBuffer() */ public abstract ByteBuffer asReadOnlyBuffer(); /** * @see FixedByteBuffer#array() */ public abstract byte[] array(); /** * @see FixedByteBuffer#arrayOffset() */ public abstract int arrayOffset(); /** * @see FixedByteBuffer#get() */ public abstract byte get(); /** * Reads one unsigned byte as a short integer. */ public short getUnsigned() { return (short)( get() & 0xff ); } /** * @see FixedByteBuffer#put(byte) */ public abstract ByteBuffer put( byte b ); /** * @see FixedByteBuffer#get(int) */ public abstract byte get( int index ); /** * Reads one byte as an unsigned short integer. */ public short getUnsigned( int index ) { return (short)( get( index ) & 0xff ); } /** * @see FixedByteBuffer#put(int, byte) */ public abstract ByteBuffer put( int index, byte b ); /** * @see FixedByteBuffer#get(byte[], int, int) */ public abstract ByteBuffer get( byte[] dst, int offset, int length ); /** * @see FixedByteBuffer#get(byte[]) */ public abstract ByteBuffer get(byte[] dst); // { // return get( dst, 0, dst.Length ); // } /** * Writes the content of the specified src into this buffer. */ public abstract ByteBuffer put( FixedByteBuffer src ); /** * Writes the content of the specified src into this buffer. */ public ByteBuffer put( ByteBuffer src ) { return put( src.buf() ); } /** * @see FixedByteBuffer#put(byte[], int, int) */ public abstract ByteBuffer put( byte[] src, int offset, int length ); /** * @see FixedByteBuffer#put(byte[]) */ public abstract ByteBuffer put(byte[] src); // { // return put(src); //// return put( src, 0, src.Length ); // } /** * @see FixedByteBuffer#compact() */ public abstract ByteBuffer compact(); public String toString() { StringBuilder buf = new StringBuilder(); if( isDirect() ) { buf.Append( "DirectBuffer" ); } else { buf.Append( "HeapBuffer" ); } buf.Append( "[pos=" ); buf.Append( position() ); buf.Append( " lim=" ); buf.Append( limit() ); buf.Append( " cap=" ); buf.Append( capacity() ); buf.Append( ": " ); buf.Append( getHexDump() ); buf.Append( ']' ); return buf.ToString(); } public int hashCode() { int h = 1; int p = position(); for( int i = limit() - 1; i >= p; i -- ) { h = 31 * h + get( i ); } return h; } public bool equals( Object o ) { if( !( o is ByteBuffer ) ) { return false; } ByteBuffer that = (ByteBuffer)o; if( this.remaining() != that.remaining() ) { return false; } int p = this.position(); for( int i = this.limit() - 1, j = that.limit() - 1; i >= p; i --, j -- ) { byte v1 = this.get( i ); byte v2 = that.get( j ); if( v1 != v2 ) { return false; } } return true; } public int CompareTo( Object o ) { ByteBuffer that = (ByteBuffer)o; int n = this.position() + Math.Min( this.remaining(), that.remaining() ); for( int i = this.position(), j = that.position(); i < n; i ++, j ++ ) { byte v1 = this.get( i ); byte v2 = that.get( j ); if( v1 == v2 ) { continue; } if( v1 < v2 ) { return -1; } return +1; } return this.remaining() - that.remaining(); } /** * @see FixedByteBuffer#order() */ public abstract ByteOrder order(); /** * @see FixedByteBuffer#order(ByteOrder) */ public abstract ByteBuffer order( ByteOrder bo ); /** * @see FixedByteBuffer#getChar() */ public abstract char getChar(); /** * @see FixedByteBuffer#putChar(char) */ public abstract ByteBuffer putChar( char value ); /** * @see FixedByteBuffer#getChar(int) */ public abstract char getChar( int index ); /** * @see FixedByteBuffer#putChar(int, char) */ public abstract ByteBuffer putChar( int index, char value ); /** * @see FixedByteBuffer#asCharBuffer() */ // public abstract CharBuffer asCharBuffer(); /** * @see FixedByteBuffer#getShort() */ public abstract short getShort(); /** * Reads two bytes unsigned integer. */ public int getUnsignedShort() { return getShort() & 0xffff; } /** * @see FixedByteBuffer#putShort(short) */ public abstract ByteBuffer putShort( short value ); /** * @see FixedByteBuffer#getShort() */ public abstract short getShort( int index ); /** * Reads two bytes unsigned integer. */ public int getUnsignedShort( int index ) { return getShort( index ) & 0xffff; } /** * @see FixedByteBuffer#putShort(int, short) */ public abstract ByteBuffer putShort( int index, short value ); /** * @see FixedByteBuffer#asShortBuffer() */ // public abstract ShortBuffer asShortBuffer(); /** * @see FixedByteBuffer#getInt() */ public abstract int getInt(); /** * Reads four bytes unsigned integer. */ public uint getUnsignedInt() { // return getInt() & 0xffffffffL; //CheckSpaceForReading(4); byte b1 = get(); byte b2 = get(); byte b3 = get(); byte b4 = get(); return (uint)((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); } /** * @see FixedByteBuffer#putInt(int) */ public abstract ByteBuffer putInt( int value ); /** * @see FixedByteBuffer#getInt(int) */ public abstract int getInt( int index ); /** * Reads four bytes unsigned integer. */ public long getUnsignedInt( int index ) { return getInt( index ) & 0xffffffffL; } /** * @see FixedByteBuffer#putInt(int, int) */ public abstract ByteBuffer putInt( int index, int value ); /** * @see FixedByteBuffer#asIntBuffer() */ // public abstract IntBuffer asIntBuffer(); /** * @see FixedByteBuffer#getLong() */ public abstract long getLong(); /** * @see FixedByteBuffer#putLong(int, long) */ public abstract ByteBuffer putLong( long value ); /** * @see FixedByteBuffer#getLong(int) */ public abstract long getLong( int index ); /** * @see FixedByteBuffer#putLong(int, long) */ public abstract ByteBuffer putLong( int index, long value ); /** * @see FixedByteBuffer#asLongBuffer() */ // public abstract LongBuffer asLongBuffer(); /** * @see FixedByteBuffer#getFloat() */ public abstract float getFloat(); /** * @see FixedByteBuffer#putFloat(float) */ public abstract ByteBuffer putFloat( float value ); /** * @see FixedByteBuffer#getFloat(int) */ public abstract float getFloat( int index ); /** * @see FixedByteBuffer#putFloat(int, float) */ public abstract ByteBuffer putFloat( int index, float value ); /** * @see FixedByteBuffer#asFloatBuffer() */ // public abstract FloatBuffer asFloatBuffer(); /** * @see FixedByteBuffer#getDouble() */ public abstract double getDouble(); /** * @see FixedByteBuffer#putDouble(double) */ public abstract ByteBuffer putDouble( double value ); /** * @see FixedByteBuffer#getDouble(int) */ public abstract double getDouble( int index ); /** * @see FixedByteBuffer#putDouble(int, double) */ public abstract ByteBuffer putDouble( int index, double value ); /** * @see FixedByteBuffer#asDoubleBuffer() */ // public abstract DoubleBuffer asDoubleBuffer(); /** * Returns an {@link InputStream} that reads the data from this buffer. * {@link InputStream#read()} returns -1 if the buffer position * reaches to the limit. */ // public InputStream asInputStream() // { // // XXX: Use System.IO.Stream here? // return new InputStream() // { // public int available() // { // return ByteBuffer.this.remaining(); // } // // public synchronized void mark( int readlimit ) // { // ByteBuffer.this.mark(); // } // // public bool markSupported() // { // return true; // } // // public int read() // { // if( ByteBuffer.this.hasRemaining() ) // { // return ByteBuffer.this.get() & 0xff; // } // else // { // return -1; // } // } // // public int read( byte[] b, int off, int len ) // { // int remaining = ByteBuffer.this.remaining(); // if( remaining > 0 ) // { // int readBytes = Math.min( remaining, len ); // ByteBuffer.this.get( b, off, readBytes ); // return readBytes; // } // else // { // return -1; // } // } // // public synchronized void reset() // { // ByteBuffer.this.reset(); // } // // public long skip( long n ) // { // int bytes; // if( n > Integer.MAX_VALUE ) // { // bytes = ByteBuffer.this.remaining(); // } // else // { // bytes = Math.min( ByteBuffer.this.remaining(), (int)n ); // } // ByteBuffer.this.skip( bytes ); // return bytes; // } // }; // } /** * Returns an {@link OutputStream} that Appends the data into this buffer. * Please note that the {@link OutputStream#write(int)} will throw a * {@link BufferOverflowException} instead of an {@link IOException} * in case of buffer overflow. Please set autoExpand property by * calling {@link #setAutoExpand(bool)} to prevent the unexpected runtime * exception. */ // public OutputStream asOutputStream() // { // return new OutputStream() // { // public void write( byte[] b, int off, int len ) // { // ByteBuffer.this.put( b, off, len ); // } // // public void write( int b ) // { // ByteBuffer.this.put( (byte)b ); // } // }; // } /** * Returns hexdump of this buffer. */ public String getHexDump() { return ByteBufferHexDumper.GetHexDump(this); } //////////////////////////////// // String getters and putters // //////////////////////////////// /** * Reads a NUL-terminated string from this buffer using the * specified decoder and returns it. This method reads * until the limit of this buffer if no NUL is found. */ // public String getString( Encoding decoder ) // { // if( !hasRemaining() ) // { // return ""; // } // // decoder. // bool utf16 = decoder.charset().name().startsWith( "UTF-16" ); // // int oldPos = position(); // int oldLimit = limit(); // int end; // // if( !utf16 ) // { // while( hasRemaining() ) // { // if( get() == 0 ) // { // break; // } // } // // end = position(); // if( end == oldLimit && get( end - 1 ) != 0 ) // { // limit( end ); // } // else // { // limit( end - 1 ); // } // } // else // { // while( remaining() >= 2 ) // { // if( ( get() == 0 ) && ( get() == 0 ) ) // { // break; // } // } // // end = position(); // if( end == oldLimit || end == oldLimit - 1 ) // { // limit( end ); // } // else // { // limit( end - 2 ); // } // } // // position( oldPos ); // if( !hasRemaining() ) // { // limit( oldLimit ); // position( end ); // return ""; // } // decoder.reset(); // // int expectedLength = (int)( remaining() * decoder.averageCharsPerByte() ) + 1; // CharBuffer out = CharBuffer.allocate( expectedLength ); // for( ; ; ) // { // CoderResult cr; // if( hasRemaining() ) // { // cr = decoder.decode( buf(), out, true ); // } // else // { // cr = decoder.flush( out ); // } // // if( cr.isUnderflow() ) // { // break; // } // // if( cr.isOverflow() ) // { // CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); // out.flip(); // o.put( out ); // out = o; // continue; // } // // cr.throwException(); // } // // limit( oldLimit ); // position( end ); // return out.flip().toString(); // } /** * Reads a NUL-terminated string from this buffer using the * specified decoder and returns it. * * @param fieldSize the maximum number of bytes to read */ // public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException // { // checkFieldSize( fieldSize ); // // if( fieldSize == 0 ) // { // return ""; // } // // if( !hasRemaining() ) // { // return ""; // } // // bool utf16 = decoder.charset().name().startsWith( "UTF-16" ); // // if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) // { // throw new IllegalArgumentException( "fieldSize is not even." ); // } // // int oldPos = position(); // int oldLimit = limit(); // int end = position() + fieldSize; // // if( oldLimit < end ) // { // throw new BufferUnderflowException(); // } // // int i; // // if( !utf16 ) // { // for( i = 0; i < fieldSize; i ++ ) // { // if( get() == 0 ) // { // break; // } // } // // if( i == fieldSize ) // { // limit( end ); // } // else // { // limit( position() - 1 ); // } // } // else // { // for( i = 0; i < fieldSize; i += 2 ) // { // if( ( get() == 0 ) && ( get() == 0 ) ) // { // break; // } // } // // if( i == fieldSize ) // { // limit( end ); // } // else // { // limit( position() - 2 ); // } // } // // position( oldPos ); // if( !hasRemaining() ) // { // limit( oldLimit ); // position( end ); // return ""; // } // decoder.reset(); // // int expectedLength = (int)( remaining() * decoder.averageCharsPerByte() ) + 1; // CharBuffer out = CharBuffer.allocate( expectedLength ); // for( ; ; ) // { // CoderResult cr; // if( hasRemaining() ) // { // cr = decoder.decode( buf(), out, true ); // } // else // { // cr = decoder.flush( out ); // } // // if( cr.isUnderflow() ) // { // break; // } // // if( cr.isOverflow() ) // { // CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); // out.flip(); // o.put( out ); // out = o; // continue; // } // // cr.throwException(); // } // // limit( oldLimit ); // position( end ); // return out.flip().toString(); // } /** * Writes the content of in into this buffer using the * specified encoder. This method doesn't terminate * string with NUL. You have to do it by yourself. * * @throws BufferOverflowException if the specified string doesn't fit */ // public ByteBuffer putString( // CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException // { // if( val.length() == 0 ) // { // return this; // } // // CharBuffer in = CharBuffer.wrap( val ); // encoder.reset(); // // int expandedState = 0; // // for( ; ; ) // { // CoderResult cr; // if( in.hasRemaining() ) // { // cr = encoder.encode( in, buf(), true ); // } // else // { // cr = encoder.flush( buf() ); // } // // if( cr.isUnderflow() ) // { // break; // } // if( cr.isOverflow() ) // { // if( isAutoExpand() ) // { // switch( expandedState ) // { // case 0: // autoExpand( (int)Math.ceil( in.remaining() * encoder.averageBytesPerChar() ) ); // expandedState ++; // break; // case 1: // autoExpand( (int)Math.ceil( in.remaining() * encoder.maxBytesPerChar() ) ); // expandedState ++; // break; // default: // throw new RuntimeException( "Expanded by " + // (int)Math.ceil( in.remaining() * encoder.maxBytesPerChar() ) + // " but that wasn't enough for '" + val + "'" ); // } // continue; // } // } // else // { // expandedState = 0; // } // cr.throwException(); // } // return this; // } /** * Writes the content of in into this buffer as a * NUL-terminated string using the specified * encoder. *

* If the charset name of the encoder is UTF-16, you cannot specify * odd fieldSize, and this method will Append two * NULs as a terminator. *

* Please note that this method doesn't terminate with NUL * if the input string is longer than fieldSize. * * @param fieldSize the maximum number of bytes to write */ // public ByteBuffer putString( // CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException // { // checkFieldSize( fieldSize ); // // if( fieldSize == 0 ) // return this; // // autoExpand( fieldSize ); // // bool utf16 = encoder.charset().name().startsWith( "UTF-16" ); // // if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) // { // throw new IllegalArgumentException( "fieldSize is not even." ); // } // // int oldLimit = limit(); // int end = position() + fieldSize; // // if( oldLimit < end ) // { // throw new BufferOverflowException(); // } // // if( val.length() == 0 ) // { // if( !utf16 ) // { // put( (byte)0x00 ); // } // else // { // put( (byte)0x00 ); // put( (byte)0x00 ); // } // position( end ); // return this; // } // // CharBuffer in = CharBuffer.wrap( val ); // limit( end ); // encoder.reset(); // // for( ; ; ) // { // CoderResult cr; // if( in.hasRemaining() ) // { // cr = encoder.encode( in, buf(), true ); // } // else // { // cr = encoder.flush( buf() ); // } // // if( cr.isUnderflow() || cr.isOverflow() ) // { // break; // } // cr.throwException(); // } // // limit( oldLimit ); // // if( position() < end ) // { // if( !utf16 ) // { // put( (byte)0x00 ); // } // else // { // put( (byte)0x00 ); // put( (byte)0x00 ); // } // } // // position( end ); // return this; // } /** * Reads a string which has a 16-bit length field before the actual * encoded string, using the specified decoder and returns it. * This method is a shortcut for getPrefixedString(2, decoder). */ // public String getPrefixedString( CharsetDecoder decoder ) throws CharacterCodingException // { // return getPrefixedString( 2, decoder ); // } /** * Reads a string which has a length field before the actual * encoded string, using the specified decoder and returns it. * * @param prefixLength the length of the length field (1, 2, or 4) */ // public String getPrefixedString( int prefixLength, CharsetDecoder decoder ) throws CharacterCodingException // { // if( !prefixedDataAvailable( prefixLength ) ) // { // throw new BufferUnderflowException(); // } // // int fieldSize = 0; // // switch( prefixLength ) // { // case 1: // fieldSize = getUnsigned(); // break; // case 2: // fieldSize = getUnsignedShort(); // break; // case 4: // fieldSize = getInt(); // break; // } // // if( fieldSize == 0 ) // { // return ""; // } // // bool utf16 = decoder.charset().name().startsWith( "UTF-16" ); // // if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) // { // throw new BufferDataException( "fieldSize is not even for a UTF-16 string." ); // } // // int oldLimit = limit(); // int end = position() + fieldSize; // // if( oldLimit < end ) // { // throw new BufferUnderflowException(); // } // // limit( end ); // decoder.reset(); // // int expectedLength = (int)( remaining() * decoder.averageCharsPerByte() ) + 1; // CharBuffer out = CharBuffer.allocate( expectedLength ); // for( ; ; ) // { // CoderResult cr; // if( hasRemaining() ) // { // cr = decoder.decode( buf(), out, true ); // } // else // { // cr = decoder.flush( out ); // } // // if( cr.isUnderflow() ) // { // break; // } // // if( cr.isOverflow() ) // { // CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); // out.flip(); // o.put( out ); // out = o; // continue; // } // // cr.throwException(); // } // // limit( oldLimit ); // position( end ); // return out.flip().toString(); // } /** * Writes the content of in into this buffer as a * string which has a 16-bit length field before the actual * encoded string, using the specified encoder. * This method is a shortcut for putPrefixedString(in, 2, 0, encoder). * * @throws BufferOverflowException if the specified string doesn't fit */ // public ByteBuffer putPrefixedString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException // { // return putPrefixedString( in, 2, 0, encoder ); // } /** * Writes the content of in into this buffer as a * string which has a 16-bit length field before the actual * encoded string, using the specified encoder. * This method is a shortcut for putPrefixedString(in, prefixLength, 0, encoder). * * @param prefixLength the length of the length field (1, 2, or 4) * * @throws BufferOverflowException if the specified string doesn't fit */ // public ByteBuffer putPrefixedString( CharSequence in, int prefixLength, CharsetEncoder encoder ) // throws CharacterCodingException // { // return putPrefixedString( in, prefixLength, 0, encoder ); // } /** * Writes the content of in into this buffer as a * string which has a 16-bit length field before the actual * encoded string, using the specified encoder. * This method is a shortcut for putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder). * * @param prefixLength the length of the length field (1, 2, or 4) * @param padding the number of padded NULs (1 (or 0), 2, or 4) * * @throws BufferOverflowException if the specified string doesn't fit */ // public ByteBuffer putPrefixedString( CharSequence in, int prefixLength, int padding, CharsetEncoder encoder ) // throws CharacterCodingException // { // return putPrefixedString( in, prefixLength, padding, (byte)0, encoder ); // } /** * Writes the content of in into this buffer as a * string which has a 16-bit length field before the actual * encoded string, using the specified encoder. * * @param prefixLength the length of the length field (1, 2, or 4) * @param padding the number of padded bytes (1 (or 0), 2, or 4) * @param padValue the value of padded bytes * * @throws BufferOverflowException if the specified string doesn't fit */ // public ByteBuffer putPrefixedString( CharSequence val, // int prefixLength, // int padding, // byte padValue, // CharsetEncoder encoder ) throws CharacterCodingException // { // int maxLength; // switch( prefixLength ) // { // case 1: // maxLength = 255; // break; // case 2: // maxLength = 65535; // break; // case 4: // maxLength = Integer.MAX_VALUE; // break; // default: // throw new IllegalArgumentException( "prefixLength: " + prefixLength ); // } // // if( val.length() > maxLength ) // { // throw new IllegalArgumentException( "The specified string is too long." ); // } // if( val.length() == 0 ) // { // switch( prefixLength ) // { // case 1: // put( (byte)0 ); // break; // case 2: // putShort( (short)0 ); // break; // case 4: // putInt( 0 ); // break; // } // return this; // } // // int padMask; // switch( padding ) // { // case 0: // case 1: // padMask = 0; // break; // case 2: // padMask = 1; // break; // case 4: // padMask = 3; // break; // default: // throw new IllegalArgumentException( "padding: " + padding ); // } // // CharBuffer in = CharBuffer.wrap( val ); // int expectedLength = (int)( in.remaining() * encoder.averageBytesPerChar() ) + 1; // // skip( prefixLength ); // make a room for the length field // int oldPos = position(); // encoder.reset(); // // for( ; ; ) // { // CoderResult cr; // if( in.hasRemaining() ) // { // cr = encoder.encode( in, buf(), true ); // } // else // { // cr = encoder.flush( buf() ); // } // // if( position() - oldPos > maxLength ) // { // throw new IllegalArgumentException( "The specified string is too long." ); // } // // if( cr.isUnderflow() ) // { // break; // } // if( cr.isOverflow() && isAutoExpand() ) // { // autoExpand( expectedLength ); // continue; // } // cr.throwException(); // } // // // Write the length field // fill( padValue, padding - ( ( position() - oldPos ) & padMask ) ); // int length = position() - oldPos; // switch( prefixLength ) // { // case 1: // put( oldPos - 1, (byte)length ); // break; // case 2: // putShort( oldPos - 2, (short)length ); // break; // case 4: // putInt( oldPos - 4, length ); // break; // } // return this; // } /** * Reads a Java object from the buffer using the context {@link ClassLoader} * of the current thread. */ // public Object getObject() throws ClassNotFoundException // { // return getObject( Thread.currentThread().getContextClassLoader() ); // } /** * Reads a Java object from the buffer using the specified classLoader. */ // public Object getObject( final ClassLoader classLoader ) throws ClassNotFoundException // { // if( !prefixedDataAvailable( 4 ) ) // { // throw new BufferUnderflowException(); // } // // int length = getInt(); // if( length <= 4 ) // { // throw new BufferDataException( "Object length should be greater than 4: " + length ); // } // // int oldLimit = limit(); // limit( position() + length ); // try // { // ObjectInputStream in = new ObjectInputStream( asInputStream() ) // { // protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException // { // String className = readUTF(); // Class clazz = Class.forName( className, true, classLoader ); // return ObjectStreamClass.lookup( clazz ); // } // }; // return in.readObject(); // } // catch( IOException e ) // { // throw new BufferDataException( e ); // } // finally // { // limit( oldLimit ); // } // } /** * Writes the specified Java object to the buffer. */ // public ByteBuffer putObject( Object o ) // { // int oldPos = position(); // skip( 4 ); // Make a room for the length field. // try // { // ObjectOutputStream out = new ObjectOutputStream( asOutputStream() ) // { // protected void writeClassDescriptor( ObjectStreamClass desc ) throws IOException // { // writeUTF( desc.getName() ); // } // }; // out.writeObject( o ); // out.flush(); // } // catch( IOException e ) // { // throw new BufferDataException( e ); // } // // // Fill the length field // int newPos = position(); // position( oldPos ); // putInt( newPos - oldPos - 4 ); // position( newPos ); // return this; // } /** * Returns true if this buffer contains a data which has a data * length as a prefix and the buffer has remaining data as enough as * specified in the data length field. This method is identical with * prefixedDataAvailable( prefixLength, Integer.MAX_VALUE ). * Please not that using this method can allow DoS (Denial of Service) * attack in case the remote peer sends too big data length value. * It is recommended to use {@link #prefixedDataAvailable(int, int)} * instead. * * @param prefixLength the length of the prefix field (1, 2, or 4) * * @throws IllegalArgumentException if prefixLength is wrong * @throws BufferDataException if data length is negative */ public bool prefixedDataAvailable( int prefixLength ) { return prefixedDataAvailable( prefixLength, int.MaxValue); } /** * Returns true if this buffer contains a data which has a data * length as a prefix and the buffer has remaining data as enough as * specified in the data length field. * * @param prefixLength the length of the prefix field (1, 2, or 4) * @param maxDataLength the allowed maximum of the read data length * * @throws IllegalArgumentException if prefixLength is wrong * @throws BufferDataException if data length is negative or greater then maxDataLength */ public bool prefixedDataAvailable( int prefixLength, int maxDataLength ) { if( remaining() < prefixLength ) { return false; } int dataLength; switch( prefixLength ) { case 1: dataLength = getUnsigned( position() ); break; case 2: dataLength = getUnsignedShort( position() ); break; case 4: dataLength = getInt( position() ); break; default: throw new ArgumentException("prefixLength: " + prefixLength); } if( dataLength < 0 || dataLength > maxDataLength ) { throw new BufferDataException( "dataLength: " + dataLength ); } return remaining() - prefixLength >= dataLength; } ////////////////////////// // Skip or fill methods // ////////////////////////// /** * Forwards the position of this buffer as the specified size * bytes. */ public ByteBuffer skip( int size ) { autoExpand( size ); return position( position() + size ); } /** * Fills this buffer with the specified value. * This method moves buffer position forward. */ // public ByteBuffer fill( byte value, int size ) // { // autoExpand( size ); // int q = size >>> 3; // int r = size & 7; // // if( q > 0 ) // { // int intValue = value | ( value << 8 ) | ( value << 16 ) // | ( value << 24 ); // long longValue = intValue; // longValue <<= 32; // longValue |= intValue; // // for( int i = q; i > 0; i -- ) // { // putLong( longValue ); // } // } // // q = r >>> 2; // r = r & 3; // // if( q > 0 ) // { // int intValue = value | ( value << 8 ) | ( value << 16 ) // | ( value << 24 ); // putInt( intValue ); // } // // q = r >> 1; // r = r & 1; // // if( q > 0 ) // { // short shortValue = (short)( value | ( value << 8 ) ); // putShort( shortValue ); // } // // if( r > 0 ) // { // put( value ); // } // // return this; // } /** * Fills this buffer with the specified value. * This method does not change buffer position. */ // public ByteBuffer fillAndReset( byte value, int size ) // { // autoExpand( size ); // int pos = position(); // try // { // fill( value, size ); // } // finally // { // position( pos ); // } // return this; // } /** * Fills this buffer with NUL (0x00). * This method moves buffer position forward. */ // public ByteBuffer fill( int size ) // { // autoExpand( size ); // int q = size >>> 3; // int r = size & 7; // // for( int i = q; i > 0; i -- ) // { // putLong( 0L ); // } // // q = r >>> 2; // r = r & 3; // // if( q > 0 ) // { // putInt( 0 ); // } // // q = r >> 1; // r = r & 1; // // if( q > 0 ) // { // putShort( (short)0 ); // } // // if( r > 0 ) // { // put( (byte)0 ); // } // // return this; // } /** * Fills this buffer with NUL (0x00). * This method does not change buffer position. */ // public ByteBuffer fillAndReset( int size ) // { // autoExpand( size ); // int pos = position(); // try // { // fill( size ); // } // finally // { // position( pos ); // } // // return this; // } /** * This method forwards the call to {@link #expand(int)} only when * autoExpand property is true. */ protected ByteBuffer autoExpand( int expectedRemaining ) { if( isAutoExpand() ) { expand( expectedRemaining ); } return this; } /** * This method forwards the call to {@link #expand(int)} only when * autoExpand property is true. */ protected ByteBuffer autoExpand( int pos, int expectedRemaining ) { if( isAutoExpand() ) { expand( pos, expectedRemaining ); } return this; } public abstract void put(ushort value); public abstract ushort GetUnsignedShort(); public abstract uint GetUnsignedInt(); public abstract void put(uint max); public abstract void put(ulong tag); public abstract ulong GetUnsignedLong(); } }