private static void Encode(BinaryCodec encoding, Stream inputStream, TextWriter outputWriter) { byte[] inputBuffer = new byte[encoding.MinimumInputBuffer]; char[] outputBuffer = new char[encoding.MinimumOutputBuffer]; bool readEof = false; int inputBufferEnd = 0; int inputBufferUsed; int outputBufferUsed; BinaryEncoder encoder = encoding.GetEncoder(); while (true) { if ((inputBufferEnd < inputBuffer.Length) && (!readEof)) { int bytesRead = inputStream.Read(inputBuffer, inputBufferEnd, inputBuffer.Length - inputBufferEnd); if (bytesRead == 0) { readEof = true; } inputBufferEnd += bytesRead; } // stop when we've read EOF and Convert returns true.. bool finished = ((encoder.Convert(inputBuffer, 0, inputBufferEnd, outputBuffer, 0, outputBuffer.Length, readEof, out inputBufferUsed, out outputBufferUsed)) && (readEof)); // dump any output produced to outputWriter.. outputWriter.Write(outputBuffer, 0, outputBufferUsed); if (finished) { break; } // shift input as needed.. if (inputBufferUsed != 0) { if (inputBufferUsed < inputBufferEnd) { Buffer.BlockCopy(inputBuffer, inputBufferUsed, inputBuffer, 0, inputBufferEnd - inputBufferUsed); inputBufferEnd -= inputBufferUsed; } else { inputBufferEnd = 0; } } } }
public override void Write(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if ((offset < 0) || (count < 0)) { throw new ArgumentOutOfRangeException((offset < 0) ? nameof(offset) : nameof(count)); } if (buffer.Length - offset < count) { throw new ArgumentException(Resources.InvalidOffsetCountLength); } // can't make progress without input... if (count == 0) { return; } // keep track of the number of bytes we've "written" _inputTotal += count; int inputUsed; int outputUsed; while (true) { if (_inputBufferEnd == 0) { // there is no data in the inputBuffer, we can convert directly from the supplied // buffer.. while (true) { var result = _encoder.Convert(buffer, offset, count, _outputBuffer, 0, _outputBuffer.Length, false, out inputUsed, out outputUsed); // write any output that was produced.. if (outputUsed > 0) { _outputWriter.Write(_outputBuffer, 0, outputUsed); } // adjust counters.. offset += inputUsed; if ((count -= inputUsed) == 0) { return; } // if we need more input to continue, then we're done.. if (result == ConvertStatus.InputRequired) { break; } } // if we reach this code, there is unused data in buffer that we need to save // for the next call to Write(). For all of the current BaseXX converters, this // should never happen. System.Diagnostics.Debug.Assert(count < _inputBufferLength); if (_inputBuffer == null) { _inputBuffer = new byte[_inputBufferLength]; } System.Diagnostics.Debug.Assert(_inputBufferEnd == 0); Buffer.BlockCopy(buffer, offset, _inputBuffer, _inputBufferEnd, count); _inputBufferEnd += count; // no more data will be handled.. return; } else { // we have existing data in the inputBuffer, add incoming data to the end // and try to convert. The goal is to get out of this loop and return to // converting directly from the buffer parameter. int inputBufferOffset = 0; int bytesToCopy = Math.Min(count, _inputBuffer.Length - _inputBufferEnd); System.Diagnostics.Debug.Assert(bytesToCopy > 0); // copy data from buffer to inputBuffer and adjust offset/count values.. Buffer.BlockCopy(buffer, offset, _inputBuffer, _inputBufferEnd, bytesToCopy); _inputBufferEnd += bytesToCopy; while (true) { var result = _encoder.Convert(_inputBuffer, inputBufferOffset, _inputBufferEnd - inputBufferOffset, _outputBuffer, 0, _outputBuffer.Length, false, out inputUsed, out outputUsed); if (outputUsed > 0) { _outputWriter.Write(_outputBuffer, 0, outputUsed); } inputBufferOffset += inputUsed; if (result == ConvertStatus.InputRequired) { // encoder needs more input, if we've processed enough of the inputBuffer to overlap // the incoming buffer then we want to switch to the other encoding loop.. no point in // copying data if we don't have to. if (inputBufferOffset >= _inputBufferEnd - bytesToCopy) { int bytesUsed = inputBufferOffset - (_inputBufferEnd - bytesToCopy); // reset inputBuffer and adjust offset, if count is zero after adjustment just // return (we've handled all of the input) _inputBufferEnd = 0; offset += bytesUsed; if ((count -= bytesUsed) == 0) { return; } break; } // we didn't process enough input to overlap the incoming buffer, we have to make // room in our inputBuffer for new data and keep trying.. Buffer.BlockCopy(_inputBuffer, inputBufferOffset, _inputBuffer, 0, _inputBufferEnd - inputBufferOffset); _inputBufferEnd -= inputBufferOffset; inputBufferOffset = 0; // copy new data into the buffer.. we have to update bytesToCopy as well to ensure that // we keep track of where the incoming buffer overlaps the inputBuffer. int newBytesToCopy = Math.Min(count - bytesToCopy, _inputBuffer.Length - _inputBufferEnd); if (newBytesToCopy == 0) { return; } Buffer.BlockCopy(buffer, offset + bytesToCopy, _inputBuffer, _inputBufferEnd, newBytesToCopy); _inputBufferEnd += newBytesToCopy; bytesToCopy += newBytesToCopy; } } } } }