/// <exception cref="System.IO.IOException"/> public static Capnproto.MessageReader Read(java.nio.channels.ReadableByteChannel bc, Capnproto.ReaderOptions options) { java.nio.ByteBuffer firstWord = makeByteBuffer(Capnproto.Constants.BYTES_PER_WORD); fillBuffer(firstWord, bc); int segmentCount = 1 + firstWord.getInt(0); int segment0Size = 0; if (segmentCount > 0) { segment0Size = firstWord.getInt(4); } int totalWords = segment0Size; if (segmentCount > 512) { throw new System.IO.IOException("too many segments"); } //In words. System.Collections.Generic.List <int> moreSizes = new System.Collections.Generic.List <int>(); if (segmentCount > 1) { java.nio.ByteBuffer moreSizesRaw = makeByteBuffer(4 * (segmentCount & ~1)); fillBuffer(moreSizesRaw, bc); for (int ii = 0; ii < segmentCount - 1; ++ii) { int size = moreSizesRaw.getInt(ii * 4); moreSizes.Add(size); totalWords += size; } } if (totalWords > options.traversalLimitInWords) { throw new Capnproto.DecodeException("Message size exceeds traversal limit."); } java.nio.ByteBuffer allSegments = makeByteBuffer(totalWords * Capnproto.Constants.BYTES_PER_WORD); fillBuffer(allSegments, bc); java.nio.ByteBuffer[] segmentSlices = new java.nio.ByteBuffer[segmentCount]; allSegments.rewind(); segmentSlices[0] = allSegments.slice(); segmentSlices[0].limit(segment0Size * Capnproto.Constants.BYTES_PER_WORD); segmentSlices[0].order(java.nio.ByteOrder.LITTLE_ENDIAN); int offset = segment0Size; for (int ii = 1; ii < segmentCount; ++ii) { allSegments.position(offset * Capnproto.Constants.BYTES_PER_WORD); segmentSlices[ii] = allSegments.slice(); segmentSlices[ii].limit(moreSizes[ii - 1] * Capnproto.Constants.BYTES_PER_WORD); segmentSlices[ii].order(java.nio.ByteOrder.LITTLE_ENDIAN); offset += moreSizes[ii - 1]; } return(new Capnproto.MessageReader(segmentSlices, options)); }
/// <exception cref="System.IO.IOException"/> public int Write(java.nio.ByteBuffer inBuf) { int length = inBuf.remaining(); java.nio.ByteBuffer @out = this.inner.GetWriteBuffer(); java.nio.ByteBuffer slowBuffer = java.nio.ByteBuffer.allocate(20); int inPtr = inBuf.position(); int inEnd = inPtr + length; while (inPtr < inEnd) { if (@out.remaining() < 10) { //# Oops, we're out of space. We need at least 10 //# bytes for the fast path, since we don't //# bounds-check on every byte. if (@out == slowBuffer) { int oldLimit = @out.limit(); @out.limit(@out.position()); @out.rewind(); this.inner.Write(@out); @out.limit(oldLimit); } @out = slowBuffer; @out.rewind(); } int tagPos = @out.position(); @out.position(tagPos + 1); byte curByte; curByte = inBuf.get(inPtr); byte bit0 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit0 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit1 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit1 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit2 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit2 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit3 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit3 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit4 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit4 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit5 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit5 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit6 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit6 - 1); inPtr += 1; curByte = inBuf.get(inPtr); byte bit7 = (curByte != 0)? unchecked ((byte)1) : unchecked ((byte)0); @out.put(curByte); @out.position(@out.position() + bit7 - 1); inPtr += 1; byte tag = unchecked ((byte)((bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3) | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7))); @out.put(tagPos, tag); if (tag == 0) { //# An all-zero word is followed by a count of //# consecutive zero words (not including the first //# one). int runStart = inPtr; int limit = inEnd; if (limit - inPtr > 255 * 8) { limit = inPtr + 255 * 8; } while (inPtr < limit && inBuf.getLong(inPtr) == 0) { inPtr += 8; } @out.put(unchecked ((byte)((inPtr - runStart) / 8))); } else if (tag == unchecked ((byte)unchecked ((int)(0xff)))) { //# An all-nonzero word is followed by a count of //# consecutive uncompressed words, followed by the //# uncompressed words themselves. //# Count the number of consecutive words in the input //# which have no more than a single zero-byte. We look //# for at least two zeros because that's the point //# where our compression scheme becomes a net win. int runStart = inPtr; int limit = inEnd; if (limit - inPtr > 255 * 8) { limit = inPtr + 255 * 8; } while (inPtr < limit) { byte c = 0; for (int ii = 0; ii < 8; ++ii) { c += (inBuf.get(inPtr) == 0 ? (byte)1 : (byte)0); inPtr += 1; } if (c >= 2) { //# Un-read the word with multiple zeros, since //# we'll want to compress that one. inPtr -= 8; break; } } int count = inPtr - runStart; @out.put(unchecked ((byte)(count / 8))); if (count <= @out.remaining()) { //# There's enough space to memcpy. inBuf.position(runStart); java.nio.ByteBuffer slice = inBuf.slice(); slice.limit(count); @out.put(slice); } else { //# Input overruns the output buffer. We'll give it //# to the output stream in one chunk and let it //# decide what to do. if (@out == slowBuffer) { int oldLimit = @out.limit(); @out.limit(@out.position()); @out.rewind(); this.inner.Write(@out); @out.limit(oldLimit); } inBuf.position(runStart); java.nio.ByteBuffer slice = inBuf.slice(); slice.limit(count); while (slice.hasRemaining()) { this.inner.Write(slice); } @out = this.inner.GetWriteBuffer(); } } } if (@out == slowBuffer) { @out.limit(@out.position()); @out.rewind(); this.inner.Write(@out); } inBuf.position(inPtr); return(length); }