예제 #1
0
        /// <summary>
        /// Reads <paramref name="count"/> bytes from the stream and appends them to the given <paramref name="buffer"/>.
        /// If <paramref name="count"/> is <c>Int32.MaxValue</c> the stream is read to the end.
        /// Unless <paramref name="preserveEndOfLines"/> is set the line endings in the appended data are normalized to "\n".
        /// </summary>
        public int AppendBytes(MutableString /*!*/ buffer, int count, bool preserveEndOfLines)
        {
            ContractUtils.RequiresNotNull(buffer, "buffer");
            ContractUtils.Requires(count >= 0, "count");

            if (count == 0)
            {
                return(0);
            }

            bool readAll = count == Int32.MaxValue;

            buffer.SwitchToBytes();
            int initialBufferSize = buffer.GetByteCount();

            if (preserveEndOfLines)
            {
                AppendRawBytes(buffer, count);
            }
            else
            {
                // allocate 3 more bytes at the end for a backstop and possible LF:
                byte[] bytes = Utils.EmptyBytes;

                int  done = initialBufferSize;
                bool eof;
                do
                {
                    AppendRawBytes(buffer, readAll ? 1024 : count);
                    int end       = buffer.GetByteCount();
                    int bytesRead = end - done;
                    if (bytesRead == 0)
                    {
                        break;
                    }

                    eof = bytesRead < count;

                    buffer.EnsureCapacity(end + 3);
                    int byteCount;
                    bytes = buffer.GetByteArray(out byteCount);

                    if (bytes[end - 1] == CR && PeekByte(0) == LF)
                    {
                        ReadByte();
                        bytes[end++] = LF;
                    }

                    // insert backstop:
                    bytes[end]     = CR;
                    bytes[end + 1] = LF;

                    int last = IndexOfCrLf(bytes, done);
                    count -= last - done;
                    done   = last;
                    while (last < end)
                    {
                        int next  = IndexOfCrLf(bytes, last + 2);
                        int chunk = next - last - 1;
                        Buffer.BlockCopy(bytes, last + 1, bytes, done, chunk);
                        done  += chunk;
                        count -= chunk;
                        last   = next;
                    }
                    buffer.Remove(done);
                } while (readAll || count > 0 && !eof);
            }

            if (readAll)
            {
                buffer.TrimExcess();
            }

            return(buffer.GetByteCount() - initialBufferSize);
        }