IRC parsing, tokenization, and state handling in C#
1using System.Text;
2
3// ReSharper disable ReplaceWithFieldKeyword
4
5namespace IRCTokens;
6
7public class StatefulEncoder
8{
9 private List<Line> _bufferedLines;
10 private Encoding _encoding;
11
12 public StatefulEncoder()
13 {
14 Clear();
15 }
16
17 public Encoding Encoding
18 {
19 get => _encoding ?? Encoding.GetEncoding(
20 Encoding.UTF8.CodePage,
21 EncoderFallback.ExceptionFallback,
22 DecoderFallback.ExceptionFallback);
23 set
24 {
25 if (value != null)
26 {
27 _encoding = Encoding.GetEncoding(
28 value.CodePage,
29 EncoderFallback.ExceptionFallback,
30 DecoderFallback.ExceptionFallback);
31 }
32 }
33 }
34
35 public byte[] PendingBytes { get; private set; }
36
37 public string Pending()
38 {
39 try
40 {
41 return Encoding.GetString(PendingBytes);
42 }
43 catch (DecoderFallbackException e)
44 {
45 Console.WriteLine(e);
46 throw;
47 }
48 }
49
50 public void Clear()
51 {
52 PendingBytes = [];
53 _bufferedLines = [];
54 }
55
56 public void Push(Line line)
57 {
58 if (line == null)
59 {
60 throw new ArgumentNullException(nameof(line));
61 }
62
63 PendingBytes = PendingBytes.Concat(Encoding.GetBytes($"{line.Format()}\r\n")).ToArray();
64 _bufferedLines.Add(line);
65 }
66
67 public List<Line> Pop(int byteCount)
68 {
69 var sent = PendingBytes.Take(byteCount).Count(c => c == '\n');
70
71 PendingBytes = PendingBytes.Skip(byteCount).ToArray();
72
73 var sentLines = _bufferedLines.Take(sent).ToList();
74 _bufferedLines = _bufferedLines.Skip(sent).ToList();
75
76 return sentLines;
77 }
78}