public static async Task <string> ReadLineAsync(ISharedBufferStream stream, MemoryStream stringBuffer) { bool cr = false; int used = 0; ArraySegment <byte> segment = await stream.SharedBufferReadAsync(Int32.MaxValue); if (segment.Count == 0) { return(null); } while (!ReadLine(segment, stringBuffer, ref cr, out used)) { segment = await stream.SharedBufferReadAsync(Int32.MaxValue); if (segment.Count == 0) { return(null); } } if (used != segment.Count) { stream.SharedBufferRewind(segment.Count - used); } return(Encoding.UTF8.GetString(stringBuffer.GetBuffer(), 0, (int)stringBuffer.Length)); }
public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { while (true) { if (isEnd) { return(0); } // do we need to flush some boundary buffer ? if (boundaryFlushLength > 0) { int size = Math.Min(boundaryFlushLength, count); if (buffer != null) { Buffer.BlockCopy(boundaryBytes, boundaryFlushPos, buffer, offset, size); } boundaryFlushLength -= size; boundaryFlushPos += size; return(size); } // do we need to load a new buffer ? if (currentBufferCount == 0) { ArraySegment <byte> segment = await stream.SharedBufferReadAsync(count); if (segment.Count == 0) { throw new Exception("Invalid boundary stream"); } currentBuffer = segment.Array; currentBufferOffset = segment.Offset; currentBufferCount = segment.Count; } int used; // if a boundary match start on the previous buffer, finish the match if (boundaryPos > 0) { int lastBoundaryPos = boundaryPos; // ok, is was a boundary if (TestBoundary(currentBuffer, currentBufferOffset, currentBufferCount, out used)) { isEnd = true; // if we read too much, rewined if (currentBufferCount - used > 0) { stream.SharedBufferRewind(currentBufferCount - used); } return(0); } else { // it was a partial boundary if (boundaryPos > 0) { currentBuffer = null; currentBufferCount = 0; currentBufferOffset = 0; continue; } // it was not a boundary else { boundaryFlushLength = lastBoundaryPos + used; boundaryFlushPos = 0; boundaryPos = 0; currentBufferOffset += used; currentBufferCount -= used; // flush what we can int size = Math.Min(boundaryFlushLength, count); if (buffer != null) { Buffer.BlockCopy(boundaryBytes, boundaryFlushPos, buffer, offset, size); } boundaryFlushLength -= size; boundaryFlushPos += size; return(size); } } } // go to the first possible boundary match int i = 0; int minSize = Math.Min(count, currentBufferCount); while (i < minSize) { if (currentBuffer[currentBufferOffset + i] == 0x0d) { // match succeed if (TestBoundary(currentBuffer, currentBufferOffset + i, currentBufferCount - i, out used)) { isEnd = true; int overflow = currentBufferCount - (i + used); // if we read too much, rewined if (overflow > 0) { stream.SharedBufferRewind(overflow); } // copy what we found before the boundary if (buffer != null) { Buffer.BlockCopy(currentBuffer, currentBufferOffset, buffer, offset, i); } return(i); } else { // partial boundary match if (boundaryPos > 0) { // return the part before the match if (buffer != null) { Buffer.BlockCopy(currentBuffer, currentBufferOffset, buffer, offset, i); } currentBufferCount -= i + used; currentBufferOffset += used; return(i); } // match fails continue search else { i++; } } } else { i++; } } // ok minSize buffer is clean, return it if (i == minSize) { if (buffer != null) { Buffer.BlockCopy(currentBuffer, currentBufferOffset, buffer, offset, minSize); } currentBufferOffset += minSize; currentBufferCount -= minSize; return(minSize); } } }