89 lines
2.7 KiB
C#
89 lines
2.7 KiB
C#
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();
|
|
|
|
// truncate message at NUL if found
|
|
if (_buffer.Contains((byte) 0))
|
|
{
|
|
_buffer = _buffer
|
|
.Take(Array.IndexOf(_buffer, (byte) 0))
|
|
.Concat(new []{(byte) '\n'})
|
|
.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;
|
|
}
|
|
}
|
|
}
|