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:
parent
b53c672768
commit
f297cb2623
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user