using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace Elwig.Helpers { static partial class Extensions { [LibraryImport("msvcrt.dll")] [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] private static unsafe partial int memcmp(void* b1, void* b2, long count); public static unsafe int CompareBuffers(char[] buffer1, int offset1, char[] buffer2, int offset2, int count) { fixed (char* b1 = buffer1, b2 = buffer2) { return memcmp(b1 + offset1, b2 + offset2, count); } } public static string? ReadUntil(this StreamReader reader, string delimiter) { return ReadUntil(reader, delimiter.ToCharArray()); } public static string? ReadUntil(this StreamReader reader, char delimiter) { return ReadUntil(reader, new char[] { delimiter }); } public static string? ReadUntil(this StreamReader reader, char[] delimiter) { var buf = new char[512]; int bufSize = 0, ret; while (!reader.EndOfStream && bufSize < buf.Length - 1) { if ((ret = reader.Read()) == -1) return null; buf[bufSize++] = (char)ret; if (bufSize >= delimiter.Length && CompareBuffers(buf, bufSize - delimiter.Length, delimiter, 0, delimiter.Length) == 0) return new string(buf, 0, bufSize); } return null; } public static Task ReadUntilAsync(this StreamReader reader, string delimiter) { return ReadUntilAsync(reader, delimiter.ToCharArray()); } public static Task ReadUntilAsync(this StreamReader reader, char delimiter) { return ReadUntilAsync(reader, new char[] { delimiter }); } public static async Task ReadUntilAsync(this StreamReader reader, char[] delimiter) { var buf = new char[512]; int bufSize = 0; var tmpBuf = new char[1]; while (!reader.EndOfStream && bufSize < buf.Length - 1) { if ((await reader.ReadAsync(tmpBuf, 0, 1)) != 1) return null; buf[bufSize++] = tmpBuf[0]; if (bufSize >= delimiter.Length && CompareBuffers(buf, bufSize - delimiter.Length, delimiter, 0, delimiter.Length) == 0) return new string(buf, 0, bufSize); } return null; } } }