From d171c3423637f2bddf851bdcaa61adea37d6362a Mon Sep 17 00:00:00 2001 From: ItsTheSky Date: Tue, 21 Jul 2026 15:50:52 +0200 Subject: [PATCH] fixed GSA writing, added always-edit button and search in file and for file --- .gitignore | 2 + .../.idea/material_theme_project_new.xml | 4 +- GsaEditor.Core/IO/GsaIndexReader.cs | 53 ++-- GsaEditor.Core/IO/GsaIndexWriter.cs | 60 +++-- GsaEditor.Core/IO/GsaWriter.cs | 11 + .../bin/Debug/net8.0/GsaEditor.Core.dll | Bin 13312 -> 13824 bytes .../bin/Debug/net8.0/GsaEditor.Core.pdb | Bin 14956 -> 15188 bytes .../bin/Debug/net8.0/GsaEditor.Core.xml | 34 ++- .../net8.0/GsaEditor.Core.AssemblyInfo.cs | 4 +- .../GsaEditor.Core.AssemblyInfoInputs.cache | 2 +- .../obj/Debug/net8.0/GsaEditor.Core.dll | Bin 13312 -> 13824 bytes .../obj/Debug/net8.0/GsaEditor.Core.pdb | Bin 14956 -> 15188 bytes .../obj/Debug/net8.0/GsaEditor.Core.xml | 34 ++- .../obj/Debug/net8.0/ref/GsaEditor.Core.dll | Bin 7680 -> 7168 bytes .../Debug/net8.0/refint/GsaEditor.Core.dll | Bin 7680 -> 7168 bytes .../ViewModels/EntryTreeNodeViewModel.cs | 3 + GsaEditor/ViewModels/MainWindowViewModel.cs | 230 ++++++++++++++++++ GsaEditor/ViewModels/SearchResultViewModel.cs | 19 ++ GsaEditor/Views/MainWindow.axaml | 74 +++++- GsaEditor/Views/MainWindow.axaml.cs | 13 + GsaEditor/bin/Debug/net8.0/GsaEditor.Core.dll | Bin 13312 -> 13824 bytes GsaEditor/bin/Debug/net8.0/GsaEditor.Core.pdb | Bin 14956 -> 15188 bytes GsaEditor/bin/Debug/net8.0/GsaEditor.Core.xml | 34 ++- GsaEditor/bin/Debug/net8.0/GsaEditor.dll | Bin 84480 -> 97280 bytes GsaEditor/bin/Debug/net8.0/GsaEditor.exe | Bin 151552 -> 151552 bytes GsaEditor/bin/Debug/net8.0/GsaEditor.pdb | Bin 45548 -> 51068 bytes .../net8.0/Avalonia/Resources.Inputs.cache | 2 +- GsaEditor/obj/Debug/net8.0/Avalonia/resources | Bin 14928 -> 18412 bytes .../Debug/net8.0/GsaEditor.AssemblyInfo.cs | 4 +- .../net8.0/GsaEditor.AssemblyInfoInputs.cache | 2 +- .../GsaEditor.csproj.AssemblyReference.cache | Bin 16477 -> 16507 bytes .../GsaEditor.csproj.CoreCompileInputs.cache | 2 +- GsaEditor/obj/Debug/net8.0/GsaEditor.dll | Bin 84480 -> 97280 bytes GsaEditor/obj/Debug/net8.0/GsaEditor.pdb | Bin 45548 -> 51068 bytes GsaEditor/obj/Debug/net8.0/apphost.exe | Bin 151552 -> 151552 bytes GsaEditor/obj/Debug/net8.0/ref/GsaEditor.dll | Bin 16896 -> 18944 bytes .../obj/Debug/net8.0/refint/GsaEditor.dll | Bin 16896 -> 18944 bytes .../net9.0/Avalonia/Resources.Inputs.cache | 2 +- obj/Debug/net9.0/Avalonia/resources | Bin 177922 -> 193007 bytes obj/Debug/net9.0/GsaViewer.AssemblyInfo.cs | 2 +- .../net9.0/GsaViewer.AssemblyInfoInputs.cache | 2 +- ....GeneratedMSBuildEditorConfig.editorconfig | 6 + 42 files changed, 538 insertions(+), 61 deletions(-) create mode 100644 .gitignore create mode 100644 GsaEditor/ViewModels/SearchResultViewModel.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..59e6eb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/bin/** +**/obj/** diff --git a/.idea/.idea.GsaViewer/.idea/material_theme_project_new.xml b/.idea/.idea.GsaViewer/.idea/material_theme_project_new.xml index 368f71c..a47b547 100644 --- a/.idea/.idea.GsaViewer/.idea/material_theme_project_new.xml +++ b/.idea/.idea.GsaViewer/.idea/material_theme_project_new.xml @@ -3,7 +3,9 @@ diff --git a/GsaEditor.Core/IO/GsaIndexReader.cs b/GsaEditor.Core/IO/GsaIndexReader.cs index 5937e0b..beffa0e 100644 --- a/GsaEditor.Core/IO/GsaIndexReader.cs +++ b/GsaEditor.Core/IO/GsaIndexReader.cs @@ -1,4 +1,4 @@ -using System.Xml.Linq; +using System.Text.RegularExpressions; namespace GsaEditor.Core.IO; @@ -34,10 +34,20 @@ public class GsaIndexEntry } /// -/// Parses .idx NML index files (XML-compatible format) into a list of . +/// Parses .idx NML index files into a list of . +/// NML is the engine's own tag syntax (<Name=value> blocks, see ), +/// not standard XML. /// public static class GsaIndexReader { + private static readonly Regex EntryRegex = new( + @".*?)\n\s*>", + RegexOptions.Singleline | RegexOptions.Compiled); + + private static readonly Regex TagRegex = new( + @"<(?\w+)=""?(?[^"">]*)""?>", + RegexOptions.Compiled); + /// /// Reads index entries from the specified .idx file. /// @@ -45,23 +55,36 @@ public static class GsaIndexReader /// A list of parsed index entries. public static List Read(string filePath) { - var doc = XDocument.Load(filePath); + var text = File.ReadAllText(filePath); var entries = new List(); - var root = doc.Root; - if (root == null || root.Name.LocalName != "Index") - return entries; - - foreach (var entryEl in root.Elements("Entry")) + foreach (Match entryMatch in EntryRegex.Matches(text)) { - var entry = new GsaIndexEntry + var entry = new GsaIndexEntry(); + + foreach (Match tag in TagRegex.Matches(entryMatch.Groups["body"].Value)) { - Id = entryEl.Element("Id")?.Value ?? string.Empty, - Method = int.TryParse(entryEl.Element("Method")?.Value, out var m) ? m : 0, - Length = uint.TryParse(entryEl.Element("Len")?.Value, out var l) ? l : 0, - CompressedLength = uint.TryParse(entryEl.Element("CompLen")?.Value, out var cl) ? cl : 0, - Offset = long.TryParse(entryEl.Element("Offset")?.Value, out var o) ? o : 0 - }; + 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); } diff --git a/GsaEditor.Core/IO/GsaIndexWriter.cs b/GsaEditor.Core/IO/GsaIndexWriter.cs index f462cae..e6604ee 100644 --- a/GsaEditor.Core/IO/GsaIndexWriter.cs +++ b/GsaEditor.Core/IO/GsaIndexWriter.cs @@ -1,36 +1,62 @@ -using System.Xml.Linq; +using System.Text; using GsaEditor.Core.Models; namespace GsaEditor.Core.IO; /// /// Writes a .idx NML index file from a . -/// The index file is XML-compatible and lists each entry with its alias, compression method, -/// sizes, and data offset for fast lookup without a full sequential scan. +/// The NML format is the engine's own tag syntax (NOT standard XML): +/// +/// <Version=1.0> +/// <Index= +/// <Entry= +/// <ID="path/in/archive"> +/// <CompLen=123> +/// <Len=456> +/// <Offset=789> +/// <Method="Zlib"> +/// > +/// > +/// +/// Tab indentation, LF line endings, no BOM. Method is "Zlib" or "Raw". +/// The engine parses this file to locate entries, so the format must match exactly. /// public static class GsaIndexWriter { + /// + /// The engine's bootstrap script is loaded by sequential archive scan and is + /// deliberately absent from the shipped index files, so it is skipped here too. + /// + private const string BootstrapAlias = "bootstrap.txt"; + /// /// Writes the index file for the given archive to the specified path. + /// Entry offsets must be up to date (i.e. call after ). /// /// The archive whose entries will be indexed. /// The output .idx file path. public static void Write(GsaArchive archive, string filePath) { - var doc = new XDocument( - new XElement("Index", - archive.Entries.Select(e => - new XElement("Entry", - new XElement("Id", e.Alias), - new XElement("Method", e.IsCompressed ? 1 : 0), - new XElement("Len", e.OriginalLength), - new XElement("CompLen", e.CompressedLength), - new XElement("Offset", e.DataOffset) - ) - ) - ) - ); + var sb = new StringBuilder(); + sb.Append("\n"); + sb.Append("\n"); + sb.Append("\t\t\n"); + sb.Append("\t\t\n"); + sb.Append("\t\t\n"); + sb.Append("\t\t\n"); + sb.Append("\t>\n"); + } + + sb.Append(">\n"); + + File.WriteAllText(filePath, sb.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); } } diff --git a/GsaEditor.Core/IO/GsaWriter.cs b/GsaEditor.Core/IO/GsaWriter.cs index 333474c..3d29e18 100644 --- a/GsaEditor.Core/IO/GsaWriter.cs +++ b/GsaEditor.Core/IO/GsaWriter.cs @@ -15,6 +15,12 @@ public static class GsaWriter /// Magic word for the NARD (enhanced) format. private const uint MAGIC_NARD = 0x4E415244; + /// + /// End-of-archive terminator written where the next entry's alias length would be. + /// The engine's sequential reader stops when it hits this invalid length. + /// + private const uint TERMINATOR = 0xFFFFFFFF; + /// /// Writes the archive to the specified file path. /// @@ -53,6 +59,11 @@ public static class GsaWriter { WriteEntry(writer, entry, archive); } + + // Write the end-of-archive terminator, aligned like an entry header + if (archive.Format == GsaFormat.NARD && archive.OffsetPadding > 0) + WritePadding(writer, archive.OffsetPadding); + writer.Write(TERMINATOR); } /// diff --git a/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.dll b/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.dll index 7e45f4aeef9c9d318ca05c826c68eade174f8fbe..d7d1423521857fe7a1b2b828a51302cf6cbb8858 100644 GIT binary patch literal 13824 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 diff --git a/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.pdb b/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.pdb index 3abb27e709606229316ad5178a18a214bfb9eb08..383ce41659a7d9a0706f27e26ba09fa478005517 100644 GIT binary patch delta 1872 zcmYjR3v5$W82-=c?d`p#TQ^{^#Ze0D9`v~m_u#R~qZMa{EDSQqL?~O?ii4828>=R? z8_WdMAi2hfGsa*D4*?$&#GnZfri4h;ut+e5Y+|BQ0+<*di3Y!Odt5t38@ZQ1%ZQebZu_Nw*G zA+$ZvcY@F>dgCJ5oATjhw@3U>oUt{1aO6r~)7gKXo`jp)=Nwj5g$SvshG;QaVLSw2 zEL8!m0CLfjfE_Ryt;4XzKr_G(PR=b7gBpPVAOc0ebghU@)h_pNa(GST_Db{%VDm|I z3ApSxlNvCS5BMBdSj{K{)C3v5I=X~6^2|kKa#0>;W>k)Z2}4WJV#2M4HbY0DB}2>5 z;ye8gi18Na7h!(~ltWvg#WNqMpu+$3M!1EZhB)$P=pH&$!eKK8h^1FS=NY;l1B5Ps z{#j2(v;ex$h>sxdhAK7mLiF)KI}9!Id7j%}-(TeSzsf8`&TmSG}kYt+lPJk^wGRt(#=LGNfF9SdDZw9*qS@5~QTj0v- z3*bcc1h_azvP>@oo!|*^E>^DzZCV~`39qF@WLGGXicoS3ZI5)vw40VC<^7S~z9>Z! zojtMsD0Ly+7JD{IsYo|Pccc>O)sa+ZkLFSWT89!VjQ6E>_N6El9Z2QE+6^VDwWuRb z_4u~XDaV(~Uu&wDbYc?^1s8jJLF^a}r7g~*JtaAOO7 z2Ysi|*KBO4#n@;iaxMmct}7}Q`(q+=>Gj+fn}!^L*i&UMq~9o3CtxQ3{8Lt|jR;E< z!dFoWlpII}q!h9Ng1yNPNrRY-aREl;rcacN(KP&hewLV61@Rb0u~>$d&hD*z+GV2i zE;E_kW?Ba^m77WONVFEx1DS!edl`KQ+2Uh#*@vn6&qR(fFJH+MhmdCx&B3u5ZGtP^ z;1akvrUJf@(#fXhMbr%2BFe(4!~uy!*2Und244oV;A!B$!nX)g0&X|_N8v98&zf|o$ghImkbBE!Gm;3eRd zlt4jY@FJkp2zbNbF7Q0)MGznSZo|LA;2z>6>Qn})zzuo9#cxDM!U;t!zXEdo7G*jD z-9nkT0fo*$x6(=MkE?wbm_lcPv(t!9>G~*;Q7e$+grYsf@o2ecs z={G7!d700FQ51Hb7PTx)47*O6WqJg(&|}vn==JU?;5|1h zfjd0gfYY8Nu-SVOc-(slSmT=lUht7DQ;NuOT~qDW)wPXv%@hmt)dti6dapas5eZT# z8YDHU2D+NVfe>wvt6|Nixa@&gursnJOd-U!MEb+pX2oj>_o%UWU6*!1c_||njj9yg zt?t~dl5WT0P1dlzk!ns?^Jv4FLEoLGhWMn`X+7HB@%1kcH{JewX6K2io3Ho}om*B% z7wWsGe;*k+;&&E(awUCDZ=j(k6yEEPMbvQ26YRCMF|#dee(}r638(F!53XISX?yMJ zsmpKrSFp*0=T65xg`eg>>i=x>!+l$}YXMuc^FE!JJHEI}4t_a);PZkXrqgfK4y+s8 z|6p5lBEG)zL2&H0ZG<_)=8p&8ah$zcJm=WdPc;S0hu&IS)7KhW)pq^B>y@m1{n*je zJH__2mUyok?)J2HcX=8kJ-f8SOL7wJC@=F$j0(A8p%N~-*Nm2|;Nn@CD2*!$S(t(>nq-+;^4Z%qeDP(TEgtv3att2F diff --git a/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.xml b/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.xml index 79f2155..30a5815 100644 --- a/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.xml +++ b/GsaEditor.Core/bin/Debug/net8.0/GsaEditor.Core.xml @@ -67,7 +67,9 @@ - Parses .idx NML index files (XML-compatible format) into a list of . + Parses .idx NML index files into a list of . + NML is the engine's own tag syntax (<Name=value> blocks, see ), + not standard XML. @@ -80,13 +82,33 @@ Writes a .idx NML index file from a . - The index file is XML-compatible and lists each entry with its alias, compression method, - sizes, and data offset for fast lookup without a full sequential scan. + The NML format is the engine's own tag syntax (NOT standard XML): + + <Version=1.0> + <Index= + <Entry= + <ID="path/in/archive"> + <CompLen=123> + <Len=456> + <Offset=789> + <Method="Zlib"> + > + > + + Tab indentation, LF line endings, no BOM. Method is "Zlib" or "Raw". + The engine parses this file to locate entries, so the format must match exactly. + + + + + The engine's bootstrap script is loaded by sequential archive scan and is + deliberately absent from the shipped index files, so it is skipped here too. Writes the index file for the given archive to the specified path. + Entry offsets must be up to date (i.e. call after ). The archive whose entries will be indexed. The output .idx file path. @@ -149,6 +171,12 @@ Magic word for the NARD (enhanced) format. + + + End-of-archive terminator written where the next entry's alias length would be. + The engine's sequential reader stops when it hits this invalid length. + + Writes the archive to the specified file path. diff --git a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfo.cs b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfo.cs index 44a6762..e4e60c7 100644 --- a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfo.cs +++ b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfo.cs @@ -13,10 +13,10 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("GsaEditor.Core")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d6d621dc92b3083d8e47827baa0ccf59d5b0a4c4")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+cbf0891ba467ebec2dd40e9b34eb1f2d6379d7dd")] [assembly: System.Reflection.AssemblyProductAttribute("GsaEditor.Core")] [assembly: System.Reflection.AssemblyTitleAttribute("GsaEditor.Core")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] -// Généré par la classe MSBuild WriteCodeFragment. +// Generated by the MSBuild WriteCodeFragment class. diff --git a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfoInputs.cache b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfoInputs.cache index f61127c..e346c7e 100644 --- a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfoInputs.cache +++ b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.AssemblyInfoInputs.cache @@ -1 +1 @@ -27416b735d6b5e6056e4f76966d345ebebb5a18e412e4170cdbcf381f9ab7092 +24bad01704fb232d5dd4f84bfcb34e9e1b11dc1475b9ee697c24bd2eb1122246 diff --git a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.dll b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.dll index 7e45f4aeef9c9d318ca05c826c68eade174f8fbe..d7d1423521857fe7a1b2b828a51302cf6cbb8858 100644 GIT binary patch literal 13824 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 diff --git a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.pdb b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.pdb index 3abb27e709606229316ad5178a18a214bfb9eb08..383ce41659a7d9a0706f27e26ba09fa478005517 100644 GIT binary patch delta 1872 zcmYjR3v5$W82-=c?d`p#TQ^{^#Ze0D9`v~m_u#R~qZMa{EDSQqL?~O?ii4828>=R? z8_WdMAi2hfGsa*D4*?$&#GnZfri4h;ut+e5Y+|BQ0+<*di3Y!Odt5t38@ZQ1%ZQebZu_Nw*G zA+$ZvcY@F>dgCJ5oATjhw@3U>oUt{1aO6r~)7gKXo`jp)=Nwj5g$SvshG;QaVLSw2 zEL8!m0CLfjfE_Ryt;4XzKr_G(PR=b7gBpPVAOc0ebghU@)h_pNa(GST_Db{%VDm|I z3ApSxlNvCS5BMBdSj{K{)C3v5I=X~6^2|kKa#0>;W>k)Z2}4WJV#2M4HbY0DB}2>5 z;ye8gi18Na7h!(~ltWvg#WNqMpu+$3M!1EZhB)$P=pH&$!eKK8h^1FS=NY;l1B5Ps z{#j2(v;ex$h>sxdhAK7mLiF)KI}9!Id7j%}-(TeSzsf8`&TmSG}kYt+lPJk^wGRt(#=LGNfF9SdDZw9*qS@5~QTj0v- z3*bcc1h_azvP>@oo!|*^E>^DzZCV~`39qF@WLGGXicoS3ZI5)vw40VC<^7S~z9>Z! zojtMsD0Ly+7JD{IsYo|Pccc>O)sa+ZkLFSWT89!VjQ6E>_N6El9Z2QE+6^VDwWuRb z_4u~XDaV(~Uu&wDbYc?^1s8jJLF^a}r7g~*JtaAOO7 z2Ysi|*KBO4#n@;iaxMmct}7}Q`(q+=>Gj+fn}!^L*i&UMq~9o3CtxQ3{8Lt|jR;E< z!dFoWlpII}q!h9Ng1yNPNrRY-aREl;rcacN(KP&hewLV61@Rb0u~>$d&hD*z+GV2i zE;E_kW?Ba^m77WONVFEx1DS!edl`KQ+2Uh#*@vn6&qR(fFJH+MhmdCx&B3u5ZGtP^ z;1akvrUJf@(#fXhMbr%2BFe(4!~uy!*2Und244oV;A!B$!nX)g0&X|_N8v98&zf|o$ghImkbBE!Gm;3eRd zlt4jY@FJkp2zbNbF7Q0)MGznSZo|LA;2z>6>Qn})zzuo9#cxDM!U;t!zXEdo7G*jD z-9nkT0fo*$x6(=MkE?wbm_lcPv(t!9>G~*;Q7e$+grYsf@o2ecs z={G7!d700FQ51Hb7PTx)47*O6WqJg(&|}vn==JU?;5|1h zfjd0gfYY8Nu-SVOc-(slSmT=lUht7DQ;NuOT~qDW)wPXv%@hmt)dti6dapas5eZT# z8YDHU2D+NVfe>wvt6|Nixa@&gursnJOd-U!MEb+pX2oj>_o%UWU6*!1c_||njj9yg zt?t~dl5WT0P1dlzk!ns?^Jv4FLEoLGhWMn`X+7HB@%1kcH{JewX6K2io3Ho}om*B% z7wWsGe;*k+;&&E(awUCDZ=j(k6yEEPMbvQ26YRCMF|#dee(}r638(F!53XISX?yMJ zsmpKrSFp*0=T65xg`eg>>i=x>!+l$}YXMuc^FE!JJHEI}4t_a);PZkXrqgfK4y+s8 z|6p5lBEG)zL2&H0ZG<_)=8p&8ah$zcJm=WdPc;S0hu&IS)7KhW)pq^B>y@m1{n*je zJH__2mUyok?)J2HcX=8kJ-f8SOL7wJC@=F$j0(A8p%N~-*Nm2|;Nn@CD2*!$S(t(>nq-+;^4Z%qeDP(TEgtv3att2F diff --git a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.xml b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.xml index 79f2155..30a5815 100644 --- a/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.xml +++ b/GsaEditor.Core/obj/Debug/net8.0/GsaEditor.Core.xml @@ -67,7 +67,9 @@ - Parses .idx NML index files (XML-compatible format) into a list of . + Parses .idx NML index files into a list of . + NML is the engine's own tag syntax (<Name=value> blocks, see ), + not standard XML. @@ -80,13 +82,33 @@ Writes a .idx NML index file from a . - The index file is XML-compatible and lists each entry with its alias, compression method, - sizes, and data offset for fast lookup without a full sequential scan. + The NML format is the engine's own tag syntax (NOT standard XML): + + <Version=1.0> + <Index= + <Entry= + <ID="path/in/archive"> + <CompLen=123> + <Len=456> + <Offset=789> + <Method="Zlib"> + > + > + + Tab indentation, LF line endings, no BOM. Method is "Zlib" or "Raw". + The engine parses this file to locate entries, so the format must match exactly. + + + + + The engine's bootstrap script is loaded by sequential archive scan and is + deliberately absent from the shipped index files, so it is skipped here too. Writes the index file for the given archive to the specified path. + Entry offsets must be up to date (i.e. call after ). The archive whose entries will be indexed. The output .idx file path. @@ -149,6 +171,12 @@ Magic word for the NARD (enhanced) format. + + + End-of-archive terminator written where the next entry's alias length would be. + The engine's sequential reader stops when it hits this invalid length. + + Writes the archive to the specified file path. diff --git a/GsaEditor.Core/obj/Debug/net8.0/ref/GsaEditor.Core.dll b/GsaEditor.Core/obj/Debug/net8.0/ref/GsaEditor.Core.dll index 3b897f711616492fd670165f9d47b9bf46ba17de..4b083fb49cc71ba122f2b56946ef521fa8e406fb 100644 GIT binary patch delta 2127 zcmbVNX=q$k7(MsBHkvm5kj~rYxcWL=?B%X^{Q@Kp}02hVKxcFOe>_lJQL=fN)=m*|0$5t2Ri~u?0 zqf{&G)yA#%Ru#;?l256H#buvX)yi#uuhyxuDW`E&x!&Az^~ICd0MCBf98r&hard4lc0Rg&m zZ#T9u)&uw4)7!Cu?;Yebio9*tVm0Vl4hZI%KX&e=N zU2v7?Jre&Uc>>a^P2$*fYnly;NV3`WAtwFU)XE97Mmmpgl%l6N|F?`|R;$FCt#`y3 zTXLj-SjVi*^h%{>yQ3VfT)k2pP%ivw#@Sk7H&}6YBM!u9E+)*I#4JgeRl>5Z&rF@> z7C4;&)Sz#q06wCd*x8~-_~^W)xV0(8R(QD$j-=yjM|@#$MwMj8AYJy5{mU_6Cn;XG=^Up>fPwCsCd>&s*=w9aT7{uk`=KZe}(x z$BX(O8Di2wDL()TQ;ZG7<2b(iFFjr-uJ=j@2c^y^&w$rbTs3_-ONrUIS>jrv3r&Kp zf*pcgg0Zdg8W7w`R6I^zs|0%m4-uU_dYSOBAU#J%Pmu}kn7e8>1U$2{>Abe*4}+a5`)Q}39!$8yiz zevNwk8_R%C87|BF@7gp^kvyAr4)5u&wa?@|H`SWI!<_n{utV9E#TA9XKmP*lO~rou zrQ*l4x-wv>!py=hJEP=6RX8;0Yiz0w4fq=Z(NHv87m4_N(WX$nKN_kXtcx_%2bv;* zNW{)|ueE({SKdr8(KlZ|1nv9XWyWmKe#E_DDsM%e84M$YL4J)JdB$oP55SKG1Q2B$ v;(!0YH_PAnm@nfmjQ&(g delta 2283 zcma)8ZERCj7=F(E=+Us-J5tNKC)|6_PR3- zFxUn*_u?*XIeuWx=5^g{|0Mrjkgput8zq;Q#>89Zj0-mnJP=K&p+J)j%6T(A>Uq!M z%_3xc674kfobV)D*+FvI0-x&H)`c4FsNup{g{#FrqY~#?n+v;@a#YOFT{x=!LHtoj zJge}M!WN|uDf^L-d3sc@Z6YbjB6Erzme5g#GJMFS-|14Bjw#)PsOe_RRlQRcRI5<1 zJi+<6qD>l|%9bo;W?2~otDZx)kv_kQJZ3IMCuh@-H-r}fBg+;f68(%4pDGy6DmrsI3bh!wG&h8Jei zao)ggPJBL1217;ckiH)!j_)1)KoJYmSL*l%=_{}l4#DmCj&rpYShx8mUv@G-V6S1qF5w8{u&xA9Cso>{*swiEuLaW>&Fo(j1e| zXToQeT;3Uem>L-@rX=OJOz1*H8b}C$_aFfD*g#!xXM1lRp zY8+H}41M;y<^JTiqJb;t9vV3H4~VnjrxHLN?IoB`y9p8Eb4U=o_&GLUJ&qH5mA;+W zf!7${g*~_;x-g2bL_{f;QY@vUlrpaHywcB0y<1#SQbr+!Or#5$NEb3uK-mFhcPMX{ zQo589QHo_Bt~i`b8M4>7LXC5-^Fub(rasr43k$MieI zxWbdTOM8p?3-LN+4210UaZ${6db6X*O-P4k4^O*f)o@egDdk+VP@)cpziSz;n}5db zktYwUBxQTM=ZL<1g_XYLiR+cU2S*cw!wp-9 zhZ;7-NA{N%K|s zHru~d?Q{2+Koh=FU%wrH;)l9eOROc-7_-_#(WYQqQ><;UxwS3S8XXu2TGq~G?XhLi z;6St0Y!6j0uuoL`JiBv8yL_M{Vf#Y$EG-eXC#$>DK`kQEo*Iwd6XPi$?+_Z!+y~lsr&0*zVllOw^FUDA~ F diff --git a/GsaEditor.Core/obj/Debug/net8.0/refint/GsaEditor.Core.dll b/GsaEditor.Core/obj/Debug/net8.0/refint/GsaEditor.Core.dll index 3b897f711616492fd670165f9d47b9bf46ba17de..4b083fb49cc71ba122f2b56946ef521fa8e406fb 100644 GIT binary patch delta 2127 zcmbVNX=q$k7(MsBHkvm5kj~rYxcWL=?B%X^{Q@Kp}02hVKxcFOe>_lJQL=fN)=m*|0$5t2Ri~u?0 zqf{&G)yA#%Ru#;?l256H#buvX)yi#uuhyxuDW`E&x!&Az^~ICd0MCBf98r&hard4lc0Rg&m zZ#T9u)&uw4)7!Cu?;Yebio9*tVm0Vl4hZI%KX&e=N zU2v7?Jre&Uc>>a^P2$*fYnly;NV3`WAtwFU)XE97Mmmpgl%l6N|F?`|R;$FCt#`y3 zTXLj-SjVi*^h%{>yQ3VfT)k2pP%ivw#@Sk7H&}6YBM!u9E+)*I#4JgeRl>5Z&rF@> z7C4;&)Sz#q06wCd*x8~-_~^W)xV0(8R(QD$j-=yjM|@#$MwMj8AYJy5{mU_6Cn;XG=^Up>fPwCsCd>&s*=w9aT7{uk`=KZe}(x z$BX(O8Di2wDL()TQ;ZG7<2b(iFFjr-uJ=j@2c^y^&w$rbTs3_-ONrUIS>jrv3r&Kp zf*pcgg0Zdg8W7w`R6I^zs|0%m4-uU_dYSOBAU#J%Pmu}kn7e8>1U$2{>Abe*4}+a5`)Q}39!$8yiz zevNwk8_R%C87|BF@7gp^kvyAr4)5u&wa?@|H`SWI!<_n{utV9E#TA9XKmP*lO~rou zrQ*l4x-wv>!py=hJEP=6RX8;0Yiz0w4fq=Z(NHv87m4_N(WX$nKN_kXtcx_%2bv;* zNW{)|ueE({SKdr8(KlZ|1nv9XWyWmKe#E_DDsM%e84M$YL4J)JdB$oP55SKG1Q2B$ v;(!0YH_PAnm@nfmjQ&(g delta 2283 zcma)8ZERCj7=F(E=+Us-J5tNKC)|6_PR3- zFxUn*_u?*XIeuWx=5^g{|0Mrjkgput8zq;Q#>89Zj0-mnJP=K&p+J)j%6T(A>Uq!M z%_3xc674kfobV)D*+FvI0-x&H)`c4FsNup{g{#FrqY~#?n+v;@a#YOFT{x=!LHtoj zJge}M!WN|uDf^L-d3sc@Z6YbjB6Erzme5g#GJMFS-|14Bjw#)PsOe_RRlQRcRI5<1 zJi+<6qD>l|%9bo;W?2~otDZx)kv_kQJZ3IMCuh@-H-r}fBg+;f68(%4pDGy6DmrsI3bh!wG&h8Jei zao)ggPJBL1217;ckiH)!j_)1)KoJYmSL*l%=_{}l4#DmCj&rpYShx8mUv@G-V6S1qF5w8{u&xA9Cso>{*swiEuLaW>&Fo(j1e| zXToQeT;3Uem>L-@rX=OJOz1*H8b}C$_aFfD*g#!xXM1lRp zY8+H}41M;y<^JTiqJb;t9vV3H4~VnjrxHLN?IoB`y9p8Eb4U=o_&GLUJ&qH5mA;+W zf!7${g*~_;x-g2bL_{f;QY@vUlrpaHywcB0y<1#SQbr+!Or#5$NEb3uK-mFhcPMX{ zQo589QHo_Bt~i`b8M4>7LXC5-^Fub(rasr43k$MieI zxWbdTOM8p?3-LN+4210UaZ${6db6X*O-P4k4^O*f)o@egDdk+VP@)cpziSz;n}5db zktYwUBxQTM=ZL<1g_XYLiR+cU2S*cw!wp-9 zhZ;7-NA{N%K|s zHru~d?Q{2+Koh=FU%wrH;)l9eOROc-7_-_#(WYQqQ><;UxwS3S8XXu2TGq~G?XhLi z;6St0Y!6j0uuoL`JiBv8yL_M{Vf#Y$EG-eXC#$>DK`kQEo*Iwd6XPi$?+_Z!+y~lsr&0*zVllOw^FUDA~ F diff --git a/GsaEditor/ViewModels/EntryTreeNodeViewModel.cs b/GsaEditor/ViewModels/EntryTreeNodeViewModel.cs index b68f02a..cca24e4 100644 --- a/GsaEditor/ViewModels/EntryTreeNodeViewModel.cs +++ b/GsaEditor/ViewModels/EntryTreeNodeViewModel.cs @@ -13,6 +13,9 @@ public partial class EntryTreeNodeViewModel : ViewModelBase [ObservableProperty] private string _name = string.Empty; + [ObservableProperty] + private bool _isExpanded; + /// /// Full relative path of this node within the archive (using '/' separator). /// diff --git a/GsaEditor/ViewModels/MainWindowViewModel.cs b/GsaEditor/ViewModels/MainWindowViewModel.cs index fad9cbd..e84e2a5 100644 --- a/GsaEditor/ViewModels/MainWindowViewModel.cs +++ b/GsaEditor/ViewModels/MainWindowViewModel.cs @@ -1,6 +1,7 @@ using System.Collections.ObjectModel; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using Avalonia.Controls; using Avalonia.Media.Imaging; using Avalonia.Platform.Storage; @@ -84,8 +85,24 @@ public partial class MainWindowViewModel : ViewModelBase [ObservableProperty] private bool _isEditingText; + [ObservableProperty] + private string? _searchQuery; + + [ObservableProperty] + private bool _searchInContents; + + [ObservableProperty] + private string? _searchStatus; + + [ObservableProperty] + private SearchResultViewModel? _selectedSearchResult; + public ObservableCollection TreeRoots { get; } = new(); + public ObservableCollection SearchResults { get; } = new(); + + public bool HasSearchResults => SearchResults.Count > 0; + // --- Derived properties --- public string Title => ArchivePath != null @@ -255,6 +272,8 @@ public partial class MainWindowViewModel : ViewModelBase _archive = archive; ArchivePath = path; IsDirty = false; + SearchQuery = null; + ClearSearchResults(); BuildTree(); NotifyStatusChanged(); } @@ -347,6 +366,8 @@ public partial class MainWindowViewModel : ViewModelBase TreeRoots.Clear(); SelectedEntry = null; SelectedNode = null; + SearchQuery = null; + ClearSearchResults(); ClearPreview(); NotifyStatusChanged(); } @@ -663,6 +684,215 @@ public partial class MainWindowViewModel : ViewModelBase } } + [RelayCommand] + private async Task OpenAsText() + { + if (SelectedNode?.Entry == null) return; + + var data = SelectedNode.Entry.GetDecompressedData(); + + try + { + new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(data); + } + catch (DecoderFallbackException) + { + if (_window != null) + { + var confirmed = await Dialogs.ConfirmAsync(_window, "Not a Text File", + "This file is not valid UTF-8 text. Editing and saving it as text will corrupt its content.\n\nOpen as text anyway?"); + if (!confirmed) return; + } + } + + PreviewMode = PreviewMode.Text; + PreviewText = Encoding.UTF8.GetString(data); + PreviewImage?.Dispose(); + PreviewImage = null; + HexDumpText = null; + } + + // ========================================================================= + // Search + // ========================================================================= + + private const int MaxNameResults = 200; + private const int MaxContentResults = 1000; + + partial void OnSearchQueryChanged(string? value) + { + // Name search is live; content search only runs on Enter / the Search button + if (!SearchInContents) + RunNameSearch(); + else if (string.IsNullOrWhiteSpace(value)) + ClearSearchResults(); + } + + partial void OnSearchInContentsChanged(bool value) + { + if (!value) + RunNameSearch(); + else + ClearSearchResults(); + } + + partial void OnSelectedSearchResultChanged(SearchResultViewModel? value) + { + if (value != null && value.Alias.Length > 0) + SelectEntryNode(value.Alias); + } + + [RelayCommand] + private async Task Search() + { + if (_archive == null) return; + + if (!SearchInContents) + { + RunNameSearch(); + return; + } + + if (string.IsNullOrEmpty(SearchQuery)) return; + + Regex regex; + try + { + regex = new Regex(SearchQuery, RegexOptions.None, TimeSpan.FromSeconds(5)); + } + catch (ArgumentException ex) + { + if (_window != null) + await Dialogs.ShowMessageAsync(_window, "Invalid Regex", $"Invalid regular expression:\n{ex.Message}"); + return; + } + + IsLoading = true; + try + { + var entries = _archive.Entries.ToList(); + var results = await Task.Run(() => + { + var found = new List(); + foreach (var entry in entries) + { + string text; + try + { + text = Encoding.UTF8.GetString(entry.GetDecompressedData()); + } + catch + { + continue; + } + + int lineNo = 0; + foreach (var rawLine in text.Split('\n')) + { + lineNo++; + var line = rawLine.TrimEnd('\r'); + + bool isMatch; + try + { + isMatch = regex.IsMatch(line); + } + catch (RegexMatchTimeoutException) + { + break; + } + + if (!isMatch) continue; + + var snippet = line.Trim(); + if (snippet.Length > 120) snippet = snippet.Substring(0, 120) + "…"; + found.Add(new SearchResultViewModel + { + Alias = entry.Alias, + Detail = $"line {lineNo}: {snippet}" + }); + + if (found.Count >= MaxContentResults) + return found; + } + } + return found; + }); + + SearchResults.Clear(); + foreach (var r in results) + SearchResults.Add(r); + OnPropertyChanged(nameof(HasSearchResults)); + + SearchStatus = results.Count >= MaxContentResults + ? $"{results.Count} matches (stopped at {MaxContentResults})" + : $"{results.Count} match(es)"; + } + finally + { + IsLoading = false; + } + } + + private void RunNameSearch() + { + SearchResults.Clear(); + + var query = SearchQuery; + if (_archive == null || string.IsNullOrWhiteSpace(query)) + { + SearchStatus = null; + OnPropertyChanged(nameof(HasSearchResults)); + return; + } + + int total = 0; + foreach (var entry in _archive.Entries) + { + if (!entry.Alias.Contains(query, StringComparison.OrdinalIgnoreCase)) continue; + total++; + if (SearchResults.Count < MaxNameResults) + SearchResults.Add(new SearchResultViewModel { Alias = entry.Alias }); + } + + SearchStatus = total > MaxNameResults + ? $"{total} file(s) (showing first {MaxNameResults})" + : $"{total} file(s)"; + OnPropertyChanged(nameof(HasSearchResults)); + } + + private void ClearSearchResults() + { + SearchResults.Clear(); + SearchStatus = null; + SelectedSearchResult = null; + OnPropertyChanged(nameof(HasSearchResults)); + } + + /// + /// Selects the tree node matching the given alias, expanding parent folders along the way. + /// + private void SelectEntryNode(string alias) + { + var parts = alias.Split('/'); + var level = TreeRoots; + EntryTreeNodeViewModel? node = null; + + foreach (var part in parts) + { + node = level.FirstOrDefault(n => n.Name == part); + if (node == null) return; + if (node.IsFolder) + { + node.IsExpanded = true; + level = node.Children; + } + } + + if (node != null && !node.IsFolder) + SelectedNode = node; + } + // ========================================================================= // About // ========================================================================= diff --git a/GsaEditor/ViewModels/SearchResultViewModel.cs b/GsaEditor/ViewModels/SearchResultViewModel.cs new file mode 100644 index 0000000..b856ddb --- /dev/null +++ b/GsaEditor/ViewModels/SearchResultViewModel.cs @@ -0,0 +1,19 @@ +namespace GsaEditor.ViewModels; + +/// +/// A single search hit: a file name match, or a matching line inside a file. +/// +public class SearchResultViewModel +{ + /// + /// Alias of the matching archive entry. + /// + public string Alias { get; init; } = string.Empty; + + /// + /// Match context for content searches (e.g. "line 12: ..."). Empty for name matches. + /// + public string Detail { get; init; } = string.Empty; + + public bool HasDetail => Detail.Length > 0; +} diff --git a/GsaEditor/Views/MainWindow.axaml b/GsaEditor/Views/MainWindow.axaml index 935ba7d..80af9fe 100644 --- a/GsaEditor/Views/MainWindow.axaml +++ b/GsaEditor/Views/MainWindow.axaml @@ -93,10 +93,61 @@ + + + + + + + + + +