/// <summary> /// Reads data from this stream /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <returns></returns> public override int Read(byte[] buffer, int offset, int count) { lock (this) { // 1. attempt to fill the circular buffer with enough data to meet our request while (BufferEndPosition < position + count) { int sourceReadCount = count; if (sourceReadCount % sourceStream.BlockAlign != 0) { sourceReadCount = (count + sourceStream.BlockAlign) - (count % sourceStream.BlockAlign); } int sourceRead = sourceStream.Read(GetSourceBuffer(sourceReadCount), 0, sourceReadCount); circularBuffer.Write(GetSourceBuffer(sourceReadCount), 0, sourceRead); if (sourceRead == 0) { // assume we have run out of data break; } } // 2. discard any unnecessary stuff from the start if (bufferStartPosition < position) { circularBuffer.Advance((int)(position - bufferStartPosition)); bufferStartPosition = position; } // 3. now whatever is in the buffer we can return int bytesRead = circularBuffer.Read(buffer, offset, count); position += bytesRead; // anything left in buffer is at start position bufferStartPosition = position; return(bytesRead); } }
/// <summary> /// Reads bytes from this stream /// </summary> /// <param name="array">Buffer to read into</param> /// <param name="offset">Offset in array to read into</param> /// <param name="count">Number of bytes to read</param> /// <returns>Number of bytes read</returns> public override int Read(byte[] array, int offset, int count) { int bytesRead = 0; if (count % BlockAlign != 0) { //throw new ApplicationException("Must read complete blocks"); count -= (count % BlockAlign); } while (bytesRead < count) { int destBytesRequired = count - bytesRead; int sourceBytes = DestToSource(destBytesRequired); sourceBytes = Math.Min(conversionStream.SourceBuffer.Length, sourceBytes); // temporary fix for alignment problems // TODO: a better solution is to save any extra we convert for the next read /* MRH: ignore this for now - need to check ramifications * if (DestToSource(SourceToDest(sourceBytes)) != sourceBytes) * { * if (bytesRead == 0) * throw new ApplicationException("Not a one-to-one conversion"); * break; * }*/ int sourceBytesRead = sourceStream.Read(conversionStream.SourceBuffer, 0, sourceBytes); if (sourceBytesRead == 0) { break; } int silenceBytes = 0; if (sourceBytesRead % sourceStream.BlockAlign != 0) { // we have been returned something that cannot be converted - a partial // buffer. We will increase the size we supposedly read, and zero out // the end. sourceBytesRead -= (sourceBytesRead % sourceStream.BlockAlign); sourceBytesRead += sourceStream.BlockAlign; silenceBytes = SourceToDest(sourceStream.BlockAlign); } int sourceBytesConverted; int bytesConverted = conversionStream.Convert(sourceBytesRead, out sourceBytesConverted); if (sourceBytesConverted < sourceBytesRead) { // MRH: would normally throw an exception here // back up - is this the right thing to do, not sure sourceStream.Position -= (sourceBytesRead - sourceBytesConverted); } if (bytesConverted > 0) { position += bytesConverted; int availableSpace = array.Length - bytesRead - offset; int toCopy = Math.Min(bytesConverted, availableSpace); //System.Diagnostics.Debug.Assert(toCopy == bytesConverted); // TODO: save leftovers Array.Copy(conversionStream.DestBuffer, 0, array, bytesRead + offset, toCopy); bytesRead += toCopy; if (silenceBytes > 0) { // clear out the final bit Array.Clear(array, bytesRead - silenceBytes, silenceBytes); } } else { break; } } return(bytesRead); }