2021-10-12 03:49:01 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2021-09-27 12:42:46 +00:00
|
|
|
using System.IO;
|
|
|
|
using System.Text;
|
2021-10-12 03:49:01 +00:00
|
|
|
using System.Text.RegularExpressions;
|
2021-09-27 12:42:46 +00:00
|
|
|
using IniParser;
|
2021-10-12 03:49:01 +00:00
|
|
|
using IniParser.Exceptions;
|
2021-09-27 12:42:46 +00:00
|
|
|
using IniParser.Model;
|
|
|
|
using IniParser.Model.Configuration;
|
|
|
|
using IniParser.Parser;
|
|
|
|
using Wabbajack.Paths;
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
namespace Wabbajack.Installer;
|
|
|
|
|
|
|
|
public static class IniExtensions
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
private static IniDataParser IniParser()
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
var config = new IniParserConfiguration {AllowDuplicateKeys = true, AllowDuplicateSections = true};
|
|
|
|
var parser = new IniDataParser(config);
|
|
|
|
return parser;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Loads INI data from the given filename and returns a dynamic type that
|
|
|
|
/// can use . operators to navigate the INI.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="file"></param>
|
|
|
|
/// <returns></returns>
|
2022-06-20 23:21:04 +00:00
|
|
|
public static IniData LoadIniFile(this AbsolutePath file)
|
2021-10-23 16:51:17 +00:00
|
|
|
{
|
|
|
|
return new FileIniDataParser(IniParser()).ReadFile(file.ToString());
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static void SaveIniFile(this IniData data, AbsolutePath file)
|
|
|
|
{
|
|
|
|
var parser = new FileIniDataParser(IniParser());
|
|
|
|
parser.WriteFile(file.ToString(), data);
|
|
|
|
}
|
2021-10-21 03:18:15 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Loads a INI from the given string
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="file"></param>
|
|
|
|
/// <returns></returns>
|
|
|
|
public static IniData LoadIniString(this string file)
|
|
|
|
{
|
|
|
|
return new FileIniDataParser(IniParser()).ReadData(
|
|
|
|
new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(file))));
|
|
|
|
}
|
2021-10-12 03:49:01 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static string FromMO2Ini(this string s)
|
|
|
|
{
|
|
|
|
if (string.IsNullOrEmpty(s)) return s;
|
2021-10-12 03:49:01 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
if (s.StartsWith("@ByteArray(") && s.EndsWith(")"))
|
|
|
|
return UnescapeUTF8(s.Substring("@ByteArray(".Length, s.Length - "@ByteArray(".Length - ")".Length));
|
2021-10-12 03:49:01 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
return UnescapeString(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static string UnescapeString(string s)
|
|
|
|
{
|
|
|
|
if (s.Trim().StartsWith("\"") || s.Contains("\\\\"))
|
|
|
|
return Regex.Unescape(s.Trim('"'));
|
|
|
|
return s;
|
|
|
|
}
|
2021-10-12 03:49:01 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
private static string UnescapeUTF8(string s)
|
|
|
|
{
|
|
|
|
var acc = new List<byte>();
|
|
|
|
for (var i = 0; i < s.Length; i++)
|
2021-10-12 03:49:01 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
var c = s[i];
|
|
|
|
switch (c)
|
2021-10-12 03:49:01 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
case '\\':
|
|
|
|
i++;
|
|
|
|
var nc = s[i];
|
|
|
|
switch (nc)
|
|
|
|
{
|
|
|
|
case '\\':
|
|
|
|
acc.Add((byte) '\\');
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
var chrs = s[i + 1] + s[i + 2].ToString();
|
|
|
|
i += 2;
|
|
|
|
acc.Add(Convert.ToByte(chrs, 16));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new ParsingException($"Not a valid escape characer {nc}");
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
acc.Add((byte) c);
|
|
|
|
break;
|
2021-10-12 03:49:01 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
|
|
|
return Encoding.UTF8.GetString(acc.ToArray());
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
}
|