mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-04 08:34:07 +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.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
using TweetDuck.Core.Utils;
|
using TweetDuck.Core.Utils;
|
||||||
|
|
||||||
namespace TweetDuck.Data.Serialization{
|
namespace TweetDuck.Data.Serialization{
|
||||||
@ -11,6 +12,44 @@ sealed class FileSerializer<T>{
|
|||||||
private const string NewLineReal = "\r\n";
|
private const string NewLineReal = "\r\n";
|
||||||
private const string NewLineCustom = "\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();
|
private static readonly ITypeConverter BasicSerializerObj = new BasicTypeConverter();
|
||||||
|
|
||||||
public delegate void HandleUnknownPropertiesHandler(T obj, Dictionary<string, string> data);
|
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;
|
Type type = prop.Value.PropertyType;
|
||||||
object value = prop.Value.GetValue(obj);
|
object value = prop.Value.GetValue(obj);
|
||||||
|
|
||||||
if (!converters.TryGetValue(type, out ITypeConverter serializer)) {
|
if (!converters.TryGetValue(type, out ITypeConverter serializer)){
|
||||||
serializer = BasicSerializerObj;
|
serializer = BasicSerializerObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serializer.TryWriteType(type, value, out string converted)){
|
if (serializer.TryWriteType(type, value, out string converted)){
|
||||||
if (converted != null){
|
if (converted != null){
|
||||||
writer.Write($"{prop.Key} {converted.Replace(Environment.NewLine, NewLineCustom)}");
|
writer.Write($"{prop.Key} {EscapeLine(converted)}");
|
||||||
writer.Write(NewLineReal);
|
writer.Write(NewLineReal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,7 +104,7 @@ public void Read(string file, T obj){
|
|||||||
throw new FormatException("Input appears to be a binary file.");
|
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(' ');
|
int space = line.IndexOf(' ');
|
||||||
|
|
||||||
if (space == -1){
|
if (space == -1){
|
||||||
@ -73,7 +112,7 @@ public void Read(string file, T obj){
|
|||||||
}
|
}
|
||||||
|
|
||||||
string property = line.Substring(0, space);
|
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 (props.TryGetValue(property, out PropertyInfo info)){
|
||||||
if (!converters.TryGetValue(info.PropertyType, out ITypeConverter serializer)) {
|
if (!converters.TryGetValue(info.PropertyType, out ITypeConverter serializer)) {
|
||||||
|
@ -13,7 +13,9 @@ private enum TestEnum{
|
|||||||
private class SerializationTestBasic{
|
private class SerializationTestBasic{
|
||||||
public bool TestBool { get; set; }
|
public bool TestBool { get; set; }
|
||||||
public int TestInt { 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 string TestStringNull { get; set; }
|
||||||
public TestEnum TestEnum { get; set; }
|
public TestEnum TestEnum { get; set; }
|
||||||
}
|
}
|
||||||
@ -25,7 +27,9 @@ public void TestBasicWriteRead(){
|
|||||||
SerializationTestBasic write = new SerializationTestBasic{
|
SerializationTestBasic write = new SerializationTestBasic{
|
||||||
TestBool = true,
|
TestBool = true,
|
||||||
TestInt = -100,
|
TestInt = -100,
|
||||||
TestString = "abc"+Environment.NewLine+"def",
|
TestStringBasic = "hello123",
|
||||||
|
TestStringNewLine = "abc"+Environment.NewLine+"def"+Environment.NewLine,
|
||||||
|
TestStringBackslash = @"C:\Test\\\Abc\",
|
||||||
TestStringNull = null,
|
TestStringNull = null,
|
||||||
TestEnum = TestEnum.D
|
TestEnum = TestEnum.D
|
||||||
};
|
};
|
||||||
@ -38,7 +42,9 @@ public void TestBasicWriteRead(){
|
|||||||
|
|
||||||
Assert.IsTrue(read.TestBool);
|
Assert.IsTrue(read.TestBool);
|
||||||
Assert.AreEqual(-100, read.TestInt);
|
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.IsNull(read.TestStringNull);
|
||||||
Assert.AreEqual(TestEnum.D, read.TestEnum);
|
Assert.AreEqual(TestEnum.D, read.TestEnum);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user