1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-04-24 06:15:48 +02:00

Add line escaping to FileSerializer for easier manual file editing

This commit is contained in:
chylex 2018-01-18 20:37:29 +01:00
parent b53c672768
commit f297cb2623
2 changed files with 52 additions and 7 deletions
Data/Serialization
tests/Data

View File

@ -4,6 +4,7 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using TweetDuck.Core.Utils;
namespace TweetDuck.Data.Serialization{
@ -11,6 +12,44 @@ sealed class FileSerializer<T>{
private const string NewLineReal = "\r\n";
private const string NewLineCustom = "\r~\n";
private static string EscapeLine(string input) => input.Replace("\\", "\\\\").Replace(Environment.NewLine, "\\\r\n");
private static string UnescapeLine(string input) => input.Replace(NewLineCustom, Environment.NewLine);
private static string UnescapeStream(StreamReader reader){
string data = reader.ReadToEnd();
StringBuilder build = new StringBuilder(data.Length);
int index = 0;
while(true){
int nextIndex = data.IndexOf('\\', index);
if (nextIndex == -1 || nextIndex+1 >= data.Length){
break;
}
else{
build.Append(data.Substring(index, nextIndex-index));
char next = data[nextIndex+1];
if (next == '\\'){ // convert double backslash to single backslash
build.Append('\\');
index = nextIndex+2;
}
else if (next == '\r' && nextIndex+2 < data.Length && data[nextIndex+2] == '\n'){ // convert backslash followed by CRLF to custom new line
build.Append(NewLineCustom);
index = nextIndex+3;
}
else{ // single backslash
build.Append('\\');
index = nextIndex+1;
}
}
}
return build.Append(data.Substring(index)).ToString();
}
private static readonly ITypeConverter BasicSerializerObj = new BasicTypeConverter();
public delegate void HandleUnknownPropertiesHandler(T obj, Dictionary<string, string> data);
@ -36,13 +75,13 @@ public void Write(string file, T obj){
Type type = prop.Value.PropertyType;
object value = prop.Value.GetValue(obj);
if (!converters.TryGetValue(type, out ITypeConverter serializer)) {
if (!converters.TryGetValue(type, out ITypeConverter serializer)){
serializer = BasicSerializerObj;
}
if (serializer.TryWriteType(type, value, out string converted)){
if (converted != null){
writer.Write($"{prop.Key} {converted.Replace(Environment.NewLine, NewLineCustom)}");
writer.Write($"{prop.Key} {EscapeLine(converted)}");
writer.Write(NewLineReal);
}
}
@ -65,7 +104,7 @@ public void Read(string file, T obj){
throw new FormatException("Input appears to be a binary file.");
}
foreach(string line in reader.ReadToEnd().Split(new string[]{ NewLineReal }, StringSplitOptions.RemoveEmptyEntries)){
foreach(string line in UnescapeStream(reader).Split(new string[]{ NewLineReal }, StringSplitOptions.RemoveEmptyEntries)){
int space = line.IndexOf(' ');
if (space == -1){
@ -73,7 +112,7 @@ public void Read(string file, T obj){
}
string property = line.Substring(0, space);
string value = line.Substring(space+1).Replace(NewLineCustom, Environment.NewLine);
string value = UnescapeLine(line.Substring(space+1));
if (props.TryGetValue(property, out PropertyInfo info)){
if (!converters.TryGetValue(info.PropertyType, out ITypeConverter serializer)) {

View File

@ -13,7 +13,9 @@ private enum TestEnum{
private class SerializationTestBasic{
public bool TestBool { get; set; }
public int TestInt { get; set; }
public string TestString { get; set; }
public string TestStringBasic { get; set; }
public string TestStringNewLine { get; set; }
public string TestStringBackslash { get; set; }
public string TestStringNull { get; set; }
public TestEnum TestEnum { get; set; }
}
@ -25,7 +27,9 @@ public void TestBasicWriteRead(){
SerializationTestBasic write = new SerializationTestBasic{
TestBool = true,
TestInt = -100,
TestString = "abc"+Environment.NewLine+"def",
TestStringBasic = "hello123",
TestStringNewLine = "abc"+Environment.NewLine+"def"+Environment.NewLine,
TestStringBackslash = @"C:\Test\\\Abc\",
TestStringNull = null,
TestEnum = TestEnum.D
};
@ -38,7 +42,9 @@ public void TestBasicWriteRead(){
Assert.IsTrue(read.TestBool);
Assert.AreEqual(-100, read.TestInt);
Assert.AreEqual("abc"+Environment.NewLine+"def", read.TestString);
Assert.AreEqual("hello123", read.TestStringBasic);
Assert.AreEqual("abc"+Environment.NewLine+"def"+Environment.NewLine, read.TestStringNewLine);
Assert.AreEqual(@"C:\Test\\\Abc\", read.TestStringBackslash);
Assert.IsNull(read.TestStringNull);
Assert.AreEqual(TestEnum.D, read.TestEnum);
}