about summary refs log tree commit diff
path: root/IRCTokens/StatefulDecoder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'IRCTokens/StatefulDecoder.cs')
-rw-r--r--IRCTokens/StatefulDecoder.cs79
1 files changed, 79 insertions, 0 deletions
diff --git a/IRCTokens/StatefulDecoder.cs b/IRCTokens/StatefulDecoder.cs
new file mode 100644
index 0000000..82630f6
--- /dev/null
+++ b/IRCTokens/StatefulDecoder.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace IRCTokens
+{
+    public class StatefulDecoder
+    {
+        private byte[] _buffer;
+        private Encoding _encoding;
+        private Encoding _fallback;
+
+        public StatefulDecoder()
+        {
+            Clear();
+        }
+
+        public Encoding Encoding
+        {
+            get => _encoding ?? Encoding.GetEncoding(Encoding.UTF8.CodePage, EncoderFallback.ExceptionFallback,
+                DecoderFallback.ExceptionFallback);
+            set
+            {
+                if (value != null)
+                    _encoding = Encoding.GetEncoding(value.CodePage, EncoderFallback.ExceptionFallback,
+                        DecoderFallback.ReplacementFallback);
+            }
+        }
+
+        public Encoding Fallback
+        {
+            get => _fallback ?? Encoding.GetEncoding(Encoding.GetEncoding("iso-8859-1").CodePage,
+                EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
+            set
+            {
+                if (value != null)
+                    _fallback = Encoding.GetEncoding(value.CodePage, EncoderFallback.ReplacementFallback,
+                        DecoderFallback.ReplacementFallback);
+            }
+        }
+
+        public string Pending => Encoding.GetString(_buffer);
+
+        public void Clear()
+        {
+            _buffer = Array.Empty<byte>();
+        }
+
+        public List<Line> Push(string data)
+        {
+            var bytes = Encoding.GetBytes(data);
+            return Push(bytes, bytes.Length);
+        }
+
+        public List<Line> Push(byte[] data, int bytesReceived)
+        {
+            if (data == null) return null;
+
+            _buffer = _buffer == null ? Array.Empty<byte>() : _buffer.Concat(data.Take(bytesReceived)).ToArray();
+
+            var listLines = _buffer.Split((byte) '\n').Select(l => l.Trim((byte) '\r')).ToList();
+            _buffer = listLines.LastOrDefault() ?? Array.Empty<byte>();
+
+            var decodeLines = new List<Line>();
+            foreach (var line in listLines.SkipLast(1).Select(l => l.ToArray()))
+                try
+                {
+                    decodeLines.Add(new Line(Encoding.GetString(line)));
+                }
+                catch (DecoderFallbackException)
+                {
+                    decodeLines.Add(new Line(Fallback.GetString(line)));
+                }
+
+            return decodeLines;
+        }
+    }
+}