diff options
Diffstat (limited to 'dotnet/Qpid.Buffer/ByteBuffer.cs')
-rw-r--r-- | dotnet/Qpid.Buffer/ByteBuffer.cs | 2543 |
1 files changed, 2243 insertions, 300 deletions
diff --git a/dotnet/Qpid.Buffer/ByteBuffer.cs b/dotnet/Qpid.Buffer/ByteBuffer.cs index 70022407a5..1a43c0b9f3 100644 --- a/dotnet/Qpid.Buffer/ByteBuffer.cs +++ b/dotnet/Qpid.Buffer/ByteBuffer.cs @@ -19,432 +19,2375 @@ * */ using System; -using System.Collections; using System.Text; namespace Qpid.Buffer { - /// <summary> - /// A buffer that manages an underlying byte oriented stream, and writes and reads to and from it in - /// BIG ENDIAN order. - /// </summary> - public abstract class ByteBuffer + public enum ByteOrder { BigEndian, LittleEndian } +// /// <summary> +// /// A buffer that manages an underlying byte oriented stream, and writes and reads to and from it in +// /// BIG ENDIAN order. +// /// </summary> +// 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() +// }; +// +// /// <summary> +// /// 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. +// /// </summary> +// /// <param name="capacity">The capacity.</param> +// /// <returns></returns> +// 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; +// } +// +// /// <summary> +// /// 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. +// /// </summary> +// public abstract void Acquire(); +// +// /// <summary> +// /// Releases the specified buffer to the buffer pool. +// /// </summary> +// public abstract void Release(); +// +// public abstract int Capacity +// { +// get; +// } +// +// public abstract bool IsAutoExpand +// { +// get; +// set; +// } +// +// /// <summary> +// /// 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. +// /// </summary> +// /// <param name="expectedRemaining">Room you want from the current position</param> +// public abstract void Expand(int expectedRemaining); +// +// /// <summary> +// /// Changes the capacity and limit of this buffer sot his buffer gets the specified +// /// expectedRemaining room from the specified position. +// /// </summary> +// /// <param name="pos">The pos you want the room to be available from.</param> +// /// <param name="expectedRemaining">The expected room you want available.</param> +// public abstract void Expand(int pos, int expectedRemaining); +// +// /// <summary> +// /// Returns true if and only if this buffer is returned back to the buffer pool when released. +// /// </summary> +// /// <value><c>true</c> if pooled; otherwise, <c>false</c>.</value> +// 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(); +// +// /// <summary> +// /// 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. +// /// </summary> +// 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); +// } +// } +// +// /// <summary> +// /// Fills the buffer with the specified specified value. This method moves the buffer position forward. +// /// </summary> +// /// <param name="value">The value.</param> +// /// <param name="size">The size.</param> +// 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. + * <p> + * 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: + * <ul> + * <li>It doesn't provide useful getters and putters such as + * <code>fill</code>, <code>get/putString</code>, and + * <code>get/putAsciiInt()</code> enough.</li> + * <li>It is hard to distinguish if the buffer is created from MINA buffer + * pool or not. MINA have to return used buffers back to pool.</li> + * <li>It is difficult to write variable-length data due to its fixed + * capacity</li> + * </ul> + * </p> + * + * <h2>Allocation</h2> + * <p> + * You can get a heap buffer from buffer pool: + * <pre> + * ByteBuffer buf = ByteBuffer.allocate(1024, false); + * </pre> + * you can also get a direct buffer from buffer pool: + * <pre> + * ByteBuffer buf = ByteBuffer.allocate(1024, true); + * </pre> + * or you can let MINA choose: + * <pre> + * ByteBuffer buf = ByteBuffer.allocate(1024); + * </pre> + * </p> + * + * <h2>Acquire/Release</h2> + * <p> + * <b>Please note that you never need to release the allocated buffer</b> + * because MINA will release it automatically when: + * <ul> + * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li> + * <li>You pass the buffer by calling {@link IoFilter.NextFilter#filterWrite(IoSession,IoFilter.WriteRequest)}.</li> + * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li> + * </ul> + * 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. + * <p> + * You have to release buffers manually by calling {@link #release()} when: + * <ul> + * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li> + * <li>You called {@link #acquire()} to prevent the buffer from being released.</li> + * </ul> + * </p> + * + * <h2>Wrapping existing NIO buffers and arrays</h2> + * <p> + * This class provides a few <tt>wrap(...)</tt> 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 <tt>true</tt> flag to enable pooling. + * + * <h2>AutoExpand</h2> + * <p> + * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really + * easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt> + * introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> 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: + * <pre> + * 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 ); + * </pre> + * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> 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. + * </p> + * + * <h2>Derived Buffers</h2> + * <p> + * 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}. + * </p> + * + * <h2>Changing Buffer Allocation and Management Policy</h2> + * <p> + * MINA provides a {@link ByteBufferAllocator} interface to let you override + * the default buffer management behavior. There are two allocators provided + * out-of-the-box: + * <ul> + * <li>{@link PooledByteBufferAllocator} (Default)</li> + * <li>{@link SimpleByteBufferAllocator}</li> + * </ul> + * You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}. + * </p> + * + * @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 { - 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() - }; - - /// <summary> - /// 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. - /// </summary> - /// <param name="capacity">The capacity.</param> - /// <returns></returns> - 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() + //private static ByteBufferAllocator allocator = new PooledByteBufferAllocator(); + private static ByteBufferAllocator allocator = new SimpleByteBufferAllocator(); + + private static bool _useDirectBuffers = false; + + public string HexDump { - RefCountingByteBuffer buf = null; - lock (_containerStack) - { - if (_containerStack.Count > 0) - { - buf = (RefCountingByteBuffer) _containerStack.Pop(); - } - } - - if (buf == null) + get { - buf = new RefCountingByteBuffer(); + return ByteBufferHexDumper.GetHexDump(this); } - return buf; } - - protected static ByteBuffer Allocate0(int capacity, bool direct) + + /** + * Returns the current allocator which manages the allocated buffers. + */ + public static ByteBufferAllocator getAllocator() { - if (direct) - { - throw new NotSupportedException("Direct buffers not currently implemented"); - } - int idx = GetBufferStackIndex(_heapBufferStacks, capacity); - Stack stack = _heapBufferStacks[idx]; - ByteBuffer buf = null; - lock (stack) + return allocator; + } + + /** + * Changes the current allocator with the specified one to manage + * the allocated buffers from now. + */ + public static void setAllocator( ByteBufferAllocator newAllocator ) + { + if( newAllocator == null ) { - if (stack.Count > 0) - { - buf = (ByteBuffer) stack.Pop(); - } + throw new NullReferenceException("allocator cannot be null"); } - if (buf == null) + ByteBufferAllocator oldAllocator = allocator; + + allocator = newAllocator; + + if( null != oldAllocator ) { - buf = new HeapByteBuffer(MINIMUM_CAPACITY << idx); + oldAllocator.dispose(); } + } - return buf; + public static bool isUseDirectBuffers() + { + return _useDirectBuffers; } - - protected static void Release0(ByteBuffer buf) + + public static void setUseDirectBuffers( bool useDirectBuffers ) { - Stack stack = _heapBufferStacks[GetBufferStackIndex(_heapBufferStacks, buf.Capacity)]; - lock (stack) - { - stack.Push(buf); - } + _useDirectBuffers = useDirectBuffers; } - - private static int GetBufferStackIndex(Stack[] bufferStacks, int size) + + /** + * 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 ) { - int targetSize = MINIMUM_CAPACITY; - int stackIdx = 0; - // each bucket contains buffers that are double the size of the previous bucket - while (size > targetSize) + if( _useDirectBuffers ) { - targetSize <<= 1; - stackIdx++; - if (stackIdx >= bufferStacks.Length) + try + { + // first try to allocate direct buffer + return allocate( capacity, true ); + } + catch (OutOfMemoryException) { - throw new ArgumentOutOfRangeException("size", "Buffer size is too big: " + size); + // fall through to heap buffer } } - return stackIdx; - } - - /// <summary> - /// 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. - /// </summary> - public abstract void Acquire(); - /// <summary> - /// Releases the specified buffer to the buffer pool. - /// </summary> - public abstract void Release(); + return allocate( capacity, false ); + } - public abstract int Capacity + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity the capacity of the buffer + * @param direct <tt>true</tt> to get a direct buffer, + * <tt>false</tt> to get a heap buffer. + */ + public static ByteBuffer allocate( int capacity, bool direct ) { - get; + return allocator.allocate( capacity, direct ); } - public abstract bool IsAutoExpand + /** + * Wraps the specified NIO {@link FixedByteBuffer} into MINA buffer. + */ + public static ByteBuffer wrap( FixedByteBuffer nioBuffer ) { - get; - set; + return allocator.wrap( nioBuffer ); } - /// <summary> - /// 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. - /// </summary> - /// <param name="expectedRemaining">Room you want from the current position</param> - public abstract void Expand(int expectedRemaining); - - /// <summary> - /// Changes the capacity and limit of this buffer sot his buffer gets the specified - /// expectedRemaining room from the specified position. - /// </summary> - /// <param name="pos">The pos you want the room to be available from.</param> - /// <param name="expectedRemaining">The expected room you want available.</param> - public abstract void Expand(int pos, int expectedRemaining); - - /// <summary> - /// Returns true if and only if this buffer is returned back to the buffer pool when released. - /// </summary> - /// <value><c>true</c> if pooled; otherwise, <c>false</c>.</value> - public abstract bool Pooled + /** + * Wraps the specified byte array into MINA heap buffer. + */ + public static ByteBuffer wrap( byte[] byteArray ) { - get; - set; + return wrap( FixedByteBuffer.wrap( byteArray ) ); } - - public abstract int Position + + /** + * 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 <tt>offset</tt> and <tt>length</tt>. + */ + public static ByteBuffer wrap( byte[] byteArray, int offset, int length ) { - get; - set; + return wrap( FixedByteBuffer.wrap( byteArray, offset, length ) ); } - public abstract int Limit + protected ByteBuffer() { - get; - set; } - //public abstract void Mark(); + /** + * 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(); - //public abstract void Reset(); + /** + * Releases the specified buffer to buffer pool. + * + * @throws IllegalStateException if you attempt to release already + * released buffer. + */ + public abstract void release(); - public abstract void Clear(); + /** + * Returns the underlying NIO buffer instance. + */ + public abstract FixedByteBuffer buf(); - /// <summary> - /// 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. - /// </summary> - public void Sweep() - { - Clear(); - FillAndReset(Remaining); - } + /** + * @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 ); - public void Sweep(byte value) + /** + * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on. + */ + public abstract bool isAutoExpand(); + + /** + * Turns on or off <tt>autoExpand</tt>. + */ + public abstract ByteBuffer setAutoExpand( bool autoExpand ); + + /** + * Changes the capacity and limit of this buffer so this buffer get + * the specified <tt>expectedRemaining</tt> room from the current position. + * This method works even if you didn't set <tt>autoExpand</tt> to + * <tt>true</tt>. + */ + public ByteBuffer expand( int expectedRemaining ) { - Clear(); - FillAndReset(value, Remaining); + return expand( position(), expectedRemaining ); } + + /** + * Changes the capacity and limit of this buffer so this buffer get + * the specified <tt>expectedRemaining</tt> room from the specified + * <tt>pos</tt>. + * This method works even if you didn't set <tt>autoExpand</tt> to + * <tt>true</tt>. + */ + public abstract ByteBuffer expand( int pos, int expectedRemaining ); + + /** + * Returns <tt>true</tt> if and only if this buffer is returned back + * to the buffer pool when released. + * <p> + * The default value of this property is <tt>true</tt> if and only if you + * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)}, + * or <tt>false</tt> 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. + * <p> + * The default value of this property is <tt>true</tt> if and only if you + * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)}, + * or <tt>false</tt> 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 <tt>-1</tt> 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 <tt>NUL</tt>. + * 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() ); +// } - public abstract void Flip(); + /** + * Clears this buffer and fills its content with <tt>value</tt>. + * 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() ); +// } - public abstract void Rewind(); + /** + * @see java.nio.Buffer#flip() + */ + public abstract ByteBuffer flip(); - public abstract int Remaining + /** + * @see java.nio.Buffer#rewind() + */ + public abstract ByteBuffer rewind(); + + /** + * @see java.nio.Buffer#remaining() + */ + public int remaining() { - get; + return limit() - position(); } - - public bool HasRemaining() + + /** + * @see java.nio.Buffer#hasRemaining() + */ + public bool hasRemaining() { - return Remaining > 0; + return remaining() > 0; } - public abstract byte Get(); + /** + * @see FixedByteBuffer#duplicate() + */ + public abstract ByteBuffer duplicate(); - public abstract byte Get(int index); - - public abstract void Get(byte[] destination); + /** + * @see FixedByteBuffer#slice() + */ + public abstract ByteBuffer slice(); - public abstract ushort GetUnsignedShort(); + /** + * @see FixedByteBuffer#asReadOnlyBuffer() + */ + public abstract ByteBuffer asReadOnlyBuffer(); - public abstract uint GetUnsignedInt(); + /** + * @see FixedByteBuffer#array() + */ + public abstract byte[] array(); - public abstract ulong GetUnsignedLong(); + /** + * @see FixedByteBuffer#arrayOffset() + */ + public abstract int arrayOffset(); - public abstract string GetString(uint length, Encoding encoder); + /** + * @see FixedByteBuffer#get() + */ + public abstract byte get(); - public abstract void Put(byte data); + /** + * Reads one unsigned byte as a short integer. + */ + public short getUnsigned() + { + return (short)( get() & 0xff ); + } - public abstract void Put(byte[] data); - public abstract void Put(byte[] data, int offset, int size); + /** + * @see FixedByteBuffer#put(byte) + */ + public abstract ByteBuffer put( byte b ); - public abstract void Put(ushort data); + /** + * @see FixedByteBuffer#get(int) + */ + public abstract byte get( int index ); - public abstract void Put(uint data); + /** + * Reads one byte as an unsigned short integer. + */ + public short getUnsigned( int index ) + { + return (short)( get( index ) & 0xff ); + } - public abstract void Put(ulong data); + /** + * @see FixedByteBuffer#put(int, byte) + */ + public abstract ByteBuffer put( int index, byte b ); - public abstract void Put(ByteBuffer buf); - - public abstract void Compact(); + /** + * @see FixedByteBuffer#get(byte[], int, int) + */ + public abstract ByteBuffer get( byte[] dst, int offset, int length ); - public abstract byte[] ToByteArray(); - - public override string ToString() + /** + * @see FixedByteBuffer#get(byte[]) + */ + public abstract ByteBuffer get(byte[] dst); +// { +// return get( dst, 0, dst.Length ); +// } + + /** + * Writes the content of the specified <tt>src</tt> into this buffer. + */ + public abstract ByteBuffer put( FixedByteBuffer src ); + + /** + * Writes the content of the specified <tt>src</tt> 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(); - buf.Append("HeapBuffer"); - buf.AppendFormat("[pos={0} lim={1} cap={2} : {3}]", Position, Limit, Capacity, HexDump); + 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 override int GetHashCode() + public int hashCode() { int h = 1; - int p = Position; - for (int i = Limit - 1; i >= p; i--) + int p = position(); + for( int i = limit() - 1; i >= p; i -- ) { - h = 31 * h + Get(i); + h = 31 * h + get( i ); } - return h; } - public override bool Equals(object obj) + public bool equals( Object o ) { - if (!(obj is ByteBuffer)) + if( !( o is ByteBuffer ) ) { return false; } - ByteBuffer that = (ByteBuffer) obj; - - if (Remaining != that.Remaining) + + ByteBuffer that = (ByteBuffer)o; + if( this.remaining() != that.remaining() ) { return false; } - int p = Position; - for (int i = Limit - 1, j = that.Limit - 1; i >= p; i--, j--) + + 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) + 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); - } - } - /// <summary> - /// Fills the buffer with the specified specified value. This method moves the buffer position forward. - /// </summary> - /// <param name="value">The value.</param> - /// <param name="size">The size.</param> - public void Fill(byte value, int size) + public int CompareTo( Object o ) { - AutoExpand(size); - int q = size >> 3; - int r = size & 7; - - if (q > 0) + 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 ++ ) { - int intValue = value | (value << 8) | (value << 16) | (value << 24); - long longValue = intValue; - longValue <<= 32; - longValue |= (ushort)intValue; - - for (int i = q; i > 0; i--) + byte v1 = this.get( i ); + byte v2 = that.get( j ); + if( v1 == v2 ) { - Put((ulong)longValue); + continue; + } + if( v1 < v2 ) + { + return -1; } - } - q = r >> 2; - r = r & 3; - - if (q > 0) - { - int intValue = value | (value << 8) | (value << 16) | (value << 24); - Put((uint)intValue); + return +1; } + return this.remaining() - that.remaining(); + } - q = r >> 1; - r = r & 1; - - if (q > 0) - { - short shortValue = (short) (value | (value << 8)); - Put((ushort) shortValue); - } - if (r > 0) - { - Put(value); - } + /** + * @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; } - - public void FillAndReset(byte value, int size) + + /** + * @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 ) { - AutoExpand(size); - int pos = Position; - try - { - Fill(value, size); - } - finally - { - Position = pos; - } + return getShort( index ) & 0xffff; } - - public void Fill(int size) + + /** + * @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() { - AutoExpand(size); - int q = size >> 3; - int r = size & 7; +// return getInt() & 0xffffffffL; - for (int i = q; i > 0; i--) - { - Put(0L); - } + //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 ); - q = r >> 2; - r = r & 3; + /** + * @see FixedByteBuffer#asDoubleBuffer() + */ +// public abstract DoubleBuffer asDoubleBuffer(); - if (q > 0) + /** + * Returns an {@link InputStream} that reads the data from this buffer. + * {@link InputStream#read()} returns <tt>-1</tt> 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 <tt>autoExpand</tt> 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 <code>NUL</code>-terminated string from this buffer using the + * specified <code>decoder</code> and returns it. This method reads + * until the limit of this buffer if no <tt>NUL</tt> 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 <code>NUL</code>-terminated string from this buffer using the + * specified <code>decoder</code> 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 <code>in</code> into this buffer using the + * specified <code>encoder</code>. This method doesn't terminate + * string with <tt>NUL</tt>. 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 <code>in</code> into this buffer as a + * <code>NUL</code>-terminated string using the specified + * <code>encoder</code>. + * <p> + * If the charset name of the encoder is UTF-16, you cannot specify + * odd <code>fieldSize</code>, and this method will Append two + * <code>NUL</code>s as a terminator. + * <p> + * Please note that this method doesn't terminate with <code>NUL</code> + * if the input string is longer than <tt>fieldSize</tt>. + * + * @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 <code>decoder</code> and returns it. + * This method is a shortcut for <tt>getPrefixedString(2, decoder)</tt>. + */ +// 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 <code>decoder</code> 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 <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * This method is a shortcut for <tt>putPrefixedString(in, 2, 0, encoder)</tt>. + * + * @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 <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>. + * + * @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 <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>. + * + * @param prefixLength the length of the length field (1, 2, or 4) + * @param padding the number of padded <tt>NUL</tt>s (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 <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * + * @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 <tt>classLoader</tt>. + */ +// 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 <tt>true</tt> 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 + * <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>. + * 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 <tt>true</tt> 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 <tt>maxDataLength</tt> + */ + public bool prefixedDataAvailable( int prefixLength, int maxDataLength ) + { + if( remaining() < prefixLength ) { - Put(0); + return false; } - q = r >> 1; - r = r & 1; - - if(q > 0) + int dataLength; + switch( prefixLength ) { - Put((ushort) 0); + 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 (r > 0) + if( dataLength < 0 || dataLength > maxDataLength ) { - Put((byte) 0); + throw new BufferDataException( "dataLength: " + dataLength ); } + + return remaining() - prefixLength >= dataLength; } - - public void FillAndReset(int size) + + ////////////////////////// + // Skip or fill methods // + ////////////////////////// + + /** + * Forwards the position of this buffer as the specified <code>size</code> + * bytes. + */ + public ByteBuffer skip( int size ) { - AutoExpand(size); - int pos = Position; - try - { - Fill(size); - } - finally - { - Position = pos; - } + autoExpand( size ); + return position( position() + size ); } - - public void Skip(int 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 <code>NUL (0x00)</code>. + * 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 <code>NUL (0x00)</code>. + * 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 + * <tt>autoExpand</tt> property is <tt>true</tt>. + */ + protected ByteBuffer autoExpand( int expectedRemaining ) { - AutoExpand(size); - Position = Position + size; + if( isAutoExpand() ) + { + expand( expectedRemaining ); + } + return this; } - - protected void AutoExpand(int expectedRemaining) + + /** + * This method forwards the call to {@link #expand(int)} only when + * <tt>autoExpand</tt> property is <tt>true</tt>. + */ + protected ByteBuffer autoExpand( int pos, int expectedRemaining ) { - if (IsAutoExpand) + if( isAutoExpand() ) { - Expand(expectedRemaining); + expand( pos, expectedRemaining ); } + return this; } - - protected void AutoExpand(int pos, int expectedRemaining) + + private static void checkFieldSize( int fieldSize ) { - if (IsAutoExpand) + if( fieldSize < 0 ) { - Expand(pos, expectedRemaining); + throw new ArgumentOutOfRangeException("fieldSize"); } - } + } + + 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(); } } - |