using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace CommonLang.NIO { public enum ByteOrder { LITTLE_ENDIAN, BIG_ENDIAN, } public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; // Used only by direct buffers // NOTE: hoisted here for speed in JNI GetDirectBufferAddress //IntPtr address; // Creates a new buffer with the given mark, position, limit, and capacity, // after checking invariants. // internal Buffer(int mark, int pos, int lim, int cap) { if (cap < 0) throw new Exception("Negative capacity: " + cap); this.capacity = cap; Limit(lim); Position(pos); if (mark >= 0) { if (mark > pos) throw new Exception("mark > position: (" + mark + " > " + pos + ")"); this.mark = mark; } } public int Capacity() { return capacity; } public int Position() { return position; } public Buffer Position(int newPosition) { if ((newPosition > limit) || (newPosition < 0)) throw new Exception("IllegalArgumentException"); position = newPosition; if (mark > position) mark = -1; return this; } public int Limit() { return limit; } public Buffer Limit(int newLimit) { if ((newLimit > capacity) || (newLimit < 0)) throw new Exception("IllegalArgumentException"); limit = newLimit; if (position > limit) position = limit; if (mark > limit) mark = -1; return this; } public Buffer Mark() { mark = position; return this; } public Buffer Reset() { int m = mark; if (m < 0) throw new Exception("InvalidMarkException"); position = m; return this; } public Buffer Clear() { position = 0; limit = capacity; mark = -1; return this; } public Buffer Flip() { limit = position; position = 0; mark = -1; return this; } public Buffer Rewind() { position = 0; mark = -1; return this; } public int Remaining() { return limit - position; } public bool HasRemaining() { return position < limit; } public abstract bool IsReadOnly(); public abstract bool HasArray(); public abstract Array Array(); public abstract int ArrayOffset(); internal int NextGetIndex() { if (position >= limit) throw new Exception("BufferUnderflowException"); return position++; } internal int NextGetIndex(int nb) { if (limit - position < nb) throw new Exception("BufferUnderflowException"); int p = position; position += nb; return p; } internal int NextPutIndex() { if (position >= limit) throw new Exception("BufferOverflowException"); return position++; } internal int NextPutIndex(int nb) { if (limit - position < nb) throw new Exception("BufferOverflowException"); int p = position; position += nb; return p; } internal int CheckIndex(int i) { if ((i < 0) || (i >= limit)) throw new IndexOutOfRangeException(); return i; } internal int CheckIndex(int i, int nb) { if ((i < 0) || (nb > limit - i)) throw new IndexOutOfRangeException(); return i; } internal int MarkValue() { return mark; } internal void Truncate() { mark = -1; position = 0; limit = 0; capacity = 0; } internal void DiscardMark() { mark = -1; } internal static void CheckBounds(int off, int len, int size) { if ((off | len | (off + len) | (size - (off + len))) < 0) throw new IndexOutOfRangeException(); } } public abstract class ByteBuffer : Buffer { readonly internal byte[] hb; readonly internal int offset; internal ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset) : base(mark, pos, lim, cap) { this.hb = hb; this.offset = offset; } internal ByteBuffer(int mark, int pos, int lim, int cap) : this(mark, pos, lim, cap, null, 0) { } public static ByteBuffer Allocate(int capacity) { if (capacity < 0) throw new Exception("IllegalArgumentException"); return new HeapByteBuffer(capacity, capacity); } public static ByteBuffer Wrap(byte[] array, int offset, int length) { try { return new HeapByteBuffer(array, offset, length); } catch (Exception err) { Console.WriteLine("Wrap 1: " + array + ", catch: " + err); throw new IndexOutOfRangeException(); } } public static ByteBuffer Wrap(byte[] array) { return Wrap(array, 0, array.Length); } public abstract ByteBuffer Slice(); public abstract ByteBuffer Duplicate(); public abstract byte Get(); public abstract ByteBuffer Put(byte b); public abstract byte Get(int index); public abstract ByteBuffer Put(int index, byte b); public virtual ByteBuffer Get(byte[] dst, int offset, int length) { CheckBounds(offset, length, dst.Length); if (length > Remaining()) throw new Exception("BufferUnderflowException"); int end = offset + length; for (int i = offset; i < end; i++) dst[i] = Get(); return this; } public virtual ByteBuffer Get(byte[] dst) { return Get(dst, 0, dst.Length); } public virtual ByteBuffer Put(ByteBuffer src) { if (src == this) throw new Exception("IllegalArgumentException"); int n = src.Remaining(); if (n > Remaining()) throw new Exception("BufferOverflowException"); for (int i = 0; i < n; i++) Put(src.Get()); return this; } public virtual ByteBuffer Put(byte[] src, int offset, int length) { CheckBounds(offset, length, src.Length); if (length > Remaining()) throw new Exception("BufferOverflowException"); int end = offset + length; for (int i = offset; i < end; i++) this.Put(src[i]); return this; } public virtual ByteBuffer Put(byte[] src) { return Put(src, 0, src.Length); } public override bool HasArray() { return (hb != null); } public override Array Array() { if (hb == null) throw new Exception("UnsupportedOperationException"); return hb; } public override int ArrayOffset() { if (hb == null) throw new Exception("UnsupportedOperationException"); return offset; } public abstract ByteBuffer Compact(); public override String ToString() { StringBuilder sb = new StringBuilder(); sb.Append(GetType().Name); sb.Append("[pos="); sb.Append(Position()); sb.Append(" lim="); sb.Append(Limit()); sb.Append(" cap="); sb.Append(Capacity()); sb.Append("]"); return sb.ToString(); } public override int GetHashCode() { int h = 1; int p = Position(); for (int i = Limit() - 1; i >= p; i--) h = 31 * h + (int)Get(i); return h; } public override bool Equals(Object ob) { if (this == ob) return true; if (!(ob is ByteBuffer)) return false; ByteBuffer that = (ByteBuffer)ob; 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--) if ((this.Get(i) != that.Get(j))) return false; return true; } } public class HeapByteBuffer : ByteBuffer { internal HeapByteBuffer(int cap, int lim) : base(-1, 0, lim, cap, new byte[cap], 0) { } internal HeapByteBuffer(byte[] buf, int off, int len) : base(-1, off, off + len, buf.Length, buf, 0) { } protected HeapByteBuffer(byte[] buf, int mark, int pos, int lim, int cap, int off) : base(mark, pos, lim, cap, buf, off) { } public override ByteBuffer Slice() { return new HeapByteBuffer(hb, -1, 0, this.Remaining(), this.Remaining(), this.Position() + offset); } public override ByteBuffer Duplicate() { return new HeapByteBuffer(hb, this.MarkValue(), this.Position(), this.Limit(), this.Capacity(), offset); } protected int ix(int i) { return i + offset; } public override byte Get() { return hb[ix(NextGetIndex())]; } public override byte Get(int i) { return hb[ix(CheckIndex(i))]; } public override ByteBuffer Get(byte[] dst, int offset, int length) { CheckBounds(offset, length, dst.Length); if (length > Remaining()) throw new Exception("BufferUnderflowException"); System.Buffer.BlockCopy(hb, ix(Position()), dst, offset, length); Position(Position() + length); return this; } public override bool IsReadOnly() { return false; } public override ByteBuffer Put(byte x) { hb[ix(NextPutIndex())] = x; return this; } public override ByteBuffer Put(int i, byte x) { hb[ix(CheckIndex(i))] = x; return this; } public override ByteBuffer Put(byte[] src, int offset, int length) { CheckBounds(offset, length, src.Length); if (length > Remaining()) throw new Exception("BufferOverflowException"); System.Buffer.BlockCopy(src, offset, hb, ix(Position()), length); Position(Position() + length); return this; } public override ByteBuffer Put(ByteBuffer src) { if (src is HeapByteBuffer) { if (src == this) throw new Exception("IllegalArgumentException"); HeapByteBuffer sb = (HeapByteBuffer)src; int n = sb.Remaining(); if (n > Remaining()) throw new Exception("BufferOverflowException"); System.Buffer.BlockCopy(sb.hb, sb.ix(sb.Position()), hb, ix(Position()), n); sb.Position(sb.Position() + n); Position(Position() + n); } else { base.Put(src); } return this; } public override ByteBuffer Compact() { System.Buffer.BlockCopy(hb, ix(Position()), hb, ix(0), Remaining()); Position(Remaining()); Limit(Capacity()); DiscardMark(); return this; } } }