94 lines
2.9 KiB
C#
94 lines
2.9 KiB
C#
using System.Text.RegularExpressions;
|
|
|
|
namespace GsaEditor.Core.IO;
|
|
|
|
/// <summary>
|
|
/// Represents a single entry parsed from a .idx NML index file.
|
|
/// </summary>
|
|
public class GsaIndexEntry
|
|
{
|
|
/// <summary>
|
|
/// The file alias (relative path) of the entry.
|
|
/// </summary>
|
|
public string Id { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Compression method: 0 = raw, 1 = zlib.
|
|
/// </summary>
|
|
public int Method { get; set; }
|
|
|
|
/// <summary>
|
|
/// Original (decompressed) size in bytes.
|
|
/// </summary>
|
|
public uint Length { get; set; }
|
|
|
|
/// <summary>
|
|
/// Compressed size in bytes.
|
|
/// </summary>
|
|
public uint CompressedLength { get; set; }
|
|
|
|
/// <summary>
|
|
/// Byte offset of the data block within the archive.
|
|
/// </summary>
|
|
public long Offset { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parses .idx NML index files into a list of <see cref="GsaIndexEntry"/>.
|
|
/// NML is the engine's own tag syntax (<Name=value> blocks, see <see cref="GsaIndexWriter"/>),
|
|
/// not standard XML.
|
|
/// </summary>
|
|
public static class GsaIndexReader
|
|
{
|
|
private static readonly Regex EntryRegex = new(
|
|
@"<Entry=(?<body>.*?)\n\s*>",
|
|
RegexOptions.Singleline | RegexOptions.Compiled);
|
|
|
|
private static readonly Regex TagRegex = new(
|
|
@"<(?<name>\w+)=""?(?<value>[^"">]*)""?>",
|
|
RegexOptions.Compiled);
|
|
|
|
/// <summary>
|
|
/// Reads index entries from the specified .idx file.
|
|
/// </summary>
|
|
/// <param name="filePath">The path to the .idx file.</param>
|
|
/// <returns>A list of parsed index entries.</returns>
|
|
public static List<GsaIndexEntry> Read(string filePath)
|
|
{
|
|
var text = File.ReadAllText(filePath);
|
|
var entries = new List<GsaIndexEntry>();
|
|
|
|
foreach (Match entryMatch in EntryRegex.Matches(text))
|
|
{
|
|
var entry = new GsaIndexEntry();
|
|
|
|
foreach (Match tag in TagRegex.Matches(entryMatch.Groups["body"].Value))
|
|
{
|
|
var value = tag.Groups["value"].Value;
|
|
switch (tag.Groups["name"].Value)
|
|
{
|
|
case "ID":
|
|
entry.Id = value;
|
|
break;
|
|
case "Method":
|
|
entry.Method = value.Equals("Zlib", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
|
|
break;
|
|
case "Len":
|
|
entry.Length = uint.TryParse(value, out var l) ? l : 0;
|
|
break;
|
|
case "CompLen":
|
|
entry.CompressedLength = uint.TryParse(value, out var cl) ? cl : 0;
|
|
break;
|
|
case "Offset":
|
|
entry.Offset = long.TryParse(value, out var o) ? o : 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
entries.Add(entry);
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
}
|