diff --git a/SabreTools.IO/StreamExtensions.cs b/SabreTools.IO/StreamExtensions.cs index a32617c..a08e622 100644 --- a/SabreTools.IO/StreamExtensions.cs +++ b/SabreTools.IO/StreamExtensions.cs @@ -230,6 +230,44 @@ namespace SabreTools.IO return encoding.GetString([.. tempBuffer]); } + /// + /// Read a string that is terminated by a newline but contains a quoted portion that + /// may also contain a newline from the stream + /// + public static string? ReadQuotedString(this Stream stream) => stream.ReadQuotedString(Encoding.Default); + + /// + /// Read a string that is terminated by a newline but contains a quoted portion that + /// may also contain a newline from the stream + /// + public static string? ReadQuotedString(this Stream stream, Encoding encoding) + { + if (stream.Position >= stream.Length) + return null; + + var bytes = new List(); + bool openQuote = false; + while (stream.Position < stream.Length) + { + // Read the byte value + byte b = stream.ReadByteValue(); + + // If we have a quote, flip the flag + if (b == (byte)'"') + openQuote = !openQuote; + + // If we have a newline not in a quoted string, exit the loop + else if (b == (byte)'\n' && !openQuote) + break; + + // Add the byte to the set + bytes.Add(b); + } + + var line = encoding.GetString([.. bytes]); + return line.TrimEnd(); + } + /// /// Seek to a specific point in the stream, if possible ///