// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.IO; using System.Text; namespace osu.Game.IO { /// <summary> /// A <see cref="StreamReader"/>-like decorator (with more limited API) for <see cref="Stream"/>s /// that allows lines to be peeked without consuming. /// </summary> public class LineBufferedReader : IDisposable { private readonly StreamReader streamReader; private string? peekedLine; public LineBufferedReader(Stream stream, bool leaveOpen = false) { streamReader = new StreamReader(stream, Encoding.UTF8, true, 1024, leaveOpen); } /// <summary> /// Reads the next line from the stream without consuming it. /// Subsequent calls to <see cref="PeekLine"/> without a <see cref="ReadLine"/> will return the same string. /// </summary> public string? PeekLine() => peekedLine ??= streamReader.ReadLine(); /// <summary> /// Reads the next line from the stream and consumes it. /// If a line was peeked, that same line will then be consumed and returned. /// </summary> public string? ReadLine() { string? line = peekedLine ?? streamReader.ReadLine(); peekedLine = null; return line; } /// <summary> /// Reads the stream to its end and returns the text read. /// This includes any peeked but unconsumed lines. /// </summary> public string ReadToEnd() { string remainingText = streamReader.ReadToEnd(); if (peekedLine == null) return remainingText; var builder = new StringBuilder(); // this might not be completely correct due to varying platform line endings builder.AppendLine(peekedLine); builder.Append(remainingText); return builder.ToString(); } public void Dispose() { streamReader.Dispose(); } } }