Files
2026-02-06 18:12:21 +08:00

274 lines
5.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
namespace DataUtils
{
public class FileResXmlDoc: IDisposable
{
private string _filepath;
private XmlDocument _doc;
private bool _available;
public FileResXmlDoc (string xmlpath)
{
Create (xmlpath);
}
public bool Create (string xmlpath)
{
Destroy ();
if (string.IsNullOrEmpty (xmlpath) || !File.Exists (xmlpath))
{
_available = false;
return false;
}
try
{
_doc = new XmlDocument ();
_doc.Load (xmlpath);
_filepath = xmlpath;
_available = true;
}
catch
{
_available = false;
}
return _available;
}
public void Destroy ()
{
if (!_available) return;
_doc = null;
_available = false;
_filepath = null;
}
public void Dispose ()
{
Destroy ();
}
// Returns the chosen absolute (or resolved) path string or empty if none found
public string Get (string id)
{
if (!_available || _doc == null) return string.Empty;
if (string.IsNullOrEmpty (id)) return string.Empty;
XmlNode root = _doc.DocumentElement;
if (root == null) return string.Empty;
foreach (XmlNode node in root.ChildNodes)
{
var attr = node.Attributes? ["id"];
if (attr == null) continue;
if (!string.Equals (attr.Value, id, StringComparison.OrdinalIgnoreCase)) continue;
// Build dpi -> path map
var map = new Dictionary<int, string> ();
foreach (XmlNode child in node.ChildNodes)
{
var dpiAttr = child.Attributes? ["dpi"];
string dpiStr = dpiAttr != null ? dpiAttr.Value : "default";
string text = child.InnerText ?? string.Empty;
int dpiKey = 0;
if (string.Equals (dpiStr, "default", StringComparison.OrdinalIgnoreCase))
{
dpiKey = 0;
}
else
{
int parsed;
if (int.TryParse (dpiStr, out parsed)) dpiKey = parsed;
else dpiKey = 0;
}
// Resolve relative path relative to xml file directory
string candidate = text;
if (!Path.IsPathRooted (candidate) && !string.IsNullOrEmpty (_filepath))
{
string dir = Path.GetDirectoryName (_filepath);
if (!string.IsNullOrEmpty (dir))
candidate = Path.Combine (dir, candidate);
}
// Normalize
try { candidate = Path.GetFullPath (candidate); } catch { /* ignore */ }
// Insert/overwrite by key (keep last if duplicate)
map [dpiKey] = candidate;
}
// Convert map to list and sort by string value (to mimic original)
var list = map.Select (kv => new KeyValuePair<int, string> (kv.Key, kv.Value)).ToList ();
list.Sort ((a, b) => string.CompareOrdinal (a.Value, b.Value));
// Keep only those whose file exists
var existList = new List<KeyValuePair<int, string>> ();
foreach (var kv in list)
{
if (!string.IsNullOrEmpty (kv.Value) && File.Exists (kv.Value))
existList.Add (kv);
}
int dpiPercent = UITheme.GetDPI (); // uses earlier helper
// Find first with dpi >= dpiPercent
foreach (var kv in existList)
{
if (kv.Key >= dpiPercent) return kv.Value;
}
// otherwise return first existing candidate
if (existList.Count > 0) return existList [0].Value;
return string.Empty;
}
return string.Empty;
}
// Overloads for convenience
//public string Get (System.String idAsString) { return Get (idAsString); }
}
public class StringResXmlDoc: IDisposable
{
private XmlDocument doc;
private bool isValid;
public bool IsValid
{
get { return isValid; }
}
public StringResXmlDoc () { }
public StringResXmlDoc (string filePath)
{
Create (filePath);
}
public bool Create (string filePath)
{
Destroy ();
if (string.IsNullOrEmpty (filePath) || !File.Exists (filePath))
return false;
try
{
doc = new XmlDocument ();
doc.Load (filePath);
isValid = true;
return true;
}
catch
{
Destroy ();
return false;
}
}
public void Destroy ()
{
doc = null;
isValid = false;
}
public void Dispose ()
{
Destroy ();
GC.SuppressFinalize (this);
}
public string Get (string id)
{
if (!isValid || doc == null || string.IsNullOrEmpty (id))
return string.Empty;
XmlElement root = doc.DocumentElement;
if (root == null)
return string.Empty;
foreach (XmlNode node in root.ChildNodes)
{
if (node.Attributes == null)
continue;
XmlAttribute idAttr = node.Attributes ["id"];
if (idAttr == null)
continue;
if (!StringEqualsNormalized (idAttr.Value, id))
continue;
Dictionary<string, string> langValues =
new Dictionary<string, string> (StringComparer.OrdinalIgnoreCase);
foreach (XmlNode sub in node.ChildNodes)
{
if (sub.Attributes == null)
continue;
XmlAttribute langAttr = sub.Attributes ["name"];
if (langAttr == null)
continue;
string lang = langAttr.Value;
if (!string.IsNullOrEmpty (lang))
{
langValues [lang] = sub.InnerText;
}
}
return GetSuitableLanguageValue (langValues);
}
return string.Empty;
}
public string GetString (string id) => Get (id);
public string this [string id]
{
get { return Get (id); }
}
private static bool StringEqualsNormalized (string a, string b)
{
return string.Equals (
a != null ? a.Trim () : null,
b != null ? b.Trim () : null,
StringComparison.OrdinalIgnoreCase
);
}
private static string GetSuitableLanguageValue (
Dictionary<string, string> values)
{
if (values == null || values.Count == 0)
return string.Empty;
CultureInfo culture = CultureInfo.CurrentUICulture;
string val;
if (values.TryGetValue (culture.Name, out val))
return val;
if (values.TryGetValue (culture.TwoLetterISOLanguageName, out val))
return val;
if (values.TryGetValue ("en", out val))
return val;
foreach (string v in values.Values)
return v;
return string.Empty;
}
}
}